diff --git a/AUTHORS b/AUTHORS
index 35da693..d060047 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1103,6 +1103,7 @@
 Timo Witte <timo.witte@gmail.com>
 Ting Shao <ting.shao@intel.com>
 Tobias Soppa <tobias@soppa.me>
+Tobias Soppa <tobias.soppa@code.berlin>
 Tom Callaway <tcallawa@redhat.com>
 Tom Harwood <tfh@skip.org>
 Tomas Popela <tomas.popela@gmail.com>
diff --git a/DEPS b/DEPS
index b29e9e20..4e8d7b1 100644
--- a/DEPS
+++ b/DEPS
@@ -307,7 +307,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': 'eb3a57e73924f5aee91edbeffa08c70aba7110b1',
+  'devtools_frontend_revision': '0c89c093baa32d638ca2f30d1b2900333ec4a973',
   # 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.
@@ -347,7 +347,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': 'c0132622c1ff89370cce6c04c1f06d229e8aefb9',
+  'dawn_revision': 'eda73e3c4e9d380a48df081041e787fda0e26b45',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -680,7 +680,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'KE3HYqVrFpOHT0InB0VOZKXAHKgl3QWwvsvJi3bvKkwC',
+          'version': '0NSMjz4jY4FrYTMdzHDk0drTvFFRnLettSXu5lvpJv0C',
         },
       ],
       'dep_type': 'cipd',
@@ -691,7 +691,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': '5UV30W-zrLzM0JBMnIQlbd46TjODW0KFanrZgiBjyqYC',
+          'version': 'Lh6-b0mM6Xaiw5zCUdUV5MhzSMo-sJciyRf52gVxz4MC',
         },
       ],
       'dep_type': 'cipd',
@@ -767,7 +767,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'zIoBx2j1PxzEKWCcYBQWLEu66f7usW-CNUQOr1ErmJ4C',
+          'version': 'JO4WtrFSgv4hKbrR0kNn-c6rw1p6XQZuWfufbsEhuD4C',
       },
     ],
     'condition': 'checkout_android',
@@ -800,7 +800,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_build_tools/aapt2',
-              'version': 'R2k5wwOlIaS6sjv2TIyHotiPJod-6KqnZO8NH-KFK8sC',
+              'version': 'aKJ5MrSRXjVPtBx2DoBnJtmmjO6W6PkQrTYuBtdu46YC',
           },
       ],
       'condition': 'checkout_android',
@@ -1003,7 +1003,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4b973b6e6e2b3d7c1adfe605b5042fda1042c081',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '699d70d878603ebb3861c8f4487c4b05f5d81643',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1389,7 +1389,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b34dc62800c061e62c78039a60b9efd9786ede89',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '91a6d3a9b815351984230325e644e263c00825f0',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1478,7 +1478,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'LSAHyvH--mg3OcjoWmJXmvjXf4kutf7lnfogQjd1CVcC'
+              'version': '21LVieOtkkse_Rl-9YyxWMe3RIxZ3Gpb_MUUrgwitckC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1618,10 +1618,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'ad1419557298bfa2829818c12ae3bca2795a7c8f',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'b46ab16f9798d2cb78e7f9f34f76d4f2470ba48a',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '97d686891b20622fc5cb04b32665e9739adce068',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '897bf9bff12f61114d05c420fee17324c5d55ebc',
+    Var('webrtc_git') + '/src.git' + '@' + 'a17ec76351cce6efee4880105af7f0cf75ed2fce',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1682,7 +1682,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@adf834fd817669b549f0c8dfe9e49031dc4b96a4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c8d317bc1a9fb9d476c6a663207143d5bd00a4c5',
     'condition': 'checkout_src_internal',
   },
 
@@ -1712,7 +1712,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'jHxeZd98fzCt3yylgt0UnTMgBRvhyUTkf8o5HJ6coZAC',
+        'version': '_233klcfaEq1FPeUvTYlnOcobJDFrtxjR4C0di1KqAgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/strings/ash_strings_nl.xtb b/ash/strings/ash_strings_nl.xtb
index e11b67d..425a5b97 100644
--- a/ash/strings/ash_strings_nl.xtb
+++ b/ash/strings/ash_strings_nl.xtb
@@ -244,6 +244,7 @@
 <translation id="2946119680249604491">Verbinding toevoegen</translation>
 <translation id="2961963223658824723">Er is iets misgegaan. Probeer het over een paar seconden opnieuw.</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="296762781903199866">Kan spraakbestanden in het <ph name="LANGUAGE" /> niet downloaden</translation>
 <translation id="2970920913501714344">Apps, extensies en thema's installeren</translation>
 <translation id="2977598380246111477">Volgend cijfer</translation>
 <translation id="2992327365391326550">De microfoonknop van het apparaat staat uit.</translation>
@@ -348,6 +349,7 @@
 <translation id="370665806235115550">Bezig met laden...</translation>
 <translation id="371370241367527062">Microfoon aan voorzijde</translation>
 <translation id="3713734891607377840">Openen na afronding</translation>
+<translation id="3732269052167349831"><ph name="DESC_TEXT" />: Klik op het dialoogvenster om het resultaat op Google Zoeken te bekijken.</translation>
 <translation id="3742055079367172538">Screenshot gemaakt</translation>
 <translation id="3771549900096082774">Modus voor hoog contrast</translation>
 <translation id="3773700760453577392">Een beheerder heeft geen toestemming gegeven voor toegang tot meerdere accounts voor <ph name="USER_EMAIL" />. Alle gebruikers moeten uitloggen om door te gaan.</translation>
@@ -485,6 +487,7 @@
 <translation id="4696813013609194136">Apparaat ontgrendelen met oudercode</translation>
 <translation id="4702647871202761252">Privacyscherm staat uit</translation>
 <translation id="4705716602320768426">Feedback geven</translation>
+<translation id="4706121060329443414">Download wordt later geprobeerd. Voorlopig wordt spraak naar Google gestuurd voor verwerking.</translation>
 <translation id="4731797938093519117">Toegang door ouders</translation>
 <translation id="4734965478015604180">Horizontaal</translation>
 <translation id="4735498845456076464">De sneltoets <ph name="LAUNCHER_KEY_NAME" /> + cijfer is veranderd. Als je functietoetsen wilt gebruiken, druk je op de <ph name="LAUNCHER_KEY_NAME" />-toets + een toets op de bovenste rij.</translation>
@@ -590,6 +593,7 @@
 <translation id="5600837773213129531">Druk op Ctrl+Alt+Z om gesproken feedback uit te zetten.</translation>
 <translation id="5601503069213153581">Pincode</translation>
 <translation id="5619862035903135339">Op basis van het beheerdersbeleid wordt schermopname uitgezet</translation>
+<translation id="5620281292257375798">Alleen voor intern gebruik</translation>
 <translation id="5625955975703555628">LTE+</translation>
 <translation id="5648021990716966815">Microfoonaansluiting</translation>
 <translation id="5662709761327382534">Microfoon opnemen <ph name="CURRENT_STATE" />. Druk op Enter om microfoonopnamen <ph name="NEW_STATE" /> te zetten.</translation>
@@ -657,6 +661,7 @@
 <translation id="6073451960410192870">Opname stoppen</translation>
 <translation id="607652042414456612">Bluetooth-apparaten in de buurt kunnen je computer vinden als <ph name="NAME" /> met het adres <ph name="ADDRESS" /></translation>
 <translation id="6094290315941448991">Op basis van het beheerdersbeleid wordt schermopname uitgezet als er vertrouwelijke content zichtbaar is</translation>
+<translation id="6114505516289286752">Spraakbestanden in het <ph name="LANGUAGE" /> gedownload</translation>
 <translation id="6119360623251949462"><ph name="CHARGING_STATE" />. <ph name="BATTERY_SAVER_STATE" />.</translation>
 <translation id="612734058257491180">De Google Assistent is niet beschikbaar in een gastsessie.</translation>
 <translation id="6137566720514957455">Dialoogvenster 'Account verwijderen' openen voor <ph name="USER_EMAIL_ADDRESS" /></translation>
@@ -738,6 +743,7 @@
 <translation id="6816797338148849397">Er is informatie met betrekking tot je selectie beschikbaar. Gebruik de pijl-omhoog om deze te openen.</translation>
 <translation id="6818242057446442178">Terug per woord</translation>
 <translation id="6820676911989879663">Neem een pauze</translation>
+<translation id="6836499262298959512">Gevaarlijk bestand</translation>
 <translation id="6837064795450991317">Bureaubladbalk verbergen</translation>
 <translation id="6850010208275816200">Je huidige app wordt op volledig scherm getoond. Als de app om je wachtwoord vraagt, moet je eerst het volledige scherm sluiten.</translation>
 <translation id="6852052252232534364">Klik om te activeren</translation>
@@ -878,6 +884,7 @@
 <translation id="7901405293566323524">Phone Hub</translation>
 <translation id="7902625623987030061">Raak de vingerafdruksensor aan</translation>
 <translation id="7904094684485781019">De beheerder van dit account heeft toegang tot meerdere accounts niet toegestaan.</translation>
+<translation id="7930731167419639574">Spraak wordt nu lokaal verwerkt en Dicteren werkt offline</translation>
 <translation id="7933084174919150729">De Google Assistent is alleen beschikbaar voor het primaire profiel.</translation>
 <translation id="79341161159229895">Account wordt beheerd door <ph name="FIRST_PARENT_EMAIL" /> en <ph name="SECOND_PARENT_EMAIL" /></translation>
 <translation id="793716872548410480">Druk op <ph name="SHORTCUT_KEY_NAME" /> + V om het klembord te bekijken. De laatste 5 items die je hebt gekopieerd, worden opgeslagen op het klembord.</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index a2f0358f..015c5c7 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -137,7 +137,7 @@
 <translation id="1990046457226896323">స్పీచ్ ఫైళ్లు డౌన్‌లోడ్ చేయబడ్డాయి</translation>
 <translation id="1993072747612765854">తాజా <ph name="SYSTEM_APP_NAME" /> అప్‌డేట్ గురించి మరింత తెలుసుకోండి</translation>
 <translation id="1998100899771863792">ప్రస్తుత డెస్క్</translation>
-<translation id="2016340657076538683">సందేశాన్ని టైప్ చేయండి</translation>
+<translation id="2016340657076538683">మెసేజ్‌ను టైప్ చేయండి</translation>
 <translation id="2018630726571919839">ఒక జోక్ చెప్పు</translation>
 <translation id="2021864487439853900">అన్‌లాక్ కోసం క్లిక్ చేయండి</translation>
 <translation id="2047639699071423250">ముఖ్య ఐడియాను జోడించు</translation>
@@ -234,7 +234,7 @@
 <translation id="2841907151129139818">టాబ్లెట్ మోడ్‌కు స్విచ్ చేయబడింది</translation>
 <translation id="2844169650293029770">USB-C పరికరం (ఎడమవైపు ముందు పోర్ట్)</translation>
 <translation id="2865888419503095837">నెట్‌వర్క్ సమాచారం</translation>
-<translation id="2872961005593481000">షట్ డౌన్ చెయ్యండి</translation>
+<translation id="2872961005593481000">షట్ డౌన్ చేయండి</translation>
 <translation id="2878884018241093801">ఇటీవలి అంశాలు ఏవీ లేవు</translation>
 <translation id="2903844815300039659"><ph name="NAME" />కి కనెక్ట్ చేయబడింది, <ph name="STRENGTH" /></translation>
 <translation id="2914580577416829331">స్క్రీన్ క్యాప్చర్‌లు</translation>
diff --git a/ash/strings/ash_strings_uz.xtb b/ash/strings/ash_strings_uz.xtb
index 36e13c6d3..a21d5ad 100644
--- a/ash/strings/ash_strings_uz.xtb
+++ b/ash/strings/ash_strings_uz.xtb
@@ -244,6 +244,7 @@
 <translation id="2946119680249604491">Ulanish qo‘shish</translation>
 <translation id="2961963223658824723">Xatolik yuz berdi. Bir necha soniyadan keyin qayta urining.</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="296762781903199866"><ph name="LANGUAGE" /> nutq fayllari yuklab olinmadi</translation>
 <translation id="2970920913501714344">Ilovalar, kengaytmalar va mavzularni oʻrnating</translation>
 <translation id="2977598380246111477">Keyingi raqam</translation>
 <translation id="2992327365391326550">Qurilmaning mikrofon tugmasi faolsizlantirildi.</translation>
@@ -348,6 +349,7 @@
 <translation id="370665806235115550">Yuklanmoqda…</translation>
 <translation id="371370241367527062">Old mikrofon</translation>
 <translation id="3713734891607377840">Yuklab olinganda ochish</translation>
+<translation id="3732269052167349831"><ph name="DESC_TEXT" />; Natijani Google qidiruvida koʻrish uchun muloqot oynasini bosing.</translation>
 <translation id="3742055079367172538">Ekran suratga olindi</translation>
 <translation id="3771549900096082774">Yuqori kontrastli rejim</translation>
 <translation id="3773700760453577392">Administrator <ph name="USER_EMAIL" /> hisobi uchun bir multi-kirish imkoniyatini o‘chirib qo‘ydi. Hisobga kirishingizdan avval barcha foydalanuvchilar hisobdan chiqishi kerak.</translation>
@@ -485,6 +487,7 @@
 <translation id="4696813013609194136">Ota-ona kodi bilan qurilmani qulfdan chiqarish</translation>
 <translation id="4702647871202761252">Maxfiylik ekrani yoniq emas</translation>
 <translation id="4705716602320768426">Fikr-mulohaza yuborish</translation>
+<translation id="4706121060329443414">Keyinroq yuklab olinadi. Hozir nutq qayta ishlanishi uchun Googlega yuboriladi.</translation>
 <translation id="4731797938093519117">Ota-ona kirishi</translation>
 <translation id="4734965478015604180">Gorizontal</translation>
 <translation id="4735498845456076464"><ph name="LAUNCHER_KEY_NAME" /> + Raqam tezkor tugmasi oʻzgardi. Funksiya tugmalaridan foydalanish uchun <ph name="LAUNCHER_KEY_NAME" /> tugmasi + yuqori qatordagi kalitni bosing.</translation>
@@ -590,6 +593,7 @@
 <translation id="5600837773213129531">Ovozli fikr-mulohaza bildirishni o‘chirish uchun Ctrl + Alt + Z tugmalarini birga bosing.</translation>
 <translation id="5601503069213153581">PIN kod</translation>
 <translation id="5619862035903135339">Administrator ekranni tasvirga olishni taqiqlagan</translation>
+<translation id="5620281292257375798">Maxfiy</translation>
 <translation id="5625955975703555628">LTE+</translation>
 <translation id="5648021990716966815">Mikrofon teshigi</translation>
 <translation id="5662709761327382534">Mikrofon bilan yozib olish <ph name="CURRENT_STATE" />, mikrofon bilan yozib olishni <ph name="NEW_STATE" /> qilish uchun Enter tugmasini bosing</translation>
@@ -657,6 +661,7 @@
 <translation id="6073451960410192870">Yozuvni toʻxtatish</translation>
 <translation id="607652042414456612">Kompyuteringiz yaqin-atrofdagi Bluetooth qurilmalariga <ph name="NAME" /> nomida <ph name="ADDRESS" /> manzilida ko‘rinadi</translation>
 <translation id="6094290315941448991">Maxfiy axborotlar koʻrinib turganda administrator ekranni yozib olishni taqiqlagan</translation>
+<translation id="6114505516289286752"><ph name="LANGUAGE" /> nutq fayllari yuklab olindi</translation>
 <translation id="6119360623251949462"><ph name="CHARGING_STATE" />. <ph name="BATTERY_SAVER_STATE" /></translation>
 <translation id="612734058257491180">Google Assistent mehmon seansida ishlamaydi.</translation>
 <translation id="6137566720514957455"><ph name="USER_EMAIL_ADDRESS" /> hisobini olib tashlash oynasini ochish</translation>
@@ -738,6 +743,7 @@
 <translation id="6816797338148849397">Tanlovga aloqador axborot mavjud. Uni ochish uchun tepaga strelkani bosing.</translation>
 <translation id="6818242057446442178">Bitta soʻz orqaga</translation>
 <translation id="6820676911989879663">Tanaffus qiling</translation>
+<translation id="6836499262298959512">Xavfli fayl</translation>
 <translation id="6837064795450991317">Ish panelini yopish</translation>
 <translation id="6850010208275816200">Joriy ilovangiz butun ekran rejimida. Ilova parol kiritishni soʻrasa, butun ekran rejimidan chiqing.</translation>
 <translation id="6852052252232534364">Faollashtirish</translation>
@@ -878,6 +884,7 @@
 <translation id="7901405293566323524">Phone Hub</translation>
 <translation id="7902625623987030061">Barmoq izi skaneriga tegining</translation>
 <translation id="7904094684485781019">Administrator bu hisobga boshqa hisoblar bilan birdaniga kirishni taqiqlab qo‘ygan.</translation>
+<translation id="7930731167419639574">Nutq qurilmada qayta ishlanadi va ovoz bilan yozish internetsiz ishlaydi</translation>
 <translation id="7933084174919150729">Google Assistent faqat asosiy profilda ishlaydi xolos.</translation>
 <translation id="79341161159229895">Hisobni <ph name="FIRST_PARENT_EMAIL" /> va <ph name="SECOND_PARENT_EMAIL" /> boshqaradi</translation>
 <translation id="793716872548410480">Klipbordni ochish uchun <ph name="SHORTCUT_KEY_NAME" /> + V tugmalarini bosing. Nusxalangan oxirgi 5 ta element klipbordga saqlandi.</translation>
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 806e13fd..b78a100 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -24,9 +24,13 @@
 
 namespace {
 
+void UnmapNow(void* reservation_start,
+              size_t reservation_size,
+              pool_handle giga_cage_pool);
+
 template <bool thread_safe>
-ALWAYS_INLINE DeferredUnmap
-PartitionDirectUnmap(SlotSpanMetadata<thread_safe>* slot_span) {
+ALWAYS_INLINE void PartitionDirectUnmap(
+    SlotSpanMetadata<thread_safe>* slot_span) {
   auto* root = PartitionRoot<thread_safe>::FromSlotSpan(slot_span);
   root->lock_.AssertAcquired();
   auto* extent = PartitionDirectMapExtent<thread_safe>::FromSlotSpan(slot_span);
@@ -43,7 +47,7 @@
     extent->next_extent->prev_extent = extent->prev_extent;
   }
 
-  // The actual decommit is deferred, when releasing the reserved memory region.
+  // The actual decommit is deferred below after releasing the lock.
   root->DecreaseCommittedPages(slot_span->bucket->slot_size);
 
   size_t reservation_size = extent->reservation_size;
@@ -57,8 +61,19 @@
   // we always reserve memory aligned to super page size.
   reservation_start = bits::AlignDown(reservation_start, kSuperPageSize);
 
-  return {reservation_start, reservation_size,
-          root->ChooseGigaCagePool(/* is_direct_map= */ true)};
+  // All the metadata have been updated above, in particular the mapping has
+  // been unlinked. We can safely release the memory outside the lock, which is
+  // important as decommitting memory can be expensive.
+  //
+  // This can create a fake "address space exhaustion" OOM, in the case where
+  // e.g. a large allocation is freed on a thread, and another large one is made
+  // from another *before* UnmapNow() has finished running. In this case the
+  // second one may not find enough space in the GigaCage, and fail. This is
+  // expected to be very rare though, and likely preferable to holding the lock
+  // while releasing the address space.
+  ScopedUnlockGuard<thread_safe> unlock{root->lock_};
+  UnmapNow(reservation_start, reservation_size,
+           root->ChooseGigaCagePool(/* is_direct_map= */ true));
 }
 
 template <bool thread_safe>
@@ -124,7 +139,7 @@
       unused(0) {}
 
 template <bool thread_safe>
-DeferredUnmap SlotSpanMetadata<thread_safe>::FreeSlowPath() {
+void SlotSpanMetadata<thread_safe>::FreeSlowPath() {
 #if DCHECK_IS_ON()
   auto* root = PartitionRoot<thread_safe>::FromSlotSpan(this);
   root->lock_.AssertAcquired();
@@ -133,7 +148,8 @@
   if (LIKELY(num_allocated_slots == 0)) {
     // Slot span became fully unused.
     if (UNLIKELY(bucket->is_direct_mapped())) {
-      return PartitionDirectUnmap(this);
+      PartitionDirectUnmap(this);
+      return;
     }
 #if DCHECK_IS_ON()
     freelist_head->CheckFreeList(bucket->slot_size);
@@ -170,9 +186,8 @@
     // Special case: for a partition slot span with just a single slot, it may
     // now be empty and we want to run it through the empty logic.
     if (UNLIKELY(num_allocated_slots == 0))
-      return FreeSlowPath();
+      FreeSlowPath();
   }
-  return {};
 }
 
 template <bool thread_safe>
@@ -215,7 +230,10 @@
     Decommit(root);
 }
 
-void DeferredUnmap::Unmap() {
+namespace {
+void UnmapNow(void* reservation_start,
+              size_t reservation_size,
+              pool_handle giga_cage_pool) {
   PA_DCHECK(reservation_start && reservation_size > 0);
   if (giga_cage_pool == GetBRPPool()) {
     // In 32-bit mode, the beginning of a reservation may be excluded from the
@@ -261,6 +279,7 @@
   AddressPoolManager::GetInstance()->UnreserveAndDecommit(
       giga_cage_pool, reservation_start, reservation_size);
 }
+}  // namespace
 
 template struct SlotSpanMetadata<ThreadSafe>;
 template struct SlotSpanMetadata<NotThreadSafe>;
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 151a710..63171d28 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -76,23 +76,6 @@
          (extent->number_of_consecutive_super_pages * kSuperPageSize);
 }
 
-// SlotSpanMetadata::Free() defers unmapping a large page until the lock is
-// released. Callers of SlotSpanMetadata::Free() must invoke Run().
-// TODO(1061437): Reconsider once the new locking mechanism is implemented.
-struct DeferredUnmap {
-  void* reservation_start = nullptr;
-  size_t reservation_size = 0;
-  pool_handle giga_cage_pool;
-
-  // In most cases there is no page to unmap and reservation_start == nullptr.
-  // This function is inlined to avoid the overhead of a function call in the
-  // common case.
-  ALWAYS_INLINE void Run();
-
- private:
-  BASE_EXPORT NOINLINE void Unmap();
-};
-
 using QuarantineBitmap =
     ObjectBitmap<kSuperPageSize, kSuperPageAlignment, kAlignment>;
 
@@ -167,9 +150,8 @@
 
   // Public API
   // Note the matching Alloc() functions are in PartitionPage.
-  // Callers must invoke DeferredUnmap::Run() after releasing the lock.
-  BASE_EXPORT NOINLINE DeferredUnmap FreeSlowPath() WARN_UNUSED_RESULT;
-  ALWAYS_INLINE DeferredUnmap Free(void* ptr) WARN_UNUSED_RESULT;
+  BASE_EXPORT NOINLINE void FreeSlowPath();
+  ALWAYS_INLINE void Free(void* ptr);
 
   void Decommit(PartitionRoot<thread_safe>* root);
   void DecommitIfPossible(PartitionRoot<thread_safe>* root);
@@ -715,9 +697,9 @@
 }
 
 template <bool thread_safe>
-ALWAYS_INLINE DeferredUnmap
-SlotSpanMetadata<thread_safe>::Free(void* slot_start) EXCLUSIVE_LOCKS_REQUIRED(
-    PartitionRoot<thread_safe>::FromSlotSpan(this)->lock_) {
+ALWAYS_INLINE void SlotSpanMetadata<thread_safe>::Free(void* slot_start)
+    EXCLUSIVE_LOCKS_REQUIRED(
+        PartitionRoot<thread_safe>::FromSlotSpan(this)->lock_) {
 #if DCHECK_IS_ON()
   auto* root = PartitionRoot<thread_safe>::FromSlotSpan(this);
   root->lock_.AssertAcquired();
@@ -734,13 +716,12 @@
   SetFreelistHead(entry);
   --num_allocated_slots;
   if (UNLIKELY(num_allocated_slots <= 0)) {
-    return FreeSlowPath();
+    FreeSlowPath();
   } else {
     // All single-slot allocations must go through the slow path to
     // correctly update the raw size.
     PA_DCHECK(!CanStoreRawSize());
   }
-  return {};
 }
 
 template <bool thread_safe>
@@ -790,12 +771,6 @@
   next_slot_span = nullptr;
 }
 
-ALWAYS_INLINE void DeferredUnmap::Run() {
-  if (UNLIKELY(reservation_start)) {
-    Unmap();
-  }
-}
-
 enum class QuarantineBitmapType { kMutator, kScanner };
 
 // Returns a quarantine bitmap from a pointer within a normal-bucket super page.
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 2a8873b..5911be8 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -372,8 +372,7 @@
 
   static uint16_t SizeToBucketIndex(size_t size);
 
-  ALWAYS_INLINE internal::DeferredUnmap FreeSlotSpan(void* slot_start,
-                                                     SlotSpan* slot_span)
+  ALWAYS_INLINE void FreeSlotSpan(void* slot_start, SlotSpan* slot_span)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Frees memory, with |slot_start| as returned by |RawAlloc()|.
@@ -1040,7 +1039,7 @@
 }
 
 template <bool thread_safe>
-ALWAYS_INLINE internal::DeferredUnmap PartitionRoot<thread_safe>::FreeSlotSpan(
+ALWAYS_INLINE void PartitionRoot<thread_safe>::FreeSlotSpan(
     void* slot_start,
     SlotSpan* slot_span) {
   total_size_of_allocated_bytes -= slot_span->GetSizeForBookkeeping();
@@ -1088,12 +1087,8 @@
   // Do not move the store above inside the locked section.
   __asm__ __volatile__("" : : "r"(slot_start) : "memory");
 
-  internal::DeferredUnmap deferred_unmap;
-  {
-    ScopedGuard guard{lock_};
-    deferred_unmap = FreeSlotSpan(slot_start, slot_span);
-  }
-  deferred_unmap.Run();
+  ScopedGuard guard{lock_};
+  FreeSlotSpan(slot_start, slot_span);
 }
 
 template <bool thread_safe>
@@ -1123,10 +1118,11 @@
 template <bool thread_safe>
 ALWAYS_INLINE void PartitionRoot<thread_safe>::RawFreeLocked(void* slot_start) {
   SlotSpan* slot_span = SlotSpan::FromSlotStartPtr(slot_start);
-  auto deferred_unmap = FreeSlotSpan(slot_start, slot_span);
-  // Only used with bucketed allocations.
-  PA_DCHECK(!deferred_unmap.reservation_start);
-  deferred_unmap.Run();
+  // Direct-mapped deallocation releases then re-acquires the lock. The caller
+  // may not expect that, but we never call this function on direct-mapped
+  // allocations.
+  PA_DCHECK(!IsDirectMappedBucket(slot_span->bucket));
+  FreeSlotSpan(slot_start, slot_span);
 }
 
 // static
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 091f17b..a458472 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -848,4 +848,9 @@
   SetNeedsPushProperties();
 }
 
+bool AnimationHost::WillCancelScrollAnimation(ElementId element_id) const {
+  return scroll_offset_animations_ &&
+         scroll_offset_animations_->HasPendingCancelUpdate(element_id);
+}
+
 }  // namespace cc
diff --git a/cc/animation/animation_host.h b/cc/animation/animation_host.h
index 224d411..2e85f8c 100644
--- a/cc/animation/animation_host.h
+++ b/cc/animation/animation_host.h
@@ -210,6 +210,7 @@
   bool HasCanvasInvalidation() const override;
   bool HasJSAnimation() const override;
   bool HasSmilAnimation() const override;
+  bool WillCancelScrollAnimation(ElementId element_id) const override;
 
   // Starts/stops throughput tracking represented by |sequence_id|.
   void StartThroughputTracking(TrackedAnimationSequenceId sequence_id);
diff --git a/cc/animation/scroll_offset_animations.cc b/cc/animation/scroll_offset_animations.cc
index 7fb3fe9..f67cf9a 100644
--- a/cc/animation/scroll_offset_animations.cc
+++ b/cc/animation/scroll_offset_animations.cc
@@ -11,7 +11,7 @@
 ScrollOffsetAnimationUpdate::ScrollOffsetAnimationUpdate() = default;
 
 ScrollOffsetAnimationUpdate::ScrollOffsetAnimationUpdate(ElementId element_id)
-    : element_id_(element_id), takeover_(false) {}
+    : element_id_(element_id) {}
 
 ScrollOffsetAnimations::ScrollOffsetAnimations(AnimationHost* animation_host)
     : animation_host_(animation_host) {}
@@ -46,6 +46,20 @@
   animation_host_->SetNeedsPushProperties();
 }
 
+void ScrollOffsetAnimations::AddCancelUpdate(ElementId element_id) {
+  DCHECK(element_id);
+  ScrollOffsetAnimationUpdate update = GetUpdateForElementId(element_id);
+  update.cancel_ = true;
+  element_to_update_map_[element_id] = update;
+  animation_host_->SetNeedsCommit();
+  animation_host_->SetNeedsPushProperties();
+}
+
+bool ScrollOffsetAnimations::HasPendingCancelUpdate(
+    ElementId element_id) const {
+  return GetUpdateForElementId(element_id).cancel_;
+}
+
 bool ScrollOffsetAnimations::HasUpdatesForTesting() const {
   return !element_to_update_map_.empty();
 }
@@ -60,6 +74,8 @@
     const auto& update = kv.second;
     if (update.takeover_)
       animations->ScrollAnimationAbort(true /*needs_completion*/);
+    else if (update.cancel_)
+      animations->ScrollAnimationAbort(false /*needs_completion*/);
     else
       animations->ScrollAnimationApplyAdjustment(update.element_id_,
                                                  update.adjustment_);
diff --git a/cc/animation/scroll_offset_animations.h b/cc/animation/scroll_offset_animations.h
index 3d2e33b..8095174 100644
--- a/cc/animation/scroll_offset_animations.h
+++ b/cc/animation/scroll_offset_animations.h
@@ -27,7 +27,11 @@
 
   // If set to true, abort the currently running impl only scroll offset
   // animation running on cc and finish it on the main thread.
-  bool takeover_;
+  // TODO(crbug.com/1018213): remove.
+  bool takeover_ = false;
+
+  // Abort any currently running impl only scroll offset animation.
+  bool cancel_ = false;
 };
 
 // ScrollOffsetAnimations contains a list of ScrollOffsetAnimationUpdates.
@@ -40,6 +44,8 @@
 
   void AddAdjustmentUpdate(ElementId, gfx::Vector2dF adjustment);
   void AddTakeoverUpdate(ElementId);
+  void AddCancelUpdate(ElementId);
+  bool HasPendingCancelUpdate(ElementId) const;
 
   bool HasUpdatesForTesting() const;
 
diff --git a/cc/test/mock_mutator_host.h b/cc/test/mock_mutator_host.h
index 8cdb567f..04995483 100644
--- a/cc/test/mock_mutator_host.h
+++ b/cc/test/mock_mutator_host.h
@@ -102,6 +102,7 @@
   MOCK_CONST_METHOD0(HasCanvasInvalidation, bool());
   MOCK_CONST_METHOD0(HasJSAnimation, bool());
   MOCK_CONST_METHOD0(MinimumTickInterval, base::TimeDelta());
+  MOCK_CONST_METHOD1(WillCancelScrollAnimation, bool(ElementId element_id));
 };
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index cf54a36..71726d9 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -984,6 +984,9 @@
     const ElementId& id,
     const gfx::ScrollOffset& delta,
     const absl::optional<TargetSnapAreaElementIds>& snap_target_ids) {
+  if (mutator_host_->WillCancelScrollAnimation(id))
+    return;
+
   if (IsUsingLayerLists()) {
     auto& scroll_tree = property_trees()->scroll_tree;
     auto new_offset = scroll_tree.current_scroll_offset(id) + delta;
diff --git a/cc/trees/mutator_host.h b/cc/trees/mutator_host.h
index e0ac5bc..500fbda8 100644
--- a/cc/trees/mutator_host.h
+++ b/cc/trees/mutator_host.h
@@ -177,6 +177,8 @@
   using PendingThroughputTrackerInfos =
       std::vector<PendingThroughputTrackerInfo>;
   virtual PendingThroughputTrackerInfos TakePendingThroughputTrackerInfos() = 0;
+
+  virtual bool WillCancelScrollAnimation(ElementId element_id) const = 0;
 };
 
 class MutatorEvents {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 59ddb71..c189af1 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1011,6 +1011,7 @@
     "//chrome/browser/xsurface:java",
     "//chrome/test:sync_integration_test_support_java",
     "//chrome/test/android:chrome_java_test_support",
+    "//components/autofill/android:full_autofill_java",
     "//components/background_task_scheduler:background_task_scheduler_java",
     "//components/background_task_scheduler:background_task_scheduler_task_ids_java",
     "//components/bookmarks/common/android:bookmarks_java",
@@ -1321,6 +1322,7 @@
     "//chrome/browser/uid/android:javatests",
     "//chrome/browser/util:java",
     "//chrome/browser/version:java",
+    "//chrome/browser/video_tutorials:test_support_java",
     "//chrome/browser/webapps/android:java",
     "//chrome/test:sync_integration_test_support_java",
     "//chrome/test/android:chrome_java_test_pagecontroller",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 1cdfe3d6..0f5e8d6 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -13,6 +13,7 @@
   "junit/src/org/chromium/chrome/browser/app/tab_activity_glue/TabReparentingControllerTest.java",
   "junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java",
   "junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java",
+  "junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java",
   "junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java",
   "junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskSchedulerTest.java",
   "junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java",
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index 2efe4b7..9322b9f647 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -94,6 +94,7 @@
     "//ui/android:ui_full_java",
     "//ui/android:ui_java_test_support",
     "//ui/android:ui_utils_java",
+    "//url:gurl_java",
   ]
 }
 
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index 8804e0e..c587025 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -31,6 +31,7 @@
     "//components/browser_ui/widget/android:java",
     "//components/embedder_support/android:util_java",
     "//components/feature_engagement/public:public_java",
+    "//components/image_fetcher:java",
     "//components/url_formatter/android:url_formatter_java",
     "//content/public/android:content_java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
index 5dfabe5..0c112e7 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
@@ -17,7 +17,7 @@
 import org.chromium.components.autofill.AutofillSuggestion;
 import org.chromium.ui.DropdownItem;
 import org.chromium.ui.base.WindowAndroid;
-
+import org.chromium.url.GURL;
 /**
  * JNI call glue for AutofillExternalDelagate C++ and Java objects.
  * This provides an alternative UI for Autofill suggestions, and replaces AutofillPopupBridge when
@@ -153,15 +153,27 @@
      * @param isDeletable Whether the item can be deleted by the user.
      * @param featureForIPH The In-Product-Help feature used for displaying the bubble for the
      *         suggestion.
+     * @param customIconUrl The url used to fetch the custom icon to be displayed in the autofill
+     *         suggestion chip.
      */
     @CalledByNative
     private static void addToAutofillSuggestionArray(AutofillSuggestion[] array, int index,
             String label, String sublabel, String itemTag, int iconId, int suggestionId,
-            boolean isDeletable, String featureForIPH) {
+            boolean isDeletable, String featureForIPH, GURL customIconUrl) {
         int drawableId = iconId == 0 ? DropdownItem.NO_ICON : iconId;
-        array[index] = new AutofillSuggestion(label, sublabel, itemTag, drawableId,
-                false /* isIconAtStart */, suggestionId, isDeletable, false /* isMultilineLabel */,
-                false /* isBoldLabel */, featureForIPH);
+        array[index] = new AutofillSuggestion.Builder()
+                               .setLabel(label)
+                               .setSubLabel(sublabel)
+                               .setItemTag(itemTag)
+                               .setIconId(drawableId)
+                               .setIsIconAtStart(false)
+                               .setSuggestionId(suggestionId)
+                               .setIsDeletable(isDeletable)
+                               .setIsMultiLineLabel(false)
+                               .setIsBoldLabel(false)
+                               .setFeatureForIPH(featureForIPH)
+                               .setCustomIconUrl(customIconUrl)
+                               .build();
     }
 
     /**
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
index e5735e3..e983ad4 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
@@ -12,11 +12,14 @@
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_SWIPING_IPH;
 
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.google.android.material.tabs.TabLayout;
 
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.keyboard_accessory.R;
 import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.AutofillBarItem;
 import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
@@ -73,14 +76,17 @@
                 }
             }
             chipView.getPrimaryTextView().setText(item.getSuggestion().getLabel());
-            if (!item.getSuggestion().getItemTag().isEmpty()) {
+            if (item.getSuggestion().getItemTag() != null
+                    && !item.getSuggestion().getItemTag().isEmpty()) {
                 chipView.getPrimaryTextView().setContentDescription(
                         item.getSuggestion().getLabel() + " " + item.getSuggestion().getItemTag());
+            } else {
+                chipView.getPrimaryTextView().setContentDescription(
+                        item.getSuggestion().getLabel());
             }
             chipView.getSecondaryTextView().setText(item.getSuggestion().getSublabel());
             chipView.getSecondaryTextView().setVisibility(
                     item.getSuggestion().getSublabel().isEmpty() ? View.GONE : View.VISIBLE);
-            chipView.setIcon(iconId != 0 ? iconId : ChipView.INVALID_ICON_ID, false);
             KeyboardAccessoryData.Action action = item.getAction();
             assert action != null : "Tried to bind item without action. Chose a wrong ViewHolder?";
             chipView.setOnClickListener(view -> {
@@ -93,6 +99,23 @@
                     return true; // Click event consumed!
                 });
             }
+            // If the custom icon url is present, fetch the bitmap from the PersonalDataManager. In
+            // the event that the bitmap is not present in the PersonalDataManager, fall back to the
+            // default `iconId`.
+            Bitmap customIconBitmap = null;
+            if (item.getSuggestion().getCustomIconUrl() != null
+                    && item.getSuggestion().getCustomIconUrl().isValid()) {
+                customIconBitmap = PersonalDataManager.getInstance()
+                                           .getCustomImageForAutofillSuggestionIfAvailable(
+                                                   item.getSuggestion().getCustomIconUrl());
+            }
+            if (customIconBitmap != null) {
+                chipView.setIcon(new BitmapDrawable(mRootViewForIPH.getContext().getResources(),
+                                         customIconBitmap),
+                        false);
+            } else {
+                chipView.setIcon(iconId != 0 ? iconId : ChipView.INVALID_ICON_ID, false);
+            }
         }
     }
 
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
index d1328e7e..c4c08d73 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -20,6 +20,9 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
@@ -34,7 +37,11 @@
 import static org.chromium.ui.test.util.ViewUtils.waitForView;
 
 import android.content.pm.ActivityInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewStub;
 
@@ -50,12 +57,15 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import org.chromium.base.Callback;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -81,6 +91,9 @@
 import org.chromium.ui.ViewProvider;
 import org.chromium.ui.modelutil.LazyConstructionPropertyMcp;
 import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.widget.ChipView;
+import org.chromium.ui.widget.ChromeImageView;
+import org.chromium.url.GURL;
 
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
@@ -96,12 +109,18 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)
 public class KeyboardAccessoryModernViewTest {
+    private static final String CUSTOM_ICON_URL = "https://www.example.com/image.png";
+    private static final Bitmap TEST_CARD_ART_IMAGE =
+            Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
     private PropertyModel mModel;
     private BlockingQueue<KeyboardAccessoryModernView> mKeyboardAccessoryView;
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
+    @Mock
+    PersonalDataManager mMockPersonalDataManager;
+
     private static class TestTracker implements Tracker {
         private boolean mWasDismissed;
         private @Nullable String mEmittedEvent;
@@ -163,7 +182,9 @@
 
     @Before
     public void setUp() throws InterruptedException {
+        MockitoAnnotations.initMocks(this);
         mActivityTestRule.startMainActivityOnBlankPage();
+        PersonalDataManager.setInstanceForTesting(mMockPersonalDataManager);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mModel =
                     KeyboardAccessoryProperties.defaultModelBuilder()
@@ -435,6 +456,112 @@
         CriteriaHelper.pollUiThread(() -> obfuscatedChildAt.get() > -1);
     }
 
+    @Test
+    @MediumTest
+    public void testCustomIconUrlSet_imageReturnedByPersonalDataManager_customIconSetOnChipView()
+            throws InterruptedException {
+        GURL customIconUrl = mock(GURL.class);
+        when(customIconUrl.isValid()).thenReturn(true);
+        when(customIconUrl.getSpec()).thenReturn(CUSTOM_ICON_URL);
+        // Return the cached image when
+        // PersonalDataManager.getCustomImageForAutofillSuggestionIfAvailable is called for the
+        // above url.
+        when(mMockPersonalDataManager.getCustomImageForAutofillSuggestionIfAvailable(any()))
+                .thenReturn(TEST_CARD_ART_IMAGE);
+        // Create an autofill suggestion and set the `customIconUrl`.
+        AutofillBarItem customIconItem = new AutofillBarItem(
+                getDefaultAutofillSuggestionBuilder().setCustomIconUrl(customIconUrl).build(),
+                new KeyboardAccessoryData.Action("", AUTOFILL_SUGGESTION, unused -> {}));
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(VISIBLE, true);
+            mModel.get(BAR_ITEMS).set(new BarItem[] {customIconItem, createTabs()});
+        });
+        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+
+        CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
+        CriteriaHelper.pollUiThread(() -> {
+            ChipView chipView = (ChipView) view.mBarItemsView.getChildAt(0);
+            ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0);
+            return ((BitmapDrawable) iconImageView.getDrawable())
+                    .getBitmap()
+                    .equals(TEST_CARD_ART_IMAGE);
+        });
+    }
+
+    @Test
+    @MediumTest
+    public void testCustomIconUrlSet_imageNotCachedInPersonalDataManager_defaultIconSetOnChipView()
+            throws InterruptedException {
+        GURL customIconUrl = mock(GURL.class);
+        when(customIconUrl.isValid()).thenReturn(true);
+        when(customIconUrl.getSpec()).thenReturn(CUSTOM_ICON_URL);
+        // Return the response of PersonalDataManager.getCustomImageForAutofillSuggestionIfAvailable
+        // to null to indicate that the image is not present in the cache.
+        when(mMockPersonalDataManager.getCustomImageForAutofillSuggestionIfAvailable(any()))
+                .thenReturn(null);
+        AutofillBarItem customIconItem = new AutofillBarItem(
+                getDefaultAutofillSuggestionBuilder().setCustomIconUrl(customIconUrl).build(),
+                new KeyboardAccessoryData.Action("", AUTOFILL_SUGGESTION, unused -> {}));
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(VISIBLE, true);
+            mModel.get(BAR_ITEMS).set(new BarItem[] {customIconItem, createTabs()});
+        });
+        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+
+        CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
+        CriteriaHelper.pollUiThread(() -> {
+            ChipView chipView = (ChipView) view.mBarItemsView.getChildAt(0);
+            ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0);
+            Drawable expectedIcon = mActivityTestRule.getActivity().getResources().getDrawable(
+                    R.drawable.visa_card);
+            return getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()));
+        });
+    }
+
+    @Test
+    @MediumTest
+    public void testCustomIconUrlNotSet_defaultIconSetOnChipView() throws InterruptedException {
+        // Create an autofill suggestion without setting the `customIconUrl`.
+        AutofillBarItem itemWithoutCustomIconUrl =
+                new AutofillBarItem(getDefaultAutofillSuggestionBuilder().build(),
+                        new KeyboardAccessoryData.Action("", AUTOFILL_SUGGESTION, unused -> {}));
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.set(VISIBLE, true);
+            mModel.get(BAR_ITEMS).set(new BarItem[] {itemWithoutCustomIconUrl, createTabs()});
+        });
+        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+
+        CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
+        CriteriaHelper.pollUiThread(() -> {
+            ChipView chipView = (ChipView) view.mBarItemsView.getChildAt(0);
+            ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0);
+            Drawable expectedIcon = mActivityTestRule.getActivity().getResources().getDrawable(
+                    R.drawable.visa_card);
+            return getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()));
+        });
+    }
+
+    private static AutofillSuggestion.Builder getDefaultAutofillSuggestionBuilder() {
+        return new AutofillSuggestion.Builder()
+                .setLabel("Johnathan")
+                .setSubLabel("Smith")
+                .setIconId(R.drawable.visa_card)
+                .setSuggestionId(70000);
+    }
+
+    // Convert a drawable to a Bitmap for comparison.
+    private static Bitmap getBitmap(Drawable drawable) {
+        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return bitmap;
+    }
+
     private ViewInteraction waitForHelpBubble(Matcher<View> matcher) {
         View mainDecorView = mActivityTestRule.getActivity().getWindow().getDecorView();
         return onView(isRoot())
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 94d3023..2eec70f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -5,10 +5,13 @@
 package org.chromium.chrome.browser.autofill;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.text.format.DateUtils;
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.Callback;
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -17,14 +20,21 @@
 import org.chromium.chrome.browser.autofill.settings.AutofillEditorBase;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileKey;
+import org.chromium.components.image_fetcher.ImageFetcher;
+import org.chromium.components.image_fetcher.ImageFetcherConfig;
+import org.chromium.components.image_fetcher.ImageFetcherFactory;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.url.GURL;
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * Android wrapper of the PersonalDataManager which provides access from the Java
@@ -37,6 +47,7 @@
  */
 @JNINamespace("autofill")
 public class PersonalDataManager {
+    private static final String TAG = "PersonalDataManager";
 
     /**
      * Observer of PersonalDataManager events.
@@ -546,15 +557,17 @@
         // the card in PaymentMethods in Settings.
         private String mCardLabel;
         private String mNickname;
+        private GURL mCardArtUrl;
 
         @CalledByNative("CreditCard")
         public static CreditCard create(String guid, String origin, boolean isLocal,
                 boolean isCached, String name, String number, String mObfuscatedNumber,
                 String month, String year, String basicCardIssuerNetwork, int iconId,
-                String billingAddressId, String serverId, String cardLabel, String nickname) {
+                String billingAddressId, String serverId, String cardLabel, String nickname,
+                GURL cardArtUrl) {
             return new CreditCard(guid, origin, isLocal, isCached, name, number, mObfuscatedNumber,
                     month, year, basicCardIssuerNetwork, iconId, billingAddressId, serverId,
-                    cardLabel, nickname);
+                    cardLabel, nickname, cardArtUrl);
         }
 
         public CreditCard(String guid, String origin, boolean isLocal, boolean isCached,
@@ -563,13 +576,13 @@
                 String serverId) {
             this(guid, origin, isLocal, isCached, name, number, obfuscatedNumber, month, year,
                     basicCardIssuerNetwork, issuerIconDrawableId, billingAddressId, serverId,
-                    /* cardLabel= */ obfuscatedNumber, /* nickname= */ "");
+                    /* cardLabel= */ obfuscatedNumber, /* nickname= */ "", /* cardArtUrl= */ null);
         }
 
         public CreditCard(String guid, String origin, boolean isLocal, boolean isCached,
                 String name, String number, String obfuscatedNumber, String month, String year,
                 String basicCardIssuerNetwork, int issuerIconDrawableId, String billingAddressId,
-                String serverId, String cardLabel, String nickname) {
+                String serverId, String cardLabel, String nickname, GURL cardArtUrl) {
             mGUID = guid;
             mOrigin = origin;
             mIsLocal = isLocal;
@@ -585,6 +598,7 @@
             mServerId = serverId;
             mCardLabel = cardLabel;
             mNickname = nickname;
+            mCardArtUrl = cardArtUrl;
         }
 
         public CreditCard() {
@@ -672,6 +686,11 @@
             return mNickname;
         }
 
+        @CalledByNative("CreditCard")
+        public GURL getCardArtUrl() {
+            return mCardArtUrl;
+        }
+
         public void setGUID(String guid) {
             mGUID = guid;
         }
@@ -720,6 +739,10 @@
             mNickname = nickname;
         }
 
+        public void setCardArtUrl(GURL cardArtUrl) {
+            mCardArtUrl = cardArtUrl;
+        }
+
         public boolean hasValidCreditCardExpirationDate() {
             if (mMonth.isEmpty() || mYear.isEmpty()) return false;
 
@@ -750,6 +773,9 @@
     private final long mPersonalDataManagerAndroid;
     private final List<PersonalDataManagerObserver> mDataObservers =
             new ArrayList<PersonalDataManagerObserver>();
+    private final Map<String, Bitmap> mCreditCardArtImages = new HashMap<>();
+    private ImageFetcher mImageFetcher = ImageFetcherFactory.createImageFetcher(
+            ImageFetcherConfig.DISK_CACHE_ONLY, ProfileKey.getLastUsedRegularProfileKey());
 
     private PersonalDataManager() {
         // Note that this technically leaks the native object, however, PersonalDataManager
@@ -766,6 +792,7 @@
         for (PersonalDataManagerObserver observer : mDataObservers) {
             observer.onPersonalDataChanged();
         }
+        fetchCreditCardArtImages();
     }
 
     /**
@@ -1075,6 +1102,11 @@
                 mPersonalDataManagerAndroid, PersonalDataManager.this);
     }
 
+    @VisibleForTesting
+    public static void setInstanceForTesting(PersonalDataManager manager) {
+        sManager = manager;
+    }
+
     /**
      * Starts loading the address validation rules for the specified {@code regionCode}.
      *
@@ -1267,6 +1299,50 @@
         return UserPrefs.get(Profile.getLastUsedRegularProfile());
     }
 
+    private void fetchCreditCardArtImages() {
+        for (CreditCard card : getCreditCardsToSuggest(/*includeServerCards= */ true)) {
+            // Fetch the image using the ImageFetcher only if it is not present in the cache.
+            if (card.getCardArtUrl() != null && card.getCardArtUrl().isValid()
+                    && !mCreditCardArtImages.containsKey(card.getCardArtUrl().getSpec())) {
+                fetchImage(card.getCardArtUrl(),
+                        bitmap -> mCreditCardArtImages.put(card.getCardArtUrl().getSpec(), bitmap));
+            }
+        }
+    }
+
+    /**
+     * Return the card art image for the given `cardArtUrl`.
+     *
+     * @param customImageUrl  URL of the image. If the image is available, it is returned, otherwise
+     *         it is fetched from this URL.
+     * @return Bitmap if found in the local cache, else return null.
+     */
+    public Bitmap getCustomImageForAutofillSuggestionIfAvailable(GURL customImageUrl) {
+        if (mCreditCardArtImages.containsKey(customImageUrl.getSpec())) {
+            return mCreditCardArtImages.get(customImageUrl.getSpec());
+        }
+        // Schedule the fetching of image and return null so that the UI thread does not have to
+        // wait and can show the default network icon.
+        fetchImage(customImageUrl,
+                bitmap -> mCreditCardArtImages.put(customImageUrl.getSpec(), bitmap));
+        return null;
+    }
+
+    @VisibleForTesting
+    public void setImageFetcherForTesting(ImageFetcher imageFetcher) {
+        this.mImageFetcher = imageFetcher;
+    }
+
+    private void fetchImage(GURL customImageUrl, Callback<Bitmap> callback) {
+        if (!customImageUrl.isValid()) {
+            Log.w(TAG, "Tried to fetch an invalid url %s", customImageUrl.getSpec());
+            return;
+        }
+        ImageFetcher.Params params = ImageFetcher.Params.create(
+                customImageUrl.getSpec(), ImageFetcher.AUTOFILL_CARD_ART_UMA_CLIENT_NAME);
+        mImageFetcher.fetchImage(params, bitmap -> callback.onResult(bitmap));
+    }
+
     @NativeMethods
     interface Natives {
         long init(PersonalDataManager caller);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMessageUiControllerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMessageUiControllerImpl.java
index 08fb07ad..2ebbb22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMessageUiControllerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMessageUiControllerImpl.java
@@ -753,8 +753,8 @@
         assert ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_PROGRESS_MESSAGE);
 
         Tab currentTab = mActivityTabProvider.get();
-        boolean shouldShowMessage =
-                currentTab != null && (info.forceShow || mPropertyModel != null);
+        boolean shouldShowMessage = currentTab != null && currentTab.getWebContents() != null
+                && (info.forceShow || mPropertyModel != null);
         if (!shouldShowMessage) return;
 
         recordMessageState(state, info);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
index 59ac7c4b..4782979f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -6,6 +6,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Bitmap;
+
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -24,8 +28,11 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.ValueWithStatus;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.video_tutorials.test.TestImageFetcher;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.url.GURL;
 
 import java.util.LinkedList;
 import java.util.List;
@@ -38,6 +45,9 @@
 @Batch(Batch.PER_CLASS)
 @Batch.SplitByFeature
 public class PersonalDataManagerTest {
+    private static final Bitmap TEST_CARD_ART_IMAGE =
+            Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+
     @Rule
     public final ChromeBrowserTestRule mChromeBrowserTestRule = new ChromeBrowserTestRule();
 
@@ -49,6 +59,10 @@
     @Before
     public void setUp() {
         mHelper = new AutofillTestHelper();
+        TestThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> PersonalDataManager.getInstance().setImageFetcherForTesting(
+                                new TestImageFetcher(TEST_CARD_ART_IMAGE)));
     }
 
     @After
@@ -197,6 +211,27 @@
     @Test
     @SmallTest
     @Feature({"Autofill"})
+    public void testCreditCardWithCardArtUrl_imageDownloaded() throws TimeoutException {
+        GURL cardArtUrl = new GURL("http://google.com/test.png");
+        CreditCard cardWithCardArtUrl = new CreditCard(/* guid= */ "serverGuid", /* origin= */ "",
+                /* isLocal= */ false, /* isCached= */ false, "John Doe Server", "41111111111111111",
+                /* obfuscatedCardNumber= */ "", "3", "2019", "Visa", /* issuerIconDrawableId= */ 0,
+                /* billingAddressId= */ "",
+                /* serverId= */ "serverId");
+        cardWithCardArtUrl.setCardArtUrl(cardArtUrl);
+
+        mHelper.addServerCreditCard(cardWithCardArtUrl);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            assertEquals(TEST_CARD_ART_IMAGE,
+                    PersonalDataManager.getInstance()
+                            .getCustomImageForAutofillSuggestionIfAvailable(cardArtUrl));
+        });
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Autofill"})
     public void testAddAndDeleteCreditCard() throws TimeoutException {
         CreditCard card = createLocalCreditCard("Visa", "1234123412341234", "5", "2020");
         card.setOrigin("Chrome settings");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java
index 3406cad..efc8b13 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java
@@ -9,6 +9,7 @@
 
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.espresso.intent.Intents;
+import androidx.test.espresso.intent.rule.IntentsTestRule;
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -18,7 +19,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.params.ParameterAnnotations;
 import org.chromium.base.test.params.ParameterProvider;
 import org.chromium.base.test.params.ParameterSet;
@@ -57,9 +57,10 @@
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 public class HistoryActivityScrollingTest {
     // clang-format on
+    // TODO(crbug.com/1238144): Migrate to BaseActivityTestRule.
     @Rule
-    public BaseActivityTestRule<HistoryActivity> mActivityTestRule =
-            new BaseActivityTestRule<>(HistoryActivity.class);
+    public IntentsTestRule<HistoryActivity> mActivityTestRule =
+            new IntentsTestRule<>(HistoryActivity.class, false, false);
 
     @ParameterAnnotations.ClassParameter
     private static List<ParameterSet> sClassParams = new TestParamsProvider().getParameters();
@@ -153,13 +154,15 @@
 
     @After
     public void tearDown() {
-        Intents.release();
+        if (mActivityTestRule.getActivity() == null) {
+            // IntentsTestRule assumes the Activity was started when tearing down the rule, so we
+            // need to work around that.
+            Intents.init();
+        }
     }
 
     private void launchHistoryActivity() {
-        mActivityTestRule.launchActivity(null);
-        HistoryActivity activity = mActivityTestRule.getActivity();
-        Intents.init();
+        HistoryActivity activity = mActivityTestRule.launchActivity(null);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mHistoryManager = activity.getHistoryManagerForTests();
             mAdapter = mHistoryManager.getContentManagerForTests().getAdapter();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java
new file mode 100644
index 0000000..c910c512
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+package org.chromium.chrome.browser.autofill;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.components.autofill.AutofillSuggestion;
+import org.chromium.url.GURL;
+
+/** Unit tests for {@link AutofillSuggestion} */
+@RunWith(BaseRobolectricTestRunner.class)
+public class AutofillSuggestionTest {
+    @Test
+    @SmallTest
+    public void testAutofillSuggestion_toBuilder() {
+        AutofillSuggestion suggestion = new AutofillSuggestion("label", "sub_label", "item_tag", 1,
+                true, 1, true, true, true, "feature_for_iph", mock(GURL.class));
+        assertEquals(suggestion.toBuilder().build(), suggestion);
+    }
+}
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 610dc845..514ff5c 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -49,7 +49,7 @@
                   android:exported="true"
                   android:relinquishTaskIdentity="true">
             {{#intent_filters}}
-            <intent-filter>
+            <intent-filter android:autoVerify="true">
                 <action android:name="android.intent.action.VIEW"></action>
                 <category android:name="android.intent.category.DEFAULT"></category>
                 <category android:name="android.intent.category.BROWSABLE"></category>
diff --git a/chrome/android/webapk/shell_apk/current_version/current_version.gni b/chrome/android/webapk/shell_apk/current_version/current_version.gni
index e583b1a..679b28b 100644
--- a/chrome/android/webapk/shell_apk/current_version/current_version.gni
+++ b/chrome/android/webapk/shell_apk/current_version/current_version.gni
@@ -12,4 +12,4 @@
 # //chrome/android/webapk/shell_apk:webapk is changed. This includes
 # Java files, Android resource files and AndroidManifest.xml. Does not affect
 # Chrome.apk
-current_shell_apk_version = 141
+current_shell_apk_version = 142
diff --git a/chrome/app/chrome.cml b/chrome/app/chrome.cml
index 79d491d..2f4ddf8 100644
--- a/chrome/app/chrome.cml
+++ b/chrome/app/chrome.cml
@@ -8,12 +8,23 @@
         {
             protocol: [
                 "fuchsia.ui.app.ViewProvider",
-                "fuchsia.ui.app.TemporaryFlatlandViewProvider",
             ],
         },
     ],
     use: [
         {
+            directory: "cache",
+            from: "parent",
+            path: "/cache",
+            rights: ["rw*"],
+        },
+        {
+            directory: "data",
+            from: "parent",
+            path: "/data",
+            rights: ["rw*"],
+        },
+        {
             protocol: [
                 "fuchsia.deprecatedtimezone.Timezone",
                 "fuchsia.device.NameProvider",
@@ -34,7 +45,6 @@
         {
             protocol: [
                 "fuchsia.ui.app.ViewProvider",
-                "fuchsia.ui.app.TemporaryFlatlandViewProvider",
             ],
             from: "self",
         },
diff --git a/chrome/app/chrome_v1.cmx b/chrome/app/chrome_v1.cmx
index f10a4eb..081d573 100644
--- a/chrome/app/chrome_v1.cmx
+++ b/chrome/app/chrome_v1.cmx
@@ -6,6 +6,8 @@
     "features": [
       "config-data",
       "deprecated-ambient-replace-as-executable",
+      "isolated-cache-storage",
+      "isolated-persistent-storage",
       "root-ssl-certificates",
       "vulkan"
     ],
diff --git a/chrome/app/resources/chromium_strings_nl.xtb b/chrome/app/resources/chromium_strings_nl.xtb
index 23229b2e..dfb5d785 100644
--- a/chrome/app/resources/chromium_strings_nl.xtb
+++ b/chrome/app/resources/chromium_strings_nl.xtb
@@ -256,6 +256,7 @@
 <translation id="7937630085815544518">Je bent ingelogd bij Chromium als <ph name="USER_EMAIL_ADDRESS" />. Gebruik hetzelfde account om opnieuw in te loggen.</translation>
 <translation id="7975919845073681630">Dit is een tweede installatie van Chromium en kan niet als standaardbrowser worden ingesteld.</translation>
 <translation id="8013436988911883588">Zodra Chromium toegang heeft, kunnen websites je om toegang vragen.</translation>
+<translation id="8045118833343856403">De volgende accounts zijn niet ingelogd bij Chromium-profielen. Als je een account wilt gebruiken in een ander profiel, verwijder je eerst dat profiel.</translation>
 <translation id="81770708095080097">Dit bestand is gevaarlijk en is daarom door Chromium geblokkeerd.</translation>
 <translation id="8248265253516264921">Als een afbeelding geen nuttige beschrijving bevat, probeert Chromium je er een te geven. Afbeeldingen worden naar Google gestuurd om beschrijvingen te maken. Je kunt dit op elk gewenst moment uitzetten in Instellingen.</translation>
 <translation id="8266560134891435528">Chromium kan je wachtwoorden niet checken omdat je niet bent ingelogd.</translation>
diff --git a/chrome/app/resources/chromium_strings_te.xtb b/chrome/app/resources/chromium_strings_te.xtb
index d2820ab9..189f58f 100644
--- a/chrome/app/resources/chromium_strings_te.xtb
+++ b/chrome/app/resources/chromium_strings_te.xtb
@@ -194,7 +194,7 @@
 <translation id="6570579332384693436">అక్షరక్రమ లోపాలను పరిష్కరించడానికి, మీరు వచన ఫీల్డ్‌లలో టైప్ చేసే వచనాన్ని, Chromium Googleకి పంపుతుంది</translation>
 <translation id="6598877126913850652">Chromium నోటిఫికేషన్ సెట్టింగ్‌లకు వెళ్లు</translation>
 <translation id="6613594504749178791">మీ మార్పులు మీరు Chromiumని మరుసటిసారి ప్రారంభించినప్పుడు ప్రభావాన్ని చూపుతాయి.</translation>
-<translation id="6676384891291319759">ఇంటర్నెట్‌ను ఆక్సెస్ చెయ్యండి</translation>
+<translation id="6676384891291319759">ఇంటర్నెట్‌ను ఆక్సెస్ చేయండి</translation>
 <translation id="6717134281241384636">మీ ప్రొఫైల్, కొత్త Chromium వెర్షన్‌కు చెందినది కాబట్టి, దీనిని ఉపయోగించడం సాధ్యపడదు.
 
 కొన్ని ఫీచర్‌లు అందుబాటులో ఉండకపోవచ్చు. దయచేసి వేరొక ప్రొఫైల్ డైరెక్టరీని పేర్కొనండి లేదా Chromium యొక్క కొత్త వెర్షన్‌ను ఉపయోగించండి.</translation>
diff --git a/chrome/app/resources/chromium_strings_uz.xtb b/chrome/app/resources/chromium_strings_uz.xtb
index 3dd715e..f9913918 100644
--- a/chrome/app/resources/chromium_strings_uz.xtb
+++ b/chrome/app/resources/chromium_strings_uz.xtb
@@ -254,6 +254,7 @@
 <translation id="7937630085815544518">Avvallari siz Chromium‘ga <ph name="USER_EMAIL_ADDRESS" /> hisobidan kirgandingiz. O‘sha hisobdan foydalanib yana qaytadan kiring.</translation>
 <translation id="7975919845073681630">Chromium takroran o‘rnatilgan, shuning uchun u asosiy brauzer bo‘la olmaydi.</translation>
 <translation id="8013436988911883588">Chromium saytlarga ulanganda sizdan ruxsat so‘raydi.</translation>
+<translation id="8045118833343856403">Quyidagi hisoblar hech qaysi Chromium profiliga kirmagan. Hisobni boshqa profilda ishlatishni xohlasangiz, avval u profilni olib tashlang.</translation>
 <translation id="81770708095080097">Bu fayl xavfli edi va u Chromium tomonidan bloklandi.</translation>
 <translation id="8248265253516264921">Agar rasmga foydali tavsif berilmagan boʻlsa, Chromium uni sizga tavsiflaydi. Tavsif yaratish uchun rasmlar Googlega yuboriladi. Bu sozlamani istalgan vaqtda faolsizlantirish mumkin.</translation>
 <translation id="8266560134891435528">Chromium parollaringizni faqat hisobingizga kirganingizdan keyin tekshira oladi</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index fe47303..a760714 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -159,6 +159,7 @@
 <translation id="1165039591588034296">Fout</translation>
 <translation id="1166212789817575481">Tabbladen aan de rechterkant sluiten</translation>
 <translation id="1166583374608765787">Naamupdate bekijken</translation>
+<translation id="1166596238782048887"><ph name="TAB_TITLE" /> hoort bij bureau <ph name="DESK_TITLE" /></translation>
 <translation id="1168020859489941584">Openen in <ph name="TIME_REMAINING" />...</translation>
 <translation id="1170288591054440704">Vragen als een site lettertypen wilt gebruiken die op je apparaat zijn geïnstalleerd</translation>
 <translation id="1171135284592304528">Markeer het object met toetsenbordfocus wanneer dit wordt gewijzigd</translation>
@@ -617,6 +618,7 @@
 <translation id="1640235262200048077"><ph name="IME_NAME" /> werkt nog niet in Linux-apps</translation>
 <translation id="1640283014264083726">PKCS nr. 1 MD4 met RSA-encryptie</translation>
 <translation id="1641113438599504367">Safe Browsing</translation>
+<translation id="1642492862748815878">Verbonden met <ph name="DEVICE" /> en <ph name="NUMBER_OF_DEVICES" /> andere bluetooth-apparaten</translation>
 <translation id="1642494467033190216">Je moet rootfs-beveiliging verwijderen en opnieuw opstarten voordat je andere foutopsporingsfuncties kunt aanzetten.</translation>
 <translation id="1643072738649235303">X9.62 ECDSA-handtekening met SHA-1</translation>
 <translation id="1643921258693943800">Als je Dichtbij delen wilt gebruiken, zet je bluetooth en wifi aan</translation>
@@ -1819,6 +1821,7 @@
 <translation id="2885378588091291677">Taakbeheer</translation>
 <translation id="2885729872133513017">Er is een probleem opgetreden bij het decoderen van de serverreactie.</translation>
 <translation id="2886771036282400576">• <ph name="PERMISSION" /></translation>
+<translation id="288734198558082692"><ph name="DEVICE" /> en <ph name="NUMBER_OF_DEVICES" /> andere</translation>
 <translation id="2889064240420137087">Link openen met...</translation>
 <translation id="2891922230654533301">Je apparaat gebruiken om in te loggen bij <ph name="APP_NAME" />?</translation>
 <translation id="2893168226686371498">Standaardbrowser</translation>
@@ -2753,6 +2756,7 @@
 <translation id="3884152383786131369">Voor webcontent die in meerdere talen beschikbaar is, wordt de eerste ondersteunde taal in deze lijst gebruikt. Deze voorkeuren worden gesynchroniseerd met je browserinstellingen. <ph name="BEGIN_LINK_LEARN_MORE" />Meer informatie<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="3885112598747515383">Updates worden beheerd door je beheerder</translation>
 <translation id="3886446263141354045">Je verzoek voor toegang tot deze website is verzonden naar <ph name="NAME" /></translation>
+<translation id="3887022758415973389">Apparaatlijst tonen</translation>
 <translation id="3888053818972567950"><ph name="WEB_DRIVE" />-verbinding</translation>
 <translation id="3888550877729210209">Notities maken met <ph name="LOCK_SCREEN_APP_NAME" /></translation>
 <translation id="3888586133700543064">Deze informatie biedt ons meer inzicht in je probleem met de Assistent. De informatie wordt maximaal 90 dagen opgeslagen en de toegang is beperkt tot de toepasselijke technische en feedbackteams.</translation>
@@ -3463,6 +3467,7 @@
 <translation id="4662373422909645029">Cijfers niet toegestaan</translation>
 <translation id="4662788913887017617">Deze bookmark delen met je iPhone</translation>
 <translation id="4663373278480897665">Camera toegestaan</translation>
+<translation id="4664289193573249666">Beveiligde DNS beheren in instellingen van Chrome OS</translation>
 <translation id="4664482161435122549">Fout bij exporteren van PKCS #12</translation>
 <translation id="4665014895760275686">Fabrikant</translation>
 <translation id="4665446389743427678">Alle gegevens die zijn opgeslagen door <ph name="SITE" />, worden verwijderd.</translation>
@@ -5993,6 +5998,7 @@
 <translation id="7478623944308207463">Je apps en instellingen worden gesynchroniseerd voor alle Chrome OS-apparaten waarop je bent ingelogd met je Google-account. Ga naar de <ph name="LINK_BEGIN" />Chrome-instellingen<ph name="LINK_END" /> voor opties voor browsersynchronisatie.</translation>
 <translation id="7478658909253570368">Niet toestaan dat sites verbinding maken met seriële poorten</translation>
 <translation id="7479221278376295180">Gebruikersoverzicht van opslagruimte</translation>
+<translation id="747981547666531654">Verbonden met de bluetooth-apparaten <ph name="FIRST_DEVICE" /> en <ph name="SECOND_DEVICE" /></translation>
 <translation id="7481312909269577407">Vooruit</translation>
 <translation id="7481358317100446445">Klaar</translation>
 <translation id="748138892655239008">Basisvereisten voor certificaten</translation>
@@ -6045,6 +6051,7 @@
 <translation id="7531771599742723865">Apparaat in gebruik</translation>
 <translation id="7531779363494549572">Ga naar Instellingen &gt; Apps en meldingen &gt; Meldingen.</translation>
 <translation id="7532009420053991888"><ph name="LINUX_APP_NAME" /> reageert niet. Selecteer 'Nu sluiten' om de app te sluiten.</translation>
+<translation id="7535730537657706072">Sluit alle incognitotabbladen om de incognito-browsegeschiedenis op je apparaat te wissen</translation>
 <translation id="7535791657097741517">Licht thema aanzetten</translation>
 <translation id="7537451260744431038">Sites mogen geen cookies gebruiken om de browsefunctionaliteit te verbeteren, bijvoorbeeld door je ingelogd te houden of door artikelen in je winkelwagen te onthouden</translation>
 <translation id="753769905878158714">Geef in de adresbalk het zoekwoord op voor de website die je wilt zoeken. Gebruik daarna een sneltoets om door te gaan.</translation>
@@ -6660,6 +6667,7 @@
 <translation id="8138217203226449454">Wilde je je zoekprovider wijzigen?</translation>
 <translation id="8138997515734480534"><ph name="VM_NAME" />-status</translation>
 <translation id="8139447493436036221">Google Drive-bestanden</translation>
+<translation id="8140070492745508800"><ph name="FIRST_DEVICE" />, <ph name="SECOND_DEVICE" /></translation>
 <translation id="8141584439523427891">Wordt nu geopend in een alternatieve browser</translation>
 <translation id="8141725884565838206">Je wachtwoorden beheren</translation>
 <translation id="814204052173971714">{COUNT,plural, =1{een video}other{# video's}}</translation>
@@ -7376,6 +7384,7 @@
 <translation id="8909782404367982052">Slepen om afbeeldingen te zoeken met Google Lens</translation>
 <translation id="8909833622202089127">Site houdt je locatie bij</translation>
 <translation id="8910222113987937043">Wijzigingen in je bookmarks, geschiedenis, wachtwoorden en andere instellingen worden niet meer gesynchroniseerd met je Google-account. Je bestaande gegevens blijven echter opgeslagen in je Google-account en kunnen worden beheerd via <ph name="BEGIN_LINK" />Google Dashboard<ph name="END_LINK" />.</translation>
+<translation id="8910987510378294980">Apparaatlijst verbergen</translation>
 <translation id="8912362522468806198">Google-account</translation>
 <translation id="8912793549644936705">Uitrekken</translation>
 <translation id="8912810933860534797">Automatisch scannen aanzetten</translation>
@@ -7493,6 +7502,7 @@
 <translation id="9033765790910064284">Toch doorgaan</translation>
 <translation id="9033857511263905942">&amp;Plakken</translation>
 <translation id="903480517321259405">Typ de pincode nog een keer</translation>
+<translation id="9037054491984310631">Verbonden met het bluetooth-apparaat <ph name="DEVICE" /></translation>
 <translation id="9037640663275993951">Apparaat is niet toegestaan</translation>
 <translation id="9037818663270399707">Je verbinding is niet privé voor alle netwerkverkeer</translation>
 <translation id="9037965129289936994">Origineel tonen</translation>
@@ -7573,6 +7583,7 @@
 <translation id="9112786533191410418"><ph name="FILE_NAME" /> is misschien gevaarlijk. Wil je het bestand naar Google sturen om het te laten scannen?</translation>
 <translation id="9112987648460918699">Zoek...</translation>
 <translation id="9113240369465613386">Alleen oneven pagina's</translation>
+<translation id="9113469270512809735">Schakelen tussen recent gesloten items</translation>
 <translation id="9114663181201435112">Gemakkelijk inloggen</translation>
 <translation id="9115675100829699941">&amp;Bladwijzers</translation>
 <translation id="9116465289595958864">Laatst gewijzigd</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index 5008e7a..cd25a91d 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -122,7 +122,7 @@
 <translation id="1124772482545689468">వినియోగదారు</translation>
 <translation id="1125550662859510761"><ph name="WIDTH" /> x <ph name="HEIGHT" /> ఉన్నట్టుంది (అసలైనది)</translation>
 <translation id="1126809382673880764">ప్రమాదకరమైన వెబ్‌సైట్‌లు, డౌన్‌లోడ్‌లు మరియు ఎక్స్‌టెన్షన్‌ల నుండి మిమ్మల్ని రక్షించదు. Gmail, Search వంటి ఇతర Google సర్వీస్‌లలో, సురక్షిత బ్రౌజింగ్ అందుబాటులో ఉన్న చోట మీరు ఇప్పటికీ రక్షణను పొందుతారు.</translation>
-<translation id="1128109161498068552">MIDI పరికరాలను యాక్సెస్ చేయడం కోసం సిస్టమ్ విశిష్ట సందేశాలను ఉపయోగించడానికి ఏ సైట్‌లను అనుమతించవద్దు</translation>
+<translation id="1128109161498068552">MIDI పరికరాలను యాక్సెస్ చేయడం కోసం సిస్టమ్ విశిష్ట మెసేజ్‌లను ఉపయోగించడానికి ఏ సైట్‌లను అనుమతించవద్దు</translation>
 <translation id="1128591060186966949">శోధన ఇంజిన్‌ను సవరించండి</translation>
 <translation id="1129850422003387628">యాప్‌లను మేనేజ్ చేయండి</translation>
 <translation id="113050636487300043">ప్రొఫైల్‌ల మధ్య తేడా కనిపించేలా పేరు, రంగు రూపాన్ని ఎంచుకోండి</translation>
@@ -408,7 +408,7 @@
 <translation id="1431188203598586230">చివరి సాఫ్ట్‌వేర్ అప్‌డేట్</translation>
 <translation id="1431432486300429272">శోధన మరియు ఇతర Google సర్వీస్‌లను వ్యక్తిగతీకరించడం కోసం Google మీ బ్రౌజింగ్ చరిత్రను ఉపయోగించవచ్చు. మీరు లేదా మీ తల్లి/తండ్రి దీన్ని ఎప్పుడైనా myaccount.google.com/activitycontrols/searchలో మార్చవచ్చు</translation>
 <translation id="1432581352905426595">సెర్చ్ ఇంజిన్‌లను మేనేజ్ చేయండి</translation>
-<translation id="1433811987160647649">ప్రాప్యత చేసే ముందు అడగాలి</translation>
+<translation id="1433811987160647649">యాక్సెస్‌ చేసే ముందు అడగాలి</translation>
 <translation id="1434696352799406980">దీని వలన మీ ప్రారంభ పేజీ, కొత్త ట్యాబ్ పేజీ, సెర్చ్ ఇంజిన్, పిన్ చేసిన ట్యాబ్‌లు రీసెట్ చేయబడతాయి. అంతే కాక, అన్ని ఎక్స్‌టెన్ష‌న్‌లను డిజేబుల్ చేసి, కుక్కీల వంటి తాత్కాలిక డేటాను తొలగిస్తుంది. మీ బుక్‌మార్క్‌లు, హిస్టరీ, సేవ్ చేసిన పాస్‌వర్డ్‌లు తొలగించబడవు.</translation>
 <translation id="1434886155212424586">హోమ్‌పేజీ అనేది కొత్త ట్యాబ్ పేజీ</translation>
 <translation id="1436390408194692385"><ph name="TICKET_TIME_LEFT" /> పాటు చెల్లుబాటు అవుతుంది</translation>
@@ -471,7 +471,7 @@
 <translation id="150411034776756821"><ph name="SITE" />ని తీసివేయి</translation>
 <translation id="1504551620756424144">Windowsలో <ph name="BASE_DIR" />లో షేర్ చేసిన ఫోల్డర్‌లు అందుబాటులో ఉన్నాయి.</translation>
 <translation id="1506061864768559482">సెర్చ్ ఇంజిన్</translation>
-<translation id="1507170440449692343">ఈ పేజీ మీ కెమెరాను ప్రాప్యత చేయకుండా బ్లాక్ చేయబడింది.</translation>
+<translation id="1507170440449692343">ఈ పేజీ మీ కెమెరాను యాక్సెస్‌ చేయకుండా బ్లాక్ చేయబడింది.</translation>
 <translation id="1507246803636407672">&amp;వదిలివేయి</translation>
 <translation id="1508491105858779599">పరికరాన్ని అన్‌లాక్ చేయడానికి వేలిముద్ర సెన్సార్‌పై మీ వేలిని ఉంచండి.</translation>
 <translation id="1508575541972276599">ప్రస్తుత వెర్షన్ Debian 9 (Stretch)</translation>
@@ -635,7 +635,7 @@
 <translation id="1656528038316521561">నేపథ్య అపారదర్శకత</translation>
 <translation id="1657406563541664238">Googleకు వినియోగ గ‌ణాంకాలు, క్రాష్ రిపోర్ట్‌లను ఆటోమేటిక్‌గా పంపడం ద్వారా <ph name="PRODUCT_NAME" />ను మరింత మెరుగుపరచడంలో సహాయపడండి</translation>
 <translation id="1657937299377480641">విద్యా సంబంధమైన వనరులకు యాక్సెస్ కోసం మళ్లీ సైన్ ఇన్ చేయడానికి, మీకు అనుమతి ఇవ్వాల్సిందిగా తల్లి/తండ్రిని అడగండి</translation>
-<translation id="1658424621194652532">ఈ పేజీ మీ మైక్రోఫోన్‌ను ప్రాప్యత చేస్తోంది.</translation>
+<translation id="1658424621194652532">ఈ పేజీ మీ మైక్రోఫోన్‌ను యాక్సెస్‌ చేస్తోంది.</translation>
 <translation id="1660204651932907780">ధ్వనిని ప్లే చేయగలిగేలా సైట్‌లను అనుమతిస్తుంది (సిఫార్సు చేయబడింది)</translation>
 <translation id="1660763353352708040">పవర్ అడాప్టర్ సమస్య ఉంది</translation>
 <translation id="1661156625580498328">AES ఎన్‌క్రిప్షన్‌ను అమలు చేయి (సిఫార్సు చేయబడినది).</translation>
@@ -903,7 +903,7 @@
 <translation id="1918141783557917887">&amp;చిన్నగా</translation>
 <translation id="1919345977826869612">యాడ్స్</translation>
 <translation id="1920390473494685033">కాంటాక్ట్‌లు</translation>
-<translation id="1921050530041573580">మీ ఫోన్‌ని సందేశాలతో జత చేయండి</translation>
+<translation id="1921050530041573580">మీ ఫోన్‌ని మెసేజ్‌లతో జత చేయండి</translation>
 <translation id="1921584744613111023"><ph name="DPI" /> dpi</translation>
 <translation id="1923468477587371721">మీరు విడిగా ప్రోడక్ట్ భాషను మార్చితే తప్ప, Gmail, Drive, ఇంకా YouTube వంటి Google సైట్‌లు మీ Google ఖాతా భాషను ఉపయోగిస్తాయి</translation>
 <translation id="192494336144674234">దీనితో తెరువు</translation>
@@ -1573,7 +1573,7 @@
 <translation id="262154978979441594">Google Assistant వాయిస్ మోడల్‌కు శిక్షణనివ్వండి</translation>
 <translation id="26224892172169984">ప్రోటోకాల్స్ నిర్వహించడానికి ఏ సైట్‌నూ అనుమతించవద్దు</translation>
 <translation id="262373406453641243">కోల్‌మాక్</translation>
-<translation id="2624142942574147739">ఈ పేజీ మీ కెమెరా మరియు మైక్రోఫోన్‌ను ప్రాప్యత చేస్తోంది.</translation>
+<translation id="2624142942574147739">ఈ పేజీ మీ కెమెరా మరియు మైక్రోఫోన్‌ను యాక్సెస్‌ చేస్తోంది.</translation>
 <translation id="2626799779920242286">దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="2627424346328942291">షేర్ చేయడం సాధ్యపడలేదు</translation>
 <translation id="2628770867680720336">ADB డీబగ్గింగ్‌ను ఎనేబుల్ చేయడానికి ఈ Chromebookను ఫ్యాక్టరీ రీసెట్ చేయాల్సి ఉంటుంది. <ph name="BEGIN_LINK_LEARN_MORE" />మరింత తెలుసుకోండి<ph name="END_LINK_LEARN_MORE" /></translation>
@@ -1673,7 +1673,7 @@
 <translation id="2729314457178420145">అలాగే బ్రౌజింగ్ డేటాను (<ph name="URL" />) క్లియర్ చేస్తుంది, దీని వలన మీరు Google.com నుండి సైన్ అవుట్ చేయబడవచ్చు. <ph name="LEARN_MORE" /></translation>
 <translation id="2730029791981212295">Linux యాప్‌లు, ఫైళ్లను బ్యాకప్ చేస్తోంది</translation>
 <translation id="2730901670247399077">ఎమోజి సూచనలు</translation>
-<translation id="273093730430620027">ఈ పేజీ మీ కెమెరాను ప్రాప్యత చేస్తోంది.</translation>
+<translation id="273093730430620027">ఈ పేజీ మీ కెమెరాను యాక్సెస్‌ చేస్తోంది.</translation>
 <translation id="2731392572903530958">మూసివేయబడిన విండోను మళ్లీ తె&amp;రవండి</translation>
 <translation id="2731700343119398978">దయచేసి వేచి ఉండండి...</translation>
 <translation id="2731971182069536520">మీరు మీ పరికరాన్ని పునఃప్రారంభించే తర్వాతిసారి, మీ నిర్వాహకుడు వ‌న్‌-టైమ్ అప్‌డేట్‌ను అమలు చేస్తారు, దీని వలన మీ స్థానిక డేటా తొలగించబడుతుంది.</translation>
@@ -1819,7 +1819,7 @@
 <translation id="2871813825302180988">ఈ ఖాతా ఈ పరికరంలో ఇప్పటికే ఉపయోగించబడుతోంది.</translation>
 <translation id="287205682142673348">పోర్ట్ ఫార్వర్డింగ్</translation>
 <translation id="287286579981869940"><ph name="PROVIDER_NAME" />ని జోడించు...</translation>
-<translation id="2872961005593481000">షట్ డౌన్ చెయ్యండి</translation>
+<translation id="2872961005593481000">షట్ డౌన్ చేయండి</translation>
 <translation id="2874939134665556319">మునుపటి ట్రాక్</translation>
 <translation id="2875698561019555027">(Chrome ఎర్రర్ పేజీలు)</translation>
 <translation id="2876336351874743617">రెండో వేలు</translation>
@@ -1850,7 +1850,7 @@
 <translation id="2904456025988372123">సైట్ మొదటి ఫైల్ తర్వాత ఆటోమేటిక్‌గా ఫైళ్లను డౌన్‌లోడ్ చేయడానికి ప్రయత్నించేటప్పుడు అడగాలి</translation>
 <translation id="2907619724991574506">ప్రారంభ URLలు</translation>
 <translation id="2907798539022650680">'<ph name="NAME" />'కు కనెక్ట్ చేయడంలో విఫలమైంది: <ph name="DETAILS" />
-    సర్వర్ సందేశం: <ph name="SERVER_MSG" /></translation>
+    సర్వర్ మెసేజ్‌: <ph name="SERVER_MSG" /></translation>
 <translation id="2908162660801918428">డైరెక్టరీ ద్వారా మీడియా గ్యాలరీని జోడించండి</translation>
 <translation id="2908358077082926882">కేటాయింపును తీసివేసి, <ph name="RESPONSE" /> కోసం "<ph name="CURRENTKEY" />"ని మళ్లీ నొక్కండి</translation>
 <translation id="2909506265808101667">Google సర్వీస్‌లతో కనెక్ట్ చేయడం సాధ్యం కాలేదు. మీ నెట్‌వర్క్ కనెక్షన్‌ను చెక్ చేసి, మళ్లీ ట్రై చేయండి. ఎర్రర్ కోడ్: <ph name="ERROR_CODE" />.</translation>
@@ -1909,7 +1909,7 @@
 <translation id="296026337010986570">పూర్తయింది! హానికరమైన సాఫ్ట్‌వేర్ తీసివేయబడింది. ఎక్స్‌టెన్షన్‌లను తిరిగి ఆన్ చేయడానికి, &lt;a href="chrome://extensions"&gt;ఎక్స్‌టెన్షన్‌లు&lt;/a&gt; సందర్శించండి.</translation>
 <translation id="2961090598421146107"><ph name="CERTIFICATE_NAME" /> (పొడిగింపు అందించినది)</translation>
 <translation id="2961210776189273067">టైటిల్</translation>
-<translation id="2961695502793809356">ముందుకు వెళ్ళడానికి క్లిక్ చెయ్యండి. చరిత్రను చూడటానికి నొక్కి ఉంచండి</translation>
+<translation id="2961695502793809356">ముందుకు వెళ్ళడానికి క్లిక్ చేయండి. చరిత్రను చూడటానికి నొక్కి ఉంచండి</translation>
 <translation id="2962131322798295505">వాల్‌పేపర్ పికర్</translation>
 <translation id="2963151496262057773">కింది ప్లగ్ఇన్‌ ప్రతిస్పందించడం లేదు: <ph name="PLUGIN_NAME" />మీరు దీనిని ఆపివేయాలనుకుంటున్నారా?</translation>
 <translation id="2964193600955408481">Wi-Fiని నిలిపివేయి</translation>
@@ -3082,7 +3082,7 @@
 <translation id="4247901771970415646"><ph name="USERNAME" />కి సమకాలీకరించడం సాధ్యం కాదు</translation>
 <translation id="4248098802131000011">డేటా ఉల్లంఘనలు, ఇతర సెక్యూరిటీ సమస్యల నుండి మీ పాస్‌వర్డ్‌లను సురక్షితంగా ఉంచుకోండి</translation>
 <translation id="4249248555939881673">నెట్‌వర్క్ కనెక్షన్ కోసం వేచి ఉంది...</translation>
-<translation id="4249373718504745892">మీ కెమెరా మరియు మైక్రోఫోన్‌ను ప్రాప్యత చేయకుండా ఈ పేజీ బ్లాక్ చేయబడింది.</translation>
+<translation id="4249373718504745892">మీ కెమెరా మరియు మైక్రోఫోన్‌ను యాక్సెస్‌ చేయకుండా ఈ పేజీ బ్లాక్ చేయబడింది.</translation>
 <translation id="424963718355121712">యాప్‌లు తప్పనిసరిగా అవి ప్రభావితమయ్యే హోస్ట్ నుండి అందించబడాలి</translation>
 <translation id="4250229828105606438">స్క్రీన్‌షాట్</translation>
 <translation id="4250680216510889253">లేదు</translation>
@@ -3895,7 +3895,7 @@
 <translation id="5142793792982256885">టచ్‌ప్యాడ్ స్క్రోల్ వేగం</translation>
 <translation id="5143374789336132547">"<ph name="EXTENSION_NAME" />" ఎక్స్‌టెన్ష‌న్‌, మీరు హోమ్ బటన్‌ను క్లిక్ చేసినప్పుడు చూపబడే పేజీని మార్చింది.</translation>
 <translation id="5143612243342258355">ఈ ఫైల్ హానికరమైనది</translation>
-<translation id="5143712164865402236">పూర్తి స్క్రీన్‌ను ఎంటర్ చెయ్యండి</translation>
+<translation id="5143712164865402236">పూర్తి స్క్రీన్‌ను ఎంటర్ చేయండి</translation>
 <translation id="514575469079499857">స్థానాన్ని (డిఫాల్ట్) గుర్తించడానికి మీ IP చిరునామాను ఉపయోగించండి</translation>
 <translation id="5147103632304200977">HID పరికరాలను సైట్ యాక్సెస్ చేయాలనుకున్నప్పుడు అడుగు (సిఫార్సు చేయబడింది)</translation>
 <translation id="5148277445782867161">మీ పరికరం లొకేషన్‌ను అంచనా వేయడంలో సహాయపడటానికి Wi-Fi, మొబైల్ నెట్‌వర్క్‌లు, సెన్సార్‌ల లాంటి సోర్సులను Google లొకేషన్ సర్వీస్ ఉపయోగిస్తుంది.</translation>
@@ -4134,7 +4134,7 @@
 <translation id="5417312524372586921">బ్రౌజర్ థీమ్‌లు</translation>
 <translation id="5419405654816502573">Voice Match</translation>
 <translation id="5420274697768050645">అదనపు భద్రత కోసం పరికరాన్ని అన్‌లాక్ చేయడానికి పాస్‌వర్డ్ అవసరం</translation>
-<translation id="5420438158931847627">వచన సందేశం మరియు చిత్రాల స్పష్టతను నిర్ణయిస్తుంది</translation>
+<translation id="5420438158931847627">వచన మెసేజ్‌ మరియు చిత్రాల స్పష్టతను నిర్ణయిస్తుంది</translation>
 <translation id="5422781158178868512">క్షమించండి, మీ బాహ్య నిల్వ పరికరం గుర్తించబడలేదు.</translation>
 <translation id="5423505005476604112">Crostini</translation>
 <translation id="5423829801105537712">ప్రాథమిక స్పెల్ చెక్</translation>
@@ -4344,7 +4344,7 @@
 <translation id="5632566673632479864">మీ ఖాతా <ph name="EMAIL" /> ఇకపై ప్రాథమిక ఖాతాగా అనుమతించబడదు. ఈ ఖాతా <ph name="DOMAIN" /> ద్వారా నిర్వహించబడుతోంది కాబట్టి, మీ బుక్‌మార్క్‌లు, చరిత్ర, పాస్‌వర్డ్‌లు మరియు ఇతర సెట్టింగ్‌లు ఈ పరికరం నుండి తొలగించబడతాయి.</translation>
 <translation id="5632592977009207922">డౌన్‌లోడ్ చేస్తోంది, <ph name="PERCENT_REMAINING" />% మిగిలి ఉంది</translation>
 <translation id="563371367637259496">మొబైల్</translation>
-<translation id="563535393368633106">ప్రాప్యత చేయడానికి ముందు అడుగుతుంది (సిఫార్సు చేయబడింది)</translation>
+<translation id="563535393368633106">యాక్సెస్‌ చేయడానికి ముందు అడుగుతుంది (సిఫార్సు చేయబడింది)</translation>
 <translation id="5636996382092289526">మీరు <ph name="NETWORK_ID" />ను ఉపయోగించడానికి మొదట కొన్నిసెకన్లలో ఆటోమేటిక్‌గా తెరవబడే <ph name="LINK_START" />నెట్‌వర్క్ సైన్ ఇన్ పేజీని సందర్శించాలి<ph name="LINK_END" />. ఇది జరగకపోతే, నెట్‌వర్క్‌ను ఉపయోగించలేరు.</translation>
 <translation id="5637476008227280525">మొబైల్ డేటాను ప్రారంభించు</translation>
 <translation id="5638309510554459422"><ph name="BEGIN_LINK" />Chrome వెబ్ స్టోర్‌లో<ph name="END_LINK" /> ఎక్స్‌టెన్ష‌న్‌లు మరియు థీమ్‌లను కనుగొనండి</translation>
@@ -4905,7 +4905,7 @@
 <translation id="6264365405983206840">&amp;అన్నీ ఎంచుకోండి</translation>
 <translation id="6265687851677020761">పోర్ట్‌ను తీసివేయండి</translation>
 <translation id="6267166720438879315"><ph name="HOST_NAME" />కు మిమ్మల్ని మీరు ప్రమాణీకరించడానికి ఒక సర్టిఫికెట్‌ను ఎంచుకోండి</translation>
-<translation id="6268252012308737255"><ph name="APP" />తో తెరువు</translation>
+<translation id="6268252012308737255"><ph name="APP" />‌తో తెరవండి</translation>
 <translation id="6270391203985052864">నోటిఫికేషన్‌లను పంపడానికి సైట్‌లు అడుగగలవు</translation>
 <translation id="6270770586500173387"><ph name="BEGIN_LINK1" />సిస్టమ్, యాప్‌ సమాచారాన్ని<ph name="END_LINK1" /> మరియు <ph name="BEGIN_LINK2" />గణాంకాలను<ph name="END_LINK2" /> పంపు</translation>
 <translation id="6271348838875430303">కరెక్షన్‌ను తీసివేశారు</translation>
@@ -4965,7 +4965,7 @@
 <translation id="6319081871916332821"><ph name="LANGUAGE" /> పరికరంలోనే ప్రాసెస్ చేయబడుతుంది, ఆఫ్‌లైన్‌లో పని చేస్తుంది.</translation>
 <translation id="6321407676395378991">స్క్రీన్ సేవర్ ఆన్ చేయి</translation>
 <translation id="6322370287306604163">వేలిముద్ర సహాయంతో మరింత వేగంగా అన్‌లాక్ చేయండి</translation>
-<translation id="6322653941595359182">మీ Chromebook నుండి వచన సందేశాలను పంపండి మరియు స్వీకరించండి</translation>
+<translation id="6322653941595359182">మీ Chromebook నుండి వచన మెసేజ్‌లను పంపండి మరియు స్వీకరించండి</translation>
 <translation id="6324916366299863871">షార్ట్‌కట్‌ను సవరించండి</translation>
 <translation id="6325191661371220117">ఆటో-లాంఛ్‌ను నిలిపివేయి</translation>
 <translation id="6326175484149238433">Chrome నుండి తీసివేయండి</translation>
@@ -5178,7 +5178,7 @@
 <translation id="6556903358015358733">రూపం &amp; వాల్‌పేపర్</translation>
 <translation id="6557290421156335491">నా షార్ట్‌కట్‌లు</translation>
 <translation id="6560151649238390891">సూచన చేర్చబడింది</translation>
-<translation id="6561560012278703671">నిశ్శబ్ద సందేశాలను ఉపయోగించండి (మీకు అంతరాయం కలిగించకుండా నోటిఫికేషన్ ప్రాంప్ట్‌లను బ్లాక్ చేస్తుంది)</translation>
+<translation id="6561560012278703671">నిశ్శబ్ద మెసేజ్‌లను ఉపయోగించండి (మీకు అంతరాయం కలిగించకుండా నోటిఫికేషన్ ప్రాంప్ట్‌లను బ్లాక్ చేస్తుంది)</translation>
 <translation id="6561726789132298588">enter</translation>
 <translation id="6562117348069327379">'డౌన్‌లోడ్స్' డైరెక్టరీలో సిస్టమ్ లాగ్స్‌ను స్టోర్ చేయండి.</translation>
 <translation id="656293578423618167">ఫైల్ పాత్ లేదా పేరు చాలా పొడవుగా ఉంది. దయచేసి చిన్న పేరుతో, లేదా మరొక స్థానానికి సేవ్ చేయండి.</translation>
@@ -5408,7 +5408,7 @@
 <translation id="6812841287760418429">మార్పులను ఉంచు</translation>
 <translation id="6813907279658683733">పూర్తి స్క్రీన్</translation>
 <translation id="6814033694018386318">మీరు Google తో ఏమి షేర్ చేస్తారు</translation>
-<translation id="6817174620439930047">MIDI పరికరాలను యాక్సెస్ చేయడానికి సిస్టమ్ విశిష్ట సందేశాలను సైట్ ఉపయోగించాలనుకున్నప్పుడు అడుగు (సిఫార్సు చేయబడింది)</translation>
+<translation id="6817174620439930047">MIDI పరికరాలను యాక్సెస్ చేయడానికి సిస్టమ్ విశిష్ట మెసేజ్‌లను సైట్ ఉపయోగించాలనుకున్నప్పుడు అడుగు (సిఫార్సు చేయబడింది)</translation>
 <translation id="6818198425579322765">పేజీని అనువదించాల్సిన భాష</translation>
 <translation id="6818802132960437751">అంతర్నిర్మిత వైరస్ రక్షణ</translation>
 <translation id="6820143000046097424">సీరియల్ పోర్ట్‌లు</translation>
@@ -5706,7 +5706,7 @@
 <translation id="7131040479572660648"><ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> మరియు <ph name="WEBSITE_3" />లోని మీ డేటాను చదవండి</translation>
 <translation id="713122686776214250">పే&amp;జీని జోడించండి...</translation>
 <translation id="7133578150266914903">మీ నిర్వాహకుడు మీ పరికరాన్ని ఉపసంహరిస్తున్నారు (<ph name="PROGRESS_PERCENT" />)</translation>
-<translation id="7134098520442464001">టెక్స్ట్‌ని చిన్నదిగా చెయ్యండి</translation>
+<translation id="7134098520442464001">టెక్స్ట్‌ని చిన్నదిగా చేయండి</translation>
 <translation id="7135729336746831607">బ్లూటూత్ ఆన్ చేయాలా?</translation>
 <translation id="7136639886842764730">వెంటనే మీ <ph name="DEVICE_TYPE" />ను అప్‌డేట్ చేయాలని <ph name="DOMAIN" /> తెలియజేస్తోంది.</translation>
 <translation id="7136694880210472378">ఆటోమేటిక్ ఆప్షన్‌గా సెట్ చేయి</translation>
@@ -5811,7 +5811,7 @@
 <translation id="7267875682732693301">మీ వేలిముద్ర కోసం వివిధ భాగాలను జోడించడానికి మీ వేలిని పైకి ఎత్తుతూ ఉండండి</translation>
 <translation id="7268127947535186412">ఈ సెట్టింగ్‌ను పరికరం యజమాని నిర్వహిస్తున్నారు.</translation>
 <translation id="7269736181983384521">సమీప షేరింగ్ డేటా వినియోగం</translation>
-<translation id="7270858098575133036">MIDI పరికరాలను యాక్సెస్ చేయడానికి సిస్టమ్ విశిష్ట సందేశాలను సైట్ ఉపయోగించాలనుకున్నప్పుడు అడుగు</translation>
+<translation id="7270858098575133036">MIDI పరికరాలను యాక్సెస్ చేయడానికి సిస్టమ్ విశిష్ట మెసేజ్‌లను సైట్ ఉపయోగించాలనుకున్నప్పుడు అడుగు</translation>
 <translation id="7272674038937250585">వివరణ ఏదీ అందించబడలేదు</translation>
 <translation id="7273110280511444812"><ph name="DATE" />న చివరిగా జోడించబడింది</translation>
 <translation id="727441411541283857"><ph name="PERCENTAGE" />% - <ph name="TIME" />లో పూర్తి ఛార్జ్ అవుతుంది</translation>
@@ -5929,7 +5929,7 @@
 <translation id="7400418766976504921">URL</translation>
 <translation id="7400447915166857470">తిరిగి <ph name="OLD_SEARCH_PROVIDER" />కు మార్చాలా?</translation>
 <translation id="7400839060291901923">మీ <ph name="PHONE_NAME" />లో కనెక్షన్‌ని సెటప్ చేయండి</translation>
-<translation id="7401778920660465883">ఈ సందేశాన్ని రద్దు చేయి</translation>
+<translation id="7401778920660465883">ఈ మెసేజ్‌ను రద్దు చేయి</translation>
 <translation id="7403642243184989645">రిసోర్స్‌ను డౌన్‌లోడ్ చేస్తోంది</translation>
 <translation id="7404065585741198296">USB కేబుల్‌తో కనెక్ట్ చేయబడిన మీ ఫోన్</translation>
 <translation id="7405938989981604410">{NUM_HOURS,plural, =1{భద్రతా తనిఖీ జరిగి 1 గంట అయింది}other{భద్రతా తనిఖీ జరిగి {NUM_HOURS} గంటలు అయింది}}</translation>
@@ -6610,7 +6610,7 @@
 <translation id="8068253693380742035">సైన్ ఇన్ చేయడానికి తాకండి</translation>
 <translation id="8069615408251337349">Google Cloud Print</translation>
 <translation id="8071432093239591881">చిత్రం లాగా ముద్రించు</translation>
-<translation id="8073499153683482226"><ph name="BEGIN_PARAGRAPH1" />పరిచయాలు, సందేశాలు మరియు ఫోటోల వంటి యాప్ సేవ్ చేసిన (డెవలపర్ సెట్టింగ్‌ల ఆధారంగా) ఎలాంటి డేటా అయినా యాప్ డేటాగా పరిగణించబడుతుంది.<ph name="END_PARAGRAPH1" />
+<translation id="8073499153683482226"><ph name="BEGIN_PARAGRAPH1" />పరిచయాలు, మెసేజ్‌లు మరియు ఫోటోల వంటి యాప్ సేవ్ చేసిన (డెవలపర్ సెట్టింగ్‌ల ఆధారంగా) ఎలాంటి డేటా అయినా యాప్ డేటాగా పరిగణించబడుతుంది.<ph name="END_PARAGRAPH1" />
     <ph name="BEGIN_PARAGRAPH2" />బ్యాకప్ డేటా మీ చిన్నారి డిస్క్ నిల్వ కోటాలో లెక్కించబడదు.<ph name="END_PARAGRAPH2" />
     <ph name="BEGIN_PARAGRAPH3" />మీరు సెట్టింగ్‌లలో ఈ సేవని ఆఫ్ చేయవచ్చు.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="8074127646604999664">డేటాను పంపడం మరియు స్వీకరించడం పూర్తి చేయడానికి ఇటీవల మూసివేసిన సైట్‌లను అనుమతించు</translation>
@@ -6630,7 +6630,7 @@
 <translation id="8093359998839330381"><ph name="PLUGIN_NAME" /> ప్రతిస్పందించడం లేదు</translation>
 <translation id="8095105960962832018"><ph name="BEGIN_PARAGRAPH1" />Google డిస్క్‌కి బ్యాకప్ చేయండి. ఏ సమయంలో అయినా సులభంగా మీ డేటాని పునరుద్ధరించండి లేదా పరికరాన్ని మార్చండి. మీ బ్యాకప్‌లో యాప్ డేటా ఉంటుంది.<ph name="END_PARAGRAPH1" />
     <ph name="BEGIN_PARAGRAPH2" />మీ బ్యాకప్‌లు Googleకి అప్‌లోడ్ చేయబడతాయి మరియు మీ Google ఖాతా పాస్‌వర్డ్‌ని ఉపయోగించి ఎన్‌క్రిప్ట్ చేయబడతాయి.<ph name="END_PARAGRAPH2" />
-    <ph name="BEGIN_PARAGRAPH3" />పరిచయాలు, సందేశాలు మరియు ఫోటోల వంటి యాప్ సేవ్ చేసిన (డెవలపర్ సెట్టింగ్‌ల ఆధారంగా) ఎలాంటి డేటా అయినా యాప్ డేటాగా పరిగణించబడుతుంది.<ph name="END_PARAGRAPH3" />
+    <ph name="BEGIN_PARAGRAPH3" />పరిచయాలు, మెసేజ్‌లు మరియు ఫోటోల వంటి యాప్ సేవ్ చేసిన (డెవలపర్ సెట్టింగ్‌ల ఆధారంగా) ఎలాంటి డేటా అయినా యాప్ డేటాగా పరిగణించబడుతుంది.<ph name="END_PARAGRAPH3" />
     <ph name="BEGIN_PARAGRAPH4" />బ్యాకప్ డేటా మీ డిస్క్ నిల్వ కోటాలో లెక్కించబడదు.<ph name="END_PARAGRAPH4" />
     <ph name="BEGIN_PARAGRAPH5" />మీరు సెట్టింగ్‌లలో ఈ సేవని ఆఫ్ చేయవచ్చు.<ph name="END_PARAGRAPH5" /></translation>
 <translation id="8096740438774030488">బ్యాటరీలో ఉన్నప్పుడు స్లీప్ మోడ్‌లో ఉండాలి</translation>
@@ -6740,7 +6740,7 @@
 <translation id="8201717382574620700"><ph name="TOPIC_SOURCE" /> ఆల్బమ్‌లను ఎంచుకోండి</translation>
 <translation id="8202160505685531999">దయచేసి మీ <ph name="DEVICE_TYPE" /> ప్రొఫైల్‌ను అప్‌డేట్ చేయ‌డానికి మీ పాస్‌వర్డ్‌ను మళ్లీ నమోదు చేయండి.</translation>
 <translation id="8203152941016626022">సమీప షేరింగ్ పరికరం పేరు</translation>
-<translation id="8203732864715032075">మీకు నోటిఫికేషన్‌లను పంపుతుంది, అలాగే సందేశాల కోసం ఈ కంప్యూటర్‌ను డిఫాల్ట్‌గా గుర్తుపెట్టుకుంటుంది. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
+<translation id="8203732864715032075">మీకు నోటిఫికేషన్‌లను పంపుతుంది, అలాగే మెసేజ్‌ల కోసం ఈ కంప్యూటర్‌ను డిఫాల్ట్‌గా గుర్తుపెట్టుకుంటుంది. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="8205432712228803050">మీ డిస్‌ప్లేలు, పెరిఫెరల్‌లు కొద్దిసేపటిలో రీసెట్ కావచ్చు. ఈ మార్పు అమలులోకి రావడం కోసం, మీ పెరిఫెరల్‌లను అన్‌ప్లగ్ చేసి, మళ్లీ ప్లగ్ చేయండి.</translation>
 <translation id="820568752112382238">అత్యంత ఎక్కువగా సందర్శించిన సైట్‌లు</translation>
 <translation id="8206745257863499010">బ్లూసై</translation>
@@ -6761,7 +6761,7 @@
 <translation id="8227119283605456246">ఫైల్‌ను జోడించు</translation>
 <translation id="8230134520748321204"><ph name="ORIGIN" /> కోసం పాస్‌వర్డ్‌ని సేవ్ చేయాలా?</translation>
 <translation id="8230446983261649357">ఇమేజ్‌లను చూపించడానికి సైట్‌లను అనుమతించకండి</translation>
-<translation id="8234795456569844941">దయచేసి ఈ సమస్యను పరిష్కరించడంలో మా ఇంజినీర్‌లకు సహాయపడండి. ప్రొఫైల్ ఎర్రర్ సందేశం ఎదురయ్యే ముందు ఏమి జరిగిందో మాకు తెలియజేయండి:</translation>
+<translation id="8234795456569844941">దయచేసి ఈ సమస్యను పరిష్కరించడంలో మా ఇంజినీర్‌లకు సహాయపడండి. ప్రొఫైల్ ఎర్రర్ మెసేజ్‌ ఎదురయ్యే ముందు ఏమి జరిగిందో మాకు తెలియజేయండి:</translation>
 <translation id="8235418492073272647"><ph name="DEVICE_NAME" /> నుండి పేజీ షేర్ చేయబడింది</translation>
 <translation id="8236911020904880539">నిష్క్రమించండి</translation>
 <translation id="8236917170563564587">బదులుగా, ఈ ట్యాబ్‌ను షేర్ చేయి</translation>
@@ -6848,7 +6848,7 @@
 <translation id="8321476692217554900">నోటిఫికేషన్‌లు</translation>
 <translation id="8321492415476219409">కేటాయించు స్విచ్: మునుపటి</translation>
 <translation id="8321837372750396788"><ph name="MANAGER" /> ఈ <ph name="DEVICE_TYPE" />ను మేనేజ్ చేస్తుంది.</translation>
-<translation id="8322814362483282060">మీ మైక్రోఫోన్‌ను ప్రాప్యత చేయనీయకుండా ఈ పేజీ బ్లాక్ చేయబడింది.</translation>
+<translation id="8322814362483282060">మీ మైక్రోఫోన్‌ను యాక్సెస్‌ చేయనీయకుండా ఈ పేజీ బ్లాక్ చేయబడింది.</translation>
 <translation id="8323167517179506834">URLను టైప్ చేయండి</translation>
 <translation id="8323317289166663449">మీ కంప్యూటర్‌లో, అన్ని వెబ్‌సైట్‌లలో మీ మొత్తం డేటాను చదవడం, మార్చడం</translation>
 <translation id="8324784016256120271">వివిధ సైట్‌లలో మీ బ్రౌజింగ్ యాక్టివిటీని చూడటానికి, ఉదాహరణకు, యాడ్‌లను వ్యక్తిగతీకరించడానికి, సైట్‌లు కుక్కీలను ఉపయోగించవచ్చు</translation>
@@ -6907,7 +6907,7 @@
 <translation id="8392451568018454956"><ph name="USER_EMAIL_ADDRESS" /> కోసం ఎంపికల మెనూ</translation>
 <translation id="8393511274964623038">ప్లగ్ఇన్‌‌ను ఆపివేయి</translation>
 <translation id="839363317075970734">బ్లూటూత్ పరికర వివరాలు</translation>
-<translation id="8393700583063109961">సందేశాన్ని పంపండి</translation>
+<translation id="8393700583063109961">మెసేజ్‌ను పంపండి</translation>
 <translation id="8397825320644530257">కనెక్ట్ చేసిన ఫోన్‌ను డిస్‌కనెక్ట్ చేయండి</translation>
 <translation id="8398877366907290961">ఏవైనా కొనసాగు</translation>
 <translation id="8401432541486058167">మీ స్మార్ట్ కార్డ్‌కు అనుబంధించబడిన పిన్‌ను అందించండి.</translation>
@@ -7602,7 +7602,7 @@
 <translation id="9128335130883257666"><ph name="INPUT_METHOD_NAME" /> కోసం సెట్టింగ్‌ల పేజీని తెరవండి</translation>
 <translation id="9128870381267983090">నెట్‌వర్క్‌కి కనెక్ట్ చేయి</translation>
 <translation id="9130015405878219958">చెల్లని మోడ్ ఎంటర్ చేయ‌బడింది.</translation>
-<translation id="9131487537093447019">బ్లూటూత్ పరికరాలకు సందేశాలను పంపడానికి మరియు వాటి నుండి స్వీకరించడానికి అనుమతి.</translation>
+<translation id="9131487537093447019">బ్లూటూత్ పరికరాలకు మెసేజ్‌లను పంపడానికి మరియు వాటి నుండి స్వీకరించడానికి అనుమతి.</translation>
 <translation id="9134066738478820307">సురక్షితమైన కంటెంట్‌ను ప్లే చేయడానికి, సైట్‌లు ఐడెంటిఫయర్‌‌లను ఉపయోగించవచ్చు</translation>
 <translation id="913411432238655354">ఆన్ అయ్యే సమయంలో యాప్‌లను రీస్టోర్ చేయండి</translation>
 <translation id="9137013805542155359">అసలును చూపించు</translation>
@@ -7716,7 +7716,7 @@
 <translation id="964286338916298286">మీ IT నిర్వాహకుడు మీ పరికరానికి Chrome కానుకలను నిలిపివేసారు.</translation>
 <translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{అప్లికేషన్}other{అప్లికేషన్‌లు}}</translation>
 <translation id="964790508619473209">స్క్రీన్ అమరిక</translation>
-<translation id="965211523698323809">మీ <ph name="DEVICE_TYPE" /> నుండి వచన సందేశాలను పంపండి, స్వీకరించండి. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
+<translation id="965211523698323809">మీ <ph name="DEVICE_TYPE" /> నుండి వచన మెసేజ్‌లను పంపండి, స్వీకరించండి. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="967398046773905967">HID పరికరాలను యాక్సెస్ చేయడానికి సైట్‌లు వేటినీ అనుమతించవద్దు</translation>
 <translation id="967624055006145463">నిల్వ చేయబడిన డేటా</translation>
 <translation id="96774243435178359">మేనేజ్ చేయబడే ప్రింటర్‌లు</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb
index b02f0a4..0535ca2e 100644
--- a/chrome/app/resources/generated_resources_uz.xtb
+++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -159,6 +159,7 @@
 <translation id="1165039591588034296">Xatolik</translation>
 <translation id="1166212789817575481">O‘ng tomondagi ichki oynalarni yopish</translation>
 <translation id="1166583374608765787">Nom oʻzgarishi tekshiruvi</translation>
+<translation id="1166596238782048887"><ph name="TAB_TITLE" /> nomli varaq <ph name="DESK_TITLE" /> ish stoliga tegishli</translation>
 <translation id="1168020859489941584"><ph name="TIME_REMAINING" /> dan so‘ng ochiladi...</translation>
 <translation id="1170288591054440704">Sayt qurilmangizda oʻrnatilgan shriftlarni ishlatishdan oldin ruxsat olsin</translation>
 <translation id="1171135284592304528">Obyekt o‘zgarganda u klaviatura fokusi bilan ajratib ko‘rsatilsin.</translation>
@@ -615,6 +616,7 @@
 <translation id="1640235262200048077"><ph name="IME_NAME" /> hozircha Linux ilovalarda ishlamaydi</translation>
 <translation id="1640283014264083726">PKCS #1 MD4 algoritmli RSA shifrlash</translation>
 <translation id="1641113438599504367">Saytlarni xavfsiz kezish</translation>
+<translation id="1642492862748815878"><ph name="DEVICE" /> va yana <ph name="NUMBER_OF_DEVICES" /> ta Bluetooth qurilmalarga ulangan</translation>
 <translation id="1642494467033190216">Boshqa nosozliklarni ko‘rib chiqish funksiyalarini yoqishdan avval tub fayllar tizimi himoyasini o‘chirib qo‘ying va qurilmani qayta ishga tushiring.</translation>
 <translation id="1643072738649235303">SHA-1 algoritmli X9.62 ECDSA imzosi</translation>
 <translation id="1643921258693943800">Nearby Share funksiyasini ishlatish uchun Bluetooth va Wi-Fi aloqalarini yoqing</translation>
@@ -1822,6 +1824,7 @@
 <translation id="2885378588091291677">Vazifalar boshqaruvi</translation>
 <translation id="2885729872133513017">Server javobi deshifrlanmadi.</translation>
 <translation id="2886771036282400576">• <ph name="PERMISSION" /></translation>
+<translation id="288734198558082692"><ph name="DEVICE" /> va yana <ph name="NUMBER_OF_DEVICES" /> ta qurilma</translation>
 <translation id="2889064240420137087">Havolani ochish...</translation>
 <translation id="2891922230654533301"><ph name="APP_NAME" /> ilovasiga qurilma orqali kirilsinmi?</translation>
 <translation id="2893168226686371498">Standart brauzer</translation>
@@ -2756,6 +2759,7 @@
 <translation id="3884152383786131369">Bir nechta tilda chiqadigan veb kontent shu roʻyxatdagi birinchi mos tilni ishlatadi. Bu parametrlar brauzeringiz sozlamalari bilan sinxronlanadi. <ph name="BEGIN_LINK_LEARN_MORE" />Batafsil<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="3885112598747515383">Yangilanishlar administrator tomonidan boshqariladi</translation>
 <translation id="3886446263141354045">Bu saytni ochishga ruxsat so‘rovi <ph name="NAME" />ga yuborildi</translation>
+<translation id="3887022758415973389">Qurilmalar roʻyxatini chiqarish</translation>
 <translation id="3888053818972567950"><ph name="WEB_DRIVE" /> ombori</translation>
 <translation id="3888550877729210209">Qaydlar <ph name="LOCK_SCREEN_APP_NAME" /> dasturida yoziladi</translation>
 <translation id="3888586133700543064">Bu axborot Assistent muammosini yaxshiroq tushunishga yordam beradi. Axborot 90 kungacha saqlanadi va faqatgina muayyan jamoa yoki muhandislar tomonidan ishlatiladi.</translation>
@@ -3467,6 +3471,7 @@
 <translation id="4662373422909645029">Taxallusga raqam kiritish mumkin emas</translation>
 <translation id="4662788913887017617">Xatcho‘pni iPhone bilan ulashing</translation>
 <translation id="4663373278480897665">Kameradan foydalanish mumkin</translation>
+<translation id="4664289193573249666">Xavfsiz DNS parametrlarini Chrome OS sozlamalaridan boshqaring</translation>
 <translation id="4664482161435122549">PKCS #12 Eksport xatoligi</translation>
 <translation id="4665014895760275686">Ishlab chiqaruvchi</translation>
 <translation id="4665446389743427678"><ph name="SITE" /> saqlagan barcha maʼlumotlar tozalanadi.</translation>
@@ -6000,6 +6005,7 @@
 <translation id="7478623944308207463">Ilova va sozlamalaringiz Google hisobingiz bilan kirilgan barcha Chrome OS qurilmalaringizda sinxronlanadi. Brauzer sinxronizatsiyasi parametrlarini <ph name="LINK_BEGIN" />Chrome sozlamalari<ph name="LINK_END" /> orqali sozlash mumkin.</translation>
 <translation id="7478658909253570368">Saytlarga seriyali portlarga ulanishni taqiqlash</translation>
 <translation id="7479221278376295180">Xotira sarfiga nazar solish</translation>
+<translation id="747981547666531654"><ph name="FIRST_DEVICE" /> va <ph name="SECOND_DEVICE" /> nomli Bluetooth qurilmalarga ulangan</translation>
 <translation id="7481312909269577407">Oldinga</translation>
 <translation id="7481358317100446445">Tayyor</translation>
 <translation id="748138892655239008">Sertifikatga asosiy cheklovlar</translation>
@@ -6052,6 +6058,7 @@
 <translation id="7531771599742723865">Qurilma band</translation>
 <translation id="7531779363494549572">Sozlamalar &gt; Ilovalar va bildirishnomalar &gt; Bildirishnomalar sahifasini oching.</translation>
 <translation id="7532009420053991888"><ph name="LINUX_APP_NAME" /> javob bermayapti Ilovani “Majburiy toʻxtatish” orqali yoping.</translation>
+<translation id="7535730537657706072">Qurilmadan Inkognito sahifalar tarixini tozalash uchun barcha Inkognito varaqlarni yoping</translation>
 <translation id="7535791657097741517">Kunduzgi mavzuni yoqish</translation>
 <translation id="7537451260744431038">Saytlar sahifalarni kezishingizni yaxshilash, jumladan, kirish axborotingiz yoki xarid qutingizni eslab qolish uchun cookie fayllardan foydalana olmaydi</translation>
 <translation id="753769905878158714">Manzil qatorida qidirilishi kerak boʻlgan veb-sayt uchun kalit soʻzni kiriting. Keyin davom etish uchun tezkor tugmadan foydalaning.</translation>
@@ -6667,6 +6674,7 @@
 <translation id="8138217203226449454">Qidiruv tizimi almashtirilsinmi?</translation>
 <translation id="8138997515734480534"><ph name="VM_NAME" /> holati</translation>
 <translation id="8139447493436036221">Google Drive fayllari</translation>
+<translation id="8140070492745508800"><ph name="FIRST_DEVICE" />, <ph name="SECOND_DEVICE" /></translation>
 <translation id="8141584439523427891">Hozir muqobil brauzerda ochiladi</translation>
 <translation id="8141725884565838206">Parollarni boshqarish</translation>
 <translation id="814204052173971714">{COUNT,plural, =1{video}other{# ta video}}</translation>
@@ -7382,6 +7390,7 @@
 <translation id="8909782404367982052">Rasmlarni Google Lens yordamida qidirish uchun tortib joylang</translation>
 <translation id="8909833622202089127">Sayt joylashuvingizni kuzatmoqda</translation>
 <translation id="8910222113987937043">Endi xatcho‘plar, brauzer tarixi va boshqa sozlamalaringiz Google hisobingizga sinxronlanmaydi. Shunday bo‘lsa-da, mavjud ma’lumotlaringiz Google hisobingizda saqlanib qoladi. Ular bilan <ph name="BEGIN_LINK" />Google Shaxsiy kabinet<ph name="END_LINK" /> orqali ishlash mumkin.</translation>
+<translation id="8910987510378294980">Qurilmalar roʻyxatini berkitish</translation>
 <translation id="8912362522468806198">Google hisobi</translation>
 <translation id="8912793549644936705">Cho‘zish</translation>
 <translation id="8912810933860534797">Avtomatik skanerlashni yoqish</translation>
@@ -7499,6 +7508,7 @@
 <translation id="9033765790910064284">Baribir davom ettirilsin</translation>
 <translation id="9033857511263905942">&amp;Joylash</translation>
 <translation id="903480517321259405">PIN kodni qayta kiriting</translation>
+<translation id="9037054491984310631"><ph name="DEVICE" /> nomli Bluetooth qurilmaga ulangan</translation>
 <translation id="9037640663275993951">Qurilmaga ruxsat berilmagan</translation>
 <translation id="9037818663270399707">Saytga ulanish butunlay xavfsiz emas</translation>
 <translation id="9037965129289936994">Asl tilda ko‘rsatish</translation>
@@ -7579,6 +7589,7 @@
 <translation id="9112786533191410418"><ph name="FILE_NAME" /> fayli xavfli boʻlishi mumkin. Tekshiruv uchun Googlega yuborilsinmi?</translation>
 <translation id="9112987648460918699">Qidirish...</translation>
 <translation id="9113240369465613386">Faqat toq sonli sahifalar</translation>
+<translation id="9113469270512809735">Oxirgi yopilganlar tugmasi</translation>
 <translation id="9114663181201435112">Osongina kirish</translation>
 <translation id="9115675100829699941">&amp;Xatcho‘plar</translation>
 <translation id="9116465289595958864">Oxirgi tahrir</translation>
diff --git a/chrome/app/resources/google_chrome_strings_nl.xtb b/chrome/app/resources/google_chrome_strings_nl.xtb
index 1cba7167..519cab4 100644
--- a/chrome/app/resources/google_chrome_strings_nl.xtb
+++ b/chrome/app/resources/google_chrome_strings_nl.xtb
@@ -274,6 +274,7 @@
 <translation id="8008534537613507642">Chrome opnieuw installeren</translation>
 <translation id="8013993649590906847">Als een afbeelding geen nuttige beschrijving bevat, probeert Chrome je er een te geven. Afbeeldingen worden naar Google verzonden om beschrijvingen te maken.</translation>
 <translation id="8129812357326543296">Over &amp;Google Chrome</translation>
+<translation id="822971176939352383">De volgende accounts zijn niet ingelogd bij Chrome-profielen. Als je een account wilt gebruiken in een ander profiel, verwijder je eerst dat profiel.</translation>
 <translation id="8255190535488645436">Google Chrome gebruikt je camera en microfoon.</translation>
 <translation id="8286862437124483331">Google Chrome probeert wachtwoorden te tonen. Geef je Windows-wachtwoord op om dit toe te staan.</translation>
 <translation id="828798499196665338">Je ouder heeft 'Rechten voor sites, apps en extensies' uitgezet voor Chrome. Je mag deze <ph name="EXTENSION_TYPE_PARAMETER" /> niet aanzetten.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_te.xtb b/chrome/app/resources/google_chrome_strings_te.xtb
index b91e057..f93208db 100644
--- a/chrome/app/resources/google_chrome_strings_te.xtb
+++ b/chrome/app/resources/google_chrome_strings_te.xtb
@@ -216,7 +216,7 @@
 <translation id="6515495397637126556"><ph name="PAGE_TITLE" /> - Google Chrome Dev</translation>
 <translation id="6568793831116033768">Chrome OS సిస్టమ్</translation>
 <translation id="664235759707825982">Chrome OSను ఇన్‌స్టాల్ చేయడానికి మీరు సిద్ధంగా ఉన్నారు</translation>
-<translation id="6676384891291319759">ఇంటర్నెట్‌ను ఆక్సెస్ చెయ్యండి</translation>
+<translation id="6676384891291319759">ఇంటర్నెట్‌ను ఆక్సెస్ చేయండి</translation>
 <translation id="6679975945624592337">Google Chromeను నేపథ్యంలో అమలు అయ్యేందుకు అనుమతించండి</translation>
 <translation id="6739177684496155661">కొత్త Chrome ప్రొఫైల్‌లో కొనసాగించాలా?</translation>
 <translation id="6750954913813541382">స్పెల్లింగ్ తప్పులను సరిదిద్దడానికి, మీరు బ్రౌజర్‌లో టైప్ చేసే పదాలను Googleకు Chrome పంపుతుంది</translation>
diff --git a/chrome/app/resources/google_chrome_strings_uz.xtb b/chrome/app/resources/google_chrome_strings_uz.xtb
index 7975481..2dbf2f2 100644
--- a/chrome/app/resources/google_chrome_strings_uz.xtb
+++ b/chrome/app/resources/google_chrome_strings_uz.xtb
@@ -275,6 +275,7 @@
 <translation id="8008534537613507642">Chrome‘ni qaytadan o‘rnatish</translation>
 <translation id="8013993649590906847">Agar rasmga foydali tavsif berilmagan boʻlsa, Google Chrome uni sizga tavsiflaydi. Tavsif yaratish uchun rasmlar Googlega yuboriladi.</translation>
 <translation id="8129812357326543296">&amp;Google Chrome haqida</translation>
+<translation id="822971176939352383">Quyidagi hisoblar hech qaysi Chrome profiliga kirmagan. Hisobni boshqa profilda ishlatishni xohlasangiz, avval u profilni olib tashlang.</translation>
 <translation id="8255190535488645436">Google Chrome kamera va mikrofoningizdan foydalanmoqda.</translation>
 <translation id="8286862437124483331">Google Chrome parollarni ko‘rsatishga urinmoqda. Ruxsat berish uchun Windows platformasidagi parolingizni kiriting.</translation>
 <translation id="828798499196665338">Chromedagi “Sayt, ilova va kengaytmalarga ruxsat” ota-onangiz tomonidan faolsizlantirilgan. Bu <ph name="EXTENSION_TYPE_PARAMETER" /> yoqilishi taqiqlangan.</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 0f327505..850ccbe 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -383,7 +383,7 @@
     "data_use_measurement/chrome_data_use_measurement.h",
     "defaults.cc",
     "defaults.h",
-    "device_reauth/chrome_biometric_authenticator.h",
+    "device_reauth/chrome_biometric_authenticator_factory.h",
     "display_capture/display_capture_permission_context.cc",
     "display_capture/display_capture_permission_context.h",
     "dom_distiller/dom_distiller_service_factory.cc",
@@ -1502,8 +1502,6 @@
     "sessions/chrome_serialized_navigation_driver.h",
     "sessions/chrome_tab_restore_service_client.cc",
     "sessions/chrome_tab_restore_service_client.h",
-    "sessions/closed_tab_cache.cc",
-    "sessions/closed_tab_cache.h",
     "sessions/restore_on_startup_policy_handler.cc",
     "sessions/restore_on_startup_policy_handler.h",
     "sessions/session_common_utils.cc",
@@ -2978,6 +2976,8 @@
       "data_reduction_proxy/data_reduction_proxy_settings_android.h",
       "device_reauth/android/biometric_authenticator_android.cc",
       "device_reauth/android/biometric_authenticator_android.h",
+      "device_reauth/android/biometric_authenticator_android_factory.cc",
+      "device_reauth/android/biometric_authenticator_android_factory.h",
       "device_reauth/android/biometric_authenticator_bridge.h",
       "device_reauth/android/biometric_authenticator_bridge_impl.cc",
       "device_reauth/android/biometric_authenticator_bridge_impl.h",
@@ -4067,6 +4067,8 @@
       "serial/serial_chooser_histograms.h",
       "serial/serial_policy_allowed_ports.cc",
       "serial/serial_policy_allowed_ports.h",
+      "sessions/closed_tab_cache.cc",
+      "sessions/closed_tab_cache.h",
       "sessions/closed_tab_cache_service.cc",
       "sessions/closed_tab_cache_service.h",
       "sessions/closed_tab_cache_service_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 824f5a8..71c43b91 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5986,6 +5986,12 @@
                                     kBackForwardCacheVariations,
                                     "BackForwardCache")},
 
+#if !defined(OS_ANDROID)
+    {"closed-tab-cache", flag_descriptions::kClosedTabCacheName,
+     flag_descriptions::kClosedTabCacheDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kClosedTabCache)},
+#endif  // !defined(OS_ANDROID)
+
     {"impulse-scroll-animations",
      flag_descriptions::kImpulseScrollAnimationsName,
      flag_descriptions::kImpulseScrollAnimationsDescription, kOsAll,
@@ -7456,6 +7462,13 @@
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillFillMerchantPromoCodeFields)},
 
+    {"passwords-account-storage-revised-opt-in-flow",
+     flag_descriptions::kPasswordsAccountStorageRevisedOptInFlowName,
+     flag_descriptions::kPasswordsAccountStorageRevisedOptInFlowDescription,
+     kOsDesktop,
+     FEATURE_VALUE_TYPE(
+         password_manager::features::kPasswordsAccountStorageRevisedOptInFlow)},
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/accuracy_tips/accuracy_service_factory.cc b/chrome/browser/accuracy_tips/accuracy_service_factory.cc
index 6b17c4e..7717df09 100644
--- a/chrome/browser/accuracy_tips/accuracy_service_factory.cc
+++ b/chrome/browser/accuracy_tips/accuracy_service_factory.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/accuracy_tips/accuracy_service_delegate.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "components/accuracy_tips/accuracy_service.h"
@@ -51,10 +52,13 @@
       g_browser_process->safe_browsing_service()
           ? g_browser_process->safe_browsing_service()->database_manager()
           : nullptr;
+  auto* history_service = HistoryServiceFactory::GetForProfile(
+      profile, ServiceAccessType::IMPLICIT_ACCESS);
   auto delegate = std::make_unique<AccuracyServiceDelegate>(profile);
   return new accuracy_tips::AccuracyService(
       std::move(delegate), profile->GetPrefs(), std::move(sb_database),
-      content::GetUIThreadTaskRunner({}), content::GetIOThreadTaskRunner({}));
+      history_service, content::GetUIThreadTaskRunner({}),
+      content::GetIOThreadTaskRunner({}));
 }
 
 void AccuracyServiceFactory::RegisterProfilePrefs(
diff --git a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
index 3b466e58..468c579 100644
--- a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -636,9 +636,7 @@
 }
 
 // Reenrollment forced. User can not skip.
-// TODO(crbug.com/1238865): Re-enable after PSM supports integration tests.
-IN_PROC_BROWSER_TEST_F(AutoEnrollmentLocalPolicyServer,
-                       DISABLED_ReenrollmentForced) {
+IN_PROC_BROWSER_TEST_F(AutoEnrollmentLocalPolicyServer, ReenrollmentForced) {
   EXPECT_TRUE(policy_server_.SetDeviceStateRetrievalResponse(
       state_keys_broker(),
       enterprise_management::DeviceStateRetrievalResponse::
@@ -829,8 +827,7 @@
   enrollment_ui_.RetryAfterError();
 }
 
-// TODO(crbug.com/1238865): Re-enable after PSM supports integration tests.
-IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest, DISABLED_EnrollmentForced) {
+IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest, EnrollmentForced) {
   auto initial_enrollment =
       enterprise_management::DeviceInitialEnrollmentStateResponse::
           INITIAL_ENROLLMENT_MODE_ENROLLMENT_ENFORCED;
@@ -864,10 +861,8 @@
 #endif
 // Zero touch with attestation authentication fail. Attestation fails because we
 // send empty cert request. Should switch to interactive authentication.
-// TODO(crbug.com/1238865): Re-enable using MAYBE prefix, after PSM supports
-// integration tests.
 IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest,
-                       DISABLED_ZeroTouchForcedAttestationFail) {
+                       MAYBE_ZeroTouchForcedAttestationFail) {
   auto initial_enrollment =
       enterprise_management::DeviceInitialEnrollmentStateResponse::
           INITIAL_ENROLLMENT_MODE_ZERO_TOUCH_ENFORCED;
@@ -902,9 +897,8 @@
   EXPECT_TRUE(InstallAttributes::Get()->IsEnterpriseManaged());
 }
 
-// TODO(crbug.com/1238865): Re-enable after PSM supports integration tests.
 IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest,
-                       DISABLED_ZeroTouchForcedAttestationSuccess) {
+                       ZeroTouchForcedAttestationSuccess) {
   AllowlistSimpleChallengeSigningKey();
   policy_server_.SetupZeroTouchForcedEnrollment();
 
diff --git a/chrome/browser/ash/login/oobe_interactive_ui_test.cc b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
index dc89712..98b4f62 100644
--- a/chrome/browser/ash/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
@@ -820,9 +820,7 @@
 // Please do not disable it for whole ChromeOS, only for specific instrumented
 // bots. Another alternative is to increase respective multiplier in
 // base/test/test_timeouts.h.
-// TODO(crbug.com/1238865): Re-enable using MAYBE prefix, after PSM supports
-// integration tests.
-IN_PROC_BROWSER_TEST_P(OobeZeroTouchInteractiveUITest, DISABLED_EndToEnd) {
+IN_PROC_BROWSER_TEST_P(OobeZeroTouchInteractiveUITest, MAYBE_EndToEnd) {
   ZeroTouchEndToEnd();
 }
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
index 4dcb7959..9c80c5c 100644
--- a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
@@ -154,7 +154,7 @@
                                 kBodyButtonsSpacing);
 }
 
-BEGIN_METADATA(PrintWarnDialog, views::BubbleDialogDelegateView)
+BEGIN_METADATA(PrintWarnDialog, views::DialogDelegateView)
 END_METADATA
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
index c2294e0..83ef4f5a 100644
--- a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
+++ b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
@@ -6,13 +6,13 @@
 #define CHROME_BROWSER_ASH_POLICY_DLP_DLP_WARN_DIALOG_H_
 
 #include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/window/dialog_delegate.h"
 
 namespace policy {
 
 // PrintWarnDialog is a system dialog that is shown when printing restriction
 // level is set to WARN.
-class PrintWarnDialog : public views::BubbleDialogDelegateView {
+class PrintWarnDialog : public views::DialogDelegateView {
  public:
   METADATA_HEADER(PrintWarnDialog);
   PrintWarnDialog(base::OnceClosure accept_callback,
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
index e07efed..22b8e2d 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
@@ -998,7 +998,8 @@
       state_download_message_processor_(
           std::move(state_download_message_processor)),
       psm_helper_(std::move(private_set_membership_helper)),
-      uma_suffix_(uma_suffix) {
+      uma_suffix_(uma_suffix),
+      recorded_psm_hash_dance_comparison_(false) {
   DCHECK_LE(current_power_, power_limit_);
   DCHECK(!progress_callback_.is_null());
 }
@@ -1021,50 +1022,27 @@
   return true;
 }
 
-bool AutoEnrollmentClientImpl::RetrievePsmCachedDecision() {
-  // PSM protocol has to be enabled whenever this function is called.
-  DCHECK(psm_helper_);
-
-  const absl::optional<bool> private_set_membership_server_state =
-      psm_helper_->GetPsmCachedDecision();
-
-  if (private_set_membership_server_state.has_value()) {
-    has_server_state_ = std::move(private_set_membership_server_state);
-    return true;
-  }
-  return false;
-}
-
-bool AutoEnrollmentClientImpl::IsClientForInitialEnrollment() const {
-  return psm_helper_ != nullptr;
-}
-
-bool AutoEnrollmentClientImpl::ShouldSendDeviceStateRequest() const {
-  return has_server_state_.has_value() && has_server_state_.value() &&
-         !device_state_available_;
-}
-
 bool AutoEnrollmentClientImpl::RetryStep() {
+  if (PsmRetryStep())
+    return true;
+
   // If there is a pending request job, let it finish.
   if (request_job_)
     return true;
 
-  if (IsClientForInitialEnrollment()) {
-    if (PsmRetryStep())
-      return true;
-  } else {
-    // Send DeviceAutoEnrollmentRequest (i.e. Hash dance protocol) if Hash dance
-    // decision has not been retrieved before.
-    if (!GetCachedDecision()) {
-      SendBucketDownloadRequest();
-      return true;
+  if (GetCachedDecision()) {
+    VLOG(1) << "Cached: has_state=" << has_server_state_;
+    // The bucket download check has completed already. If it came back
+    // positive, then device state should be (re-)downloaded.
+    if (has_server_state_) {
+      if (!device_state_available_) {
+        SendDeviceStateRequest();
+        return true;
+      }
     }
-  }
-
-  // Send DeviceStateRetrievalRequest if it has a server-backed state
-  // (determined by either PSM or Hash dance protocol).
-  if (ShouldSendDeviceStateRequest()) {
-    SendDeviceStateRequest();
+  } else {
+    // Start bucket download.
+    SendBucketDownloadRequest();
     return true;
   }
 
@@ -1072,21 +1050,23 @@
 }
 
 bool AutoEnrollmentClientImpl::PsmRetryStep() {
-  // PSM protocol has to be enabled whenever this function is called.
-  DCHECK(psm_helper_);
-
-  // Don't retry if the protocol had an error.
-  if (psm_helper_->HasPsmError())
+  // Don't retry if the protocol is disabled, or an error occurred while
+  // executing the protocol.
+  if (!psm_helper_ || psm_helper_->HasPsmError()) {
     return false;
+  }
 
   // If the PSM protocol is in progress, signal to the caller
   // that nothing else needs to be done.
   if (psm_helper_->IsCheckMembershipInProgress())
     return true;
 
-  if (RetrievePsmCachedDecision()) {
+  const absl::optional<bool> private_set_membership_server_state =
+      psm_helper_->GetPsmCachedDecision();
+
+  if (private_set_membership_server_state.has_value()) {
     LOG(WARNING) << "PSM Cached: psm_server_state="
-                 << has_server_state_.value();
+                 << private_set_membership_server_state.value();
     return false;
   } else {
     psm_helper_->CheckMembership(base::BindOnce(
@@ -1108,6 +1088,16 @@
 
 void AutoEnrollmentClientImpl::ReportProgress(AutoEnrollmentState state) {
   state_ = state;
+  // If hash dance finished with an error or result, record comparison with PSM.
+  // Note that hash dance might be retried but for recording we only care about
+  // the first attempt. If |psm_helper_| is non-null, a PSM request has been
+  // made at this point because it is executed before hash dance.
+  const bool has_hash_dance_result = (state != AUTO_ENROLLMENT_STATE_IDLE &&
+                                      state != AUTO_ENROLLMENT_STATE_PENDING);
+  if (psm_helper_ && !recorded_psm_hash_dance_comparison_ &&
+      has_hash_dance_result) {
+    RecordPsmHashDanceComparison();
+  }
   if (progress_callback_.is_null()) {
     base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
   } else {
@@ -1302,11 +1292,10 @@
     has_server_state_ = IsIdHashInProtobuf(enrollment_response.hashes());
     // Cache the current decision in local_state, so that it is reused in case
     // the device reboots before enrolling.
-    local_state_->SetBoolean(prefs::kShouldAutoEnroll,
-                             has_server_state_.value());
+    local_state_->SetBoolean(prefs::kShouldAutoEnroll, has_server_state_);
     local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_);
     local_state_->CommitPendingWrite();
-    VLOG(1) << "Received has_state=" << has_server_state_.value();
+    VLOG(1) << "Received has_state=" << has_server_state_;
     progress = true;
     // Report timing if hash dance finished successfully and if the caller is
     // still interested in the result.
@@ -1422,4 +1411,69 @@
   }
 }
 
+void AutoEnrollmentClientImpl::RecordPsmHashDanceComparison() {
+  // PSM timeout is enforced in the helper class. This method should only be
+  // called after PSM request finished or ran into timeout.
+  DCHECK(psm_helper_);
+  DCHECK(!psm_helper_->IsCheckMembershipInProgress());
+
+  // Make sure to only record once per instance.
+  recorded_psm_hash_dance_comparison_ = true;
+
+  bool psm_error = psm_helper_->HasPsmError();
+
+  bool hash_dance_decision = has_server_state_;
+  bool hash_dance_error = false;
+  switch (state_) {
+    case AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
+    case AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
+    case AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH:
+    case AUTO_ENROLLMENT_STATE_DISABLED:
+      hash_dance_error = false;
+      break;
+    case AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
+    case AUTO_ENROLLMENT_STATE_SERVER_ERROR:
+      hash_dance_error = true;
+      break;
+    // This method should only be called if hash dance finished.
+    case AUTO_ENROLLMENT_STATE_IDLE:
+    case AUTO_ENROLLMENT_STATE_PENDING:
+    default:
+      NOTREACHED();
+  }
+
+  auto comparison = PsmHashDanceComparison::kEqualResults;
+  if (!hash_dance_error && !psm_error) {
+    absl::optional<bool> psm_decision = psm_helper_->GetPsmCachedDecision();
+
+    // There was no error and this function is only invoked after PSM has been
+    // performed, so there must be a decision.
+    DCHECK(psm_decision.has_value());
+
+    comparison = (hash_dance_decision == psm_decision.value())
+                     ? PsmHashDanceComparison::kEqualResults
+                     : PsmHashDanceComparison::kDifferentResults;
+
+    if (hash_dance_decision != psm_decision.value()) {
+      // Reports the different values of the protocols, after both have finished
+      // executing successfully.
+      auto different_protocols_results_comparison =
+          (psm_decision.value()
+               ? PsmHashDanceDifferentResultsComparison::kPsmTrueHashDanceFalse
+               : PsmHashDanceDifferentResultsComparison::
+                     kHashDanceTruePsmFalse);
+      base::UmaHistogramEnumeration(kUMAPsmHashDanceDifferentResultsComparison,
+                                    different_protocols_results_comparison);
+    }
+  } else if (hash_dance_error && !psm_error) {
+    comparison = PsmHashDanceComparison::kPSMSuccessHashDanceError;
+  } else if (!hash_dance_error && psm_error) {
+    comparison = PsmHashDanceComparison::kPSMErrorHashDanceSuccess;
+  } else {
+    comparison = PsmHashDanceComparison::kBothError;
+  }
+
+  base::UmaHistogramEnumeration(kUMAPsmHashDanceComparison, comparison);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h
index 6931e46..d7a4793 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h
@@ -177,27 +177,14 @@
   // local state. Returns true if that decision has been made and is valid.
   bool GetCachedDecision();
 
-  // Returns true if PSM has a cached decision, then store its value locally
-  // (i.e. store it in |has_server_state_|). Otherwise, false.
-  bool RetrievePsmCachedDecision();
-
-  // Returns true if the current client got created for initial enrollment use
-  // case. Otherwise, false.
-  bool IsClientForInitialEnrollment() const;
-
-  // Returns true if the device has a server-backed state and its state hasn't
-  // been retrieved yet. Otherwise, false.
-  bool ShouldSendDeviceStateRequest() const;
-
-  // For detailed design, see go/psm-source-of-truth-initial-enrollment.
   // Kicks protocol processing, restarting the current step if applicable.
   // Returns true if progress has been made, false if the protocol is done.
   bool RetryStep();
 
-  // Retries running PSM protocol, if it is possible to start it.
-  // Returns true if the protocol is in progress, false if the protocol is done
-  // or had an error.
-  // Note that the PSM protocol is only performed once per OOBE flow.
+  // Retries running PSM protocol, if the protocol
+  // is enabled and it is possible to start. Returns true if the protocol is
+  // enabled or it's in progress, false if the protocol is done. Note that the
+  // PSM protocol is only performed once per OOBE flow.
   bool PsmRetryStep();
 
   // Cleans up and invokes |progress_callback_|.
@@ -247,6 +234,10 @@
   // Updates the UMA histogram for successful hash dance.
   void RecordHashDanceSuccessTimeHistogram();
 
+  // Records the UMA histogram comparing results of hash dance and PSM. This
+  // function should be called after PSM and hash dance requests finished.
+  void RecordPsmHashDanceComparison();
+
   // Callback to invoke when the protocol generates a relevant event. This can
   // be either successful completion or an error that requires external action.
   ProgressCallback progress_callback_;
@@ -254,12 +245,9 @@
   // Current state.
   AutoEnrollmentState state_;
 
-  // Indicates whether the device has a server-backed state or not, regardless
-  // of which protocol (i.e. PSM or Hash dance) collected that information.
-  // Note that if it doesn't have an associated value after starting the auto
-  // enrollment client, then the used protocol failed to collect that
-  // information.
-  absl::optional<bool> has_server_state_;
+  // Whether the hash bucket check succeeded, indicating that the server knows
+  // this device and might have keep state for it.
+  bool has_server_state_;
 
   // Whether the download of server-kept device state completed successfully.
   bool device_state_available_;
@@ -323,6 +311,11 @@
   // |AutoEnrollmentclient| used for initial enrollment.
   const std::string uma_suffix_;
 
+  // Whether this instance already recorded the comparison of PSM and hash
+  // dance. This is required because we do not want to record the result again
+  // on a hash dance retry.
+  bool recorded_psm_hash_dance_comparison_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientImpl);
 };
 
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl_unittest.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl_unittest.cc
index 09438352..bb4bc53 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl_unittest.cc
@@ -1277,9 +1277,8 @@
   EXPECT_EQ(state_retrieval_job_type_, GetExpectedStateRetrievalJobType());
 }
 
-// PSM is disabed to test only Hash dance for FRE case extensively instead. That
-// is because PSM is running only for initial enrollment, and Hash dance for FRE
-// use case.
+// PSM is disabed to test only FRE case extensively instead. That is necessary
+// as both protocols are running in sequential order starting off with PSM.
 INSTANTIATE_TEST_SUITE_P(
     FRE,
     AutoEnrollmentClientImplTest,
@@ -1288,6 +1287,17 @@
                          PsmState::kDisabled)),
                      testing::Values(kInvalidPsmTestCaseIndex)));
 
+// PSM is disabed to test only initial enrollment case extensively instead. That
+// is necessary as both protocols are running in sequential order starting off
+// with PSM.
+INSTANTIATE_TEST_SUITE_P(
+    InitialEnrollment,
+    AutoEnrollmentClientImplTest,
+    testing::Combine(testing::Values(AutoEnrollmentClientImplTestState(
+                         AutoEnrollmentProtocol::kInitialEnrollment,
+                         PsmState::kDisabled)),
+                     testing::Values(kInvalidPsmTestCaseIndex)));
+
 using AutoEnrollmentClientImplFREToInitialEnrollmentTest =
     AutoEnrollmentClientImplTest;
 
@@ -1398,9 +1408,9 @@
   EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
 }
 
-// PSM is disabed to test only Hash dance for FRE case extensively instead. That
-// is because PSM is running only for initial enrollment, and Hash dance for FRE
-// use case.
+// PSM is disabed to test only switching from FRE to initial enrollment case
+// extensively instead. That is necessary as both protocols are running in
+// sequential order starting off with PSM.
 INSTANTIATE_TEST_SUITE_P(
     FREToInitialEnrollment,
     AutoEnrollmentClientImplFREToInitialEnrollmentTest,
@@ -1715,10 +1725,8 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillReplyWithPsmQueryResponse();
 
-  // Fail for DeviceInitialEnrollmentStateRequest if the device has a
-  // server-backed state.
-  if (kExpectedMembershipResult)
-    ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
 
   client()->Start();
 
@@ -1749,6 +1757,9 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillReplyWithEmptyPsmResponse();
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1767,6 +1778,9 @@
   InSequence sequence;
   ServerWillReplyWithEmptyPsmResponse();
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1786,6 +1800,9 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillFailForPsm(net::ERR_FAILED, DeviceManagementService::kSuccess);
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1807,6 +1824,9 @@
   InSequence sequence;
   ServerWillFailForPsm(net::ERR_FAILED, DeviceManagementService::kSuccess);
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1826,6 +1846,9 @@
   InSequence sequence;
   ServerWillFailForPsm(net::OK, net::ERR_CONNECTION_CLOSED);
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1844,6 +1867,9 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillFailForPsm(net::OK, net::ERR_CONNECTION_CLOSED);
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
@@ -1863,7 +1889,6 @@
 TEST_P(PsmHelperTest, RetryLogicAfterMembershipSuccessfullyRetrieved) {
   InSequence sequence;
 
-  const bool kExpectedMembershipResult = GetExpectedMembershipResult();
   const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
   const base::Time kExpectedPsmDeterminationTimestamp =
       base::Time::NowFromSystemTime() + kOneSecondTimeDelta;
@@ -1874,23 +1899,21 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillReplyWithPsmQueryResponse();
 
-  // Fail for DeviceInitialEnrollmentStateRequest if the device has a
-  // server-backed state.
-  if (kExpectedMembershipResult)
-    ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
 
   client()->Start();
   base::RunLoop().RunUntilIdle();
 
   const StateDiscoveryResult expected_state_result =
-      kExpectedMembershipResult
+      GetExpectedMembershipResult()
           ? StateDiscoveryResult::kSuccessHasServerSideState
           : StateDiscoveryResult::kSuccessNoServerSideState;
   EXPECT_EQ(GetStateDiscoveryResult(), expected_state_result);
 
   EXPECT_EQ(
       GetPsmExecutionResult(),
-      kExpectedMembershipResult
+      GetExpectedMembershipResult()
           ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE
           : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE);
   EXPECT_EQ(kExpectedPsmDeterminationTimestamp, GetPsmDeterminationTimestamp());
@@ -1898,10 +1921,8 @@
   // Verify that none of the PSM requests have been sent again. And its cached
   // membership result hasn't changed.
 
-  // Fail for DeviceInitialEnrollmentStateRequest if the device has a
-  // server-backed state.
-  if (kExpectedMembershipResult)
-    ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
 
   client()->Retry();
   base::RunLoop().RunUntilIdle();
@@ -1920,6 +1941,9 @@
   ServerWillReplyWithPsmOprfResponse();
   ServerWillFailForPsm(net::OK, net::ERR_CONNECTION_CLOSED);
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Start();
   base::RunLoop().RunUntilIdle();
 
@@ -1934,6 +1958,9 @@
   // Verify that none of the PSM requests have been sent again. And its cached
   // membership result hasn't changed.
 
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
   client()->Retry();
   base::RunLoop().RunUntilIdle();
 
@@ -1957,5 +1984,649 @@
                          AutoEnrollmentProtocol::kInitialEnrollment,
                          PsmState::kEnabled)),
                      ::testing::Range(0, kNumberOfPsmTestCases)));
+
+using PsmHelperAndHashDanceTest = PsmHelperTest;
+
+TEST_P(PsmHelperAndHashDanceTest, PsmRlweQueryFailedAndHashDanceSucceeded) {
+  InSequence sequence;
+
+  // Fail for PSM RLWE query request.
+  ServerWillReplyWithPsmOprfResponse();
+  ServerWillFailForPsm(net::OK, net::ERR_CONNECTION_CLOSED);
+
+  // Succeed for both DeviceAutoEnrollmentRequest and
+  // DeviceStateRetrievalRequest. And the result of DeviceAutoEnrollmentRequest
+  // is positive.
+  ServerWillReply(/*modulus=*/-1, /*with_hashes=*/true, /*with_id_hash=*/true);
+  ServerWillSendState(
+      "example.com",
+      em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED,
+      kDisabledMessage, kWithLicense,
+      em::DeviceInitialEnrollmentStateResponse::CHROME_ENTERPRISE);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify failure of PSM protocol.
+  EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
+  EXPECT_EQ(GetPsmExecutionResult(),
+            em::DeviceRegisterRequest::PSM_RESULT_ERROR);
+  EXPECT_TRUE(GetPsmDeterminationTimestamp().is_null());
+  ExpectPsmHistograms(PsmResult::kServerError,
+                      /*success_time_recorded=*/false);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_SUCCESS,
+                                  /*dm_status_count=*/1);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_HTTP_STATUS_ERROR,
+                                  /*dm_status_count=*/1);
+  VerifyPsmRlweQueryRequest();
+  VerifyPsmLastRequestJobType();
+
+  // Verify Hash dance result.
+  VerifyCachedResult(true, kPowerLimit);
+
+  // Verify recorded comparison value between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      PsmHashDanceComparison::kPSMErrorHashDanceSuccess);
+
+  // Verify Hash dance protocol overall execution time and its success time
+  // histograms were recorded correctly with the same value.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(0),
+      /*success_time_recorded=*/true);
+
+  // Verify device state result.
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+  EXPECT_EQ(state_retrieval_job_type_, GetExpectedStateRetrievalJobType());
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
+  VerifyServerBackedState(
+      "example.com", kDeviceStateRestoreModeReEnrollmentEnforced,
+      kDisabledMessage, kWithLicense, kDeviceStateLicenseTypeEnterprise);
+}
+
+TEST_P(PsmHelperAndHashDanceTest, PsmRlweOprfFailedAndHashDanceSucceeded) {
+  InSequence sequence;
+
+  // Fail for PSM RLWE OPRF request.
+  ServerWillFailForPsm(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  // Succeed for both DeviceAutoEnrollmentRequest and
+  // DeviceStateRetrievalRequest. And the result of DeviceAutoEnrollmentRequest
+  // is positive.
+  ServerWillReply(/*modulus=*/-1, /*with_hashes=*/true, /*with_id_hash=*/true);
+  ServerWillSendState(
+      "example.com",
+      em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED,
+      kDisabledMessage, kWithLicense,
+      em::DeviceInitialEnrollmentStateResponse::CHROME_ENTERPRISE);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify failure of PSM protocol.
+  EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
+  EXPECT_EQ(GetPsmExecutionResult(),
+            em::DeviceRegisterRequest::PSM_RESULT_ERROR);
+  EXPECT_TRUE(GetPsmDeterminationTimestamp().is_null());
+  ExpectPsmHistograms(PsmResult::kServerError,
+                      /*success_time_recorded=*/false);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                                  /*dm_status_count=*/1);
+  VerifyPsmLastRequestJobType();
+
+  // Verify Hash dance result.
+  VerifyCachedResult(true, kPowerLimit);
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      PsmHashDanceComparison::kPSMErrorHashDanceSuccess);
+
+  // Verify Hash dance protocol overall execution time and its success time
+  // histograms were recorded correctly with the same value.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(0),
+      /*success_time_recorded=*/true);
+
+  // Verify device state result.
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+  EXPECT_EQ(state_retrieval_job_type_, GetExpectedStateRetrievalJobType());
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
+  VerifyServerBackedState(
+      "example.com", kDeviceStateRestoreModeReEnrollmentEnforced,
+      kDisabledMessage, kWithLicense, kDeviceStateLicenseTypeEnterprise);
+}
+
+TEST_P(PsmHelperAndHashDanceTest, PsmSucceedAndHashDanceSucceed) {
+  InSequence sequence;
+
+  const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
+  const base::Time kExpectedPsmDeterminationTimestamp =
+      base::Time::NowFromSystemTime() + kOneSecondTimeDelta;
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Succeed for both PSM RLWE requests.
+  ServerWillReplyWithPsmOprfResponse();
+  ServerWillReplyWithPsmQueryResponse();
+
+  // Succeed for both DeviceAutoEnrollmentRequest and
+  // DeviceStateRetrievalRequest. And the result of DeviceAutoEnrollmentRequest
+  // is positive.
+  const bool kExpectedHashDanceResult = true;
+  ServerWillReply(/*modulus=*/-1, /*with_hashes=*/true,
+                  /*with_id_hash=*/kExpectedHashDanceResult);
+  ServerWillSendState(
+      "example.com",
+      em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED,
+      kDisabledMessage, kWithLicense,
+      em::DeviceInitialEnrollmentStateResponse::CHROME_ENTERPRISE);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify PSM result.
+  EXPECT_EQ(GetStateDiscoveryResult(),
+            GetExpectedMembershipResult()
+                ? StateDiscoveryResult::kSuccessHasServerSideState
+                : StateDiscoveryResult::kSuccessNoServerSideState);
+  EXPECT_EQ(
+      GetPsmExecutionResult(),
+      GetExpectedMembershipResult()
+          ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE
+          : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE);
+  EXPECT_EQ(kExpectedPsmDeterminationTimestamp, GetPsmDeterminationTimestamp());
+  ExpectPsmHistograms(PsmResult::kSuccessfulDetermination,
+                      /*success_time_recorded=*/true);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_SUCCESS,
+                                  /*dm_status_count=*/2);
+  VerifyPsmRlweQueryRequest();
+  VerifyPsmLastRequestJobType();
+
+  // Verify Hash dance result.
+  VerifyCachedResult(kExpectedHashDanceResult, kPowerLimit);
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      (GetExpectedMembershipResult() == kExpectedHashDanceResult)
+          ? PsmHashDanceComparison::kEqualResults
+          : PsmHashDanceComparison::kDifferentResults);
+
+  if (GetExpectedMembershipResult() != kExpectedHashDanceResult) {
+    // Verify recorded different results for PSM and Hash dance.
+    ExpectPsmHashDanceDifferentResultsComparisonRecorded(
+        PsmHashDanceDifferentResultsComparison::kHashDanceTruePsmFalse);
+  }
+
+  // Verify Hash dance protocol overall execution time and its success time
+  // histograms were recorded correctly with the same value.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(0),
+      /*success_time_recorded=*/true);
+
+  // Verify device state result.
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+  EXPECT_EQ(state_retrieval_job_type_, GetExpectedStateRetrievalJobType());
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
+  VerifyServerBackedState(
+      "example.com", kDeviceStateRestoreModeReEnrollmentEnforced,
+      kDisabledMessage, kWithLicense, kDeviceStateLicenseTypeEnterprise);
+}
+
+TEST_P(PsmHelperAndHashDanceTest,
+       PsmSucceedAndHashDanceSucceedForNoEnrollment) {
+  InSequence sequence;
+
+  const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
+  const base::Time kExpectedPsmDeterminationTimestamp =
+      base::Time::NowFromSystemTime() + kOneSecondTimeDelta;
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Succeed for both PSM RLWE requests.
+  ServerWillReplyWithPsmOprfResponse();
+  ServerWillReplyWithPsmQueryResponse();
+
+  // Succeed with a negative result for DeviceAutoEnrollmentRequest i.e. Hash
+  // dance request.
+  const bool kExpectedHashDanceResult = false;
+  ServerWillReply(/*modulus=*/-1, /*with_hashes=*/true,
+                  /*with_id_hash=*/kExpectedHashDanceResult);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify PSM result.
+  EXPECT_EQ(GetStateDiscoveryResult(),
+            GetExpectedMembershipResult()
+                ? StateDiscoveryResult::kSuccessHasServerSideState
+                : StateDiscoveryResult::kSuccessNoServerSideState);
+  EXPECT_EQ(
+      GetPsmExecutionResult(),
+      GetExpectedMembershipResult()
+          ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE
+          : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE);
+  EXPECT_EQ(kExpectedPsmDeterminationTimestamp, GetPsmDeterminationTimestamp());
+  ExpectPsmHistograms(PsmResult::kSuccessfulDetermination,
+                      /*success_time_recorded=*/true);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_SUCCESS,
+                                  /*dm_status_count=*/2);
+  VerifyPsmRlweQueryRequest();
+  VerifyPsmLastRequestJobType();
+
+  // Verify Hash dance result.
+  VerifyCachedResult(kExpectedHashDanceResult, kPowerLimit);
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      (GetExpectedMembershipResult() == kExpectedHashDanceResult)
+          ? PsmHashDanceComparison::kEqualResults
+          : PsmHashDanceComparison::kDifferentResults);
+
+  if (GetExpectedMembershipResult() != kExpectedHashDanceResult) {
+    // Verify recorded different results for PSM and Hash dance.
+    ExpectPsmHashDanceDifferentResultsComparisonRecorded(
+        PsmHashDanceDifferentResultsComparison::kPsmTrueHashDanceFalse);
+  }
+
+  // Verify Hash dance protocol overall execution time and its success time
+  // histograms were recorded correctly with the same value.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(0),
+      /*success_time_recorded=*/true);
+
+  // Verify that no enrollment has been done, and no state has been retrieved.
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
+  EXPECT_FALSE(HasServerBackedState());
+}
+
+TEST_P(PsmHelperAndHashDanceTest, PsmRlweOprfFailedAndHashDanceFailed) {
+  InSequence sequence;
+
+  // Fail for PSM RLWE OPRF request.
+  ServerWillFailForPsm(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify failure of PSM protocol.
+  EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
+  EXPECT_EQ(GetPsmExecutionResult(),
+            em::DeviceRegisterRequest::PSM_RESULT_ERROR);
+  EXPECT_TRUE(GetPsmDeterminationTimestamp().is_null());
+  ExpectPsmHistograms(PsmResult::kServerError,
+                      /*success_time_recorded=*/false);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                                  /*dm_status_count=*/1);
+  VerifyPsmLastRequestJobType();
+
+  // Verify failure of Hash dance by inexistence of its cached decision.
+  EXPECT_FALSE(HasCachedDecision());
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(PsmHashDanceComparison::kBothError);
+
+  // Verify that no enrollment has been done, and no state has been retrieved.
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT,
+            failed_job_type_);
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_SERVER_ERROR);
+  EXPECT_FALSE(HasServerBackedState());
+}
+
+TEST_P(PsmHelperAndHashDanceTest,
+       RetryLogicAfterPsmSucceededAndHashDanceSucceeded) {
+  InSequence sequence;
+
+  const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
+  const base::Time kExpectedPsmDeterminationTimestamp =
+      base::Time::NowFromSystemTime() + kOneSecondTimeDelta;
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Succeed for both PSM RLWE requests.
+  ServerWillReplyWithPsmOprfResponse();
+  ServerWillReplyWithPsmQueryResponse();
+
+  // Succeed for both DeviceAutoEnrollmentRequest and
+  // DeviceStateRetrievalRequest. And the result of DeviceAutoEnrollmentRequest
+  // is positive.
+  const bool kExpectedHashDanceResult = true;
+  ServerWillReply(/*modulus=*/-1, /*with_hashes=*/true,
+                  /*with_id_hash=*/kExpectedHashDanceResult);
+  ServerWillSendState(
+      "example.com",
+      em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED,
+      kDisabledMessage, kWithLicense,
+      em::DeviceInitialEnrollmentStateResponse::CHROME_ENTERPRISE);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify PSM result.
+  const StateDiscoveryResult expected_psm_state_result =
+      GetExpectedMembershipResult()
+          ? StateDiscoveryResult::kSuccessHasServerSideState
+          : StateDiscoveryResult::kSuccessNoServerSideState;
+  EXPECT_EQ(GetStateDiscoveryResult(), expected_psm_state_result);
+  EXPECT_EQ(
+      GetPsmExecutionResult(),
+      GetExpectedMembershipResult()
+          ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE
+          : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE);
+  EXPECT_EQ(kExpectedPsmDeterminationTimestamp, GetPsmDeterminationTimestamp());
+
+  // Verify Hash dance result.
+  VerifyCachedResult(kExpectedHashDanceResult, kPowerLimit);
+
+  // Verify device state result.
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+  EXPECT_EQ(state_retrieval_job_type_, GetExpectedStateRetrievalJobType());
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
+  VerifyServerBackedState(
+      "example.com", kDeviceStateRestoreModeReEnrollmentEnforced,
+      kDisabledMessage, kWithLicense, kDeviceStateLicenseTypeEnterprise);
+
+  // Trigger AutoEnrollmentClientImpl retry.
+  client()->Retry();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that PSM cached decision hasn't changed, and no new requests have
+  // been sent.
+  EXPECT_EQ(GetStateDiscoveryResult(), expected_psm_state_result);
+  ExpectPsmHistograms(PsmResult::kSuccessfulDetermination,
+                      /*success_time_recorded=*/true);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_SUCCESS,
+                                  /*dm_status_count=*/2);
+  VerifyPsmRlweQueryRequest();
+  VerifyPsmLastRequestJobType();
+
+  // Verify Hash dance protocol overall execution time and its success time
+  // histograms were recorded correctly with the same value.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(0),
+      /*success_time_recorded=*/true);
+
+  // Verify that Hash dance cached decision hasn't changed, and no new request
+  // has been sent.
+  VerifyCachedResult(kExpectedHashDanceResult, kPowerLimit);
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT);
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      (GetExpectedMembershipResult() == kExpectedHashDanceResult)
+          ? PsmHashDanceComparison::kEqualResults
+          : PsmHashDanceComparison::kDifferentResults);
+
+  if (GetExpectedMembershipResult() != kExpectedHashDanceResult) {
+    // Verify recorded different results for PSM and Hash dance.
+    ExpectPsmHashDanceDifferentResultsComparisonRecorded(
+        PsmHashDanceDifferentResultsComparison::kHashDanceTruePsmFalse);
+  }
+}
+
+TEST_P(PsmHelperAndHashDanceTest,
+       RetryLogicAfterPsmRlweOprfFailedAndHashDanceFailed) {
+  InSequence sequence;
+
+  // Fail for PSM RLWE OPRF request.
+  ServerWillFailForPsm(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify failure of PSM protocol.
+  const StateDiscoveryResult expected_psm_state_result =
+      StateDiscoveryResult::kFailure;
+  EXPECT_EQ(GetStateDiscoveryResult(), expected_psm_state_result);
+  EXPECT_EQ(GetPsmExecutionResult(),
+            em::DeviceRegisterRequest::PSM_RESULT_ERROR);
+  EXPECT_TRUE(GetPsmDeterminationTimestamp().is_null());
+
+  // Verify failure of Hash dance by inexistence of its cached decision.
+  EXPECT_FALSE(HasCachedDecision());
+
+  // Verify that no enrollment has been done, and no state has been retrieved.
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT,
+            failed_job_type_);
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_SERVER_ERROR);
+  EXPECT_FALSE(HasServerBackedState());
+
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request.
+  ServerWillFail(net::OK, DeviceManagementService::kServiceUnavailable);
+
+  // Trigger AutoEnrollmentClientImpl retry.
+  client()->Retry();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that PSM cached decision hasn't changed, and no
+  // new requests have been sent.
+  EXPECT_EQ(GetStateDiscoveryResult(), expected_psm_state_result);
+  ExpectPsmHistograms(PsmResult::kServerError,
+                      /*success_time_recorded=*/false);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                                  /*dm_status_count=*/1);
+  VerifyPsmRlweOprfRequest();
+  VerifyPsmLastRequestJobType();
+
+  // Verify inexistence of Hash dance cached decision, and its new request
+  // has failed again.
+  EXPECT_FALSE(HasCachedDecision());
+  EXPECT_EQ(auto_enrollment_job_type_,
+            DeviceManagementService::JobConfiguration::TYPE_INVALID);
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT,
+            failed_job_type_);
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(PsmHashDanceComparison::kBothError);
+}
+
+TEST_P(PsmHelperAndHashDanceTest,
+       RetryWhileWaitingForPsmOprfResponseAndHashDanceFails) {
+  InSequence sequence;
+
+  const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
+
+  DeviceManagementService::JobForTesting psm_rlwe_oprf_job;
+  DeviceManagementService::JobForTesting hash_dance_job;
+
+  // Expect two requests and capture them, in order, when available in
+  // |psm_rlwe_oprf_job| and |hash_dance_job|.
+  ServerWillReplyAsyncForPsm(&psm_rlwe_oprf_job);
+  ServerWillReplyAsync(&hash_dance_job);
+
+  // Expect none of the jobs have been captured.
+  EXPECT_FALSE(psm_rlwe_oprf_job.IsActive());
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify the only job that has been captured is the PSM RLWE OPRF request.
+  VerifyPsmRlweOprfRequest();
+  VerifyPsmLastRequestJobType();
+  ASSERT_TRUE(psm_rlwe_oprf_job.IsActive());
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  // Trigger RetryStep.
+  client()->Retry();
+
+  // Verify hash dance job has not been triggered after RetryStep.
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Fail for PSM RLWE OPRF request.
+  ServerFailsForAsyncJob(&psm_rlwe_oprf_job);
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Verify failure of PSM protocol.
+  EXPECT_EQ(GetStateDiscoveryResult(), StateDiscoveryResult::kFailure);
+  EXPECT_EQ(GetPsmExecutionResult(),
+            em::DeviceRegisterRequest::PSM_RESULT_ERROR);
+  EXPECT_TRUE(GetPsmDeterminationTimestamp().is_null());
+  ExpectPsmHistograms(PsmResult::kServerError,
+                      /*success_time_recorded=*/false);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                                  /*dm_status_count=*/1);
+
+  // Verify hash dance job has been captured.
+  ASSERT_TRUE(hash_dance_job.IsActive());
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT,
+            last_async_job_type_);
+
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request by sending
+  // an empty response.
+  ServerRepliesEmptyResponseForAsyncJob(&hash_dance_job);
+
+  // Verify Hash dance protocol overall execution time histogram has been
+  // recorded correctly. And its success time histogram has not been recorded.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(1),
+      /*success_time_recorded=*/false);
+
+  // Verify failure of Hash dance by inexistence of its cached decision.
+  EXPECT_FALSE(HasCachedDecision());
+
+  // Verify that no enrollment has been done, and no state has been retrieved.
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_SERVER_ERROR);
+  EXPECT_FALSE(HasServerBackedState());
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(PsmHashDanceComparison::kBothError);
+
+  // Verify both jobs have finished.
+  EXPECT_FALSE(hash_dance_job.IsActive());
+  EXPECT_FALSE(psm_rlwe_oprf_job.IsActive());
+}
+
+TEST_P(PsmHelperAndHashDanceTest,
+       RetryWhileWaitingForPsmQueryResponseAndHashDanceFails) {
+  InSequence sequence;
+
+  const base::TimeDelta kOneSecondTimeDelta = base::TimeDelta::FromSeconds(1);
+  const base::Time kExpectedPsmDeterminationTimestamp =
+      base::Time::NowFromSystemTime() + kOneSecondTimeDelta;
+
+  DeviceManagementService::JobForTesting psm_rlwe_oprf_job;
+  DeviceManagementService::JobForTesting psm_rlwe_query_job;
+  DeviceManagementService::JobForTesting hash_dance_job;
+
+  // Expect three requests and capture them, in order, when available in
+  // |psm_rlwe_oprf_job|, |psm_rlwe_query_job|, and |hash_dance_job|.
+  ServerWillReplyAsyncForPsm(&psm_rlwe_oprf_job);
+  ServerWillReplyAsyncForPsm(&psm_rlwe_query_job);
+  ServerWillReplyAsync(&hash_dance_job);
+
+  // Expect none of the jobs have been captured.
+  EXPECT_FALSE(psm_rlwe_oprf_job.IsActive());
+  EXPECT_FALSE(psm_rlwe_query_job.IsActive());
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  client()->Start();
+  base::RunLoop().RunUntilIdle();
+
+  // Verify the only job that has been captured is the PSM RLWE OPRF request.
+  VerifyPsmRlweOprfRequest();
+  VerifyPsmLastRequestJobType();
+  ASSERT_TRUE(psm_rlwe_oprf_job.IsActive());
+  EXPECT_FALSE(psm_rlwe_query_job.IsActive());
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  // Reply with PSM RLWE OPRF response.
+  ServerReplyForPsmAsyncJobWithOprfResponse(&psm_rlwe_oprf_job);
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Verify the only job that has been captured is the PSM RLWE Query request.
+  VerifyPsmRlweQueryRequest();
+  VerifyPsmLastRequestJobType();
+  ASSERT_TRUE(psm_rlwe_query_job.IsActive());
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  // Trigger RetryStep.
+  client()->Retry();
+
+  // Verify hash dance job has not been triggered after RetryStep.
+  EXPECT_FALSE(hash_dance_job.IsActive());
+
+  // Reply with PSM RLWE Query response.
+  ServerReplyForPsmAsyncJobWithQueryResponse(&psm_rlwe_query_job);
+
+  // Advance the time forward one second.
+  task_environment_.FastForwardBy(kOneSecondTimeDelta);
+
+  // Verify PSM result.
+  EXPECT_EQ(GetStateDiscoveryResult(),
+            GetExpectedMembershipResult()
+                ? StateDiscoveryResult::kSuccessHasServerSideState
+                : StateDiscoveryResult::kSuccessNoServerSideState);
+  EXPECT_EQ(
+      GetPsmExecutionResult(),
+      GetExpectedMembershipResult()
+          ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE
+          : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE);
+  EXPECT_EQ(kExpectedPsmDeterminationTimestamp, GetPsmDeterminationTimestamp());
+  ExpectPsmHistograms(PsmResult::kSuccessfulDetermination,
+                      /*success_time_recorded=*/true);
+  ExpectPsmRequestStatusHistogram(DM_STATUS_SUCCESS,
+                                  /*dm_status_count=*/2);
+
+  // Verify hash dance job has been captured.
+  ASSERT_TRUE(hash_dance_job.IsActive());
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_AUTO_ENROLLMENT,
+            last_async_job_type_);
+
+  // Fail for DeviceAutoEnrollmentRequest i.e. hash dance request by sending
+  // an empty response.
+  ServerRepliesEmptyResponseForAsyncJob(&hash_dance_job);
+
+  // Verify Hash dance protocol overall execution time histogram has been
+  // recorded correctly. And its success time histogram has not been recorded.
+  ExpectHashDanceExecutionTimeHistogram(
+      /*expected_time_recorded=*/base::TimeDelta::FromSeconds(1),
+      /*success_time_recorded=*/false);
+
+  // Verify failure of Hash dance by inexistence of its cached decision.
+  EXPECT_FALSE(HasCachedDecision());
+
+  // Verify that no enrollment has been done, and no state has been retrieved.
+  EXPECT_EQ(state_, AUTO_ENROLLMENT_STATE_SERVER_ERROR);
+  EXPECT_FALSE(HasServerBackedState());
+
+  // Verify recorded comparison between PSM and Hash dance.
+  ExpectPsmHashDanceComparisonRecorded(
+      PsmHashDanceComparison::kPSMSuccessHashDanceError);
+
+  // Verify all jobs have finished.
+  EXPECT_FALSE(hash_dance_job.IsActive());
+  EXPECT_FALSE(psm_rlwe_oprf_job.IsActive());
+  EXPECT_FALSE(psm_rlwe_query_job.IsActive());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PsmAndHashDance,
+    PsmHelperAndHashDanceTest,
+    testing::Combine(testing::Values(AutoEnrollmentClientImplTestState(
+                         AutoEnrollmentProtocol::kInitialEnrollment,
+                         PsmState::kEnabled)),
+                     ::testing::Range(0, kNumberOfPsmTestCases)));
 }  // namespace
 }  // namespace policy
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index df401a6..646ebd6 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -51,6 +51,7 @@
 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/android/gurl_android.h"
 
 namespace autofill {
 namespace {
@@ -242,7 +243,8 @@
       ConvertUTF8ToJavaString(env, card.server_id()),
       ConvertUTF16ToJavaString(env,
                                card.CardIdentifierStringForAutofillDisplay()),
-      ConvertUTF16ToJavaString(env, card.nickname()));
+      ConvertUTF16ToJavaString(env, card.nickname()),
+      url::GURLAndroid::FromNativeGURL(env, card.card_art_url()));
 }
 
 // static
@@ -270,7 +272,12 @@
       ConvertJavaStringToUTF8(Java_CreditCard_getServerId(env, jcard)));
   card->SetNickname(
       ConvertJavaStringToUTF16(Java_CreditCard_getNickname(env, jcard)));
-
+  base::android::ScopedJavaLocalRef<jobject> java_card_art_url =
+      Java_CreditCard_getCardArtUrl(env, jcard);
+  if (!java_card_art_url.is_null()) {
+    card->set_card_art_url(
+        *url::GURLAndroid::ToNativeGURL(env, java_card_art_url));
+  }
   // Only set the guid if it is an existing card (java guid not empty).
   // Otherwise, keep the generated one.
   std::string guid =
diff --git a/chrome/browser/data_saver/lite_video_browsertest.cc b/chrome/browser/data_saver/lite_video_browsertest.cc
index 854d32fd..01c6e9a0 100644
--- a/chrome/browser/data_saver/lite_video_browsertest.cc
+++ b/chrome/browser/data_saver/lite_video_browsertest.cc
@@ -699,103 +699,4 @@
           lite_video::LiteVideoThrottleResult::kThrottleStoppedOnRebuffer));
 }
 
-class LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest
-    : public LiteVideoStopThrottlingOnPlaybackSeekBrowserTest {
- public:
-  LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest()
-      : prerender_helper_(base::BindRepeating(
-            &LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest::
-                GetWebContents,
-            base::Unretained(this))) {}
-  ~LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest() override =
-      default;
-  LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest(
-      const LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest&) =
-      delete;
-
-  LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest& operator=(
-      const LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest&) =
-      delete;
-
-  void SetUp() override {
-    prerender_helper_.SetUp(&http_server_);
-    LiteVideoBrowserTest::SetUp();
-  }
-
-  void SetUpOnMainThread() override {
-    host_resolver()->AddRule("*", "127.0.0.1");
-    LiteVideoStopThrottlingOnPlaybackSeekBrowserTest::SetUpOnMainThread();
-  }
-
-  content::test::PrerenderTestHelper& prerender_test_helper() {
-    return prerender_helper_;
-  }
-
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
- private:
-  content::test::PrerenderTestHelper prerender_helper_;
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    ,
-    LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest,
-    ::testing::Bool());
-
-IN_PROC_BROWSER_TEST_P(
-    LiteVideoStopThrottlingOnPlaybackSeekPrerenderBrowserTest,
-    PrerenderingShouldNotAffectPlaybackSeekTest) {
-  ukm::TestAutoSetUkmRecorder ukm_recorder;
-  TestMSEPlayback("bear-vp9.webm", "2000", "2000", false);
-
-  // Load the media page in the prerender and the prerendering shouldn't
-  // affect the existing media playback seek test.
-  prerender_test_helper().AddPrerender(media_url());
-
-  RetryForHistogramUntilCountReached(histogram_tester(),
-                                     "Media.VideoHeight.Initial.MSE", 1);
-
-  histogram_tester().ExpectUniqueSample("LiteVideo.HintAgent.HasHint", true, 1);
-
-  // Trigger a media playback seek.
-  ASSERT_TRUE(
-      content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(),
-                      "document.querySelector('video').currentTime = 1"));
-
-  // Verify some responses were throttled and then throttling is stopped.
-  if (should_disable_lite_videos_on_seek()) {
-    RetryForHistogramUntilCountReached(
-        histogram_tester(), "LiteVideo.MediaPlayerSeek.StopThrottling", 1);
-  }
-
-  EXPECT_GE(1U, histogram_tester()
-                    .GetAllSamples("LiteVideo.URLLoader.ThrottleLatency")
-                    .size());
-  EXPECT_EQ(should_disable_lite_videos_on_seek() ? 1U : 0U,
-            histogram_tester()
-                .GetAllSamples("LiteVideo.MediaPlayerSeek.StopThrottling")
-                .size());
-  EXPECT_GE(
-      1U, histogram_tester()
-              .GetAllSamples("LiteVideo.NavigationMetrics.FrameRebufferMapSize")
-              .size());
-
-  // Close the tab to flush the UKM metrics.
-  browser()->tab_strip_model()->GetActiveWebContents()->Close();
-
-  auto entries =
-      ukm_recorder.GetEntriesByName(ukm::builders::LiteVideo::kEntryName);
-  ASSERT_EQ(1u, entries.size());
-  auto* entry = entries[0];
-  ukm_recorder.ExpectEntrySourceHasUrl(entry, media_url());
-  ukm_recorder.ExpectEntryMetric(
-      entry, ukm::builders::LiteVideo::kThrottlingStartDecisionName,
-      static_cast<int>(lite_video::LiteVideoDecision::kAllowed));
-  ukm_recorder.ExpectEntryMetric(
-      entry, ukm::builders::LiteVideo::kBlocklistReasonName,
-      static_cast<int>(lite_video::LiteVideoBlocklistReason::kUnknown));
-}
-
 }  // namespace
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android.cc b/chrome/browser/device_reauth/android/biometric_authenticator_android.cc
index e170b75..89a5f22 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_android.cc
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_android.cc
@@ -65,19 +65,6 @@
 
 }  // namespace
 
-// static
-scoped_refptr<device_reauth::BiometricAuthenticator>
-ChromeBiometricAuthenticator::Create(WebContents* web_contents) {
-  auto* window_android = web_contents->GetNativeView()->GetWindowAndroid();
-  if (!window_android) {
-    // GetWindowAndroid() can be null in tests.
-    return nullptr;
-  }
-
-  return base::WrapRefCounted(new BiometricAuthenticatorAndroid(
-      std::make_unique<BiometricAuthenticatorBridgeImpl>(window_android)));
-}
-
 BiometricAuthenticatorAndroid::BiometricAuthenticatorAndroid(
     std::unique_ptr<BiometricAuthenticatorBridge> bridge)
     : bridge_(std::move(bridge)) {}
@@ -95,8 +82,10 @@
 void BiometricAuthenticatorAndroid::Authenticate(
     device_reauth::BiometricAuthRequester requester,
     AuthenticateCallback callback) {
-  DCHECK(!callback_);
-  DCHECK(!requester_.has_value());
+  // Previous authentication is not yet completed, so return.
+  if (callback_ || requester_.has_value())
+    return;
+
   callback_ = std::move(callback);
   requester_ = requester;
 
@@ -127,6 +116,14 @@
   bridge_->Cancel();
 }
 
+// static
+scoped_refptr<BiometricAuthenticatorAndroid>
+BiometricAuthenticatorAndroid::CreateForTesting(
+    std::unique_ptr<BiometricAuthenticatorBridge> bridge) {
+  return base::WrapRefCounted(
+      new BiometricAuthenticatorAndroid(std::move(bridge)));
+}
+
 void BiometricAuthenticatorAndroid::OnAuthenticationCompleted(
     BiometricAuthUIResult ui_result) {
   bool success = IsSuccessfulResult(ui_result);
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android.h b/chrome/browser/device_reauth/android/biometric_authenticator_android.h
index f1561d8..d764fb82 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_android.h
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_android.h
@@ -8,19 +8,15 @@
 #include "base/callback.h"
 #include "base/time/time.h"
 #include "chrome/browser/device_reauth/android/biometric_authenticator_bridge.h"
-#include "chrome/browser/device_reauth/chrome_biometric_authenticator.h"
+#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h"
 #include "components/device_reauth/biometric_authenticator.h"
 #include "components/password_manager/core/browser/origin_credential_store.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-#include "ui/android/window_android.h"
-
 // Android implementation of the BiometricAuthenticator interface.
-class BiometricAuthenticatorAndroid : public ChromeBiometricAuthenticator {
+class BiometricAuthenticatorAndroid
+    : public device_reauth::BiometricAuthenticator {
  public:
-  explicit BiometricAuthenticatorAndroid(
-      std::unique_ptr<BiometricAuthenticatorBridge> bridge);
-
   // Checks whether biometrics are available.
   device_reauth::BiometricsAvailability CanAuthenticate() override;
 
@@ -35,7 +31,16 @@
   // destroyed.
   void Cancel(device_reauth::BiometricAuthRequester requester) override;
 
+  // Creates an instance of BiometricAuthenticatorAndroid for testing purposes
+  // only.
+  static scoped_refptr<BiometricAuthenticatorAndroid> CreateForTesting(
+      std::unique_ptr<BiometricAuthenticatorBridge> bridge);
+
  private:
+  friend class BiometricAuthenticatorAndroidFactory;
+
+  explicit BiometricAuthenticatorAndroid(
+      std::unique_ptr<BiometricAuthenticatorBridge> bridge);
   ~BiometricAuthenticatorAndroid() override;
 
   // Called when the authentication compeletes with the result
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc
new file mode 100644
index 0000000..f37960813
--- /dev/null
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
+
+#include "chrome/browser/device_reauth/android/biometric_authenticator_android.h"
+#include "chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h"
+#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h"
+
+// static
+scoped_refptr<device_reauth::BiometricAuthenticator>
+ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator() {
+  return BiometricAuthenticatorAndroidFactory::GetInstance()
+      ->GetOrCreateBiometricAuthenticator();
+}
+
+BiometricAuthenticatorAndroidFactory::~BiometricAuthenticatorAndroidFactory() =
+    default;
+
+// static
+BiometricAuthenticatorAndroidFactory*
+BiometricAuthenticatorAndroidFactory::GetInstance() {
+  static base::NoDestructor<BiometricAuthenticatorAndroidFactory> instance;
+  return instance.get();
+}
+
+scoped_refptr<device_reauth::BiometricAuthenticator>
+BiometricAuthenticatorAndroidFactory::GetOrCreateBiometricAuthenticator() {
+  if (!biometric_authenticator_) {
+    biometric_authenticator_ =
+        base::WrapRefCounted(new BiometricAuthenticatorAndroid(
+            std::make_unique<BiometricAuthenticatorBridgeImpl>()));
+  }
+  return biometric_authenticator_;
+}
+
+BiometricAuthenticatorAndroidFactory::BiometricAuthenticatorAndroidFactory() =
+    default;
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h
new file mode 100644
index 0000000..62d5e53
--- /dev/null
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_
+#define CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h"
+
+// A singleton factory that is responsible for creating and providing a shared
+// instance of BiometricAuthenticator in Android.
+class BiometricAuthenticatorAndroidFactory
+    : public ChromeBiometricAuthenticatorFactory {
+ public:
+  BiometricAuthenticatorAndroidFactory(
+      const BiometricAuthenticatorAndroidFactory& other) = delete;
+  BiometricAuthenticatorAndroidFactory& operator=(
+      const BiometricAuthenticatorAndroidFactory&) = delete;
+  ~BiometricAuthenticatorAndroidFactory();
+
+  static BiometricAuthenticatorAndroidFactory* GetInstance();
+
+  scoped_refptr<device_reauth::BiometricAuthenticator>
+  GetOrCreateBiometricAuthenticator();
+
+ private:
+  friend class base::NoDestructor<BiometricAuthenticatorAndroidFactory>;
+
+  BiometricAuthenticatorAndroidFactory();
+
+  // The BiometricAuthenticator instance which holds the actual logic for
+  // re-authentication. This factory is responsible for creating and owning this
+  // instance. Clients can get access to it via
+  // ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator method.
+  scoped_refptr<device_reauth::BiometricAuthenticator> biometric_authenticator_;
+};
+
+#endif  // CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android_unittest.cc b/chrome/browser/device_reauth/android/biometric_authenticator_android_unittest.cc
index 5078d8c..7f894ea 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_android_unittest.cc
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_android_unittest.cc
@@ -52,7 +52,7 @@
         std::make_unique<MockBiometricAuthenticatorBridge>();
     bridge_ = bridge.get();
     authenticator_ =
-        base::MakeRefCounted<BiometricAuthenticatorAndroid>(std::move(bridge));
+        BiometricAuthenticatorAndroid::CreateForTesting(std::move(bridge));
   }
 
   BiometricAuthenticatorAndroid* authenticator() {
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_bridge.h b/chrome/browser/device_reauth/android/biometric_authenticator_bridge.h
index bfb0cee..b46d4683 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_bridge.h
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_bridge.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_BRIDGE_H_
 
 #include "base/callback_forward.h"
-#include "chrome/browser/device_reauth/android/biometric_authenticator_android.h"
 #include "components/device_reauth/biometric_authenticator.h"
 
 namespace device_reauth {
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.cc b/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.cc
index 261b460..98a590f 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.cc
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.cc
@@ -9,17 +9,14 @@
 #include "chrome/browser/device_reauth/android/biometric_authenticator_android.h"
 #include "chrome/browser/device_reauth/android/jni_headers/BiometricAuthenticatorBridge_jni.h"
 #include "components/device_reauth/biometric_authenticator.h"
-#include "ui/android/window_android.h"
 
 using base::android::AttachCurrentThread;
 using device_reauth::BiometricAuthUIResult;
 using device_reauth::BiometricsAvailability;
 
-BiometricAuthenticatorBridgeImpl::BiometricAuthenticatorBridgeImpl(
-    ui::WindowAndroid* window_android) {
+BiometricAuthenticatorBridgeImpl::BiometricAuthenticatorBridgeImpl() {
   java_object_ = Java_BiometricAuthenticatorBridge_create(
-      AttachCurrentThread(), reinterpret_cast<intptr_t>(this),
-      window_android->GetJavaObject());
+      AttachCurrentThread(), reinterpret_cast<intptr_t>(this));
 }
 
 BiometricAuthenticatorBridgeImpl::~BiometricAuthenticatorBridgeImpl() {
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h b/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h
index 63f0969..74bdb11 100644
--- a/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h
+++ b/chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h
@@ -5,13 +5,13 @@
 #ifndef CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_BRIDGE_IMPL_H_
 #define CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_BRIDGE_IMPL_H_
 
+#include "base/android/scoped_java_ref.h"
 #include "base/callback_forward.h"
 #include "chrome/browser/device_reauth/android/biometric_authenticator_android.h"
-#include "ui/android/window_android.h"
 
 class BiometricAuthenticatorBridgeImpl : public BiometricAuthenticatorBridge {
  public:
-  explicit BiometricAuthenticatorBridgeImpl(ui::WindowAndroid* controller);
+  BiometricAuthenticatorBridgeImpl();
   ~BiometricAuthenticatorBridgeImpl() override;
 
   BiometricAuthenticatorBridgeImpl(const BiometricAuthenticatorBridgeImpl&) =
diff --git a/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/BiometricAuthenticatorBridge.java b/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/BiometricAuthenticatorBridge.java
index 2fc3cb1..07a737f 100644
--- a/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/BiometricAuthenticatorBridge.java
+++ b/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/BiometricAuthenticatorBridge.java
@@ -20,11 +20,11 @@
 
 import androidx.annotation.RequiresApi;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.task.PostTask;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
-import org.chromium.ui.base.WindowAndroid;
 
 import java.util.concurrent.Executor;
 
@@ -34,9 +34,9 @@
     private long mNativeBiometricAuthenticator;
     private BiometricPrompt mBiometricPrompt;
 
-    private BiometricAuthenticatorBridge(long nativeBiometricAuthenticator, Context context) {
+    private BiometricAuthenticatorBridge(long nativeBiometricAuthenticator) {
         mNativeBiometricAuthenticator = nativeBiometricAuthenticator;
-        mContext = context;
+        mContext = ContextUtils.getApplicationContext();
         mNativeBiometricAuthenticator = nativeBiometricAuthenticator;
         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
             BiometricPrompt.Builder promptBuilder = new BiometricPrompt.Builder(mContext).setTitle(
@@ -49,10 +49,8 @@
     }
 
     @CalledByNative
-    private static BiometricAuthenticatorBridge create(
-            long nativeBiometricAuthenticator, WindowAndroid windowAndroid) {
-        return new BiometricAuthenticatorBridge(
-                nativeBiometricAuthenticator, windowAndroid.getApplicationContext());
+    private static BiometricAuthenticatorBridge create(long nativeBiometricAuthenticator) {
+        return new BiometricAuthenticatorBridge(nativeBiometricAuthenticator);
     }
 
     @CalledByNative
diff --git a/chrome/browser/device_reauth/chrome_biometric_authenticator.h b/chrome/browser/device_reauth/chrome_biometric_authenticator.h
deleted file mode 100644
index f1840e5..0000000
--- a/chrome/browser/device_reauth/chrome_biometric_authenticator.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_H_
-#define CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_H_
-
-#include "components/device_reauth/biometric_authenticator.h"
-
-namespace content {
-class WebContents;
-}
-
-// Chrome wrapper around BiometricAuthenticator. Subclasses are expected to
-// provide an implementation for Create(), instantiating authenticators for a
-// given platform.
-class ChromeBiometricAuthenticator
-    : public device_reauth::BiometricAuthenticator {
- public:
-  // Create an instance of the ChromeBiometricAuthenticator. Trying to use this
-  // API on platforms that do not provide an implementation will result in a
-  // link error. So far only Android provides an implementation.
-  static scoped_refptr<device_reauth::BiometricAuthenticator> Create(
-      content::WebContents* web_contents);
-
- protected:
-  ~ChromeBiometricAuthenticator() override = default;
-};
-
-#endif  // CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_H_
diff --git a/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h
new file mode 100644
index 0000000..070a4c7
--- /dev/null
+++ b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_FACTORY_H_
+#define CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_FACTORY_H_
+
+#include "base/memory/scoped_refptr.h"
+
+namespace device_reauth {
+class BiometricAuthenticator;
+}
+
+// Subclasses are expected to provide an implementation for
+// GetBiometricAuthenticator(), instantiating authenticators for a given
+// platform. They would also be responsible for deciding whether to create
+// multiple/single instances of BiometricAuthenticator.
+class ChromeBiometricAuthenticatorFactory {
+ public:
+  // Get or create an instance of the BiometricAuthenticator. Trying to use this
+  // API on platforms that do not provide an implementation will result in a
+  // link error. So far only Android provides an implementation.
+  static scoped_refptr<device_reauth::BiometricAuthenticator>
+  GetBiometricAuthenticator();
+};
+
+#endif  // CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_FACTORY_H_
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS
index 60e773c..d3aad9a7 100644
--- a/chrome/browser/extensions/DEPS
+++ b/chrome/browser/extensions/DEPS
@@ -82,12 +82,6 @@
 
   # This DEPS violation snuck in while there was a bug in the checkdeps tool.
   # https://crbug.com/1084826
-  "extension_browser_window_helper\.cc": [
-    "+chrome/browser/apps/app_service/launch_utils.h",
-  ],
-
-  # This DEPS violation snuck in while there was a bug in the checkdeps tool.
-  # https://crbug.com/1084826
   "extension_browsertest\.cc": [
     "+chrome/browser/apps/app_service/app_launch_params.h",
     "+chrome/browser/apps/app_service/app_service_proxy.h",
diff --git a/chrome/browser/extensions/extension_browser_window_helper.cc b/chrome/browser/extensions/extension_browser_window_helper.cc
index f586bda..1bab1e7 100644
--- a/chrome/browser/extensions/extension_browser_window_helper.cc
+++ b/chrome/browser/extensions/extension_browser_window_helper.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/extension_browser_window_helper.h"
 
-#include "chrome/browser/apps/app_service/launch_utils.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -58,7 +57,8 @@
   // Case 2: Check if the page is a page associated with a hosted app, which
   // can have non-extension schemes. For example, the Gmail hosted app would
   // have a URL of https://mail.google.com.
-  if (apps::GetAppIdForWebContents(web_contents) == extension->id()) {
+  if (TabHelper::FromWebContents(web_contents)->GetExtensionAppId() ==
+      extension->id()) {
     return true;
   }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 0ebd32d..0413942 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -674,6 +674,16 @@
     "expiry_milestone": 94
   },
   {
+    "name": "closed-tab-cache",
+    "owners": [
+      "altimin@chromium.org",
+      "sky@chromium.org",
+      "sreejakshetty@chromium.org",
+      "tobias.soppa@code.berlin"
+    ],
+    "expiry_milestone": 99
+  },
+  {
     "name": "collections-card-presentation-style",
     "owners": [ "sczs", "bling-flags@google.com" ],
     "expiry_milestone": 80
@@ -2764,11 +2774,6 @@
     "expiry_milestone": 104
   },
   {
-    "name": "enable-webassembly-threads",
-    "owners": [ "binji", "hablich", "wasm-team@google.com" ],
-    "expiry_milestone": 92
-  },
-  {
     "name": "enable-webassembly-tiering",
     "owners": [ "clemensb", "wasm-team@google.com" ],
     // This flag is often used by developers and partners to test
@@ -4374,14 +4379,9 @@
     "expiry_milestone": 95
   },
   {
-    "name": "passwords-account-storage",
+    "name": "passwords-account-storage-revised-opt-in-flow",
     "owners": [ "mamir", "treib" ],
-    "expiry_milestone": 95
-  },
-  {
-    "name": "passwords-account-storage-iph",
-    "owners": [ "mamir", "treib" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 100
   },
   {
     "name": "pdf-unseasoned",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index e9245f3..2fce40e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -421,6 +421,12 @@
     "Access Chrome Labs through the toolbar menu to see featured user-facing "
     "experimental features.";
 
+const char kClosedTabCacheName[] = "Closed Tab Cache";
+const char kClosedTabCacheDescription[] =
+    "Enables closed tab cache to instantaneously restore recently closed tabs. "
+    "NOTE: This feature is higly experimental and will lead to various "
+    "breakages, enable at your own risk.";
+
 const char kCompositeAfterPaintName[] = "Composite after paint";
 const char kCompositeAfterPaintDescription[] =
     "A new algorithm to create compositing layers. "
@@ -1945,6 +1951,12 @@
 const char kPasswordImportDescription[] =
     "Import functionality in password settings.";
 
+const char kPasswordsAccountStorageRevisedOptInFlowName[] =
+    "Revised opt-in flow for account-scoped passwore storage";
+const char kPasswordsAccountStorageRevisedOptInFlowDescription[] =
+    "Enables the revised opt-in flow for the account-scoped passwords storage "
+    "during first-time save.";
+
 const char kPasswordScriptsFetchingName[] = "Fetch password scripts";
 const char kPasswordScriptsFetchingDescription[] =
     "Fetches scripts for password change flows.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index be5a130..882c050 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -268,6 +268,9 @@
 extern const char kClientStorageAccessContextAuditingName[];
 extern const char kClientStorageAccessContextAuditingDescription[];
 
+extern const char kClosedTabCacheName[];
+extern const char kClosedTabCacheDescription[];
+
 extern const char kConditionalTabStripAndroidName[];
 extern const char kConditionalTabStripAndroidDescription[];
 
@@ -1109,6 +1112,9 @@
 extern const char kPasswordImportName[];
 extern const char kPasswordImportDescription[];
 
+extern const char kPasswordsAccountStorageRevisedOptInFlowName[];
+extern const char kPasswordsAccountStorageRevisedOptInFlowDescription[];
+
 extern const char kPasswordScriptsFetchingName[];
 extern const char kPasswordScriptsFetchingDescription[];
 
diff --git a/chrome/browser/net/private_network_access_browsertest.cc b/chrome/browser/net/private_network_access_browsertest.cc
index 9b491412..cf04030 100644
--- a/chrome/browser/net/private_network_access_browsertest.cc
+++ b/chrome/browser/net/private_network_access_browsertest.cc
@@ -49,9 +49,7 @@
 
 using blink::mojom::WebFeature;
 using testing::ElementsAre;
-using testing::Gt;
 using testing::IsEmpty;
-using testing::Optional;
 using testing::Pair;
 
 // We use a custom page that explicitly disables its own favicon (by providing
@@ -904,21 +902,6 @@
 
     error_page::NetErrorAutoReloader::CreateForWebContents(web_contents());
   }
-
- protected:
-  error_page::NetErrorAutoReloader* GetAutoReloader() {
-    return error_page::NetErrorAutoReloader::FromWebContents(web_contents());
-  }
-
-  absl::optional<base::TimeDelta> GetCurrentAutoReloadDelay() {
-    const absl::optional<base::OneShotTimer>& timer =
-        GetAutoReloader()->next_reload_timer_for_testing();
-    if (!timer.has_value()) {
-      return absl::nullopt;
-    }
-
-    return timer->GetCurrentDelay();
-  }
 };
 
 // This test verifies that when a document in the `local` address space fails to
@@ -936,9 +919,6 @@
     NetErrorInterceptor interceptor(url, net::ERR_UNEXPECTED);
 
     EXPECT_FALSE(content::NavigateToURL(web_contents(), url));
-
-    // The auto-reloader should be waiting a non-zero amount of time.
-    EXPECT_THAT(GetCurrentAutoReloadDelay(), Optional(Gt(base::TimeDelta())));
   }
 
   // Observe second navigation, which succeeds.
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 41ab09b..b06a275a 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -25,7 +25,7 @@
 #include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/device_reauth/chrome_biometric_authenticator.h"
+#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/password_manager/account_password_store_factory.h"
@@ -475,12 +475,9 @@
 scoped_refptr<device_reauth::BiometricAuthenticator>
 ChromePasswordManagerClient::GetBiometricAuthenticator() {
 #if defined(OS_ANDROID)
-  if (!biometric_authenticator_) {
-    biometric_authenticator_ =
-        ChromeBiometricAuthenticator::Create(web_contents());
-  }
+  return ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator();
 #endif
-  return biometric_authenticator_;
+  return nullptr;
 }
 
 void ChromePasswordManagerClient::GeneratePassword(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index f8bada8..8357571 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -74,6 +74,10 @@
 class WebContents;
 }
 
+namespace device_reauth {
+class BiometricAuthenticator;
+}
+
 // ChromePasswordManagerClient implements the PasswordManagerClient interface.
 class ChromePasswordManagerClient
     : public password_manager::PasswordManagerClient,
@@ -373,8 +377,6 @@
       generated_password_saved_message_delegate_;
 #endif  // defined(OS_ANDROID)
 
-  scoped_refptr<device_reauth::BiometricAuthenticator> biometric_authenticator_;
-
   password_manager::ContentPasswordManagerDriverFactory* driver_factory_;
 
   // As a mojo service, will be registered into service registry
diff --git a/chrome/browser/profiles/incognito_profile_containment_browsertest.cc b/chrome/browser/profiles/incognito_profile_containment_browsertest.cc
index bdbb7c1..b6f8fb5 100644
--- a/chrome/browser/profiles/incognito_profile_containment_browsertest.cc
+++ b/chrome/browser/profiles/incognito_profile_containment_browsertest.cc
@@ -31,18 +31,23 @@
 // List of file or directory prefixes that are known to be modified during an
 // Incognito session.
 // TODO(http://crbug.com/1234755): Audit why these files are changed.
-constexpr std::array<const char*, 7> kAllowListPrefixesForAllPlatforms = {
-    "/Default/GCM Store/",      "/Default/Network Action Predictor",
-    "/Default/PreferredApps",   "/Default/Reporting and NEL",
-    "/Default/shared_proto_db", "/Default/Trust Tokens",
+constexpr std::array<const char*, 10> kAllowListPrefixesForAllPlatforms = {
+    "/Default/data_reduction_proxy_leveldb",
+    "/Default/Extension State",
+    "/Default/GCM Store/",
+    "/Default/Network Action Predictor",
+    "/Default/Preferences",
+    "/Default/PreferredApps",
+    "/Default/Reporting and NEL",
+    "/Default/shared_proto_db",
+    "/Default/Trust Tokens",
     "/GrShaderCache/GPUCache"};
 #if defined(OS_MAC)
-constexpr std::array<const char*, 4> kAllowListPrefixesForPlatform = {
-    "/Default/data_reduction_proxy_leveldb", "/Default/Preferences",
+constexpr std::array<const char*, 2> kAllowListPrefixesForPlatform = {
     "/Default/Shortcuts", "/Default/Visited Links"};
 #elif defined(OS_WIN)
 constexpr std::array<const char*, 5> kAllowListPrefixesForPlatform = {
-    "/Default/data_reduction_proxy_leveldb", "/Default/Shortcuts",
+    "/Default/heavy_ad_intervention_opt_out.db", "/Default/Shortcuts",
     "/Default/Top Sites", "/GrShaderCache/old_GPUCache", "/Last Browser"};
 #elif defined(OS_CHROMEOS)
 constexpr std::array<const char*, 7> kAllowListPrefixesForPlatform = {
@@ -53,6 +58,9 @@
     "/test-user/shared_proto_db",
     "/test-user/Shortcuts",
     "/test-user/Trust Tokens"};
+#elif defined(OS_LINUX)
+constexpr std::array<const char*, 1> kAllowListPrefixesForPlatform = {
+    "/Default/Web Data"};
 #else
 constexpr std::array<const char*, 0> kAllowListPrefixesForPlatform = {};
 #endif
diff --git a/chrome/browser/resources/chromeos/login/images/sync-consent.svg b/chrome/browser/resources/chromeos/login/images/sync-consent.svg
index a2a03dc..ca1fbf3d8 100644
--- a/chrome/browser/resources/chromeos/login/images/sync-consent.svg
+++ b/chrome/browser/resources/chromeos/login/images/sync-consent.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="440" height="228" fill="none"><path fill="#fff" d="M0 0h440v228H0z"/><g clip-path="url(#clip0)"><path fill="#fff" stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M262.978 93.27h142.965c5.165 0 9.354 4.189 9.354 9.354v104.911H253.633v-104.92a9.34 9.34 0 0 1 9.345-9.346z"/><path fill="#4285F4" d="M264.231 100.359h140.646a3.428 3.428 0 0 1 3.428 3.428v94.662H260.803v-94.671a3.42 3.42 0 0 1 3.428-3.419z"/><path fill="#fff" stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M424.526 211.017H244.395a3.74 3.74 0 0 1-3.742-3.741v-1.37c0-1.029.842-1.871 1.871-1.871h183.873c1.029 0 1.871.842 1.871 1.871v1.37a3.74 3.74 0 0 1-3.742 3.741z"/><path fill="#D2E3FC" d="M333.338 98.398a1.128 1.128 0 1 0 0-2.255 1.128 1.128 0 0 0 0 2.255z"/><path stroke="#EA4335" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M109.935 74.382c4.261 1.978 6.114 7.044 4.135 11.305l-8.369 18.073c-1.979 4.261-7.045 6.114-11.306 4.136-4.261-1.978-6.114-7.045-4.136-11.306l8.37-18.073c1.978-4.27 7.045-6.114 11.306-4.135z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M270.444 34.449c-.949 6.23-6.768 10.51-12.998 9.57l-26.398-3.975c-6.23-.95-10.509-6.768-9.569-12.998.949-6.23 6.767-10.509 12.998-9.569l26.398 3.974c6.23.95 10.518 6.768 9.569 12.998z"/><path fill="#FBBC05" d="M286.208 67.453a17.185 17.185 0 0 1-1.781-3.643l-1.916-3.912a14.629 14.629 0 0 0-6.481-6.58c-1.083-.554-2.264-.94-3.41-1.342-1.253-.439-2.524-.823-3.751-1.307-2.963-1.164-5.389-3.142-6.821-6.015a12.327 12.327 0 0 1-1.002-8.128 12.41 12.41 0 0 1 1.799-4.199 12.322 12.322 0 0 1 8.996-5.361c3.026-.296 6.114.572 8.522 2.425 2.104 1.62 3.733 3.84 5.469 5.828a14.575 14.575 0 0 0 9.963 4.95l4.342.304a17.704 17.704 0 0 1 4.055.278 17.472 17.472 0 0 1 7.877 3.679c6.615 5.407 8.325 15.003 4.01 22.37-5.156 8.8-16.569 11.306-24.903 5.702a17.33 17.33 0 0 1-4.968-5.049z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M341.044 113.831l-13.686 5.881a4.912 4.912 0 0 1-4.87-.573l-11.932-8.916a4.9 4.9 0 0 1-1.934-4.511l1.755-14.797a4.902 4.902 0 0 1 2.936-3.93l13.686-5.88a4.911 4.911 0 0 1 4.87.572l11.932 8.916a4.901 4.901 0 0 1 1.934 4.511l-1.755 14.797a4.888 4.888 0 0 1-2.936 3.93z"/><path fill="#D2E3FC" d="M160.725 205.557H16.105a5.847 5.847 0 0 1-5.845-5.845v-93.311a5.847 5.847 0 0 1 5.845-5.845h144.62a5.847 5.847 0 0 1 5.846 5.845v93.319c0 3.223-2.623 5.837-5.846 5.837z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.292" d="M128.616 112.801h5.103m20.158-4.986l4.986 4.986m0-4.986l-4.986 4.986"/><path fill="#2A84FC" d="M142.098 113.383a1.416 1.416 0 0 1-1.414-1.414v-3.33c0-.779.635-1.414 1.414-1.414h3.33c.779 0 1.414.635 1.414 1.414v3.33c0 .779-.635 1.414-1.414 1.414h-3.33z"/><path fill="#2A84FC" d="M145.436 107.681c.528 0 .967.43.967.967v3.33c0 .528-.43.967-.967.967h-3.33a.969.969 0 0 1-.967-.967v-3.33c0-.528.43-.967.967-.967h3.33zm0-.895h-3.33a1.861 1.861 0 0 0-1.862 1.862v3.33c0 1.029.833 1.862 1.862 1.862h3.33a1.861 1.861 0 0 0 1.862-1.862v-3.33a1.861 1.861 0 0 0-1.862-1.862z"/><mask id="a" width="157" height="106" x="10" y="100" maskUnits="userSpaceOnUse"><path fill="#D2E3FC" d="M160.725 205.557H16.105a5.847 5.847 0 0 1-5.845-5.845v-93.311a5.847 5.847 0 0 1 5.845-5.845h144.62a5.847 5.847 0 0 1 5.846 5.845v93.319c0 3.223-2.623 5.837-5.846 5.837z"/></mask><g mask="url(#a)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M109.935 74.382c4.261 1.978 6.114 7.044 4.135 11.305l-8.369 18.073c-1.979 4.261-7.045 6.114-11.306 4.136-4.261-1.978-6.114-7.045-4.136-11.306l8.37-18.073c1.978-4.27 7.045-6.114 11.306-4.135z"/></g><path fill="#fff" d="M87.914 143.827l-7.161-8.79a2.626 2.626 0 0 1 .376-3.688l8.889-7.242a2.626 2.626 0 0 1 3.688.376l7.161 8.791a2.626 2.626 0 0 1-.376 3.688l-8.889 7.241a2.625 2.625 0 0 1-3.688-.376z"/><mask id="b" width="59" height="50" x="260" y="26" maskUnits="userSpaceOnUse"><path fill="#FBBC05" d="M286.208 67.453a17.185 17.185 0 0 1-1.781-3.643l-1.916-3.912a14.629 14.629 0 0 0-6.481-6.58c-1.083-.554-2.264-.94-3.41-1.342-1.253-.439-2.524-.823-3.751-1.307-2.963-1.164-5.389-3.142-6.821-6.015a12.327 12.327 0 0 1-1.002-8.128 12.41 12.41 0 0 1 1.799-4.199 12.322 12.322 0 0 1 8.996-5.361c3.026-.296 6.114.572 8.522 2.425 2.104 1.62 3.733 3.84 5.469 5.828a14.575 14.575 0 0 0 9.963 4.95l4.342.304a17.704 17.704 0 0 1 4.055.278 17.472 17.472 0 0 1 7.877 3.679c6.615 5.407 8.325 15.003 4.01 22.37-5.156 8.8-16.569 11.306-24.903 5.702a17.33 17.33 0 0 1-4.968-5.049z"/></mask><g mask="url(#b)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M270.444 34.449c-.949 6.23-6.768 10.51-12.998 9.57l-26.398-3.975c-6.23-.95-10.509-6.768-9.569-12.998.949-6.23 6.767-10.509 12.998-9.569l26.398 3.974c6.23.95 10.518 6.768 9.569 12.998z"/></g><path fill="#D2E3FC" d="M333.641 173.17c12.123 0 21.95-9.827 21.95-21.949 0-12.122-9.827-21.949-21.95-21.949-12.122 0-21.949 9.827-21.949 21.949 0 12.122 9.827 21.949 21.949 21.949z"/><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M322.882 148.196l8.665 8.665a1.448 1.448 0 0 0 2.059 0l23.82-23.543"/><mask id="c" width="45" height="45" x="311" y="129" maskUnits="userSpaceOnUse"><path fill="#D2E3FC" d="M333.641 173.17c12.123 0 21.95-9.827 21.95-21.949 0-12.122-9.827-21.949-21.95-21.949-12.122 0-21.949 9.827-21.949 21.949 0 12.122 9.827 21.949 21.949 21.949z"/></mask><g mask="url(#c)"><path stroke="#34A853" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M322.882 148.196l8.665 8.665a1.448 1.448 0 0 0 2.059 0l21.08-20.956"/></g><path fill="#fff" d="M83.295 174.522a7.224 7.224 0 1 0 0-14.447 7.224 7.224 0 0 0 0 14.447z"/><mask id="d" width="149" height="99" x="260" y="100" maskUnits="userSpaceOnUse"><path fill="#4285F4" d="M264.231 100.359h140.646a3.428 3.428 0 0 1 3.428 3.428v94.662H260.803v-94.671a3.42 3.42 0 0 1 3.428-3.419z"/></mask><g mask="url(#d)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.685" d="M341.044 113.831l-13.686 5.881a4.912 4.912 0 0 1-4.87-.573l-11.932-8.916a4.9 4.9 0 0 1-1.934-4.511l1.755-14.797a4.902 4.902 0 0 1 2.936-3.93l13.686-5.88a4.911 4.911 0 0 1 4.87.572l11.932 8.916a4.901 4.901 0 0 1 1.934 4.511l-1.755 14.797a4.888 4.888 0 0 1-2.936 3.93z"/></g><path fill="#D2E3FC" d="M146.385 56.971a14.27 14.27 0 0 0 .108-1.674c0-.582-.045-1.137-.126-1.674l3.599-2.828c.322-.26.403-.726.215-1.093l-3.402-5.934c-.215-.385-.662-.51-1.047-.385l-4.234 1.718a12.5 12.5 0 0 0-2.874-1.674l-.635-4.547a.85.85 0 0 0-.851-.725h-6.812a.83.83 0 0 0-.832.725l-.636 4.547a12.71 12.71 0 0 0-2.873 1.674l-4.234-1.718a.844.844 0 0 0-1.048.384l-3.41 5.935a.832.832 0 0 0 .215 1.093l3.598 2.828a10.452 10.452 0 0 0-.152 1.674c0 .555.045 1.137.125 1.674l-3.598 2.829c-.323.26-.403.725-.215 1.092l3.41 5.935c.215.385.663.51 1.048.385l4.234-1.72a12.49 12.49 0 0 0 2.873 1.675l.636 4.547c.089.43.429.725.85.725h6.812a.82.82 0 0 0 .833-.725l.635-4.547a12.714 12.714 0 0 0 2.874-1.674l4.234 1.719c.385.152.832 0 1.047-.385l3.402-5.935a.833.833 0 0 0-.215-1.092l-3.554-2.829zm-12.666 4.753c-3.509 0-6.383-2.891-6.383-6.427 0-3.536 2.874-6.427 6.383-6.427s6.382 2.891 6.382 6.427c.009 3.536-2.864 6.427-6.382 6.427z"/><path fill="#4285F4" d="M133.719 63.873c-4.726 0-8.575-3.85-8.575-8.576 0-4.726 3.849-8.575 8.575-8.575 4.726 0 8.576 3.849 8.576 8.575 0 4.727-3.85 8.576-8.576 8.576zm0-14.197a5.63 5.63 0 0 0-5.621 5.621 5.63 5.63 0 0 0 5.621 5.622 5.632 5.632 0 0 0 5.622-5.622 5.632 5.632 0 0 0-5.622-5.621z"/><path fill="#8AB4F8" d="M133.719 65.645c-5.702 0-10.348-4.646-10.348-10.348 0-5.702 4.646-10.348 10.348-10.348 5.702 0 10.348 4.646 10.348 10.348 0 5.702-4.637 10.348-10.348 10.348zm0-18.333c-4.404 0-7.985 3.58-7.985 7.985 0 4.404 3.581 7.985 7.985 7.985s7.985-3.58 7.985-7.985c0-4.404-3.581-7.985-7.985-7.985z"/><path fill="#34A853" d="M178.334 28.622c-2.847-2.381-6.992-2.793-10.25-.672-3.983 2.596-5.111 7.94-2.524 11.924 2.596 3.983 7.94 5.11 11.923 2.524 3.258-2.122 4.583-6.096 3.536-9.65l8.504-5.756 4.028 6.195 4.127-2.686-4.028-6.194 4.126-2.685-2.685-4.127-16.757 11.127zm-3.536 9.65a3.698 3.698 0 0 1-5.112-1.084 3.697 3.697 0 0 1 1.084-5.111 3.697 3.697 0 0 1 5.111 1.083 3.7 3.7 0 0 1-1.083 5.111z"/></g><defs><clipPath id="clip0"><path fill="#fff" d="M0 0h419.351v196.36H0z" transform="translate(10.26 16)"/></clipPath></defs></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" width="440" height="228" fill="none"><path fill="#fff" d="M0 0h440v228H0z"/><g clip-path="url(#clip0)"><path fill="#fff" stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M261.005 94.228h136.411a8.927 8.927 0 018.926 8.925v100.103H252.088V103.145a8.913 8.913 0 018.917-8.917z"/><path fill="#4285F4" d="M262.201 100.992H396.4a3.272 3.272 0 013.272 3.272v90.323H258.93v-90.332a3.264 3.264 0 013.271-3.263z"/><path fill="#fff" stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M415.149 206.579H243.274a3.568 3.568 0 01-3.57-3.57v-1.307a1.79 1.79 0 011.785-1.785h175.445a1.79 1.79 0 011.785 1.785v1.307a3.568 3.568 0 01-3.57 3.57z"/><path fill="#D2E3FC" d="M328.14 99.122a1.076 1.076 0 100-2.153 1.076 1.076 0 000 2.153z"/><path stroke="#EA4335" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M114.977 76.206a8.126 8.126 0 013.946 10.787l-7.986 17.245a8.126 8.126 0 01-10.787 3.946 8.126 8.126 0 01-3.947-10.787l7.987-17.245c1.887-4.074 6.721-5.834 10.787-3.946z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M268.129 38.103c-.905 5.945-6.457 10.028-12.402 9.131l-25.188-3.792c-5.944-.906-10.027-6.457-9.13-12.402.905-5.945 6.457-10.027 12.401-9.13l25.189 3.792c5.944.905 10.035 6.457 9.13 12.401z"/><path fill="#FBBC05" d="M283.171 69.595a16.378 16.378 0 01-1.7-3.476l-1.828-3.733a13.957 13.957 0 00-6.184-6.278c-1.033-.53-2.161-.896-3.254-1.28-1.196-.42-2.408-.787-3.579-1.248-2.827-1.11-5.141-2.998-6.508-5.74a11.77 11.77 0 01-.957-7.755 11.847 11.847 0 011.717-4.006 11.758 11.758 0 018.584-5.116c2.887-.282 5.834.547 8.131 2.315 2.007 1.546 3.562 3.664 5.219 5.56a13.905 13.905 0 009.506 4.723l4.143.29a16.671 16.671 0 0111.385 3.775c6.312 5.16 7.944 14.316 3.827 21.345-4.92 8.396-15.81 10.788-23.762 5.441a16.513 16.513 0 01-4.74-4.817z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M335.493 113.847l-13.059 5.611a4.686 4.686 0 01-4.647-.546l-11.385-8.507a4.68 4.68 0 01-1.845-4.305l1.674-14.119a4.68 4.68 0 012.802-3.75l13.059-5.61a4.686 4.686 0 014.647.546l11.385 8.507a4.679 4.679 0 011.845 4.305l-1.674 14.118a4.669 4.669 0 01-2.802 3.75z"/><path fill="#D2E3FC" d="M163.439 201.369H25.447a5.58 5.58 0 01-5.577-5.578v-89.033a5.58 5.58 0 015.578-5.578h137.991a5.58 5.58 0 015.578 5.578V195.8c0 3.075-2.503 5.569-5.578 5.569z"/><path stroke="#2A84FC" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.187" d="M132.802 112.865h4.868M156.904 108.107l4.758 4.758M161.662 108.107l-4.758 4.758"/><path fill="#2A84FC" d="M145.666 113.42c-.743 0-1.35-.607-1.35-1.35v-3.177c0-.743.607-1.35 1.35-1.35h3.177c.743 0 1.35.607 1.35 1.35v3.177c0 .743-.607 1.35-1.35 1.35h-3.177z"/><path fill="#2A84FC" d="M148.85 107.979c.504 0 .923.41.923.923v3.177c0 .504-.41.922-.923.922h-3.177a.924.924 0 01-.922-.922v-3.177c0-.504.41-.923.922-.923h3.177zm0-.854h-3.177c-.982 0-1.777.794-1.777 1.777v3.177c0 .982.795 1.776 1.777 1.776h3.177c.983 0 1.777-.794 1.777-1.776v-3.177c0-.983-.794-1.777-1.777-1.777z"/><mask id="a" width="151" height="101" x="19" y="101" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#D2E3FC" d="M163.439 201.369H25.447a5.58 5.58 0 01-5.577-5.578v-89.033a5.58 5.58 0 015.578-5.578h137.991a5.58 5.58 0 015.578 5.578V195.8c0 3.075-2.503 5.569-5.578 5.569z"/></mask><g mask="url(#a)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M114.977 76.206a8.126 8.126 0 013.946 10.787l-7.986 17.245a8.126 8.126 0 01-10.787 3.946 8.126 8.126 0 01-3.947-10.787l7.987-17.245c1.887-4.074 6.721-5.834 10.787-3.946z"/></g><path fill="#fff" d="M93.965 142.468l-6.833-8.387a2.506 2.506 0 01.359-3.519l8.481-6.91a2.505 2.505 0 013.52.359l6.832 8.387a2.505 2.505 0 01-.359 3.519l-8.481 6.91a2.505 2.505 0 01-3.519-.359z"/><mask id="b" width="56" height="48" x="258" y="30" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#FBBC05" d="M283.171 69.595a16.378 16.378 0 01-1.7-3.476l-1.828-3.733a13.957 13.957 0 00-6.184-6.278c-1.033-.53-2.161-.896-3.254-1.28-1.196-.42-2.408-.787-3.579-1.248-2.827-1.11-5.141-2.998-6.508-5.74a11.77 11.77 0 01-.957-7.755 11.847 11.847 0 011.717-4.006 11.758 11.758 0 018.584-5.116c2.887-.282 5.834.547 8.131 2.315 2.007 1.546 3.562 3.664 5.219 5.56a13.905 13.905 0 009.506 4.723l4.143.29a16.671 16.671 0 0111.385 3.775c6.312 5.16 7.944 14.316 3.827 21.345-4.92 8.396-15.81 10.788-23.762 5.441a16.513 16.513 0 01-4.74-4.817z"/></mask><g mask="url(#b)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M268.129 38.103c-.905 5.945-6.457 10.028-12.402 9.131l-25.188-3.792c-5.944-.906-10.027-6.457-9.13-12.402.905-5.945 6.457-10.027 12.401-9.13l25.189 3.792c5.944.905 10.035 6.457 9.13 12.401z"/></g><path fill="#D2E3FC" d="M328.429 170.467c11.567 0 20.943-9.377 20.943-20.943 0-11.567-9.376-20.944-20.943-20.944-11.566 0-20.943 9.377-20.943 20.944 0 11.566 9.377 20.943 20.943 20.943z"/><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M318.163 146.637l8.268 8.267a1.38 1.38 0 001.964 0l22.729-22.463"/><mask id="c" width="43" height="43" x="307" y="128" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#D2E3FC" d="M328.429 170.467c11.567 0 20.943-9.377 20.943-20.943 0-11.567-9.376-20.944-20.943-20.944-11.566 0-20.943 9.377-20.943 20.944 0 11.566 9.377 20.943 20.943 20.943z"/></mask><g mask="url(#c)"><path stroke="#34A853" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M318.163 146.637l8.268 8.267a1.38 1.38 0 001.964 0l20.115-19.995"/></g><path fill="#fff" d="M89.558 171.756a6.893 6.893 0 100-13.785 6.893 6.893 0 000 13.785z"/><mask id="d" width="142" height="95" x="258" y="100" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#4285F4" d="M262.201 100.992H396.4a3.272 3.272 0 013.272 3.272v90.323H258.93v-90.332a3.264 3.264 0 013.271-3.263z"/></mask><g mask="url(#d)"><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.562" d="M335.493 113.847l-13.059 5.611a4.686 4.686 0 01-4.647-.546l-11.385-8.507a4.68 4.68 0 01-1.845-4.305l1.674-14.119a4.68 4.68 0 012.802-3.75l13.059-5.61a4.686 4.686 0 014.647.546l11.385 8.507a4.679 4.679 0 011.845 4.305l-1.674 14.118a4.669 4.669 0 01-2.802 3.75z"/></g><path fill="#D2E3FC" d="M149.756 59.593c.06-.512.102-1.042.102-1.597 0-.555-.042-1.085-.119-1.597l3.433-2.7a.847.847 0 00.205-1.041l-3.245-5.663c-.205-.367-.632-.487-1-.367l-4.04 1.64a11.932 11.932 0 00-2.741-1.598l-.607-4.339a.81.81 0 00-.811-.691h-6.5c-.41 0-.735.29-.794.691l-.607 4.34c-.999.41-1.913.965-2.742 1.596l-4.04-1.64a.804.804 0 00-.999.368l-3.254 5.663a.794.794 0 00.205 1.042l3.433 2.699a9.961 9.961 0 00-.145 1.597c0 .53.043 1.085.12 1.597l-3.434 2.7c-.307.247-.384.691-.205 1.041l3.254 5.663c.205.367.633.487 1 .367l4.04-1.64a11.914 11.914 0 002.742 1.598l.606 4.338c.085.41.41.692.811.692h6.5c.41 0 .752-.29.795-.692l.606-4.338c.999-.41 1.913-.966 2.742-1.598l4.04 1.64c.367.145.794 0 .999-.367l3.246-5.663a.795.795 0 00-.205-1.042l-3.391-2.699zM137.67 64.13c-3.348 0-6.09-2.76-6.09-6.133 0-3.374 2.742-6.133 6.09-6.133s6.09 2.76 6.09 6.133c.008 3.374-2.733 6.133-6.09 6.133z"/><path fill="#4285F4" d="M137.671 66.178c-4.51 0-8.183-3.672-8.183-8.182s3.673-8.183 8.183-8.183 8.182 3.673 8.182 8.183-3.672 8.182-8.182 8.182zm0-13.546a5.373 5.373 0 00-5.364 5.364 5.373 5.373 0 005.364 5.364 5.373 5.373 0 005.364-5.364 5.373 5.373 0 00-5.364-5.364z"/><path fill="#8AB4F8" d="M137.671 67.87c-5.441 0-9.874-4.433-9.874-9.874 0-5.44 4.433-9.874 9.874-9.874 5.44 0 9.873 4.433 9.873 9.874 0 5.44-4.424 9.874-9.873 9.874zm0-17.493c-4.203 0-7.619 3.417-7.619 7.619s3.416 7.619 7.619 7.619c4.202 0 7.618-3.417 7.618-7.619s-3.416-7.619-7.618-7.619z"/><path fill="#34A853" d="M180.24 32.543c-2.716-2.272-6.671-2.665-9.78-.64-3.801 2.477-4.877 7.576-2.408 11.377 2.477 3.8 7.576 4.877 11.377 2.408 3.109-2.024 4.373-5.817 3.373-9.207l8.114-5.492 3.844 5.91 3.938-2.562-3.844-5.91 3.937-2.563-2.562-3.938-15.989 10.617zm-3.374 9.208a3.528 3.528 0 01-4.877-1.034 3.527 3.527 0 011.034-4.877 3.528 3.528 0 014.877 1.034 3.529 3.529 0 01-1.034 4.877z"/></g><defs><clipPath id="clip0"><path fill="#fff" d="M0 0h400.13v187.36H0z" transform="translate(19.87 20.5)"/></clipPath></defs></svg>
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index 29c7c6d..ba4f3ad 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -61,7 +61,19 @@
       }
 
       img[slot='subtitle'] {
-        padding-top: 10px;
+        padding-top: 20px;
+      }
+
+      @media screen and (max-height: 610px) {
+        :host-context([screen=gaia-signin]) img[slot='subtitle'] {
+          display: none;
+        }
+      }
+
+      @media screen and (max-height: 740px) {
+        :host-context([screen=oobe]) img[slot='subtitle'] {
+          display: none;
+        }
       }
 
       #splitSettingsSyncConsentDialog .overview-list-item-title {
diff --git a/chrome/browser/resources/print_preview/data/cdd.js b/chrome/browser/resources/print_preview/data/cdd.js
index 1d8c07f..218c2e3 100644
--- a/chrome/browser/resources/print_preview/data/cdd.js
+++ b/chrome/browser/resources/print_preview/data/cdd.js
@@ -58,16 +58,18 @@
  *       vendor_id: (string|undefined),
  *       custom_display_name: (string|undefined),
  *       is_default: (boolean|undefined)
- *     }>
+ *     }>,
+ *     reset_to_default: (boolean | undefined)
  *   }|undefined),
  *   copies: ({default: (number|undefined),
  *             max: (number|undefined)}|undefined),
  *   duplex: ({option: !Array<{type: (string|undefined),
- *                             is_default: (boolean|undefined)}>}|undefined),
+ *                             is_default: (boolean|undefined)}>,
+ *             reset_to_default: (boolean | undefined)}|undefined),
  *   page_orientation: ({
  *     option: !Array<{type: (string|undefined),
- *                      is_default: (boolean|undefined)}>
- *   }|undefined),
+ *                      is_default: (boolean|undefined)}>,
+ *     reset_to_default: (boolean | undefined)}|undefined),
  *   media_size: ({
  *     option: !Array<{
  *       type: (string|undefined),
@@ -75,7 +77,8 @@
  *       custom_display_name: (string|undefined),
  *       is_default: (boolean|undefined),
  *       name: (string|undefined),
- *     }>
+ *     }>,
+ *     reset_to_default: (boolean | undefined)
  *   }|undefined),
  *   dpi: ({
  *     option: !Array<{
@@ -83,7 +86,8 @@
  *       horizontal_dpi: number,
  *       vertical_dpi: number,
  *       is_default: (boolean|undefined)
- *     }>
+ *     }>,
+ *     reset_to_default: (boolean|undefined)
  *   }|undefined),
  *   pin: ({supported: (boolean|undefined)}|undefined)
  * }}
diff --git a/chrome/browser/resources/print_preview/data/model.js b/chrome/browser/resources/print_preview/data/model.js
index 0241f5f2..3a462df 100644
--- a/chrome/browser/resources/print_preview/data/model.js
+++ b/chrome/browser/resources/print_preview/data/model.js
@@ -694,6 +694,7 @@
     }
 
     this.updateSettingsValues_(caps);
+    this.applyPersistentCddDefaults_();
   }
 
   /**
@@ -1190,6 +1191,7 @@
         }
       });
     }
+    this.applyPersistentCddDefaults_();
     this.applyPolicySettings_();
     this.initialized_ = true;
     this.updateManaged_();
@@ -1285,6 +1287,85 @@
   }
 
   /**
+   * If the setting has a default value specified in the CDD capabilities and
+   * the attribute `reset_to_default` is true, this method will return the
+   * default value for the setting; otherwise it will return null.
+   * @param {*} setting The setting
+   * @return {*} The default value for the setting
+   * @private
+   */
+  getResetValue_(setting) {
+    if (!setting.reset_to_default) {
+      return null;
+    }
+    const cddDefault = setting.option.find(o => !!o.is_default);
+    if (!cddDefault) {
+      return null;
+    }
+    return cddDefault;
+  }
+
+  /**
+   * For PrinterProvider printers, it's possible to specify for a setting to
+   * always reset to the default value using the `reset_to_default` attribute.
+   * If `reset_to_default` is true and a default value for the
+   * setting is specified, this method will reset the setting
+   * value to the default value.
+   *  @private
+   */
+  applyPersistentCddDefaults_() {
+    if (!this.destination || !this.destination.isExtension) {
+      return;
+    }
+
+    const caps = this.destination && this.destination.capabilities ?
+        this.destination.capabilities.printer :
+        null;
+    if (!caps) {
+      return;
+    }
+
+    if (this.settings.mediaSize.available) {
+      const cddDefault = this.getResetValue_(caps['media_size']);
+      if (cddDefault) {
+        this.set('settings.mediaSize.value', cddDefault);
+      }
+    }
+
+    if (this.settings.color.available) {
+      const cddDefault = this.getResetValue_(caps['color']);
+      if (cddDefault) {
+        this.set(
+            'settings.color.value',
+            !['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME'].includes(
+                cddDefault.type));
+      }
+    }
+
+    if (this.settings.duplex.available) {
+      const cddDefault = this.getResetValue_(caps['duplex']);
+      if (cddDefault) {
+        this.set(
+            'settings.duplex.value',
+            cddDefault.type === DuplexType.LONG_EDGE ||
+                cddDefault.type === DuplexType.SHORT_EDGE);
+        if (!this.settings.duplexShortEdge.available) {
+          this.set(
+              'settings.duplexShortEdge.value',
+              cddDefault.type === DuplexType.SHORT_EDGE);
+        }
+      }
+    }
+
+    if (this.settings.dpi.available) {
+      const cddDefault = this.getResetValue_(caps['dpi']);
+      if (cddDefault) {
+        this.set('settings.dpi.value', cddDefault);
+      }
+    }
+  }
+
+  /**
    * Restricts settings and applies defaults as defined by policy applicable to
    * current destination.
    */
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 733c1afa..bad0412 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -117,7 +117,7 @@
     "autofill_page/show_password_mixin.js",
     "base_mixin.js",
     "chrome_cleanup_page/chrome_cleanup_proxy.js",
-    "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js",
+    "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts",
     "controls/pref_control_behavior.js",
     "controls/settings_boolean_control_behavior.js",
     "controls/settings_idle_load.js",
@@ -131,8 +131,8 @@
     "lazy_load.ts",
     "lifetime_browser_proxy.ts",
     "metrics_browser_proxy.js",
-    "on_startup_page/on_startup_browser_proxy.js",
-    "on_startup_page/startup_urls_page_browser_proxy.js",
+    "on_startup_page/on_startup_browser_proxy.ts",
+    "on_startup_page/startup_urls_page_browser_proxy.ts",
     "open_window_proxy.js",
     "page_visibility.js",
     "people_page/sync_browser_proxy.js",
@@ -223,10 +223,10 @@
     "autofill_page/passwords_export_dialog.js",
     "autofill_page/payments_section.js",
     "basic_page/basic_page.js",
-    "clear_browsing_data_dialog/clear_browsing_data_dialog.js",
-    "clear_browsing_data_dialog/history_deletion_dialog.js",
-    "clear_browsing_data_dialog/installed_app_checkbox.js",
-    "clear_browsing_data_dialog/passwords_deletion_dialog.js",
+    "clear_browsing_data_dialog/clear_browsing_data_dialog.ts",
+    "clear_browsing_data_dialog/history_deletion_dialog.ts",
+    "clear_browsing_data_dialog/installed_app_checkbox.ts",
+    "clear_browsing_data_dialog/passwords_deletion_dialog.ts",
     "controls/controlled_button.js",
     "controls/controlled_radio_button.js",
     "controls/extension_controlled_indicator.js",
@@ -240,10 +240,10 @@
     "downloads_page/downloads_page.ts",
     "icons.ts",
     "settings_menu/settings_menu.js",
-    "on_startup_page/on_startup_page.js",
-    "on_startup_page/startup_url_dialog.js",
-    "on_startup_page/startup_url_entry.js",
-    "on_startup_page/startup_urls_page.js",
+    "on_startup_page/on_startup_page.ts",
+    "on_startup_page/startup_url_dialog.ts",
+    "on_startup_page/startup_url_entry.ts",
+    "on_startup_page/startup_urls_page.ts",
     "people_page/sync_account_control.js",
     "people_page/sync_encryption_options.js",
     "people_page/people_page.js",
@@ -263,7 +263,7 @@
     "privacy_page/privacy_review/privacy_review_description_item.js",
     "privacy_page/privacy_review/privacy_review_msbb_fragment.js",
     "privacy_page/privacy_review/privacy_review_page.js",
-    "privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js",
+    "privacy_page/privacy_review/privacy_review_shared_css.js",
     "privacy_page/security_keys_bio_enroll_dialog.js",
     "privacy_page/security_keys_credential_management_dialog.js",
     "privacy_page/security_keys_pin_field.js",
@@ -378,9 +378,7 @@
     "about_page:closure_compile",
     "autofill_page:closure_compile",
     "basic_page:closure_compile",
-    "clear_browsing_data_dialog:closure_compile",
     "controls:closure_compile",
-    "on_startup_page:closure_compile",
     "people_page:closure_compile",
     "prefs:closure_compile",
     "privacy_page:closure_compile",
@@ -498,7 +496,6 @@
     "autofill_page:autofill_section",
     "autofill_page:payments_section",
     "chrome_cleanup_page:chrome_cleanup_proxy",
-    "clear_browsing_data_dialog:clear_browsing_data_browser_proxy",
     "privacy_page:cookies_page",
     "privacy_page:security_page",
     "privacy_page/privacy_review:privacy_review_page",
@@ -697,11 +694,11 @@
     "autofill_page/upi_id_list_entry.js",
     "base_mixin.js",
     "basic_page/basic_page.js",
-    "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js",
-    "clear_browsing_data_dialog/clear_browsing_data_dialog.js",
-    "clear_browsing_data_dialog/history_deletion_dialog.js",
-    "clear_browsing_data_dialog/installed_app_checkbox.js",
-    "clear_browsing_data_dialog/passwords_deletion_dialog.js",
+    "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts",
+    "clear_browsing_data_dialog/clear_browsing_data_dialog.ts",
+    "clear_browsing_data_dialog/history_deletion_dialog.ts",
+    "clear_browsing_data_dialog/installed_app_checkbox.ts",
+    "clear_browsing_data_dialog/passwords_deletion_dialog.ts",
     "controls/controlled_button.js",
     "controls/controlled_radio_button.js",
     "controls/extension_controlled_indicator.js",
@@ -726,12 +723,12 @@
     "lazy_load.ts",
     "lifetime_browser_proxy.ts",
     "metrics_browser_proxy.js",
-    "on_startup_page/on_startup_browser_proxy.js",
-    "on_startup_page/on_startup_page.js",
-    "on_startup_page/startup_url_dialog.js",
-    "on_startup_page/startup_url_entry.js",
-    "on_startup_page/startup_urls_page_browser_proxy.js",
-    "on_startup_page/startup_urls_page.js",
+    "on_startup_page/on_startup_browser_proxy.ts",
+    "on_startup_page/on_startup_page.ts",
+    "on_startup_page/startup_url_dialog.ts",
+    "on_startup_page/startup_url_entry.ts",
+    "on_startup_page/startup_urls_page_browser_proxy.ts",
+    "on_startup_page/startup_urls_page.ts",
     "open_window_proxy.js",
     "page_visibility.js",
     "people_page/people_page.js",
@@ -757,7 +754,7 @@
     "privacy_page/privacy_review/privacy_review_description_item.js",
     "privacy_page/privacy_review/privacy_review_msbb_fragment.js",
     "privacy_page/privacy_review/privacy_review_page.js",
-    "privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js",
+    "privacy_page/privacy_review/privacy_review_shared_css.js",
     "privacy_page/privacy_review_promo.js",
     "privacy_page/secure_dns_input.js",
     "privacy_page/secure_dns.js",
@@ -897,6 +894,7 @@
   definitions = [
     "//tools/typescript/definitions/chrome_send.d.ts",
     "//tools/typescript/definitions/management.d.ts",
+    "//tools/typescript/definitions/metrics_private.d.ts",
     "//tools/typescript/definitions/settings_private.d.ts",
   ]
 
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.js b/chrome/browser/resources/settings/a11y_page/captions_subpage.js
index b948ff1..e7f2556 100644
--- a/chrome/browser/resources/settings/a11y_page/captions_subpage.js
+++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.js
@@ -4,7 +4,8 @@
 
 /**
  * @fileoverview 'settings-captions' is a component for showing captions
- * settings subpage (chrome://settings/captions).
+ * settings subpage (chrome://settings/captions, and
+ * chrome://os-settings/manageAccessibility/captions on Chrome OS).
  */
 
 import '//resources/cr_elements/shared_style_css.m.js';
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.js b/chrome/browser/resources/settings/autofill_page/passwords_section.js
index f3bac9b..d29c6ccc 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.js
@@ -256,14 +256,6 @@
       },
 
       /** @private */
-      accountStorageFeatureEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean('enableAccountStorage');
-        }
-      },
-
-      /** @private */
       profileEmail_: {
         type: String,
         value: '',
@@ -434,9 +426,8 @@
     // (|!this.syncStatus_.signedin|). They should not be using a custom
     // passphrase to encrypt their sync data, since there's no way for account
     // storage users to input their passphrase and decrypt the passwords.
-    return this.accountStorageFeatureEnabled_ &&
-        (!!this.syncStatus_ && !this.syncStatus_.signedIn) && this.signedIn_ &&
-        (!this.syncPrefs_ || !this.syncPrefs_.encryptAllData);
+    return (!!this.syncStatus_ && !this.syncStatus_.signedIn) &&
+        this.signedIn_ && (!this.syncPrefs_ || !this.syncPrefs_.encryptAllData);
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
index 2acfac6a..2a97d6d 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
@@ -8,7 +8,6 @@
 <link rel="import" href="../deep_linking_behavior.html">
 <link rel="import" href="../os_route.html">
 <link rel="import" href="../../router.html">
-<link rel="import" href="../../appearance_page/fonts_browser_proxy.html">
 <link rel="import" href="../../settings_page/settings_animated_pages.html">
 <link rel="import" href="../../settings_page/settings_subpage.html">
 <link rel="import" href="../../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index 91830ea9..fbc0e77 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -236,7 +236,6 @@
                              "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.html|WallpaperBrowserProxy,WallpaperBrowserProxyImpl",
                              "chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.html|ParentalControlsBrowserProxy,ParentalControlsBrowserProxyImpl",
                              "chrome/browser/resources/settings/chromeos/route_origin_behavior.html|RouteOriginBehaviorImpl,RouteOriginBehavior",
-                             "chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html|FontsBrowserProxyImpl",
                              "chrome/browser/resources/settings/controls/settings_dropdown_menu.html|DropdownMenuOptionList",
                              "chrome/browser/resources/settings/chromeos/global_scroll_target_behavior.html|GlobalScrollTargetBehavior,setGlobalScrollTarget",
                              "chrome/browser/resources/settings/languages_page/languages_browser_proxy.html|LanguagesBrowserProxy,LanguagesBrowserProxyImpl",
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/BUILD.gn b/chrome/browser/resources/settings/clear_browsing_data_dialog/BUILD.gn
index bd6258f..ced3265 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/BUILD.gn
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/BUILD.gn
@@ -2,67 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/html_to_js.gni")
-import("../settings.gni")
-
-js_type_check("closure_compile") {
-  is_polymer3 = true
-  closure_flags = settings_closure_flags
-  deps = [
-    ":clear_browsing_data_browser_proxy",
-    ":clear_browsing_data_dialog",
-    ":history_deletion_dialog",
-    ":installed_app_checkbox",
-    ":passwords_deletion_dialog",
-  ]
-}
-
-js_library("clear_browsing_data_browser_proxy") {
-  deps = [ "//ui/webui/resources/js:cr.m" ]
-}
-
-js_library("clear_browsing_data_dialog") {
-  deps = [
-    ":clear_browsing_data_browser_proxy",
-    "..:route",
-    "..:router",
-    "../controls:settings_checkbox",
-    "../controls:settings_dropdown_menu",
-    "../people_page:sync_browser_proxy",
-    "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer",
-    "//ui/webui/resources/js:i18n_behavior.m",
-    "//ui/webui/resources/js:load_time_data.m",
-    "//ui/webui/resources/js:web_ui_listener_behavior.m",
-  ]
-}
-
-js_library("history_deletion_dialog") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
-}
-
-js_library("passwords_deletion_dialog") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
-}
-
-js_library("installed_app_checkbox") {
-  deps = [
-    ":clear_browsing_data_browser_proxy",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
 
 html_to_js("web_components") {
   js_files = [
-    "clear_browsing_data_dialog.js",
-    "history_deletion_dialog.js",
-    "installed_app_checkbox.js",
-    "passwords_deletion_dialog.js",
+    "clear_browsing_data_dialog.ts",
+    "history_deletion_dialog.ts",
+    "installed_app_checkbox.ts",
+    "passwords_deletion_dialog.ts",
   ]
 }
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js
deleted file mode 100644
index 44f759c..0000000
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview A helper object used from the "Clear browsing data" dialog
- * to interact with the browser.
- */
-
-// clang-format off
-import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
-// clang-format on
-
-/**
- * An InstalledApp represents a domain with data that the user might want
- * to protect from being deleted.
- *
- * @typedef {{
- *   registerableDomain: string,
- *   reasonBitfield: number,
- *   exampleOrigin: string,
- *   isChecked: boolean,
- *   storageSize: number,
- *   hasNotifications: boolean,
- *   appName: string
- * }}
- */
-export let InstalledApp;
-
-/**
- * ClearBrowsingDataResult contains any possible follow-up notices that should
- * be shown to the user.
- *
- * @typedef {{
- *   showHistoryNotice: boolean,
- *   showPasswordsNotice: boolean
- * }}
- */
-export let ClearBrowsingDataResult;
-
-/** @interface */
-export class ClearBrowsingDataBrowserProxy {
-  /**
-   * @param {!Array<string>} dataTypes
-   * @param {number} timePeriod
-   * @param {Array<InstalledApp>} installedApps
-   * @return {!Promise<!ClearBrowsingDataResult>}
-   *     A promise resolved when data clearing has completed. The boolean
-   *     indicates whether an additional dialog should be shown, informing the
-   *     user about other forms of browsing history.
-   */
-  clearBrowsingData(dataTypes, timePeriod, installedApps) {}
-
-  /**
-   * @param {number} timePeriod
-   * @return {!Promise<!Array<!InstalledApp>>}
-   *     A promise resolved after fetching all installed apps. The array
-   *     will contain a list of origins for which there are installed apps.
-   */
-  getInstalledApps(timePeriod) {}
-
-  /**
-   * Kick off counter updates and return initial state.
-   * @return {!Promise<void>} Signal when the setup is complete.
-   */
-  initialize() {}
-}
-
-/**
- * @implements {ClearBrowsingDataBrowserProxy}
- */
-export class ClearBrowsingDataBrowserProxyImpl {
-  /** @override */
-  clearBrowsingData(dataTypes, timePeriod, installedApps) {
-    return sendWithPromise(
-        'clearBrowsingData', dataTypes, timePeriod, installedApps);
-  }
-
-  /** @override */
-  getInstalledApps(timePeriod) {
-    return sendWithPromise('getInstalledApps', timePeriod);
-  }
-
-  /** @override */
-  initialize() {
-    return sendWithPromise('initializeClearBrowsingData');
-  }
-}
-
-addSingletonGetter(ClearBrowsingDataBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
new file mode 100644
index 0000000..fef6e54
--- /dev/null
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
@@ -0,0 +1,86 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A helper object used from the "Clear browsing data" dialog
+ * to interact with the browser.
+ */
+
+// clang-format off
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+// clang-format on
+
+/**
+ * An InstalledApp represents a domain with data that the user might want
+ * to protect from being deleted.
+ */
+export type InstalledApp = {
+  registerableDomain: string,
+  reasonBitfield: number,
+  exampleOrigin: string,
+  isChecked: boolean,
+  storageSize: number,
+  hasNotifications: boolean,
+  appName: string,
+};
+
+/**
+ * ClearBrowsingDataResult contains any possible follow-up notices that should
+ * be shown to the user.
+ */
+export type ClearBrowsingDataResult = {
+  showHistoryNotice: boolean,
+  showPasswordsNotice: boolean,
+};
+
+export interface ClearBrowsingDataBrowserProxy {
+  /**
+   * @return A promise resolved when data clearing has completed. The boolean
+   *     indicates whether an additional dialog should be shown, informing the
+   *     user about other forms of browsing history.
+   */
+  clearBrowsingData(
+      dataTypes: Array<string>, timePeriod: number,
+      installedApps: Array<InstalledApp>): Promise<ClearBrowsingDataResult>;
+
+  /**
+   * @return A promise resolved after fetching all installed apps. The array
+   *     will contain a list of origins for which there are installed apps.
+   */
+  getInstalledApps(timePeriod: number): Promise<Array<InstalledApp>>;
+
+  /**
+   * Kick off counter updates and return initial state.
+   * @return Signal when the setup is complete.
+   */
+  initialize(): Promise<void>;
+}
+
+export class ClearBrowsingDataBrowserProxyImpl implements
+    ClearBrowsingDataBrowserProxy {
+  clearBrowsingData(
+      dataTypes: Array<string>, timePeriod: number,
+      installedApps: Array<InstalledApp>) {
+    return sendWithPromise(
+        'clearBrowsingData', dataTypes, timePeriod, installedApps);
+  }
+
+  getInstalledApps(timePeriod: number) {
+    return sendWithPromise('getInstalledApps', timePeriod);
+  }
+
+  initialize() {
+    return sendWithPromise('initializeClearBrowsingData');
+  }
+
+  static getInstance(): ClearBrowsingDataBrowserProxy {
+    return instance || (instance = new ClearBrowsingDataBrowserProxyImpl());
+  }
+
+  static setInstance(obj: ClearBrowsingDataBrowserProxy) {
+    instance = obj;
+  }
+}
+
+let instance: ClearBrowsingDataBrowserProxy|null = null;
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
index ece8ce0..777ce41 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -341,8 +341,8 @@
         <template is="dom-repeat" items="[[installedApps_]]">
           <div class="row">
             <installed-app-checkbox
-              installed_app="[[item]]"
-              disabled="[[clearingInProgress_]]">
+                installed-app="[[item]]"
+                disabled="[[clearingInProgress_]]">
             </installed-app-checkbox>
           </div>
         </template>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
similarity index 67%
rename from chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js
rename to chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
index 825cebc..ce058b9 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
@@ -20,12 +20,15 @@
 import '../icons.js';
 import '../settings_shared_css.js';
 
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
-import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
-import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import {IronPagesElement} from 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {PrefControlBehaviorInterface} from '../controls/pref_control_behavior.js';
 import {DropdownMenuOptionList} from '../controls/settings_dropdown_menu.js';
 import {loadTimeData} from '../i18n_setup.js';
 import {StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '../people_page/sync_browser_proxy.js';
@@ -39,20 +42,18 @@
  * These values are persisted to logs and should not be renumbered or
  * re-used.
  * See tools/metrics/histograms/enums.xml.
- * @enum {number}
  */
-const InstalledAppsDialogActions = {
-  CLOSE: 0,
-  CANCEL_BUTTON: 1,
-  CLEAR_BUTTON: 2,
-};
+enum InstalledAppsDialogActions {
+  CLOSE = 0,
+  CANCEL_BUTTON = 1,
+  CLEAR_BUTTON = 2,
+}
 
 /**
- * @param {!CrDialogElement} dialog the dialog to close
- * @param {boolean} isLast whether this is the last CBD-related dialog
- * @private
+ * @param dialog the dialog to close
+ * @param isLast whether this is the last CBD-related dialog
  */
-function closeDialog(dialog, isLast) {
+function closeDialog(dialog: CrDialogElement, isLast: boolean) {
   // If this is not the last dialog, then stop the 'close' event from
   // propagating so that other (following) dialogs don't get closed as well.
   if (!isLast) {
@@ -64,40 +65,49 @@
 }
 
 /**
- * @param {!CrDialogElement} oldDialog the dialog to close
- * @param {!CrDialogElement} newDialog the dialog to open
- * @private
+ * @param oldDialog the dialog to close
+ * @param newDialog the dialog to open
  */
-function replaceDialog(oldDialog, newDialog) {
+function replaceDialog(oldDialog: CrDialogElement, newDialog: CrDialogElement) {
   closeDialog(oldDialog, false);
   if (!newDialog.open) {
     newDialog.showModal();
   }
 }
 
-/**
- * @typedef {{
- *   signedIn: boolean,
- *   syncConsented: boolean,
- *   syncingHistory: boolean,
- *   shouldShowCookieException: boolean,
- *   isNonGoogleDse: boolean,
- *   nonGoogleSearchHistoryString: string,
- * }}
- */
-let UpdateSyncStateEvent;
+type UpdateSyncStateEvent = {
+  signedIn: boolean,
+  syncConsented: boolean,
+  syncingHistory: boolean,
+  shouldShowCookieException: boolean,
+  isNonGoogleDse: boolean,
+  nonGoogleSearchHistoryString: string,
+};
 
-/**
- * @constructor
- * @extends {PolymerElement}
- * @implements {I18nBehaviorInterface}
- * @implements {RouteObserverMixinInterface}
- * @implements {WebUIListenerBehaviorInterface}
- */
-const SettingsClearBrowsingDataDialogElementBase = mixinBehaviors(
-    [I18nBehavior, WebUIListenerBehavior], RouteObserverMixin(PolymerElement));
+// TODO(crbug.com/1234307): Remove when settings_checkbox.js is migrated to
+// TypeScript.
+interface SettingsCheckboxElement extends HTMLElement {
+  checked: boolean;
+  pref: chrome.settingsPrivate.PrefObject;
+  sendPrefChange(): void;
+}
 
-/** @polymer */
+interface SettingsClearBrowsingDataDialogElement {
+  $: {
+    clearBrowsingDataDialog: CrDialogElement,
+    installedAppsDialog: CrDialogElement,
+    tabs: IronPagesElement,
+  };
+}
+
+const SettingsClearBrowsingDataDialogElementBase =
+    mixinBehaviors(
+        [I18nBehavior, WebUIListenerBehavior],
+        RouteObserverMixin(PolymerElement)) as {
+      new (): PolymerElement & WebUIListenerBehavior & I18nBehavior &
+      RouteObserverMixinInterface
+    };
+
 class SettingsClearBrowsingDataDialogElement extends
     SettingsClearBrowsingDataDialogElementBase {
   static get is() {
@@ -120,8 +130,6 @@
 
       /**
        * The current sync status, supplied by SyncBrowserProxy.
-       * TODO(dpapad): make |syncStatus| private.
-       * @type {?SyncStatus}
        */
       syncStatus: Object,
 
@@ -129,7 +137,6 @@
        * Results of browsing data counters, keyed by the suffix of
        * the corresponding data type deletion preference, as reported
        * by the C++ side.
-       * @private {!Object<string>}
        */
       counters_: {
         type: Object,
@@ -141,7 +148,6 @@
 
       /**
        * List of options for the dropdown menu.
-       * @private {!DropdownMenuOptionList}
        */
       clearFromOptions_: {
         readOnly: true,
@@ -155,25 +161,21 @@
         ],
       },
 
-      /** @private */
       clearingInProgress_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       clearingDataAlertString_: {
         type: String,
         value: '',
       },
 
-      /** @private */
       clearButtonDisabled_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       isSupervised_: {
         type: Boolean,
         value() {
@@ -181,63 +183,53 @@
         },
       },
 
-      /** @private */
       showHistoryDeletionDialog_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       showPasswordsDeletionDialogLater_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       showPasswordsDeletionDialog_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       isSignedIn_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       isSyncConsented_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       isSyncingHistory_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       shouldShowCookieException_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
       isSyncPaused_: {
         type: Boolean,
         value: false,
         computed: 'computeIsSyncPaused_(syncStatus)',
       },
 
-      /** @private */
       hasPassphraseError_: {
         type: Boolean,
         value: false,
         computed: 'computeHasPassphraseError_(syncStatus)',
       },
 
-      /** @private */
       hasOtherSyncError_: {
         type: Boolean,
         value: false,
@@ -245,7 +237,6 @@
             'computeHasOtherError_(syncStatus, isSyncPaused_, hasPassphraseError_)',
       },
 
-      /** @private {Array<string>} */
       tabsNames_: {
         type: Array,
         value: () =>
@@ -257,55 +248,67 @@
       /**
        * Installed apps that might be cleared if the user clears browsing data
        * for the selected time period.
-       * @private {!Array<!InstalledApp>}
        */
       installedApps_: {
         type: Array,
         value: () => [],
       },
 
-      /** @private */
       installedAppsFlagEnabled_: {
         type: Boolean,
         value: () => loadTimeData.getBoolean('installedAppsInCbd'),
       },
 
-      /** @private */
       searchHistoryLinkFlagEnabled_: {
         type: Boolean,
         value: () => loadTimeData.getBoolean('searchHistoryLink'),
       },
 
-      /** @private */
       googleSearchHistoryString_: {
         type: String,
         computed: 'computeGoogleSearchHistoryString_(isNonGoogleDse_)',
       },
 
-      /** @private */
       isNonGoogleDse_: {
         type: Boolean,
         value: false,
       },
 
-      /** @private */
-      nonGoogleSearchHistoryString_: {
-        type: String,
-      },
+      nonGoogleSearchHistoryString_: String,
     };
   }
 
-  constructor() {
-    super();
+  // TODO(dpapad): make |syncStatus| private.
+  syncStatus: SyncStatus|undefined;
+  private counters_: {[k: string]: string};
+  private clearFromOptions_: DropdownMenuOptionList;
+  private clearingInProgress_: boolean;
+  private clearingDataAlertString_: string;
+  private clearButtonDisabled_: boolean;
+  private isSupervised_: boolean;
+  private showHistoryDeletionDialog_: boolean;
+  private showPasswordsDeletionDialogLater_: boolean;
+  private showPasswordsDeletionDialog_: boolean;
+  private isSignedIn_: boolean;
+  private isSyncConsented_: boolean;
+  private isSyncingHistory_: boolean;
+  private shouldShowCookieException_: boolean;
+  private isSyncPaused_: boolean;
+  private hasPassphraseError_: boolean;
+  private hasOtherSyncError_: boolean;
+  private tabsNames_: Array<string>;
+  private installedApps_: Array<InstalledApp>;
+  private installedAppsFlagEnabled_: boolean;
+  private searchHistoryLinkFlagEnabled_: boolean;
+  private googleSearchHistoryString_: string;
+  private isNonGoogleDse_: boolean;
+  private nonGoogleSearchHistoryString_: string;
 
-    /** @private {!ClearBrowsingDataBrowserProxy} */
-    this.browserProxy_ = ClearBrowsingDataBrowserProxyImpl.getInstance();
+  private browserProxy_: ClearBrowsingDataBrowserProxy =
+      ClearBrowsingDataBrowserProxyImpl.getInstance();
+  private syncBrowserProxy_: SyncBrowserProxy =
+      SyncBrowserProxyImpl.getInstance();
 
-    /** @private {!SyncBrowserProxy} */
-    this.syncBrowserProxy_ = SyncBrowserProxyImpl.getInstance();
-  }
-
-  /** @override */
   ready() {
     super.ready();
 
@@ -323,7 +326,6 @@
         'settings-boolean-control-change', this.updateClearButtonState_);
   }
 
-  /** @override */
   connectedCallback() {
     super.connectedCallback();
 
@@ -334,45 +336,39 @@
 
   /**
    * Handler for when the sync state is pushed from the browser.
-   * @param {?SyncStatus} syncStatus
-   * @private
    */
-  handleSyncStatus_(syncStatus) {
+  private handleSyncStatus_(syncStatus: SyncStatus) {
     this.syncStatus = syncStatus;
   }
 
   /**
-   * Returns true if either clearing is in progress or no data type is selected.
-   * @param {boolean} clearingInProgress
-   * @param {boolean} clearButtonDisabled
-   * @return {boolean}
-   * @private
+   * @return Whether either clearing is in progress or no data type is selected.
    */
-  isClearButtonDisabled_(clearingInProgress, clearButtonDisabled) {
+  private isClearButtonDisabled_(
+      clearingInProgress: boolean, clearButtonDisabled: boolean): boolean {
     return clearingInProgress || clearButtonDisabled;
   }
 
   /**
    * Disables the Clear Data button if no data type is selected.
-   * @private
    */
-  updateClearButtonState_() {
+  private updateClearButtonState_() {
     // on-select-item-changed gets called with undefined during a tab change.
     // https://github.com/PolymerElements/iron-selector/issues/95
     const tab = this.$.tabs.selectedItem;
     if (!tab) {
       return;
     }
-    this.clearButtonDisabled_ = this.getSelectedDataTypes_(tab).length === 0;
+    this.clearButtonDisabled_ =
+        this.getSelectedDataTypes_(tab as HTMLElement).length === 0;
   }
 
   /**
    * Record visits to the CBD dialog.
    *
    * RouteObserverMixin
-   * @override
    */
-  currentRouteChanged(currentRoute) {
+  currentRouteChanged(currentRoute: Route) {
     if (currentRoute === routes.CLEAR_BROWSER_DATA) {
       chrome.metricsPrivate.recordUserAction('ClearBrowsingData_DialogCreated');
     }
@@ -381,11 +377,8 @@
   /**
    * Updates the history description to show the relevant information
    * depending on sync and signin state.
-   *
-   * @param {UpdateSyncStateEvent} event
-   * @private
    */
-  updateSyncState_(event) {
+  private updateSyncState_(event: UpdateSyncStateEvent) {
     this.isSignedIn_ = event.signedIn;
     this.isSyncConsented_ = event.syncConsented;
     this.isSyncingHistory_ = event.syncingHistory;
@@ -395,21 +388,12 @@
     this.nonGoogleSearchHistoryString_ = event.nonGoogleSearchHistoryString;
   }
 
-  /**
-   * Choose a label for the history checkbox.
-   * @param {boolean} isSyncConsented
-   * @param {boolean} isSyncingHistory
-   * @param {string} historySummary
-   * @param {string} historySummarySignedIn
-   * @param {string} historySummarySignedInNoLink
-   * @param {string} historySummarySynced
-   * @return {string}
-   * @private
-   */
-  browsingCheckboxLabel_(
-      isSyncConsented, isSyncingHistory, hasSyncError, historySummary,
-      historySummarySignedIn, historySummarySignedInNoLink,
-      historySummarySynced) {
+  /** Choose a label for the history checkbox. */
+  private browsingCheckboxLabel_(
+      isSyncConsented: boolean, isSyncingHistory: boolean,
+      hasSyncError: boolean, historySummary: string,
+      historySummarySignedIn: string, historySummarySignedInNoLink: string,
+      historySummarySynced: string): string {
     if (this.searchHistoryLinkFlagEnabled_) {
       return isSyncingHistory ? historySummarySignedInNoLink : historySummary;
     } else if (isSyncingHistory && !hasSyncError) {
@@ -420,16 +404,10 @@
     return historySummary;
   }
 
-  /**
-   * Choose a label for the cookie checkbox.
-   * @param {boolean} shouldShowCookieException
-   * @param {string} cookiesSummary
-   * @param {string} cookiesSummarySignedIn
-   * @return {string}
-   * @private
-   */
-  cookiesCheckboxLabel_(
-      shouldShowCookieException, cookiesSummary, cookiesSummarySignedIn) {
+  /** Choose a label for the cookie checkbox. */
+  private cookiesCheckboxLabel_(
+      shouldShowCookieException: boolean, cookiesSummary: string,
+      cookiesSummarySignedIn: string): string {
     if (shouldShowCookieException) {
       return cookiesSummarySignedIn;
     }
@@ -439,26 +417,23 @@
   /**
    * Updates the text of a browsing data counter corresponding to the given
    * preference.
-   * @param {string} prefName Browsing data type deletion preference.
-   * @param {string} text The text with which to update the counter
-   * @private
+   * @param prefName Browsing data type deletion preference.
+   * @param text The text with which to update the counter
    */
-  updateCounterText_(prefName, text) {
+  private updateCounterText_(prefName: string, text: string) {
     // Data type deletion preferences are named "browser.clear_data.<datatype>".
     // Strip the common prefix, i.e. use only "<datatype>".
-    const matches = prefName.match(/^browser\.clear_data\.(\w+)$/);
+    const matches = prefName.match(/^browser\.clear_data\.(\w+)$/)!;
     this.set('counters_.' + assert(matches[1]), text);
   }
 
   /**
-   * Returns a list of selected data types.
-   * @param {!HTMLElement} tab
-   * @return {!Array<string>}
-   * @private
+   * @return A list of selected data types.
    */
-  getSelectedDataTypes_(tab) {
-    const checkboxes = tab.querySelectorAll('settings-checkbox');
-    const dataTypes = [];
+  private getSelectedDataTypes_(tab: HTMLElement): Array<string> {
+    const checkboxes = tab.querySelectorAll('settings-checkbox') as
+        NodeListOf<SettingsCheckboxElement>;
+    const dataTypes: Array<string> = [];
     checkboxes.forEach((checkbox) => {
       if (checkbox.checked && !checkbox.hidden) {
         dataTypes.push(checkbox.pref.key);
@@ -472,17 +447,18 @@
    * within the time period selected. This is used to warn the user
    * that data for these apps will be cleared as well, and offers
    * them the option to exclude deletion of this data.
-   * @return {!Promise}
-   * @private
    */
-  async getInstalledApps_() {
-    const tab = this.$.tabs.selectedItem;
-    const timePeriod = tab.querySelector('.time-range-select').pref.value;
+  private async getInstalledApps_() {
+    const tab = this.$.tabs.selectedItem as HTMLElement;
+    // TODO(crbug.com/1234307): Cast to SettingsDropdownMenuElement when
+    // settings_dropdown_menu.js is migrated to TypeScript.
+    const timePeriod = (tab.querySelector('.time-range-select') as unknown as
+                        PrefControlBehaviorInterface)
+                           .pref!.value;
     this.installedApps_ = await this.browserProxy_.getInstalledApps(timePeriod);
   }
 
-  /** @private */
-  shouldShowInstalledApps_() {
+  private shouldShowInstalledApps_(): boolean {
     if (!this.installedAppsFlagEnabled_) {
       return false;
     }
@@ -493,11 +469,8 @@
     return haveInstalledApps;
   }
 
-  /**
-   * Logs interactions with the installed app dialog to UMA.
-   * @private
-   */
-  recordInstalledAppsInteractions_() {
+  /** Logs interactions with the installed app dialog to UMA. */
+  private recordInstalledAppsInteractions_() {
     if (this.installedApps_.length === 0) {
       return;
     }
@@ -513,17 +486,15 @@
         Math.round(100 * uncheckedAppCount / this.installedApps_.length));
   }
 
-  /**
-   * Clears browsing data and maybe shows a history notice.
-   * @return {!Promise}
-   * @private
-   */
-  async clearBrowsingData_() {
+  /** Clears browsing data and maybe shows a history notice. */
+  private async clearBrowsingData_() {
     this.clearingInProgress_ = true;
     this.clearingDataAlertString_ = loadTimeData.getString('clearingData');
-    const tab = this.$.tabs.selectedItem;
+    const tab = this.$.tabs.selectedItem as HTMLElement;
     const dataTypes = this.getSelectedDataTypes_(tab);
-    const timePeriod = tab.querySelector('.time-range-select').pref.value;
+    const timePeriod = (tab.querySelector('.time-range-select') as unknown as
+                        PrefControlBehaviorInterface)
+                           .pref!.value;
 
     if (tab.id === 'basic-tab') {
       chrome.metricsPrivate.recordUserAction('ClearBrowsingData_BasicTab');
@@ -531,7 +502,8 @@
       chrome.metricsPrivate.recordUserAction('ClearBrowsingData_AdvancedTab');
     }
 
-    this.shadowRoot.querySelectorAll('settings-checkbox[no-set-pref]')
+    (this.shadowRoot!.querySelectorAll('settings-checkbox[no-set-pref]') as
+     NodeListOf<SettingsCheckboxElement>)
         .forEach(checkbox => checkbox.sendPrefChange());
 
     const {showHistoryNotice, showPasswordsNotice} =
@@ -556,28 +528,21 @@
     // Close the clear browsing data or installed apps dialog if they are open.
     const isLastDialog = !showHistoryNotice && !showPasswordsNotice;
     if (this.$.clearBrowsingDataDialog.open) {
-      closeDialog(
-          /** @type {!CrDialogElement} */ (this.$.clearBrowsingDataDialog),
-          isLastDialog);
+      closeDialog(this.$.clearBrowsingDataDialog, isLastDialog);
     }
     if (this.$.installedAppsDialog.open) {
-      closeDialog(
-          /** @type {!CrDialogElement} */ (this.$.installedAppsDialog),
-          isLastDialog);
+      closeDialog(this.$.installedAppsDialog, isLastDialog);
     }
   }
 
-  /** @private */
-  onCancelTap_() {
+  private onCancelTap_() {
     this.$.clearBrowsingDataDialog.cancel();
   }
 
   /**
    * Handles the closing of the notice about other forms of browsing history.
-   * @param {!Event} e
-   * @private
    */
-  onHistoryDeletionDialogClose_(e) {
+  private onHistoryDeletionDialogClose_(e: Event) {
     this.showHistoryDeletionDialog_ = false;
     if (this.showPasswordsDeletionDialogLater_) {
       // Stop the close event from propagating further and also automatically
@@ -590,19 +555,15 @@
 
   /**
    * Handles the closing of the notice about incomplete passwords deletion.
-   * @param {!Event} e
-   * @private
    */
-  onPasswordsDeletionDialogClose_(e) {
+  private onPasswordsDeletionDialogClose_() {
     this.showPasswordsDeletionDialog_ = false;
   }
 
   /**
    * Records an action when the user changes between the basic and advanced tab.
-   * @param {!Event} event
-   * @private
    */
-  recordTabChange_(event) {
+  private recordTabChange_(event: CustomEvent<{value: number}>) {
     if (event.detail.value === 0) {
       chrome.metricsPrivate.recordUserAction(
           'ClearBrowsingData_SwitchTo_BasicTab');
@@ -612,15 +573,12 @@
     }
   }
 
-  /**
-   * Called when the user clicks the link in the footer.
-   * @param {!Event} e
-   * @private
-   */
-  onSyncDescriptionLinkClicked_(e) {
-    if (e.target.tagName === 'A') {
+  // <if expr="not chromeos">
+  /** Called when the user clicks the link in the footer. */
+  private onSyncDescriptionLinkClicked_(e: Event) {
+    if ((e.target as HTMLElement).tagName === 'A') {
       e.preventDefault();
-      if (!this.syncStatus.hasError) {
+      if (!this.syncStatus!.hasError) {
         chrome.metricsPrivate.recordUserAction('ClearBrowsingData_Sync_Pause');
         this.syncBrowserProxy_.pauseSync();
       } else if (this.isSyncPaused_) {
@@ -639,115 +597,74 @@
       }
     }
   }
+  // </if>
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  computeIsSyncPaused_() {
-    return !!this.syncStatus.hasError &&
-        !this.syncStatus.hasUnrecoverableError &&
-        this.syncStatus.statusAction === StatusAction.REAUTHENTICATE;
+  private computeIsSyncPaused_(): boolean {
+    return !!this.syncStatus!.hasError &&
+        !this.syncStatus!.hasUnrecoverableError &&
+        this.syncStatus!.statusAction === StatusAction.REAUTHENTICATE;
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  computeHasPassphraseError_() {
-    return !!this.syncStatus.hasError &&
-        this.syncStatus.statusAction === StatusAction.ENTER_PASSPHRASE;
+  private computeHasPassphraseError_(): boolean {
+    return !!this.syncStatus!.hasError &&
+        this.syncStatus!.statusAction === StatusAction.ENTER_PASSPHRASE;
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  computeHasOtherError_() {
-    return this.syncStatus !== undefined && !!this.syncStatus.hasError &&
+  private computeHasOtherError_(): boolean {
+    return this.syncStatus !== undefined && !!this.syncStatus!.hasError &&
         !this.isSyncPaused_ && !this.hasPassphraseError_;
   }
 
-  /**
-   * @return {string}
-   * @private
-   */
-  computeGoogleSearchHistoryString_(isNonGoogleDse) {
+  private computeGoogleSearchHistoryString_(isNonGoogleDse: boolean): string {
     return isNonGoogleDse ?
         this.i18nAdvanced('clearGoogleSearchHistoryNonGoogleDse') :
         this.i18nAdvanced('clearGoogleSearchHistoryGoogleDse');
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  shouldShowGoogleSearchHistoryLabel_(isSignedIn) {
+  private shouldShowGoogleSearchHistoryLabel_(isSignedIn: boolean): boolean {
     return this.searchHistoryLinkFlagEnabled_ && isSignedIn;
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  shouldShowNonGoogleSearchHistoryLabel_(isNonGoogleDse) {
+  private shouldShowNonGoogleSearchHistoryLabel_(isNonGoogleDse: boolean):
+      boolean {
     return this.searchHistoryLinkFlagEnabled_ && isNonGoogleDse;
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  shouldShowFooter_() {
+  private shouldShowFooter_(): boolean {
     let showFooter = false;
     // <if expr="not chromeos">
-    showFooter = !!this.syncStatus && !!this.syncStatus.signedIn;
+    showFooter = !!this.syncStatus && !!this.syncStatus!.signedIn;
     // </if>
     return showFooter;
   }
 
-  /**
-   * @return {!Promise}
-   * @private
-   */
-  async onClearBrowsingDataClick_() {
+  private async onClearBrowsingDataClick_() {
     await this.getInstalledApps_();
     if (this.shouldShowInstalledApps_()) {
-      replaceDialog(
-          /** @type {!CrDialogElement} */ (this.$.clearBrowsingDataDialog),
-          /** @type {!CrDialogElement} */ (this.$.installedAppsDialog));
+      replaceDialog(this.$.clearBrowsingDataDialog, this.$.installedAppsDialog);
     } else {
       await this.clearBrowsingData_();
     }
   }
 
-  /** @private */
-  hideInstalledApps_() {
+  private hideInstalledApps_() {
     chrome.metricsPrivate.recordEnumerationValue(
         'History.ClearBrowsingData.InstalledAppsDialogAction',
         InstalledAppsDialogActions.CLOSE,
         Object.keys(InstalledAppsDialogActions).length);
-    replaceDialog(
-        /** @type {!CrDialogElement} */ (this.$.installedAppsDialog),
-        /** @type {!CrDialogElement} */ (this.$.clearBrowsingDataDialog));
+    replaceDialog(this.$.installedAppsDialog, this.$.clearBrowsingDataDialog);
   }
 
-  /** @private */
-  onCancelInstalledApps_() {
+  private onCancelInstalledApps_() {
     chrome.metricsPrivate.recordEnumerationValue(
         'History.ClearBrowsingData.InstalledAppsDialogAction',
         InstalledAppsDialogActions.CANCEL_BUTTON,
         Object.keys(InstalledAppsDialogActions).length);
-    replaceDialog(
-        /** @type {!CrDialogElement} */ (this.$.installedAppsDialog),
-        /** @type {!CrDialogElement} */ (this.$.clearBrowsingDataDialog));
+    replaceDialog(this.$.installedAppsDialog, this.$.clearBrowsingDataDialog);
   }
 
-  /**
-   * Handles the tap confirm button in installed apps.
-   * @private
-   */
-  async onInstalledAppsConfirmClick_() {
+  /** Handles the tap confirm button in installed apps. */
+  private async onInstalledAppsConfirmClick_() {
     chrome.metricsPrivate.recordEnumerationValue(
         'History.ClearBrowsingData.InstalledAppsDialogAction',
         InstalledAppsDialogActions.CLEAR_BUTTON,
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.ts
similarity index 80%
rename from chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js
rename to chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.ts
index d78a031..c5450ca 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.ts
@@ -12,9 +12,15 @@
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import '../settings_shared_css.js';
 
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-/** @polymer */
+interface SettingsHistoryDeletionDialogElement {
+  $: {
+    dialog: CrDialogElement,
+  };
+}
+
 class SettingsHistoryDeletionDialogElement extends PolymerElement {
   static get is() {
     return 'settings-history-deletion-dialog';
@@ -24,11 +30,8 @@
     return html`{__html_template__}`;
   }
 
-  /**
-   * Click handler for the "OK" button.
-   * @private
-   */
-  onOkClick_() {
+  /** Click handler for the "OK" button. */
+  private onOkClick_() {
     this.$.dialog.close();
   }
 }
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.html
index 71e0bea..5a42f3a2 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.html
@@ -29,14 +29,14 @@
     </style>
 
     <div id="outerRow">
-      <cr-checkbox id="checkbox" checked="{{installed_app.isChecked}}"
+      <cr-checkbox id="checkbox" checked="{{installedApp.isChecked}}"
           disabled="[[disabled]]">
         <div id="innerRow">
-          <site-favicon url="[[installed_app.registerableDomain]]">
+          <site-favicon url="[[installedApp.registerableDomain]]">
           </site-favicon>
-          <div class="label">[[installed_app.appName]]</div>
+          <div class="label">[[installedApp.appName]]</div>
           <div class="secondary label">
-            &nbsp([[installed_app.registerableDomain]])
+            &nbsp([[installedApp.registerableDomain]])
           </div>
         </div>
       </cr-checkbox>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts
similarity index 93%
rename from chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.js
rename to chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts
index ec15f26..d0bdf8c 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.js
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/installed_app_checkbox.ts
@@ -16,7 +16,6 @@
 
 import {InstalledApp} from './clear_browsing_data_browser_proxy.js';
 
-/** @polymer */
 class InstalledAppCheckboxElement extends PolymerElement {
   static get is() {
     return 'installed-app-checkbox';
@@ -28,14 +27,15 @@
 
   static get properties() {
     return {
-      /** @type {InstalledApp} */
-      installed_app: Object,
+      installedApp: Object,
       disabled: {
         type: Boolean,
         value: false,
       },
     };
   }
+
+  installedApp: InstalledApp;
 }
 
 customElements.define(
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.ts
similarity index 80%
rename from chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.js
rename to chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.ts
index de1291af..1840bc52 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.js
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/passwords_deletion_dialog.ts
@@ -12,10 +12,15 @@
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import '../settings_shared_css.js';
 
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+interface SettingsPasswordsDeletionDialogElement {
+  $: {
+    dialog: CrDialogElement,
+  };
+}
 
-/** @polymer */
 class SettingsPasswordsDeletionDialogElement extends PolymerElement {
   static get is() {
     return 'settings-passwords-deletion-dialog';
@@ -25,17 +30,12 @@
     return html`{__html_template__}`;
   }
 
-
-
-  /**
-   * Click handler for the "OK" button.
-   * @private
-   */
-  onOkClick_() {
+  /** Click handler for the "OK" button. */
+  private onOkClick_() {
     this.$.dialog.close();
   }
 }
 
 customElements.define(
     SettingsPasswordsDeletionDialogElement.is,
-    SettingsPasswordsDeletionDialogElement);
\ No newline at end of file
+    SettingsPasswordsDeletionDialogElement);
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 081d344b..a17f911 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -13,7 +13,6 @@
 import './privacy_page/privacy_review/privacy_review_description_item.js';
 import './privacy_page/privacy_review/privacy_review_msbb_fragment.js';
 import './privacy_page/privacy_review/privacy_review_page.js';
-import './privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js';
 import './privacy_page/security_keys_subpage.js';
 import './privacy_page/security_page.js';
 import './site_settings/all_sites.js';
@@ -88,7 +87,6 @@
 export {PrivacyReviewDescriptionItemElement} from './privacy_page/privacy_review/privacy_review_description_item.js';
 export {PrivacyReviewMsbbFragmentElement} from './privacy_page/privacy_review/privacy_review_msbb_fragment.js';
 export {SettingsPrivacyReviewPageElement} from './privacy_page/privacy_review/privacy_review_page.js';
-export {PrivacyReviewTwoStateSettingFragmentElement} from './privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js';
 export {BioEnrollDialogPage} from './privacy_page/security_keys_bio_enroll_dialog.js';
 export {Ctap2Status, SampleStatus, SecurityKeysBioEnrollProxyImpl, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysPINBrowserProxyImpl, SecurityKeysResetBrowserProxyImpl} from './privacy_page/security_keys_browser_proxy.js';
 export {CredentialManagementDialogPage} from './privacy_page/security_keys_credential_management_dialog.js';
diff --git a/chrome/browser/resources/settings/on_startup_page/BUILD.gn b/chrome/browser/resources/settings/on_startup_page/BUILD.gn
index 53ed9d8..ba594ff 100644
--- a/chrome/browser/resources/settings/on_startup_page/BUILD.gn
+++ b/chrome/browser/resources/settings/on_startup_page/BUILD.gn
@@ -2,74 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/html_to_js.gni")
-import("../settings.gni")
-
-js_type_check("closure_compile") {
-  is_polymer3 = true
-  closure_flags = settings_closure_flags
-  deps = [
-    ":on_startup_browser_proxy",
-    ":on_startup_page",
-    ":startup_url_dialog",
-    ":startup_url_entry",
-    ":startup_urls_page",
-    ":startup_urls_page_browser_proxy",
-  ]
-}
-
-js_library("on_startup_browser_proxy") {
-  deps = [ "//ui/webui/resources/js:cr.m" ]
-}
-
-js_library("on_startup_page") {
-  deps = [
-    ":on_startup_browser_proxy",
-    "//ui/webui/resources/js:web_ui_listener_behavior.m",
-  ]
-}
-
-js_library("startup_url_dialog") {
-  deps = [
-    ":startup_urls_page_browser_proxy",
-    "..:i18n_setup",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
-}
-
-js_library("startup_url_entry") {
-  deps = [
-    ":startup_urls_page_browser_proxy",
-    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
-    "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render.m",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:icon",
-    "//ui/webui/resources/js/cr/ui:focus_row_behavior.m",
-  ]
-}
-
-js_library("startup_urls_page") {
-  deps = [
-    ":startup_url_entry",
-    ":startup_urls_page_browser_proxy",
-    "//ui/webui/resources/cr_elements:cr_scrollable_behavior.m",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:web_ui_listener_behavior.m",
-    "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
-  ]
-  externs_list = [ "$externs_path/settings_private.js" ]
-}
-
-js_library("startup_urls_page_browser_proxy") {
-  deps = [ "//ui/webui/resources/js:cr.m" ]
-}
 
 html_to_js("web_components") {
   js_files = [
-    "on_startup_page.js",
-    "startup_url_dialog.js",
-    "startup_url_entry.js",
-    "startup_urls_page.js",
+    "on_startup_page.ts",
+    "startup_url_dialog.ts",
+    "startup_url_entry.ts",
+    "startup_urls_page.ts",
   ]
 }
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js b/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js
deleted file mode 100644
index accc657..0000000
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
-// clang-format on
-
-/** @typedef {{id: string, name: string, canBeDisabled: boolean}} */
-export let NtpExtension;
-
-/** @interface */
-export class OnStartupBrowserProxy {
-  /** @return {!Promise<?NtpExtension>} */
-  getNtpExtension() {}
-}
-
-/**
- * @implements {OnStartupBrowserProxy}
- */
-export class OnStartupBrowserProxyImpl {
-  /** @override */
-  getNtpExtension() {
-    return sendWithPromise('getNtpExtension');
-  }
-}
-
-addSingletonGetter(OnStartupBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.ts b/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.ts
new file mode 100644
index 0000000..b1eb1b8
--- /dev/null
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.ts
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+// clang-format on
+
+export type NtpExtension = {
+  id: string,
+  name: string,
+  canBeDisabled: boolean,
+};
+
+export interface OnStartupBrowserProxy {
+  getNtpExtension(): Promise<NtpExtension|null>;
+}
+
+export class OnStartupBrowserProxyImpl implements OnStartupBrowserProxy {
+  getNtpExtension() {
+    return sendWithPromise('getNtpExtension');
+  }
+
+  static getInstance(): OnStartupBrowserProxy {
+    return instance || (instance = new OnStartupBrowserProxyImpl());
+  }
+
+  static setInstance(obj: OnStartupBrowserProxy) {
+    instance = obj;
+  }
+}
+
+let instance: OnStartupBrowserProxy|null = null;
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.js b/chrome/browser/resources/settings/on_startup_page/on_startup_page.ts
similarity index 62%
rename from chrome/browser/resources/settings/on_startup_page/on_startup_page.js
rename to chrome/browser/resources/settings/on_startup_page/on_startup_page.ts
index 5d95d9f7..acd7a28 100644
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.js
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.ts
@@ -15,21 +15,23 @@
 import '../i18n_setup.js';
 import '../settings_shared_css.js';
 
-import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {NtpExtension, OnStartupBrowserProxyImpl} from './on_startup_browser_proxy.js';
 
 
-/**
- * @constructor
- * @extends {PolymerElement}
- * @implements {WebUIListenerBehaviorInterface}
- */
-const SettingsOnStartupPageElementBase =
-    mixinBehaviors([WebUIListenerBehavior], PolymerElement);
+/** Enum values for the 'session.restore_on_startup' preference. */
+enum PrefValues {
+  CONTINUE = 1,
+  OPEN_NEW_TAB = 5,
+  OPEN_SPECIFIC = 4,
+}
 
-/** @polymer */
+const SettingsOnStartupPageElementBase =
+    mixinBehaviors([WebUIListenerBehavior], PolymerElement) as
+    {new (): PolymerElement & WebUIListenerBehavior};
+
 class SettingsOnStartupPageElement extends SettingsOnStartupPageElementBase {
   static get is() {
     return 'settings-on-startup-page';
@@ -46,33 +48,18 @@
         notify: true,
       },
 
-      /** @private {?NtpExtension} */
       ntpExtension_: Object,
 
-      /**
-       * Enum values for the 'session.restore_on_startup' preference.
-       * @private {!Object<string, number>}
-       */
-      prefValues_: {
-        readOnly: true,
-        type: Object,
-        value: {
-          CONTINUE: 1,
-          OPEN_NEW_TAB: 5,
-          OPEN_SPECIFIC: 4,
-        },
-      },
-
+      prefValues_: {readOnly: true, type: Object, value: PrefValues},
     };
   }
 
+  private ntpExtension_: NtpExtension|null;
 
-
-  /** @override */
   connectedCallback() {
     super.connectedCallback();
 
-    const updateNtpExtension = ntpExtension => {
+    const updateNtpExtension = (ntpExtension: NtpExtension|null) => {
       // Note that |ntpExtension| is empty if there is no NTP extension.
       this.ntpExtension_ = ntpExtension;
     };
@@ -81,23 +68,17 @@
     this.addWebUIListener('update-ntp-extension', updateNtpExtension);
   }
 
-  /**
-   * @param {number} value
-   * @return {string}
-   * @private
-   */
-  getName_(value) {
+  private getName_(value: number): string {
     return value.toString();
   }
 
   /**
    * Determine whether to show the user defined startup pages.
-   * @param {number} restoreOnStartup Enum value from prefValues_.
-   * @return {boolean} Whether the open specific pages is selected.
-   * @private
+   * @param restoreOnStartup Enum value from PrefValues.
+   * @return Whether the open specific pages is selected.
    */
-  showStartupUrls_(restoreOnStartup) {
-    return restoreOnStartup === this.prefValues_.OPEN_SPECIFIC;
+  private showStartupUrls_(restoreOnStartup: PrefValues): boolean {
+    return restoreOnStartup === PrefValues.OPEN_SPECIFIC;
   }
 }
 
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.ts
similarity index 79%
rename from chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js
rename to chrome/browser/resources/settings/on_startup_page/startup_url_dialog.ts
index 810a198a..b33823d 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.ts
@@ -7,6 +7,8 @@
 import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
 import '../settings_shared_css.js';
 
+import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
@@ -18,18 +20,24 @@
  * Describe the current URL input error status.
  * @enum {number}
  */
-const UrlInputError = {
-  NONE: 0,
-  INVALID_URL: 1,
-  TOO_LONG: 2,
-};
+enum UrlInputError {
+  NONE = 0,
+  INVALID_URL = 1,
+  TOO_LONG = 2,
+}
 
 /**
  * @fileoverview 'settings-startup-url-dialog' is a component for adding
  * or editing a startup URL entry.
  */
 
-/** @polymer */
+interface SettingsStartupUrlDialogElement {
+  $: {
+    dialog: CrDialogElement,
+    actionButton: CrButtonElement,
+  };
+}
+
 class SettingsStartupUrlDialogElement extends PolymerElement {
   static get is() {
     return 'settings-startup-url-dialog';
@@ -41,16 +49,13 @@
 
   static get properties() {
     return {
-      /** @private {UrlInputError} */
       error_: {
         type: Number,
         value: UrlInputError.NONE,
       },
 
-      /** @private */
       url_: String,
 
-      /** @private */
       urlLimit_: {
         readOnly: true,
         type: Number,
@@ -60,29 +65,25 @@
       /**
        * If specified the dialog acts as an "Edit page" dialog, otherwise as an
        * "Add new page" dialog.
-       * @type {?StartupPageInfo}
        */
       model: Object,
 
-      /** @private */
       dialogTitle_: String,
 
-      /** @private */
       actionButtonText_: String,
 
     };
   }
 
+  private error_: UrlInputError;
+  private url_: string;
+  private urlLimit_: number;
+  model: StartupPageInfo|null;
+  private dialogTitle_: string;
+  private actionButtonText_: string;
+  private browserProxy_: StartupUrlsPageBrowserProxy =
+      StartupUrlsPageBrowserProxyImpl.getInstance();
 
-
-  constructor() {
-    super();
-
-    /** @private {!StartupUrlsPageBrowserProxy} */
-    this.browserProxy_ = StartupUrlsPageBrowserProxyImpl.getInstance();
-  }
-
-  /** @override */
   connectedCallback() {
     super.connectedCallback();
 
@@ -100,31 +101,19 @@
     this.$.dialog.showModal();
   }
 
-  /**
-   * @return {boolean}
-   * @private
-   */
-  hasError_() {
+  private hasError_(): boolean {
     return this.error_ !== UrlInputError.NONE;
   }
 
-  /**
-   * @param {string} invalidUrl
-   * @param {string} tooLong
-   * @return {string}
-   * @private
-   */
-  errorMessage_(invalidUrl, tooLong) {
+  private errorMessage_(invalidUrl: string, tooLong: string): string {
     return ['', invalidUrl, tooLong][this.error_];
   }
 
-  /** @private */
-  onCancelTap_() {
+  private onCancelTap_() {
     this.$.dialog.close();
   }
 
-  /** @private */
-  onActionButtonTap_() {
+  private onActionButtonTap_() {
     const whenDone = this.model ?
         this.browserProxy_.editStartupPage(this.model.modelIndex, this.url_) :
         this.browserProxy_.addStartupPage(this.url_);
@@ -138,8 +127,7 @@
     });
   }
 
-  /** @private */
-  validate_() {
+  private validate_() {
     if (this.url_.length === 0) {
       this.$.actionButton.disabled = true;
       this.error_ = UrlInputError.NONE;
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.ts
similarity index 68%
rename from chrome/browser/resources/settings/on_startup_page/startup_url_entry.js
rename to chrome/browser/resources/settings/on_startup_page/startup_url_entry.ts
index 778e8f4..23b8d44 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.ts
@@ -16,8 +16,9 @@
 import '../site_favicon.js';
 
 import {CrActionMenuElement} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
+import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
-import {FocusRowBehavior, FocusRowBehaviorInterface} from 'chrome://resources/js/cr/ui/focus_row_behavior.m.js';
+import {FocusRowBehavior} from 'chrome://resources/js/cr/ui/focus_row_behavior.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {StartupPageInfo, StartupUrlsPageBrowserProxyImpl} from './startup_urls_page_browser_proxy.js';
@@ -25,20 +26,13 @@
 /**
  * The name of the event fired from this element when the "Edit" option is
  * clicked.
- * @type {string}
  */
-export const EDIT_STARTUP_URL_EVENT = 'edit-startup-url';
+export const EDIT_STARTUP_URL_EVENT: string = 'edit-startup-url';
 
-
-/**
- * @constructor
- * @extends {PolymerElement}
- * @implements {FocusRowBehaviorInterface}
- */
 const SettingsStartupUrlEntryElementBase =
-    mixinBehaviors([FocusRowBehavior], PolymerElement);
+    mixinBehaviors([FocusRowBehavior], PolymerElement) as
+    {new (): PolymerElement & FocusRowBehavior};
 
-/** @polymer */
 class SettingsStartupUrlEntryElement extends
     SettingsStartupUrlEntryElementBase {
   static get is() {
@@ -56,44 +50,37 @@
         reflectToAttribute: true,
       },
 
-      /** @type {!StartupPageInfo} */
       model: Object,
-
     };
   }
 
+  editable: boolean;
+  model: StartupPageInfo;
 
-
-  /** @private */
-  onRemoveTap_() {
-    this.shadowRoot.querySelector('cr-action-menu').close();
+  private onRemoveTap_() {
+    this.shadowRoot!.querySelector('cr-action-menu')!.close();
     StartupUrlsPageBrowserProxyImpl.getInstance().removeStartupPage(
         this.model.modelIndex);
   }
 
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onEditTap_(e) {
+  private onEditTap_(e: Event) {
     e.preventDefault();
-    this.shadowRoot.querySelector('cr-action-menu').close();
+    this.shadowRoot!.querySelector('cr-action-menu')!.close();
     this.dispatchEvent(new CustomEvent(EDIT_STARTUP_URL_EVENT, {
       bubbles: true,
       composed: true,
       detail: {
         model: this.model,
-        anchor: this.shadowRoot.querySelector('#dots'),
+        anchor: this.shadowRoot!.querySelector('#dots'),
       },
     }));
   }
 
-  /** @private */
-  onDotsTap_() {
-    const actionMenu =
-        /** @type {!CrActionMenuElement} */ (
-            this.shadowRoot.querySelector('#menu').get());
-    actionMenu.showAt(assert(this.shadowRoot.querySelector('#dots')));
+  private onDotsTap_() {
+    const actionMenu = (this.shadowRoot!.querySelector('#menu') as
+                        CrLazyRenderElement<CrActionMenuElement>)
+                           .get();
+    actionMenu.showAt(assert(this.shadowRoot!.querySelector('#dots')!));
   }
 }
 
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
deleted file mode 100644
index ea25546f..0000000
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview 'settings-startup-urls-page' is the settings page
- * containing the urls that will be opened when chrome is started.
- */
-
-import 'chrome://resources/js/action_link.js';
-import 'chrome://resources/cr_elements/action_link_css.m.js';
-import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
-import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
-import '../controls/extension_controlled_indicator.js';
-import '../settings_shared_css.js';
-import './startup_url_dialog.js';
-
-import {CrScrollableBehavior, CrScrollableBehaviorInterface} from 'chrome://resources/cr_elements/cr_scrollable_behavior.m.js';
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
-import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
-import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {EDIT_STARTUP_URL_EVENT} from './startup_url_entry.js';
-import {StartupPageInfo, StartupUrlsPageBrowserProxy, StartupUrlsPageBrowserProxyImpl} from './startup_urls_page_browser_proxy.js';
-
-
-/**
- * @constructor
- * @extends {PolymerElement}
- * @implements {WebUIListenerBehaviorInterface}
- * @implements {CrScrollableBehaviorInterface}
- */
-const SettingsStartupUrlsPageElementBase = mixinBehaviors(
-    [CrScrollableBehavior, WebUIListenerBehavior], PolymerElement);
-
-/** @polymer */
-class SettingsStartupUrlsPageElement extends
-    SettingsStartupUrlsPageElementBase {
-  static get is() {
-    return 'settings-startup-urls-page';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      prefs: Object,
-
-      /**
-       * Pages to load upon browser startup.
-       * @private {!Array<!StartupPageInfo>}
-       */
-      startupPages_: Array,
-
-      /** @private */
-      showStartupUrlDialog_: Boolean,
-
-      /** @private {?StartupPageInfo} */
-      startupUrlDialogModel_: Object,
-
-      /** @private {Object}*/
-      lastFocused_: Object,
-
-      /** @private */
-      listBlurred_: Boolean,
-
-    };
-  }
-
-
-
-  constructor() {
-    super();
-
-    /** @private {!StartupUrlsPageBrowserProxy} */
-    this.browserProxy_ = StartupUrlsPageBrowserProxyImpl.getInstance();
-
-    /**
-     * The element to return focus to, when the startup-url-dialog is closed.
-     * @private {?HTMLElement}
-     */
-    this.startupUrlDialogAnchor_ = null;
-  }
-
-  /** @override */
-  connectedCallback() {
-    super.connectedCallback();
-
-    this.addWebUIListener('update-startup-pages', startupPages => {
-      // If an "edit" URL dialog was open, close it, because the underlying page
-      // might have just been removed (and model indices have changed anyway).
-      if (this.startupUrlDialogModel_) {
-        this.destroyUrlDialog_();
-      }
-      this.startupPages_ = startupPages;
-      this.updateScrollableContents();
-    });
-    this.browserProxy_.loadStartupPages();
-
-    this.addEventListener(EDIT_STARTUP_URL_EVENT, event => {
-      this.startupUrlDialogModel_ = event.detail.model;
-      this.startupUrlDialogAnchor_ = event.detail.anchor;
-      this.showStartupUrlDialog_ = true;
-      event.stopPropagation();
-    });
-  }
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onAddPageTap_(e) {
-    e.preventDefault();
-    this.showStartupUrlDialog_ = true;
-    this.startupUrlDialogAnchor_ =
-        /** @type {!HTMLElement} */ (
-            this.shadowRoot.querySelector('#addPage a[is=action-link]'));
-  }
-
-  /** @private */
-  destroyUrlDialog_() {
-    this.showStartupUrlDialog_ = false;
-    this.startupUrlDialogModel_ = null;
-    if (this.startupUrlDialogAnchor_) {
-      focusWithoutInk(assert(this.startupUrlDialogAnchor_));
-      this.startupUrlDialogAnchor_ = null;
-    }
-  }
-
-  /** @private */
-  onUseCurrentPagesTap_() {
-    this.browserProxy_.useCurrentPages();
-  }
-
-  /**
-   * @return {boolean} Whether "Add new page" and "Use current pages" are
-   *     allowed.
-   * @private
-   */
-  shouldAllowUrlsEdit_() {
-    return this.get('prefs.session.startup_urls.enforcement') !==
-        chrome.settingsPrivate.Enforcement.ENFORCED;
-  }
-}
-
-customElements.define(
-    SettingsStartupUrlsPageElement.is, SettingsStartupUrlsPageElement);
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.ts b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.ts
new file mode 100644
index 0000000..6711b45
--- /dev/null
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.ts
@@ -0,0 +1,133 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview 'settings-startup-urls-page' is the settings page
+ * containing the urls that will be opened when chrome is started.
+ */
+
+import 'chrome://resources/js/action_link.js';
+import 'chrome://resources/cr_elements/action_link_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
+import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
+import '../controls/extension_controlled_indicator.js';
+import '../settings_shared_css.js';
+import './startup_url_dialog.js';
+
+import {CrScrollableBehavior} from 'chrome://resources/cr_elements/cr_scrollable_behavior.m.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
+import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {EDIT_STARTUP_URL_EVENT} from './startup_url_entry.js';
+import {StartupPageInfo, StartupUrlsPageBrowserProxy, StartupUrlsPageBrowserProxyImpl} from './startup_urls_page_browser_proxy.js';
+
+
+const SettingsStartupUrlsPageElementBase =
+    mixinBehaviors(
+        [CrScrollableBehavior, WebUIListenerBehavior], PolymerElement) as
+    {new (): PolymerElement & WebUIListenerBehavior & CrScrollableBehavior};
+
+class SettingsStartupUrlsPageElement extends
+    SettingsStartupUrlsPageElementBase {
+  static get is() {
+    return 'settings-startup-urls-page';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      prefs: Object,
+
+      /**
+       * Pages to load upon browser startup.
+       */
+      startupPages_: Array,
+
+      showStartupUrlDialog_: Boolean,
+      startupUrlDialogModel_: Object,
+      lastFocused_: Object,
+      listBlurred_: Boolean,
+    };
+  }
+
+  private startupPages_: Array<StartupPageInfo>;
+  private showStartupUrlDialog_: boolean;
+  private startupUrlDialogModel_: StartupPageInfo|null;
+  private lastFocused_: HTMLElement;
+  private listBlurred_: boolean;
+  private browserProxy_: StartupUrlsPageBrowserProxy =
+      StartupUrlsPageBrowserProxyImpl.getInstance();
+  private startupUrlDialogAnchor_: HTMLElement|null;
+
+  constructor() {
+    super();
+
+    /**
+     * The element to return focus to, when the startup-url-dialog is closed.
+     */
+    this.startupUrlDialogAnchor_ = null;
+  }
+
+  connectedCallback() {
+    super.connectedCallback();
+
+    this.addWebUIListener(
+        'update-startup-pages', (startupPages: Array<StartupPageInfo>) => {
+          // If an "edit" URL dialog was open, close it, because the underlying
+          // page might have just been removed (and model indices have changed
+          // anyway).
+          if (this.startupUrlDialogModel_) {
+            this.destroyUrlDialog_();
+          }
+          this.startupPages_ = startupPages;
+          this.updateScrollableContents();
+        });
+    this.browserProxy_.loadStartupPages();
+
+    this.addEventListener(EDIT_STARTUP_URL_EVENT, (event: Event) => {
+      const e =
+          event as CustomEvent<{model: StartupPageInfo, anchor: HTMLElement}>;
+      this.startupUrlDialogModel_ = e.detail.model;
+      this.startupUrlDialogAnchor_ = e.detail.anchor;
+      this.showStartupUrlDialog_ = true;
+      e.stopPropagation();
+    });
+  }
+
+  private onAddPageTap_(e: Event) {
+    e.preventDefault();
+    this.showStartupUrlDialog_ = true;
+    this.startupUrlDialogAnchor_ =
+        this.shadowRoot!.querySelector('#addPage a[is=action-link]');
+  }
+
+  private destroyUrlDialog_() {
+    this.showStartupUrlDialog_ = false;
+    this.startupUrlDialogModel_ = null;
+    if (this.startupUrlDialogAnchor_) {
+      focusWithoutInk(assert(this.startupUrlDialogAnchor_));
+      this.startupUrlDialogAnchor_ = null;
+    }
+  }
+
+  private onUseCurrentPagesTap_() {
+    this.browserProxy_.useCurrentPages();
+  }
+
+  /**
+   * @return Whether "Add new page" and "Use current pages" are allowed.
+   */
+  private shouldAllowUrlsEdit_(): boolean {
+    return this.get('prefs.session.startup_urls.enforcement') !==
+        chrome.settingsPrivate.Enforcement.ENFORCED;
+  }
+}
+
+customElements.define(
+    SettingsStartupUrlsPageElement.is, SettingsStartupUrlsPageElement);
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js
deleted file mode 100644
index 736b295..0000000
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
-// clang-format on
-
-/**
- * @typedef {{
- *   modelIndex: number,
- *   title: string,
- *   tooltip: string,
- *   url: string
- * }}
- */
-export let StartupPageInfo;
-
-/** @interface */
-export class StartupUrlsPageBrowserProxy {
-  loadStartupPages() {}
-  useCurrentPages() {}
-
-  /**
-   * @param {string} url
-   * @return {!Promise<boolean>} Whether the URL is valid.
-   */
-  validateStartupPage(url) {}
-
-  /**
-   * @param {string} url
-   * @return {!Promise<boolean>} Whether the URL was actually added, or
-   *     ignored because it was invalid.
-   */
-  addStartupPage(url) {}
-
-  /**
-   * @param {number} modelIndex
-   * @param {string} url
-   * @return {!Promise<boolean>} Whether the URL was actually edited, or
-   *     ignored because it was invalid.
-   */
-  editStartupPage(modelIndex, url) {}
-
-  /** @param {number} index */
-  removeStartupPage(index) {}
-}
-
-/**
- * @implements {StartupUrlsPageBrowserProxy}
- */
-export class StartupUrlsPageBrowserProxyImpl {
-  /** @override */
-  loadStartupPages() {
-    chrome.send('onStartupPrefsPageLoad');
-  }
-
-  /** @override */
-  useCurrentPages() {
-    chrome.send('setStartupPagesToCurrentPages');
-  }
-
-  /** @override */
-  validateStartupPage(url) {
-    return sendWithPromise('validateStartupPage', url);
-  }
-
-  /** @override */
-  addStartupPage(url) {
-    return sendWithPromise('addStartupPage', url);
-  }
-
-  /** @override */
-  editStartupPage(modelIndex, url) {
-    return sendWithPromise('editStartupPage', modelIndex, url);
-  }
-
-  /** @override */
-  removeStartupPage(index) {
-    chrome.send('removeStartupPage', [index]);
-  }
-}
-
-addSingletonGetter(StartupUrlsPageBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.ts b/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.ts
new file mode 100644
index 0000000..c8be8c1d
--- /dev/null
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.ts
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+// clang-format on
+
+export type StartupPageInfo = {
+  modelIndex: number,
+  title: string,
+  tooltip: string,
+  url: string,
+};
+
+export interface StartupUrlsPageBrowserProxy {
+  loadStartupPages(): void;
+  useCurrentPages(): void;
+
+  /** @return Whether the URL is valid. */
+  validateStartupPage(url: string): Promise<boolean>;
+
+  /**
+   * @return Whether the URL was actually added, or ignored because it was
+   *     invalid.
+   */
+  addStartupPage(url: string): Promise<boolean>;
+
+  /**
+   * @return Whether the URL was actually edited, or ignored because it was
+   *     invalid.
+   */
+  editStartupPage(modelIndex: number, url: string): Promise<boolean>;
+
+  removeStartupPage(index: number): void;
+}
+
+export class StartupUrlsPageBrowserProxyImpl implements
+    StartupUrlsPageBrowserProxy {
+  loadStartupPages() {
+    chrome.send('onStartupPrefsPageLoad');
+  }
+
+  useCurrentPages() {
+    chrome.send('setStartupPagesToCurrentPages');
+  }
+
+  validateStartupPage(url: string) {
+    return sendWithPromise('validateStartupPage', url);
+  }
+
+  addStartupPage(url: string) {
+    return sendWithPromise('addStartupPage', url);
+  }
+
+  editStartupPage(modelIndex: number, url: string) {
+    return sendWithPromise('editStartupPage', modelIndex, url);
+  }
+
+  removeStartupPage(index: number) {
+    chrome.send('removeStartupPage', [index]);
+  }
+
+  static getInstance(): StartupUrlsPageBrowserProxy {
+    return instance || (instance = new StartupUrlsPageBrowserProxyImpl());
+  }
+
+  static setInstance(obj: StartupUrlsPageBrowserProxy) {
+    instance = obj;
+  }
+}
+
+let instance: StartupUrlsPageBrowserProxy|null = null;
diff --git a/chrome/browser/resources/settings/people_page/sync_browser_proxy.js b/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
index af6f9f3e..9af1bbd4 100644
--- a/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
+++ b/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
 // clang-format on
 
   /**
@@ -353,6 +353,17 @@
     sendOfferTrustedVaultOptInChanged() {
       chrome.send('SyncOfferTrustedVaultOptInDispatch');
     }
+
+    /** @return {!SyncBrowserProxy} */
+    static getInstance() {
+      return instance || (instance = new SyncBrowserProxyImpl());
+    }
+
+    /** @param {!SyncBrowserProxy} obj */
+    static setInstance(obj) {
+      instance = obj;
+    }
   }
 
-  addSingletonGetter(SyncBrowserProxyImpl);
+  /** @type {?SyncBrowserProxy} */
+  let instance = null;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn b/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn
index 2518d1f..ce8f71e 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn
@@ -13,7 +13,6 @@
     ":privacy_review_description_item",
     ":privacy_review_msbb_fragment",
     ":privacy_review_page",
-    ":privacy_review_two_state_setting_fragment",
   ]
 }
 
@@ -26,7 +25,6 @@
 js_library("privacy_review_msbb_fragment") {
   deps = [
     ":privacy_review_description_item",
-    ":privacy_review_two_state_setting_fragment",
     "../../controls:settings_toggle_button",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
@@ -42,17 +40,11 @@
   ]
 }
 
-js_library("privacy_review_two_state_setting_fragment") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
 html_to_js("web_components") {
   js_files = [
     "privacy_review_description_item.js",
     "privacy_review_msbb_fragment.js",
     "privacy_review_page.js",
-    "privacy_review_two_state_setting_fragment.js",
+    "privacy_review_shared_css.js",
   ]
 }
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.html
index a0da061..28191fb 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.html
@@ -1,40 +1,46 @@
-<style>
+<style include="privacy-review-shared">
   settings-toggle-button {
     padding-bottom: 8px;
     padding-top: 8px;
   }
 </style>
-<privacy-review-two-state-setting-fragment
-    feature-header="$i18n{privacyReviewFeatureDescriptionHeader}"
-    privacy-header="$i18n{privacyReviewWhatYouShareWithGoogle}">
-  <div slot="embedded-setting">
+<div class="fragment-wrapper">
+  <div class="embedded-setting-wrapper">
     <settings-toggle-button id="urlCollectionToggle"
         pref="{{prefs.url_keyed_anonymized_data_collection.enabled}}"
         label="$i18n{urlKeyedAnonymizedDataCollection}">
     </settings-toggle-button>
   </div>
-  <div slot="feature-description">
-    <privacy-review-description-item
-        icon="settings20:flash-on"
-        label="$i18n{privacyReviewMsbbFeatureDescription1}">
-    </privacy-review-description-item>
-    <privacy-review-description-item
-        icon="settings20:lightbulb"
-        label="$i18n{privacyReviewMsbbFeatureDescription2}">
-    </privacy-review-description-item>
-    <privacy-review-description-item
-        icon="settings20:bar-chart"
-        label="$i18n{privacyReviewMsbbFeatureDescription3}">
-    </privacy-review-description-item>
+  <div class="two-column-description">
+    <div class="description-column description-column-first">
+      <div class=description-header>
+        $i18n{privacyReviewFeatureDescriptionHeader}
+      </div>
+      <privacy-review-description-item
+          icon="settings20:flash-on"
+          label="$i18n{privacyReviewMsbbFeatureDescription1}">
+      </privacy-review-description-item>
+      <privacy-review-description-item
+          icon="settings20:lightbulb"
+          label="$i18n{privacyReviewMsbbFeatureDescription2}">
+      </privacy-review-description-item>
+      <privacy-review-description-item
+          icon="settings20:bar-chart"
+          label="$i18n{privacyReviewMsbbFeatureDescription3}">
+      </privacy-review-description-item>
+    </div>
+    <div class="description-column">
+      <div class=description-header>
+        $i18n{privacyReviewWhatYouShareWithGoogle}
+      </div>
+      <privacy-review-description-item
+          icon="settings20:link"
+          label="$i18n{privacyReviewMsbbPrivacyDescription1}">
+      </privacy-review-description-item>
+      <privacy-review-description-item
+          icon="settings20:data-connectors-system"
+          label="$i18n{privacyReviewMsbbPrivacyDescription2}">
+      </privacy-review-description-item>
+    </div>
   </div>
-  <div slot="privacy-description">
-    <privacy-review-description-item
-        icon="settings20:link"
-        label="$i18n{privacyReviewMsbbPrivacyDescription1}">
-    </privacy-review-description-item>
-    <privacy-review-description-item
-        icon="settings20:data-connectors-system"
-        label="$i18n{privacyReviewMsbbPrivacyDescription2}">
-    </privacy-review-description-item>
-  </div>
-</privacy-review-two-state-setting-fragment>
+</div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.js b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.js
index 0c8dc36..fc1d4c0 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_msbb_fragment.js
@@ -9,11 +9,11 @@
  */
 import '../../controls/settings_toggle_button.js';
 import '../../prefs/prefs.js';
+import './privacy_review_shared_css.js';
 
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {PrivacyReviewDescriptionItemElement} from './privacy_review_description_item.js';
-import {PrivacyReviewTwoStateSettingFragmentElement} from './privacy_review_two_state_setting_fragment.js';
 
 /** @polymer */
 export class PrivacyReviewMsbbFragmentElement extends PolymerElement {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.html
new file mode 100644
index 0000000..eb5d9f1
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.html
@@ -0,0 +1,36 @@
+<template>
+  <style include="cr-shared-style settings-shared">
+    .description-column {
+      width: 50%;
+    }
+
+    .description-column-first {
+      padding-inline-end: 12px;
+    }
+
+    .description-header {
+      font-weight: 400;
+      text-transform: uppercase;
+    }
+
+    .embedded-setting-wrapper {
+      border: 1px solid var(--google-grey-refresh-300);
+      border-radius: 4px;
+    }
+
+    @media (prefers-color-scheme: dark) {
+      .embedded-setting-wrapper {
+        border: 1px solid var(--google-grey-refresh-700);
+      }
+    }
+
+    .fragment-wrapper {
+      padding: 12px;
+    }
+
+    .two-column-description {
+      display: flex;
+      padding: 16px;
+    }
+  </style>
+</template>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.js b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.js
new file mode 100644
index 0000000..6d6f49ea
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_shared_css.js
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const template = document.createElement('template');
+template.innerHTML = `
+<dom-module id="privacy-review-shared">{__html_template__}</dom-module>
+`;
+document.body.appendChild(template.content.cloneNode(true));
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.html
deleted file mode 100644
index c7e5f99..0000000
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<style include="cr-shared-style settings-shared">
-  #descriptionWrapper {
-    display: flex;
-    padding: 16px;
-  }
-
-  #fragmentWrapper {
-    padding: 12px;
-  }
-
-  #settingWrapper {
-    border: 1px solid var(--google-grey-refresh-300);
-    border-radius: 4px;
-  }
-
-  @media (prefers-color-scheme: dark) {
-    #settingWrapper {
-      border: 1px solid var(--google-grey-refresh-700);
-    }
-  }
-
-  .description-column {
-    width: 50%;
-  }
-
-  .description-column-first {
-    padding-inline-end: 12px;
-  }
-
-  .description-header {
-    font-weight: 400;
-    text-transform: uppercase;
-  }
-</style>
-<div id="fragmentWrapper">
-  <div id="settingWrapper">
-    <slot name="embedded-setting"></slot>
-  </div>
-  <div id="descriptionWrapper">
-    <div class="description-column description-column-first">
-      <div class=description-header>
-        [[featureHeader]]
-      </div>
-      <slot name="feature-description"></slot>
-    </div>
-    <div class="description-column">
-      <div class=description-header>
-        [[privacyHeader]]
-      </div>
-      <slot name="privacy-description"></slot>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js
deleted file mode 100644
index a9c9d2e5..0000000
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_two_state_setting_fragment.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * 'privacy-review-two-state-settings-fragment' is the fragment in a privacy
- * review card that contains an embedded two-state setting and a two-column
- * description of the setting.
- */
-import 'chrome://resources/cr_elements/shared_style_css.m.js';
-import '../../settings_shared_css.js';
-
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-/** @polymer */
-export class PrivacyReviewTwoStateSettingFragmentElement extends
-    PolymerElement {
-  static get is() {
-    return 'privacy-review-two-state-setting-fragment';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      featureHeader: {
-        type: String,
-        value: '',
-      },
-
-      privacyHeader: {
-        type: String,
-        value: '',
-      },
-    };
-  }
-}
-
-customElements.define(
-    PrivacyReviewTwoStateSettingFragmentElement.is,
-    PrivacyReviewTwoStateSettingFragmentElement);
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 3da6af9..23c75e8b 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -134,9 +134,7 @@
     r.PASSWORDS = r.AUTOFILL.createChild('/passwords');
     r.CHECK_PASSWORDS = r.PASSWORDS.createChild('check');
 
-    if (loadTimeData.getBoolean('enableAccountStorage')) {
-      r.DEVICE_PASSWORDS = r.PASSWORDS.createChild('device');
-    }
+    r.DEVICE_PASSWORDS = r.PASSWORDS.createChild('device');
 
     r.PAYMENTS = r.AUTOFILL.createChild('/payments');
     r.ADDRESSES = r.AUTOFILL.createChild('/addresses');
diff --git a/chrome/browser/sessions/closed_tab_cache.cc b/chrome/browser/sessions/closed_tab_cache.cc
index 9c61371..d68d9f6 100644
--- a/chrome/browser/sessions/closed_tab_cache.cc
+++ b/chrome/browser/sessions/closed_tab_cache.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/trace_event/trace_event.h"
-#include "chrome/browser/browser_features.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
@@ -48,25 +47,43 @@
 }
 ClosedTabCache::~ClosedTabCache() = default;
 
-base::TimeDelta ClosedTabCache::GetTimeToLiveInClosedTabCache() {
-  // We use the following order of priority if multiple values exist:
-  // - The programmatical value set in params. Used in specific tests.
-  // - Default value otherwise, kDefaultTimeToLiveInClosedTabCacheInSeconds.
+bool ClosedTabCache::CanCacheWebContents(absl::optional<SessionID> id) {
+  TRACE_EVENT0("browser", "ClosedTabCache::CanCacheWebContents");
 
-  return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
-      features::kClosedTabCache, "time_to_live_in_closed_tab_cache_in_seconds",
-      kDefaultTimeToLiveInClosedTabCacheInSeconds.InSeconds()));
+  // Only store if the kClosedTabCache feature is enabled.
+  if (!base::FeatureList::IsEnabled(features::kClosedTabCache))
+    return false;
+
+  // We need to assume that the caller took care of obtaining a SessionID.
+  DCHECK(id.has_value());
+
+  // Only store if tab has valid session id associated with it.
+  if (!id.value().is_valid())
+    return false;
+
+  // If the current memory pressure exceeds the threshold, we should not cache
+  // any WebContents. `memory_pressure_level_` is initialized to
+  // MEMORY_PRESSURE_LEVEL_NONE and will only be updated if the feature gets
+  // enabled, thus this branch won't be taken if the feature is disabled.
+  if (memory_pressure_level_ >= kClosedTabCacheMemoryPressureThreshold)
+    return false;
+
+  // For all other cases, you can store the tab in ClosedTabCache.
+  return true;
 }
 
-void ClosedTabCache::StoreEntry(SessionID id,
-                                std::unique_ptr<content::WebContents> wc,
-                                base::TimeTicks timestamp) {
-  TRACE_EVENT2("browser", "ClosedTabCache::StoreEntry", "SessionID", id.id(),
-               "URL", wc->GetURL().spec());
+void ClosedTabCache::CacheWebContents(
+    std::pair<absl::optional<SessionID>, std::unique_ptr<content::WebContents>>
+        cached) {
+  TRACE_EVENT0("browser", "ClosedTabCache::CacheWebContents");
 
-  auto entry = std::make_unique<Entry>(id, std::move(wc), timestamp);
-
-  // TODO: Dispatch pagehide() before freezing.
+  DCHECK(CanCacheWebContents(cached.first));
+  auto entry = std::make_unique<Entry>(
+      cached.first.value(), std::move(cached.second), base::TimeTicks::Now());
+  // TODO(https://crbug.com/1117377): Add a WebContents::SetInClosedTabCache()
+  // method to replace freezing the page.
+  entry->web_contents->WasHidden();
+  DCHECK_EQ(content::Visibility::HIDDEN, entry->web_contents->GetVisibility());
   entry->web_contents->SetPageFrozen(/*frozen=*/true);
   StartEvictionTimer(entry.get());
 
@@ -107,6 +124,46 @@
   return (*matching_entry).get()->web_contents.get();
 }
 
+base::TimeDelta ClosedTabCache::GetTimeToLiveInClosedTabCache() {
+  // We use the following order of priority if multiple values exist:
+  // - The programmatical value set in params. Used in specific tests.
+  // - Infinite if kClosedTabCacheNoTimeEviction is enabled.
+  // - Default value otherwise, kDefaultTimeToLiveInClosedTabCacheInSeconds.
+  if (base::FeatureList::IsEnabled(kClosedTabCacheNoTimeEviction) &&
+      GetFieldTrialParamValueByFeature(
+          features::kClosedTabCache,
+          "time_to_live_in_closed_tab_cache_in_seconds")
+          .empty()) {
+    return base::TimeDelta::Max();
+  }
+
+  return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
+      features::kClosedTabCache, "time_to_live_in_closed_tab_cache_in_seconds",
+      kDefaultTimeToLiveInClosedTabCacheInSeconds.InSeconds()));
+}
+
+void ClosedTabCache::SetCacheSizeLimitForTesting(size_t limit) {
+  cache_size_limit_ = limit;
+}
+
+void ClosedTabCache::SetTaskRunnerForTesting(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  task_runner_ = task_runner;
+}
+
+bool ClosedTabCache::IsEmpty() {
+  return entries_.empty();
+}
+
+// static
+bool ClosedTabCache::IsFeatureEnabled() {
+  return base::FeatureList::IsEnabled(features::kClosedTabCache);
+}
+
+size_t ClosedTabCache::EntriesCount() {
+  return entries_.size();
+}
+
 void ClosedTabCache::StartEvictionTimer(Entry* entry) {
   base::TimeDelta evict_after = GetTimeToLiveInClosedTabCache();
   entry->eviction_timer.SetTaskRunner(task_runner_);
@@ -128,26 +185,17 @@
   entries_.erase(matching_entry);
 }
 
-void ClosedTabCache::SetCacheSizeLimitForTesting(size_t limit) {
-  cache_size_limit_ = limit;
-}
-
-void ClosedTabCache::SetTaskRunnerForTesting(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  task_runner_ = task_runner;
-}
-
-bool ClosedTabCache::IsEmpty() {
-  return entries_.empty();
-}
-
-size_t ClosedTabCache::EntriesCount() {
-  return entries_.size();
-}
-
 void ClosedTabCache::OnMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel level) {
-  if (level >= kClosedTabCacheMemoryPressureThreshold)
+  if (!base::FeatureList::IsEnabled(kClosedTabCacheMemoryPressure)) {
+    // Don't flush entries if MemoryPressure is disabled for ClosedTabCache.
+    return;
+  }
+
+  if (memory_pressure_level_ != level)
+    memory_pressure_level_ = level;
+
+  if (memory_pressure_level_ >= kClosedTabCacheMemoryPressureThreshold)
     Flush();
 }
 
diff --git a/chrome/browser/sessions/closed_tab_cache.h b/chrome/browser/sessions/closed_tab_cache.h
index 3b827f1..aed58c5 100644
--- a/chrome/browser/sessions/closed_tab_cache.h
+++ b/chrome/browser/sessions/closed_tab_cache.h
@@ -12,12 +12,23 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chrome/browser/browser_features.h"
 #include "components/sessions/core/session_id.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace content {
 class WebContents;
 }  // namespace content
 
+// Removes the time limit for cached content. This is used by tests to identify
+// accidentally passing tests.
+const base::Feature kClosedTabCacheNoTimeEviction{
+    "ClosedTabCacheNoTimeEviction", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables MemoryPressure for closed tab cache.
+const base::Feature kClosedTabCacheMemoryPressure{
+    "ClosedTabCacheMemoryPressure", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // ClosedTabCache:
 //
 // A browser feature implemented with the purpose of instantaneously restoring
@@ -28,8 +39,6 @@
 // - stores WebContents instances uniquely identified by a SessionID.
 // - evicts cache entries after a timeout.
 // - evicts the least recently closed tab when the cache is full.
-//
-// TODO(aebacanu): Hook ClosedTabCache into the tab restore flow.
 class ClosedTabCache {
  public:
   ClosedTabCache();
@@ -37,11 +46,15 @@
   ClosedTabCache& operator=(const ClosedTabCache&) = delete;
   ~ClosedTabCache();
 
-  // Creates a ClosedTabCache::Entry from the given |id|, |wc| and |timestamp|.
-  // Moves the entry into the ClosedTabCache and evicts one if necessary.
-  void StoreEntry(SessionID id,
-                  std::unique_ptr<content::WebContents> wc,
-                  base::TimeTicks timestamp);
+  // ClosedTabCache needs to decide if it could cache a WebContents or not.
+  bool CanCacheWebContents(absl::optional<SessionID> id);
+
+  // Stores all |cacheable_web_contents| in ClosedTabCache. It is assumed that
+  // each passed WebContents is cacheable. This needs to be checked upfront by
+  // calling ClosedTabCache::CanCacheWebContents.
+  void CacheWebContents(
+      std::pair<absl::optional<SessionID>,
+                std::unique_ptr<content::WebContents>> cached);
 
   // Moves a WebContents out of ClosedTabCache knowing its |id|. Returns nullptr
   // if none is found.
@@ -65,6 +78,9 @@
   // Whether the entries list is empty or not.
   bool IsEmpty();
 
+  // Returns true if ClosedTabCache feature is currently enabled.
+  static bool IsFeatureEnabled();
+
   // Get the number of currently stored entries.
   size_t EntriesCount();
 
@@ -117,6 +133,11 @@
   // Listener that sets up a callback to flush the cache if there is not enough
   // memory available.
   std::unique_ptr<base::MemoryPressureListener> listener_;
+
+  // Current `memory_pressure_level_` used to determine if we are able to cache
+  // an entry or not. Needs to be updated from `listener_` callback.
+  base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level_ =
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
 };
 
 #endif  // CHROME_BROWSER_SESSIONS_CLOSED_TAB_CACHE_H_
diff --git a/chrome/browser/sessions/closed_tab_cache_browsertest.cc b/chrome/browser/sessions/closed_tab_cache_browsertest.cc
index f5e388a..331ab834 100644
--- a/chrome/browser/sessions/closed_tab_cache_browsertest.cc
+++ b/chrome/browser/sessions/closed_tab_cache_browsertest.cc
@@ -10,180 +10,189 @@
 #include "base/time/time.h"
 #include "base/util/memory_pressure/fake_memory_pressure_monitor.h"
 #include "chrome/browser/browser_features.h"
+#include "chrome/browser/sessions/closed_tab_cache_service_factory.h"
+#include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "chrome/browser/sessions/tab_restore_service_load_waiter.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/sessions/core/session_id.h"
 #include "content/public/test/browser_test.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
 
 using content::WebContents;
 
-class ClosedTabCacheTest : public InProcessBrowserTest {
+class ClosedTabCacheBrowserTest : public InProcessBrowserTest {
  public:
-  ClosedTabCacheTest() = default;
-  ClosedTabCacheTest(const ClosedTabCacheTest&) = delete;
-  ClosedTabCacheTest& operator=(const ClosedTabCacheTest&) = delete;
+  ClosedTabCacheBrowserTest() = default;
+  ~ClosedTabCacheBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
 
  protected:
-  // Add a tab to the given browser.
-  void AddTab(Browser* browser) {
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{features::kClosedTabCache, {}}, {kClosedTabCacheNoTimeEviction, {}}},
+        {});
+
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+  }
+
+  // Add a tab to the given browser and navigate to url.
+  void NavigateToURL(Browser* browser, const std::string& origin) {
+    GURL server_url = embedded_test_server()->GetURL(origin, "/title1.html");
     ui_test_utils::NavigateToURLWithDisposition(
-        browser, GURL(chrome::kChromeUINewTabURL),
-        WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        browser, server_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
         ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
   }
 
+  void CloseTabAt(int index) {
+    browser()->tab_strip_model()->CloseWebContentsAt(
+        index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
+  }
+
+  void RestoreMostRecentTab() {
+    TabRestoreServiceLoadWaiter waiter(
+        TabRestoreServiceFactory::GetForProfile(browser()->profile()));
+    chrome::RestoreTab(browser());
+    waiter.Wait();
+  }
+
+  ClosedTabCache& closed_tab_cache() {
+    return ClosedTabCacheServiceFactory::GetForProfile(browser()->profile())
+        ->closed_tab_cache();
+  }
+
   util::test::FakeMemoryPressureMonitor fake_memory_pressure_monitor_;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // Add an entry to the cache when the cache is empty.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, StoreEntryWhenEmpty) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, StoreEntryWhenEmpty) {
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
-
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  ASSERT_EQ(browser()->tab_strip_model()->count(), 1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 }
 
 // Add an entry to the cache when there is enough space.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, StoreEntryBasic) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, StoreEntryBasic) {
+  closed_tab_cache().SetCacheSizeLimitForTesting(2);
 
-  cache.SetCacheSizeLimitForTesting(2);
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
+  NavigateToURL(browser(), "b.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
 
-  std::unique_ptr<WebContents> wc1 =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-  std::unique_ptr<WebContents> wc2 =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc1),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc2),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 2U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 2U);
 }
 
 // Add an entry to the cache when the cache is at its limit.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, StoreEntryWhenFull) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, StoreEntryWhenFull) {
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
+  NavigateToURL(browser(), "b.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
 
-  std::unique_ptr<WebContents> wc1 =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-  std::unique_ptr<WebContents> wc2 =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-  SessionID id1 = SessionID::NewUnique();
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(id1, std::move(wc1), base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc2),
-                   base::TimeTicks::Now());
+  CloseTabAt(1);
 
-  // Expect the cache size to still be 1 and the removed entry to be entry1.
-  EXPECT_EQ(cache.EntriesCount(), 1U);
-  EXPECT_EQ(cache.GetWebContents(id1), nullptr);
+  // Expect the cache size to still be 1.
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 }
 
 // Restore an entry when the cache is empty.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, RestoreEntryWhenEmpty) {
-  ClosedTabCache cache;
-
-  ASSERT_TRUE(cache.IsEmpty())
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, RestoreEntryWhenEmpty) {
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
   SessionID id = SessionID::NewUnique();
-  EXPECT_EQ(cache.RestoreEntry(id), nullptr);
+  EXPECT_EQ(closed_tab_cache().RestoreEntry(id), nullptr);
 }
 
 // Restore an entry that is not in the cache.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, RestoreEntryWhenNotFound) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, RestoreEntryWhenNotFound) {
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
   SessionID id = SessionID::NewUnique();
-  EXPECT_EQ(cache.RestoreEntry(id), nullptr);
+  EXPECT_EQ(closed_tab_cache().RestoreEntry(id), nullptr);
 }
 
 // Restore an entry that is in the cache.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, RestoreEntryWhenFound) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, RestoreEntryWhenFound) {
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  SessionID id = SessionID::NewUnique();
-  cache.StoreEntry(id, std::move(wc), base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  WebContents* wc = browser()->tab_strip_model()->GetWebContentsAt(1);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
-  EXPECT_NE(cache.RestoreEntry(id), nullptr);
+  RestoreMostRecentTab();
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 0U);
+  ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
+  EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1), wc);
 }
 
 // Evict an entry after timeout.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, EvictEntryOnTimeout) {
-  ClosedTabCache cache;
-
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTest, EvictEntryOnTimeout) {
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner =
       base::MakeRefCounted<base::TestMockTimeTaskRunner>();
-  cache.SetTaskRunnerForTesting(task_runner);
+  closed_tab_cache().SetTaskRunnerForTesting(task_runner);
 
-  AddTab(browser());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
   // Fast forward to just before eviction is due.
   base::TimeDelta delta = base::TimeDelta::FromMilliseconds(1);
@@ -191,67 +200,103 @@
   task_runner->FastForwardBy(ttl - delta);
 
   // Expect the entry to still be in the cache.
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
   // Fast forward to when eviction is due.
   task_runner->FastForwardBy(delta);
 
   // Expect the entry to have been evicted.
-  EXPECT_EQ(cache.EntriesCount(), 0U);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 0U);
 }
 
-// Check that the cache is cleared if the memory pressure level is critical and
-// the threshold is critical.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, MemoryPressureLevelCritical) {
-  ClosedTabCache cache;
+// Test for functionality of memory pressure in closed tab cache.
+class ClosedTabCacheBrowserTestWithMemoryPressure
+    : public ClosedTabCacheBrowserTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ClosedTabCacheBrowserTest::SetUpCommandLine(command_line);
 
-  AddTab(browser());
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{kClosedTabCacheMemoryPressure, {}}}, {});
+  }
+
+  void SetMemoryPressure(
+      util::test::FakeMemoryPressureMonitor::MemoryPressureLevel level) {
+    fake_memory_pressure_monitor_.SetAndNotifyMemoryPressure(level);
+
+    // Wait for all the pressure callbacks to be run.
+    base::RunLoop().RunUntilIdle();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Check that no WebContents reaches the cache if the memory pressure level is
+// critical and the threshold is critical.
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTestWithMemoryPressure,
+                       MemoryPressureLevelCritical) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
-
-  fake_memory_pressure_monitor_.SetAndNotifyMemoryPressure(
+  SetMemoryPressure(
       base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
 
-  // Wait for all the pressure callbacks to be run.
-  base::RunLoop().RunUntilIdle();
-
-  // Expect the cache to have been cleared since the memory pressure level is
-  // at the threshold.
-  EXPECT_EQ(cache.EntriesCount(), 0U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 0U);
 }
 
 // Check that the cache is not cleared if the memory pressure level is moderate
 // and the threshold is critical.
-IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, MemoryPressureLevelModerate) {
-  ClosedTabCache cache;
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTestWithMemoryPressure,
+                       MemoryPressureLevelModerate) {
+  ASSERT_TRUE(embedded_test_server()->Start());
 
-  AddTab(browser());
+  NavigateToURL(browser(), "a.com");
   ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
 
-  std::unique_ptr<WebContents> wc =
-      browser()->tab_strip_model()->DetachWebContentsAtForInsertion(0);
-
-  ASSERT_TRUE(cache.IsEmpty())
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
       << "Expected cache to be empty at the start of the test.";
 
-  cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
-                   base::TimeTicks::Now());
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
 
-  fake_memory_pressure_monitor_.SetAndNotifyMemoryPressure(
+  SetMemoryPressure(
       base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
-  base::RunLoop().RunUntilIdle();
 
   // Expect the cache to not have been cleared since the memory pressure level
   // is below the threshold.
-  EXPECT_EQ(cache.EntriesCount(), 1U);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
+}
+
+// Check that a WebContents reaches the cache if the memory pressure level is
+// critical and the threshold is moderate, but gets flushed once the threshold
+// reaches critical.
+IN_PROC_BROWSER_TEST_F(ClosedTabCacheBrowserTestWithMemoryPressure,
+                       MemoryPressureLevelModerateThenCritical) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  NavigateToURL(browser(), "a.com");
+  ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
+
+  ASSERT_TRUE(closed_tab_cache().IsEmpty())
+      << "Expected cache to be empty at the start of the test.";
+
+  SetMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+  CloseTabAt(1);
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 1U);
+
+  SetMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+
+  // Expect the cache to have been cleared since the memory pressure level is
+  // at the threshold.
+  EXPECT_EQ(closed_tab_cache().EntriesCount(), 0U);
 }
diff --git a/chrome/browser/sessions/closed_tab_cache_service_factory.cc b/chrome/browser/sessions/closed_tab_cache_service_factory.cc
index 91bfe753..a54dab95 100644
--- a/chrome/browser/sessions/closed_tab_cache_service_factory.cc
+++ b/chrome/browser/sessions/closed_tab_cache_service_factory.cc
@@ -5,12 +5,17 @@
 #include "chrome/browser/sessions/closed_tab_cache_service_factory.h"
 
 #include "build/build_config.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 
 ClosedTabCacheServiceFactory::ClosedTabCacheServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "ClosedTabCacheService",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(HostContentSettingsMapFactory::GetInstance());
+  DependsOn(HistoryServiceFactory::GetInstance());
+}
 
 // static
 ClosedTabCacheService* ClosedTabCacheServiceFactory::GetForProfile(
diff --git a/chrome/browser/touch_to_fill/touch_to_fill_controller.cc b/chrome/browser/touch_to_fill/touch_to_fill_controller.cc
index e30c5c2..32397b14 100644
--- a/chrome/browser/touch_to_fill/touch_to_fill_controller.cc
+++ b/chrome/browser/touch_to_fill/touch_to_fill_controller.cc
@@ -11,7 +11,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/ranges/algorithm.h"
 #include "base/types/pass_key.h"
-#include "chrome/browser/device_reauth/chrome_biometric_authenticator.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/touch_to_fill/touch_to_fill_view.h"
 #include "chrome/browser/touch_to_fill/touch_to_fill_view_factory.h"
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
index 64fa80977..b5bf99d 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
@@ -20,6 +20,7 @@
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "url/android/gurl_android.h"
 
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
@@ -101,7 +102,8 @@
         ConvertUTF16ToJavaString(env, item_tag), android_icon_id,
         suggestion.frontend_id,
         controller_->GetRemovalConfirmationText(i, nullptr, nullptr),
-        ConvertUTF8ToJavaString(env, suggestion.feature_for_iph));
+        ConvertUTF8ToJavaString(env, suggestion.feature_for_iph),
+        url::GURLAndroid::FromNativeGURL(env, suggestion.custom_icon_url));
   }
   Java_AutofillKeyboardAccessoryViewBridge_show(env, java_object_, data_array,
                                                 controller_->IsRTL());
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_es-419.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_es-419.xtb
index 155b195d..d916bc3 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_es-419.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_es-419.xtb
@@ -213,7 +213,7 @@
 <translation id="235789365079050412">Política de Privacidad de Google</translation>
 <translation id="2359808026110333948">Continuar</translation>
 <translation id="2369533728426058518">pestañas abiertas</translation>
-<translation id="2386938421315164605">Ocultar y mostrar temas</translation>
+<translation id="2386938421315164605">Oculta y muestra temas.</translation>
 <translation id="2387895666653383613">Ajuste de texto</translation>
 <translation id="2394602618534698961">Los archivos que descargues aparecerán aquí</translation>
 <translation id="2407481962792080328">Esta función se activa cuando accedes a tu Cuenta de Google</translation>
@@ -302,7 +302,7 @@
 <translation id="2904414404539560095">La lista de dispositivos con los que se puede compartir una pestaña está totalmente abierta.</translation>
 <translation id="2908243544703713905">Hay contenido disponible sin leer</translation>
 <translation id="2909615210195135082">Plataforma de notificaciones de Google</translation>
-<translation id="2912296070571964914">Administra los temas que te interesan</translation>
+<translation id="2912296070571964914">Administra los temas que te interesan.</translation>
 <translation id="2923908459366352541">El nombre no es válido</translation>
 <translation id="2932150158123903946">Almacenamiento de Google <ph name="APP_NAME" /></translation>
 <translation id="2932222164150889403">No cambiará tu teclado.</translation>
@@ -1155,7 +1155,7 @@
 <translation id="8076492880354921740">Pestañas</translation>
 <translation id="8078096376109663956">Comparte texto solamente.</translation>
 <translation id="8084114998886531721">Se guardó la contraseña</translation>
-<translation id="8084285576995584326">Controla los datos de tu Cuenta de Google</translation>
+<translation id="8084285576995584326">Controla los datos de tu Cuenta de Google.</translation>
 <translation id="808747664143081553">Se estableció conexión con el dispositivo.</translation>
 <translation id="8088176524274673045">Para compartir contenido con personas cercanas, permíteles escanear este código QR.</translation>
 <translation id="8103578431304235997">Pestaña de incógnito</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_nl.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_nl.xtb
index 5915f3d3..8c98e9d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_nl.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_nl.xtb
@@ -181,6 +181,7 @@
 <translation id="2158408438301413340">Chrome kan niet alle wachtwoorden checken</translation>
 <translation id="2169830938017475061">Nu</translation>
 <translation id="2172688499998841696">Afbeeldingsbeschrijvingen staan uit</translation>
+<translation id="2172905120685242547">Venster sluiten?</translation>
 <translation id="2175927920773552910">QR-code</translation>
 <translation id="218608176142494674">Delen</translation>
 <translation id="2195339740518523951">Gebruik het hoogste beveiligingsniveau van Chrome</translation>
@@ -280,6 +281,7 @@
 <translation id="2779651927720337254">mislukt</translation>
 <translation id="2781151931089541271">1 seconde resterend</translation>
 <translation id="2788468313014644040">Groepsnummer</translation>
+<translation id="2800066122460699237">Het tabblad <ph name="TAB_TITLE" /> wordt gesloten</translation>
 <translation id="2801022321632964776">Voer een update uit om jouw taal te gebruiken in de nieuwste versie van Chrome</translation>
 <translation id="2805756323405976993">Apps</translation>
 <translation id="2806840421670364300">FLoC</translation>
@@ -288,6 +290,7 @@
 <translation id="2827278682606527653">Feedkaartmenu halve hoogte</translation>
 <translation id="2830783625999891985">Content van klembord verborgen</translation>
 <translation id="2839327205551510876"><ph name="SITE_NAME" /> wordt niet meer gevolgd</translation>
+<translation id="2840810876587895427">{TAB_COUNT,plural, =1{<ph name="TAB_COUNT_ONE" /> incognitotabblad wordt gesloten}other{<ph name="TAB_COUNT_MANY" /> incognitotabbladen worden gesloten}}</translation>
 <translation id="2841216154655874070">{NUM_DAYS,plural, =1{1 dag geleden gecheckt}other{# dagen geleden gecheckt}}</translation>
 <translation id="2842985007712546952">Bovenliggende map</translation>
 <translation id="2856503607207334158">Inloggen mislukt</translation>
@@ -673,6 +676,7 @@
 <translation id="5222676887888702881">Uitloggen</translation>
 <translation id="5227554086496586518">Tik om zoekresultaten te bekijken</translation>
 <translation id="5233638681132016545">Nieuw tabblad</translation>
+<translation id="5235196193381275927">Er is iets misgegaan bij het inloggen</translation>
 <translation id="5246093389635966745">Snelkoppeling voor werkbalk bewerken</translation>
 <translation id="5250483651202458397">Screenshot. Tik om te sluiten.</translation>
 <translation id="5262378156578470238">Je ziet een melding als deze download start op <ph name="DATE" />.</translation>
@@ -896,6 +900,7 @@
 <translation id="6541983376925655882">{NUM_HOURS,plural, =1{1 uur geleden gecheckt}other{# uur geleden gecheckt}}</translation>
 <translation id="6545017243486555795">Alle gegevens wissen</translation>
 <translation id="6546511553472444032">Bestand kan schadelijk zijn</translation>
+<translation id="6556542240154580383">{TAB_COUNT,plural, =1{<ph name="TAB_TITLE" /> en nog <ph name="TAB_COUNT_ONE" /> tabblad worden gesloten}other{<ph name="TAB_TITLE" /> en nog <ph name="TAB_COUNT_MANY" /> tabbladen worden gesloten}}</translation>
 <translation id="6560414384669816528">Zoeken met Sogou</translation>
 <translation id="656065428026159829">Meer tonen</translation>
 <translation id="6565959834589222080">Wifi wordt gebruikt als dat beschikbaar is</translation>
@@ -936,6 +941,7 @@
 <translation id="6767294960381293877">De lijst met apparaten om een tabblad mee te delen, is op halve hoogte geopend.</translation>
 <translation id="6783942555455976443">Deze pagina voor later opslaan en een herinnering ontvangen</translation>
 <translation id="6795633245022906657">Open snel een nieuw tabblad. Je kunt deze snelkoppeling bewerken via Instellingen.</translation>
+<translation id="6802555630140434547">Het venster wordt gesloten</translation>
 <translation id="6811034713472274749">Pagina kan nu worden bekeken</translation>
 <translation id="6813446258015311409">Inloggen bij Chrome, geopend.</translation>
 <translation id="6817747507826986771">Deel deze pagina snel. Tik en houd vast om deze snelkoppeling te bewerken.</translation>
@@ -1163,6 +1169,7 @@
 <translation id="8109613176066109935">Zet de synchronisatie aan om op al je apparaten toegang tot je bookmarks te hebben</translation>
 <translation id="8110087112193408731">Chrome-activiteit in Digitaal welzijn tonen?</translation>
 <translation id="8127542551745560481">Homepage bewerken</translation>
+<translation id="8130309322784422030">Je opgeslagen inloggegevens zijn misschien verouderd</translation>
 <translation id="813082847718468539">Sitegegevens bekijken</translation>
 <translation id="8137558756159375272">Met 'Tikken om te zoeken' worden het geselecteerde woord en de huidige pagina als context naar Google Zoeken gestuurd. Je kunt deze functie uitzetten via <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
 <translation id="8153351135626613369">De Assistent verschijnt op ondersteunde websites als hij vaststelt dat hij je kan helpen</translation>
@@ -1293,6 +1300,7 @@
 <translation id="8945143127965743188"><ph name="LANG" /> - Deze taal kan niet worden gedownload. Probeer het later opnieuw.</translation>
 <translation id="8951232171465285730">Chrome bespaart je <ph name="MEGABYTES" /> MB</translation>
 <translation id="8965591936373831584">in behandeling</translation>
+<translation id="8968085728801125376">{TAB_COUNT,plural, =1{<ph name="INCOGNITO_TAB_COUNT" /> incognitotabbladen en nog <ph name="TAB_COUNT_ONE" /> tabblad worden gesloten}other{<ph name="INCOGNITO_TAB_COUNT" /> incognitotabbladen en nog <ph name="TAB_COUNT_MANY" /> tabbladen worden gesloten}}</translation>
 <translation id="8970887620466824814">Er is iets misgegaan.</translation>
 <translation id="8972098258593396643">Downloaden naar standaardmap?</translation>
 <translation id="8987641763863173640">Instellingen voor videovoorbeeld beheren</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
index bcda7c1..d5347ee 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
@@ -1196,7 +1196,7 @@
 <translation id="835847953965672673"><ph name="NUMBER_OF_DOWNLOADS" /> డౌన్‌లోడ్‌లు రీస్టోర్ చేయబడ్డాయి</translation>
 <translation id="8364299278605033898">ప్రసిద్ధ వెబ్‌సైట్‌లను చూడండి</translation>
 <translation id="8387617938027387193">ఇది మీరేనని వెరిఫై చేయండి</translation>
-<translation id="8393700583063109961">సందేశాన్ని పంపండి</translation>
+<translation id="8393700583063109961">మెసేజ్‌ను పంపండి</translation>
 <translation id="8410695015584479363">ధరలను ట్రాక్ చేయండి</translation>
 <translation id="8413126021676339697">పూర్తి చరిత్రను చూపించు</translation>
 <translation id="8424781820952413435">పేజీ పంపబడింది. దానిని చూడటానికి మీ <ph name="DEVICE_TYPE" />లో Chromeను తెరవండి</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
index 9b3a77d57..4e6b50a5 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
@@ -181,6 +181,7 @@
 <translation id="2158408438301413340">Chrome barcha parollarni tekshira olmadi.</translation>
 <translation id="2169830938017475061">Hozir</translation>
 <translation id="2172688499998841696">Rasmlar tavsifi yoqilmagan</translation>
+<translation id="2172905120685242547">Oyna yopilsinmi?</translation>
 <translation id="2175927920773552910">QR kod</translation>
 <translation id="218608176142494674">Ulashish</translation>
 <translation id="2195339740518523951">Chrome brauzerining kuchli xavfsizligidan foydalaning</translation>
@@ -280,6 +281,7 @@
 <translation id="2779651927720337254">xatolik:</translation>
 <translation id="2781151931089541271">1 soniya qoldi</translation>
 <translation id="2788468313014644040">Guruh raqami</translation>
+<translation id="2800066122460699237"><ph name="TAB_TITLE" /> nomli varaq yopiladi</translation>
 <translation id="2801022321632964776">Chromeni eng oxirgi versiyagacha yangilab, internetni oʻz tilingizda kezing</translation>
 <translation id="2805756323405976993">Ilovalar</translation>
 <translation id="2806840421670364300">FLoC</translation>
@@ -288,6 +290,7 @@
 <translation id="2827278682606527653">Quyi bildirgi menyu yarim hajmda ochildi</translation>
 <translation id="2830783625999891985">Vaqtincha xotira kontenti berkitildi</translation>
 <translation id="2839327205551510876"><ph name="SITE_NAME" /> mavzusiga obuna bekor qilindi</translation>
+<translation id="2840810876587895427">{TAB_COUNT,plural, =1{<ph name="TAB_COUNT_ONE" /> ta inkognito varaq yopiladi}other{<ph name="TAB_COUNT_MANY" /> ta inkognito varaq yopiladi}}</translation>
 <translation id="2841216154655874070">{NUM_DAYS,plural, =1{1 kun oldin tekshirilgan}other{# kun oldin tekshirilgan}}</translation>
 <translation id="2842985007712546952">Ota jild</translation>
 <translation id="2856503607207334158">Kirish amalga oshmadi</translation>
@@ -673,6 +676,7 @@
 <translation id="5222676887888702881">Tizimdan chiqish</translation>
 <translation id="5227554086496586518">Qidiruv natijalarni koʻrish uchun bosing</translation>
 <translation id="5233638681132016545">Yangi varaq</translation>
+<translation id="5235196193381275927">Hisobga kirishda muammo yuz berdi</translation>
 <translation id="5246093389635966745">Asboblar panelidagi tugmani oʻzgartirish</translation>
 <translation id="5250483651202458397">Skrinshot. Bosib yopish.</translation>
 <translation id="5262378156578470238">Yuklab olish boshlanganda bildirishnoma olasiz: <ph name="DATE" />.</translation>
@@ -896,6 +900,7 @@
 <translation id="6541983376925655882">{NUM_HOURS,plural, =1{1 soat oldin tekshirilgan}other{# soat oldin tekshirilgan}}</translation>
 <translation id="6545017243486555795">Barcha ma’lumotlarni tozalash</translation>
 <translation id="6546511553472444032">Fayl xavfli boʻlishi mumkin</translation>
+<translation id="6556542240154580383">{TAB_COUNT,plural, =1{<ph name="TAB_TITLE" /> va yana <ph name="TAB_COUNT_ONE" /> ta varaq yopiladi}other{<ph name="TAB_TITLE" /> va yana <ph name="TAB_COUNT_MANY" /> ta varaq yopiladi}}</translation>
 <translation id="6560414384669816528">Sogou orqali qidirib ko‘ring</translation>
 <translation id="656065428026159829">Yana</translation>
 <translation id="6565959834589222080">Mavjud boʻlganda Wi-Fi ishlatiladi</translation>
@@ -936,6 +941,7 @@
 <translation id="6767294960381293877">Yarim hajmda ochilgan varaq uzatiladigan qurilmalar roʻyxati.</translation>
 <translation id="6783942555455976443">Bu sahifani saqlab qolish va keyinroq eslatish</translation>
 <translation id="6795633245022906657">Tezda yangi varaqda ochish. Bu yorliqni tahrirlash uchun Sozlamalarga kiring.</translation>
+<translation id="6802555630140434547">Oyna yopiladi</translation>
 <translation id="6811034713472274749">Sahifani koʻrish mumkin</translation>
 <translation id="6813446258015311409">Chrome hisobiga kirish, ochildi.</translation>
 <translation id="6817747507826986771">Bu sahifani tezda ulashish. Bu yorliqni tahrirlash uchun ustiga bosib turing.</translation>
@@ -1163,6 +1169,7 @@
 <translation id="8109613176066109935">Boshqa qurilmalardagi xatcho‘plaringizni ko‘rish uchun sinxronizatsiyani yoqing</translation>
 <translation id="8110087112193408731">Raqamli muvozanat xizmatida Chrome amallari chiqsinmi?</translation>
 <translation id="8127542551745560481">Bosh sahifani oʻzgartirish</translation>
+<translation id="8130309322784422030">Kirishga oid saqlangan axborotingiz eskirgan</translation>
 <translation id="813082847718468539">Sayt haqidagi ma’lumotlar</translation>
 <translation id="8137558756159375272">"Tegib qidirish" funksiyasi tanlangan so‘zni va kontekst sifatida joriy sahifani Google Qidiruv xizmatiga yuboradi. Uni <ph name="BEGIN_LINK" />Sozlamalarda<ph name="END_LINK" /> o‘chirib qo‘yish mumkin.</translation>
 <translation id="8153351135626613369">Assistent mos saytlarda yordam berish imkoni boʻlishi bilan chiqadi</translation>
@@ -1293,6 +1300,7 @@
 <translation id="8945143127965743188"><ph name="LANG" /> – Bu til yuklab olinmadi. Keyinroq urining.</translation>
 <translation id="8951232171465285730">Chrome <ph name="MEGABYTES" /> MB tejab qoldi</translation>
 <translation id="8965591936373831584">kutilmoqda</translation>
+<translation id="8968085728801125376">{TAB_COUNT,plural, =1{yana <ph name="TAB_COUNT_ONE" /> ta varaq yopiladi (<ph name="INCOGNITO_TAB_COUNT" /> tasi inkognito)}other{yana <ph name="TAB_COUNT_MANY" /> ta varaq yopiladi (<ph name="INCOGNITO_TAB_COUNT" /> tasi inkognito)}}</translation>
 <translation id="8970887620466824814">Xatolik yuz berdi.</translation>
 <translation id="8972098258593396643">Yuklanma standart jildga saqlansinmi?</translation>
 <translation id="8987641763863173640">Video bilan tanishish sozlamalarini boshqarish</translation>
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc
index 755b90a..76fcd8c 100644
--- a/chrome/browser/ui/browser_live_tab_context.cc
+++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -10,10 +10,14 @@
 #include "base/feature_list.h"
 #include "base/token.h"
 #include "chrome/browser/apps/app_service/launch_utils.h"
+#include "chrome/browser/browser_features.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/closed_tab_cache.h"
+#include "chrome/browser/sessions/closed_tab_cache_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/browser_tabrestore.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
@@ -152,10 +156,32 @@
   const bool first_tab_in_group =
       group.has_value() ? !group_model->ContainsTabGroup(group.value()) : false;
 
-  WebContents* web_contents = chrome::AddRestoredTab(
-      browser_, navigations, tab_index, selected_navigation, extension_app_id,
-      group, select, pin, base::TimeTicks(), storage_namespace,
-      user_agent_override, false /* from_session_restore */);
+  bool restored_from_closed_tab_cache = false;
+  WebContents* web_contents = nullptr;
+  if (tab_id) {
+    // Try to restore the WebContents from the ClosedTabCache rather than
+    // creating it again.
+    ClosedTabCache& cache =
+        ClosedTabCacheServiceFactory::GetForProfile(browser_->profile())
+            ->closed_tab_cache();
+    std::unique_ptr<WebContents> wc = cache.RestoreEntry(*tab_id);
+
+    if (wc) {
+      // Cache hit.
+      restored_from_closed_tab_cache = true;
+      web_contents = chrome::AddRestoredTabFromCache(std::move(wc), browser_,
+                                                     tab_index, group, select,
+                                                     pin, user_agent_override);
+    }
+  }
+
+  if (!restored_from_closed_tab_cache) {
+    // Cache miss, ClosedTabCache feature disabled or non-existent |tab_id|.
+    web_contents = chrome::AddRestoredTab(
+        browser_, navigations, tab_index, selected_navigation, extension_app_id,
+        group, select, pin, base::TimeTicks(), storage_namespace,
+        user_agent_override, false /* from_session_restore */);
+  }
 
   // Only update the metadata if the group doesn't already exist since the
   // existing group has the latest metadata, which may have changed from the
@@ -166,23 +192,25 @@
     group_model->GetTabGroup(group.value())->SetVisualData(new_data);
   }
 
+  if (!restored_from_closed_tab_cache) {
 #if BUILDFLAG(ENABLE_SESSION_SERVICE)
-  // The focused tab will be loaded by Browser, and TabLoader will load the
-  // rest.
-  if (!select) {
-    // Regression check: make sure that the tab hasn't started to load
-    // immediately.
-    DCHECK(web_contents->GetController().NeedsReload());
-    DCHECK(!web_contents->IsLoading());
-  }
-  std::vector<TabLoader::RestoredTab> restored_tabs;
-  restored_tabs.emplace_back(web_contents, select, !extension_app_id.empty(),
-                             pin, group);
-  TabLoader::RestoreTabs(restored_tabs, base::TimeTicks::Now());
+    // The focused tab will be loaded by Browser, and TabLoader will load the
+    // rest.
+    if (!select) {
+      // Regression check: make sure that the tab hasn't started to load
+      // immediately.
+      DCHECK(web_contents->GetController().NeedsReload());
+      DCHECK(!web_contents->IsLoading());
+    }
+    std::vector<TabLoader::RestoredTab> restored_tabs;
+    restored_tabs.emplace_back(web_contents, select, !extension_app_id.empty(),
+                               pin, group);
+    TabLoader::RestoreTabs(restored_tabs, base::TimeTicks::Now());
 #else   // BUILDFLAG(ENABLE_SESSION_SERVICE)
-  // Load the tab manually if there is no TabLoader.
-  web_contents->GetController().LoadIfNecessary();
+    // Load the tab manually if there is no TabLoader.
+    web_contents->GetController().LoadIfNecessary();
 #endif  // BUILDFLAG(ENABLE_SESSION_SERVICE)
+  }
 
   return sessions::ContentLiveTab::GetForWebContents(web_contents);
 }
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.cc b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
index 72ff219..623baebc 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.cc
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
@@ -8,7 +8,11 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "build/build_config.h"
+#include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/closed_tab_cache.h"
+#include "chrome/browser/sessions/closed_tab_cache_service_factory.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
 #include "chrome/browser/ui/browser.h"
@@ -228,6 +232,33 @@
   chrome::MoveTabToReadLater(browser_, web_contents);
 }
 
+void BrowserTabStripModelDelegate::CacheWebContents(
+    const std::vector<std::unique_ptr<TabStripModel::DetachedWebContents>>&
+        web_contents) {
+  if (browser_shutdown::HasShutdownStarted() ||
+      browser_->profile()->IsOffTheRecord() ||
+      !ClosedTabCache::IsFeatureEnabled()) {
+    return;
+  }
+
+  ClosedTabCache& cache =
+      ClosedTabCacheServiceFactory::GetForProfile(browser_->profile())
+          ->closed_tab_cache();
+
+  // We assume a cache size of one. Only the last recently closed tab will be
+  // cached.
+  // TODO(https://crbug.com/1236077): Cache more than one tab in ClosedTabCache.
+  auto& dwc = web_contents.back();
+  if (!cache.CanCacheWebContents(dwc->id))
+    return;
+
+  std::unique_ptr<content::WebContents> wc;
+  dwc->owned_contents.swap(wc);
+  dwc->remove_reason = TabStripModelChange::RemoveReason::kCached;
+  auto cached = std::make_pair(dwc->id, std::move(wc));
+  cache.CacheWebContents(std::move(cached));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserTabStripModelDelegate, private:
 
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.h b/chrome/browser/ui/browser_tab_strip_model_delegate.h
index 5e42404d..b73f27e3 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.h
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.h
@@ -52,6 +52,9 @@
   bool ShouldDisplayFavicon(content::WebContents* contents) const override;
   bool CanReload() const override;
   void AddToReadLater(content::WebContents* web_contents) override;
+  void CacheWebContents(
+      const std::vector<std::unique_ptr<TabStripModel::DetachedWebContents>>&
+          web_contents) override;
 
   void CloseFrame();
 
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index b1fc278..11dac69 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -40,6 +40,10 @@
 
 namespace {
 
+// TODO(https://crbug.com/1119368): Consider making CreateRestoredTab public and
+// separate AddRestoredTab from CreateRestoredTab to distinguish the cases where
+// a tab doesn't need to be created when it can be restored from the cache. At
+// that point, there would be no need for the AddRestoredTabFromCache method.
 std::unique_ptr<WebContents> CreateRestoredTab(
     Browser* browser,
     const std::vector<SerializedNavigationEntry>& navigations,
@@ -115,27 +119,13 @@
   web_contents->GetController().LoadIfNecessary();
 }
 
-}  // namespace
-
-WebContents* AddRestoredTab(
-    Browser* browser,
-    const std::vector<SerializedNavigationEntry>& navigations,
-    int tab_index,
-    int selected_navigation,
-    const std::string& extension_app_id,
-    absl::optional<tab_groups::TabGroupId> group,
-    bool select,
-    bool pin,
-    base::TimeTicks last_active_time,
-    content::SessionStorageNamespace* session_storage_namespace,
-    const sessions::SerializedUserAgentOverride& user_agent_override,
-    bool from_session_restore) {
-  const bool initially_hidden = !select || browser->window()->IsMinimized();
-  std::unique_ptr<WebContents> web_contents = CreateRestoredTab(
-      browser, navigations, selected_navigation, extension_app_id,
-      last_active_time, session_storage_namespace, user_agent_override,
-      initially_hidden, from_session_restore);
-
+WebContents* AddRestoredTabImpl(std::unique_ptr<WebContents> web_contents,
+                                Browser* browser,
+                                int tab_index,
+                                absl::optional<tab_groups::TabGroupId> group,
+                                bool select,
+                                bool pin,
+                                bool from_session_restore) {
   TabStripModel* const tab_strip_model = browser->tab_strip_model();
 
   int add_types = select ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
@@ -165,6 +155,7 @@
     tab_strip_model->AddToGroupForRestore({actual_index}, group.value());
   }
 
+  const bool initially_hidden = !select || browser->window()->IsMinimized();
   if (initially_hidden) {
     // We set the size of the view here, before Blink does its initial layout.
     // If we don't, the initial layout of background tabs will be performed
@@ -214,6 +205,52 @@
   return raw_web_contents;
 }
 
+}  // namespace
+
+WebContents* AddRestoredTab(
+    Browser* browser,
+    const std::vector<SerializedNavigationEntry>& navigations,
+    int tab_index,
+    int selected_navigation,
+    const std::string& extension_app_id,
+    absl::optional<tab_groups::TabGroupId> group,
+    bool select,
+    bool pin,
+    base::TimeTicks last_active_time,
+    content::SessionStorageNamespace* session_storage_namespace,
+    const sessions::SerializedUserAgentOverride& user_agent_override,
+    bool from_session_restore) {
+  const bool initially_hidden = !select || browser->window()->IsMinimized();
+  std::unique_ptr<WebContents> web_contents = CreateRestoredTab(
+      browser, navigations, selected_navigation, extension_app_id,
+      last_active_time, session_storage_namespace, user_agent_override,
+      initially_hidden, from_session_restore);
+
+  return AddRestoredTabImpl(std::move(web_contents), browser, tab_index, group,
+                            select, pin, from_session_restore);
+}
+
+WebContents* AddRestoredTabFromCache(
+    std::unique_ptr<WebContents> web_contents,
+    Browser* browser,
+    int tab_index,
+    absl::optional<tab_groups::TabGroupId> group,
+    bool select,
+    bool pin,
+    const sessions::SerializedUserAgentOverride& user_agent_override) {
+  // TODO(crbug.com/1227397): Check whether |ua_override| has changed for the
+  // tab we're trying to restore from ClosedTabCache. Don't restore if the
+  // values differ.
+  blink::UserAgentOverride ua_override;
+  ua_override.ua_string_override = user_agent_override.ua_string_override;
+  ua_override.ua_metadata_override = blink::UserAgentMetadata::Demarshal(
+      user_agent_override.opaque_ua_metadata_override);
+  web_contents->SetUserAgentOverride(ua_override, false);
+
+  return AddRestoredTabImpl(std::move(web_contents), browser, tab_index, group,
+                            select, pin, /*from_session_restore=*/false);
+}
+
 WebContents* ReplaceRestoredTab(
     Browser* browser,
     const std::vector<SerializedNavigationEntry>& navigations,
diff --git a/chrome/browser/ui/browser_tabrestore.h b/chrome/browser/ui/browser_tabrestore.h
index 4743113..bddf76ef 100644
--- a/chrome/browser/ui/browser_tabrestore.h
+++ b/chrome/browser/ui/browser_tabrestore.h
@@ -53,6 +53,19 @@
     const sessions::SerializedUserAgentOverride& user_agent_override,
     bool from_session_restore);
 
+// Same functionality as AddRestoreTab, except that the |web_contents| is
+// passed as it was never deleted. Used when restoring entry from
+// ClosedTabCache. Note that ClosedTabCache is an experimental desktop feature
+// to instantly restore recently closed tabs.
+content::WebContents* AddRestoredTabFromCache(
+    std::unique_ptr<content::WebContents> web_contents,
+    Browser* browser,
+    int tab_index,
+    absl::optional<tab_groups::TabGroupId> group,
+    bool select,
+    bool pin,
+    const sessions::SerializedUserAgentOverride& user_agent_override);
+
 // Replaces the state of the currently selected tab with the session
 // history restored from the SessionRestore and TabRestoreService systems.
 // Returns the WebContents of the restored tab.
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
index c40dc793..61a3954 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -75,26 +75,14 @@
       break;
     case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM:
       num_buttons_ = 2;
-      switch (controller_->type()) {
-        case javascript_dialogs::AppModalDialogController::Type::kBeforeUnload:
-          params->primary_button_text = l10n_util::GetStringUTF16(
-              IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
-          break;
-        case javascript_dialogs::AppModalDialogController::Type::
-            kBeforeUnloadReload:
+      if (controller_->is_before_unload_dialog()) {
+        if (controller_->is_reload()) {
           params->primary_button_text = l10n_util::GetStringUTF16(
               IDS_BEFORERELOAD_MESSAGEBOX_OK_BUTTON_LABEL);
-          break;
-        case javascript_dialogs::AppModalDialogController::Type::
-            kBeforeUnloadQuitOrHide:
+        } else {
           params->primary_button_text = l10n_util::GetStringUTF16(
-              IDS_BEFOREUNLOAD_MESSAGEBOX_QUIT_BUTTON_LABEL);
-          params->secondary_button_with_hide_text = l10n_util::GetStringUTF16(
-              IDS_BEFOREUNLOAD_MESSAGEBOX_HIDE_BUTTON_LABEL);
-          break;
-        default:
-          NOTREACHED();
-          break;
+              IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
+        }
       }
       params->secondary_button_text.emplace(
           l10n_util::GetStringUTF16(IDS_APP_CANCEL));
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 08ee951..533dcef 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -164,7 +164,9 @@
   // Accuracy tips survey.
   survey_configs.emplace_back(
       &accuracy_tips::features::kAccuracyTipsSurveyFeature,
-      kHatsSurveyTriggerAccuracyTips);
+      kHatsSurveyTriggerAccuracyTips,
+      /*presupplied_trigger_id=*/absl::nullopt, std::vector<std::string>{},
+      std::vector<std::string>{"Tip shown for URL", "UI interaction"});
 
   return survey_configs;
 }
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.cc b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.cc
index b03dd57..c31a656 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.cc
+++ b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.cc
@@ -60,8 +60,3 @@
 bool JavaScriptTabModalDialogManagerDelegateAndroid::IsApp() {
   return false;
 }
-
-absl::optional<std::u16string>
-JavaScriptTabModalDialogManagerDelegateAndroid::GetAppName() {
-  return absl::nullopt;
-}
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h
index bb1dc2b..fcbeb13 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h
+++ b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h
@@ -37,7 +37,6 @@
   void SetTabNeedsAttention(bool attention) override;
   bool IsWebContentsForemost() override;
   bool IsApp() override;
-  absl::optional<std::u16string> GetAppName() override;
 
  private:
   content::WebContents* web_contents_;
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.cc b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.cc
index 20cd05a..47e7bfb 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.cc
+++ b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "components/javascript_dialogs/app_modal_dialog_manager.h"
 #include "components/javascript_dialogs/tab_modal_dialog_manager.h"
 #include "components/javascript_dialogs/tab_modal_dialog_view.h"
@@ -85,17 +84,6 @@
   return browser && (browser->is_type_app() || browser->is_type_app_popup());
 }
 
-absl::optional<std::u16string>
-JavaScriptTabModalDialogManagerDelegateDesktop::GetAppName() {
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
-  if (!browser)
-    return absl::nullopt;
-  const auto* app_controller = browser->app_controller();
-  if (!app_controller)
-    return absl::nullopt;
-  return app_controller->GetAppShortName();
-}
-
 void JavaScriptTabModalDialogManagerDelegateDesktop::OnBrowserSetLastActive(
     Browser* browser) {
   javascript_dialogs::TabModalDialogManager::FromWebContents(web_contents_)
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h
index dfb4425..05bb128 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h
+++ b/chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h
@@ -36,7 +36,6 @@
   void SetTabNeedsAttention(bool attention) override;
   bool IsWebContentsForemost() override;
   bool IsApp() override;
-  absl::optional<std::u16string> GetAppName() override;
 
   // BrowserListObserver:
   void OnBrowserSetLastActive(Browser* browser) override;
diff --git a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
index 10231d19..1efe81e9 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
@@ -13,7 +13,6 @@
 #include "components/favicon/core/favicon_util.h"
 #include "components/password_manager/core/browser/password_feature_manager.h"
 #include "components/password_manager/core/browser/password_manager_features_util.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_ui.h"
 #include "components/signin/public/identity_manager/consent_level.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -28,10 +27,7 @@
     base::WeakPtr<PasswordsModelDelegate> delegate)
     : PasswordBubbleControllerBase(
           std::move(delegate),
-          password_manager::metrics_util::AUTOMATIC_MOVE_TO_ACCOUNT_STORE) {
-  DCHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kEnablePasswordsAccountStorage));
-}
+          password_manager::metrics_util::AUTOMATIC_MOVE_TO_ACCOUNT_STORE) {}
 
 MoveToAccountStoreBubbleController::~MoveToAccountStoreBubbleController() {
   // Make sure the interactions are reported even if Views didn't notify the
diff --git a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller_unittest.cc
index 10ce044e..702af916 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller_unittest.cc
@@ -4,14 +4,12 @@
 
 #include "chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.h"
 
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/password_manager/core/browser/mock_password_feature_manager.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/sync/driver/test_sync_service.h"
@@ -38,9 +36,6 @@
 class MoveToAccountStoreBubbleControllerTest : public ::testing::Test {
  public:
   MoveToAccountStoreBubbleControllerTest() {
-    feature_list_.InitAndEnableFeature(
-        password_manager::features::kEnablePasswordsAccountStorage);
-
     // Make sure no real SyncService gets created (it's not needed for these
     // tests, and it'd require more setup).
     SyncServiceFactory::GetInstance()->SetTestingFactory(
@@ -70,7 +65,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   content::BrowserTaskEnvironment task_environment_;
   content::RenderViewHostTestEnabler test_render_host_factories_;
   TestingProfile profile_;
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
index fb0af4e..3da2920d 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
@@ -30,7 +29,6 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/statistics_table.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_ui.h"
 #include "components/sync/driver/test_sync_service.h"
 #include "components/ukm/test_ukm_recorder.h"
@@ -74,12 +72,7 @@
 
 class SaveUpdateBubbleControllerTest : public ::testing::Test {
  public:
-  SaveUpdateBubbleControllerTest() {
-    // If kEnablePasswordsAccountStorage is disabled, then
-    // SaveUpdateBubbleController is used instead of this class.
-    feature_list_.InitAndEnableFeature(
-        password_manager::features::kEnablePasswordsAccountStorage);
-  }
+  SaveUpdateBubbleControllerTest() = default;
   ~SaveUpdateBubbleControllerTest() override = default;
 
   void SetUp() override {
@@ -167,7 +160,6 @@
       const;
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   content::BrowserTaskEnvironment task_environment_;
   content::RenderViewHostTestEnabler rvh_enabler_;
   std::unique_ptr<TestingProfile> profile_;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 71f71ef7..20460ea7 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -523,16 +523,13 @@
   save_fallback_timer_.Stop();
   passwords_data_.form_manager()->Save();
 
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kEnablePasswordsAccountStorage)) {
-    // If we just saved a password to the account store, notify the IPH tracker
-    // about it (so it can decide not to show the IPH again).
-    if (GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
-        password_manager::PasswordForm::Store::kAccountStore) {
-      feature_engagement::TrackerFactory::GetForBrowserContext(
-          Profile::FromBrowserContext(web_contents()->GetBrowserContext()))
-          ->NotifyEvent("passwords_account_storage_used");
-    }
+  // If we just saved a password to the account store, notify the IPH tracker
+  // about it (so it can decide not to show the IPH again).
+  if (GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
+      password_manager::PasswordForm::Store::kAccountStore) {
+    feature_engagement::TrackerFactory::GetForBrowserContext(
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext()))
+        ->NotifyEvent("passwords_account_storage_used");
   }
 
   post_save_compromised_helper_ =
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index ed1ea236..45f8696 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 
 #include <algorithm>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -259,36 +260,22 @@
   NOTREACHED();
 }
 
-// Holds state for a WebContents that has been detached from the tab strip. Will
-// also handle WebContents deletion if |remove_reason| is kDeleted.
-struct TabStripModel::DetachedWebContents {
-  DetachedWebContents(int index_before_any_removals,
-                      int index_at_time_of_removal,
-                      std::unique_ptr<WebContents> contents,
-                      TabStripModelChange::RemoveReason remove_reason)
-      : contents(std::move(contents)),
-        index_before_any_removals(index_before_any_removals),
-        index_at_time_of_removal(index_at_time_of_removal),
-        remove_reason(remove_reason) {}
-  DetachedWebContents(const DetachedWebContents&) = delete;
-  DetachedWebContents& operator=(const DetachedWebContents&) = delete;
-  ~DetachedWebContents() = default;
-  DetachedWebContents(DetachedWebContents&&) = default;
-
-  std::unique_ptr<WebContents> contents;
-
-  // The index of the WebContents in the original selection model of the tab
-  // strip [prior to any tabs being removed, if multiple tabs are being
-  // simultaneously removed].
-  const int index_before_any_removals;
-
-  // The index of the WebContents at the time it is being removed. If multiple
-  // tabs are being simultaneously removed, the index reflects previously
-  // removed tabs in this batch.
-  const int index_at_time_of_removal;
-
-  const TabStripModelChange::RemoveReason remove_reason;
-};
+TabStripModel::DetachedWebContents::DetachedWebContents(
+    int index_before_any_removals,
+    int index_at_time_of_removal,
+    std::unique_ptr<WebContents> owned_contents,
+    content::WebContents* contents,
+    TabStripModelChange::RemoveReason remove_reason,
+    absl::optional<SessionID> id)
+    : owned_contents(std::move(owned_contents)),
+      contents(contents),
+      index_before_any_removals(index_before_any_removals),
+      index_at_time_of_removal(index_at_time_of_removal),
+      remove_reason(remove_reason),
+      id(id) {}
+TabStripModel::DetachedWebContents::~DetachedWebContents() = default;
+TabStripModel::DetachedWebContents::DetachedWebContents(DetachedWebContents&&) =
+    default;
 
 // Holds all state necessary to send notifications for detached tabs.
 struct TabStripModel::DetachNotifications {
@@ -300,7 +287,8 @@
   DetachNotifications& operator=(const DetachNotifications&) = delete;
   ~DetachNotifications() = default;
 
-  // The WebContents that was active prior to any detaches happening.
+  // The WebContents that was active prior to any detaches happening. If this
+  // is nullptr, the active WebContents was not removed.
   //
   // It's safe to use a raw pointer here because the active web contents, if
   // detached, is owned by |detached_web_contents|.
@@ -430,8 +418,9 @@
 
 std::unique_ptr<content::WebContents>
 TabStripModel::DetachWebContentsAtForInsertion(int index) {
-  return DetachWebContentsWithReasonAt(
+  auto dwc = DetachWebContentsWithReasonAt(
       index, TabStripModelChange::RemoveReason::kInsertedIntoOtherTabStrip);
+  return std::move(dwc->owned_contents);
 }
 
 void TabStripModel::DetachAndDeleteWebContentsAt(int index) {
@@ -440,7 +429,7 @@
                                 TabStripModelChange::RemoveReason::kDeleted);
 }
 
-std::unique_ptr<content::WebContents>
+std::unique_ptr<TabStripModel::DetachedWebContents>
 TabStripModel::DetachWebContentsWithReasonAt(
     int index,
     TabStripModelChange::RemoveReason reason) {
@@ -454,47 +443,49 @@
 
   DetachNotifications notifications(initially_active_web_contents,
                                     selection_model_);
-  std::unique_ptr<DetachedWebContents> dwc =
-      std::make_unique<DetachedWebContents>(
-          index, index,
-          DetachWebContentsImpl(index, /*create_historical_tab=*/false),
-          reason);
+  auto dwc = DetachWebContentsImpl(index, index,
+                                   /*create_historical_tab=*/false, reason);
   notifications.detached_web_contents.push_back(std::move(dwc));
   SendDetachWebContentsNotifications(&notifications);
-  return std::move(notifications.detached_web_contents[0]->contents);
+  return std::move(notifications.detached_web_contents[0]);
 }
 
-std::unique_ptr<content::WebContents> TabStripModel::DetachWebContentsImpl(
-    int index,
-    bool create_historical_tab) {
+std::unique_ptr<TabStripModel::DetachedWebContents>
+TabStripModel::DetachWebContentsImpl(int index_before_any_removals,
+                                     int index_at_time_of_removal,
+                                     bool create_historical_tab,
+                                     TabStripModelChange::RemoveReason reason) {
   if (contents_data_.empty())
     return nullptr;
-  CHECK(ContainsIndex(index));
+  CHECK(ContainsIndex(index_at_time_of_removal));
 
-  FixOpeners(index);
+  FixOpeners(index_at_time_of_removal);
 
   // Ask the delegate to save an entry for this tab in the historical tab
   // database.
-  WebContents* raw_web_contents = GetWebContentsAtImpl(index);
+  WebContents* raw_web_contents =
+      GetWebContentsAtImpl(index_at_time_of_removal);
+  absl::optional<SessionID> id = absl::nullopt;
   if (create_historical_tab)
-    delegate_->CreateHistoricalTab(raw_web_contents);
+    id = delegate_->CreateHistoricalTab(raw_web_contents);
 
   absl::optional<int> next_selected_index =
-      order_controller_->DetermineNewSelectedIndex(index);
+      order_controller_->DetermineNewSelectedIndex(index_at_time_of_removal);
 
-  UngroupTab(index);
+  UngroupTab(index_at_time_of_removal);
 
-  std::unique_ptr<WebContentsData> old_data = std::move(contents_data_[index]);
-  contents_data_.erase(contents_data_.begin() + index);
+  std::unique_ptr<WebContentsData> old_data =
+      std::move(contents_data_[index_at_time_of_removal]);
+  contents_data_.erase(contents_data_.begin() + index_at_time_of_removal);
 
   if (empty()) {
     selection_model_.Clear();
   } else {
     int old_active = active_index();
-    selection_model_.DecrementFrom(index);
+    selection_model_.DecrementFrom(index_at_time_of_removal);
     ui::ListSelectionModel old_model;
     old_model = selection_model_;
-    if (index == old_active) {
+    if (index_at_time_of_removal == old_active) {
       if (!selection_model_.empty()) {
         // The active tab was removed, but there is still something selected.
         // Move the active and anchor to the first selected index.
@@ -509,7 +500,12 @@
       }
     }
   }
-  return old_data->ReplaceWebContents(nullptr);
+
+  auto owned_contents = old_data->ReplaceWebContents(nullptr);
+  auto* contents = owned_contents.get();
+  return std::make_unique<DetachedWebContents>(
+      index_before_any_removals, index_at_time_of_removal,
+      std::move(owned_contents), contents, reason, id);
 }
 
 void TabStripModel::SendDetachWebContentsNotifications(
@@ -528,9 +524,8 @@
 
   TabStripModelChange::Remove remove;
   for (auto& dwc : notifications->detached_web_contents) {
-    remove.contents.push_back({dwc->contents.get(),
-                               dwc->index_before_any_removals,
-                               dwc->remove_reason});
+    remove.contents.push_back(
+        {dwc->contents, dwc->index_before_any_removals, dwc->remove_reason});
   }
   TabStripModelChange change(std::move(remove));
 
@@ -558,7 +553,8 @@
     if (dwc->remove_reason == TabStripModelChange::RemoveReason::kDeleted) {
       // This destroys the WebContents, which will also send
       // WebContentsDestroyed notifications.
-      dwc->contents.reset();
+      dwc->owned_contents.reset();
+      dwc->contents = nullptr;
     }
   }
 
@@ -1847,6 +1843,7 @@
   for (size_t i = 0; i < items.size(); ++i)
     original_indices[i] = GetIndexOfWebContents(items[i]);
 
+  std::vector<std::unique_ptr<DetachedWebContents>> detached_web_contents;
   for (size_t i = 0; i < items.size(); ++i) {
     WebContents* closing_contents = items[i];
 
@@ -1868,15 +1865,30 @@
       continue;
     }
 
-    std::unique_ptr<DetachedWebContents> dwc =
-        std::make_unique<DetachedWebContents>(
-            original_indices[i], current_index,
-            DetachWebContentsImpl(current_index,
-                                  close_types & CLOSE_CREATE_HISTORICAL_TAB),
-            TabStripModelChange::RemoveReason::kDeleted);
-    notifications->detached_web_contents.push_back(std::move(dwc));
+    bool create_historical_tab = close_types & CLOSE_CREATE_HISTORICAL_TAB;
+    auto dwc = DetachWebContentsImpl(
+        original_indices[i], current_index, create_historical_tab,
+        TabStripModelChange::RemoveReason::kDeleted);
+    detached_web_contents.push_back(std::move(dwc));
   }
 
+  // ClosedTabCache will only take ownership of the last recently closed tab.
+  delegate_->CacheWebContents(detached_web_contents);
+
+  // If the delegate takes ownership, it must reset the reason.
+#if DCHECK_IS_ON()
+  for (auto& dwc : detached_web_contents)
+    if (dwc->owned_contents) {
+      DCHECK_EQ(TabStripModelChange::RemoveReason::kDeleted,
+                dwc->remove_reason);
+    } else {
+      DCHECK_EQ(TabStripModelChange::RemoveReason::kCached, dwc->remove_reason);
+    }
+#endif
+
+  for (auto& dwc : detached_web_contents)
+    notifications->detached_web_contents.push_back(std::move(dwc));
+
   return closed_all;
 }
 
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 5980dd1..6437c07 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -26,6 +26,7 @@
 #include "chrome/browser/ui/tabs/tab_group_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
 #include "chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h"
+#include "components/sessions/core/session_id.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -153,6 +154,49 @@
     kMaxValue = kContextMenu,
   };
 
+  // Holds state for a WebContents that has been detached from the tab strip.
+  // Will also handle WebContents deletion if |remove_reason| is kDeleted, or
+  // WebContents caching if |remove_reason| is kCached.
+  // TODO(https://crbug.com/1234327): Don't make DetachedWebContents an inner
+  // class, so it can be forward declared in TabStripModelDelegate.
+  struct DetachedWebContents {
+    DetachedWebContents(int index_before_any_removals,
+                        int index_at_time_of_removal,
+                        std::unique_ptr<content::WebContents> owned_contents,
+                        content::WebContents* contents,
+                        TabStripModelChange::RemoveReason remove_reason,
+                        absl::optional<SessionID> id);
+    DetachedWebContents(const DetachedWebContents&) = delete;
+    DetachedWebContents& operator=(const DetachedWebContents&) = delete;
+    ~DetachedWebContents();
+    DetachedWebContents(DetachedWebContents&&);
+
+    // When a WebContents is removed the delegate is given a chance to
+    // take ownership of it (generally for caching). If the delegate takes
+    // ownership, `owned_contents` will be null, and `contents` will be
+    // non-null. In other words, all observers should use `contents`, it is
+    // guaranteed to be valid for the life time of the notification (and
+    // possibly longer).
+    std::unique_ptr<content::WebContents> owned_contents;
+    content::WebContents* contents;
+
+    // The index of the WebContents in the original selection model of the tab
+    // strip [prior to any tabs being removed, if multiple tabs are being
+    // simultaneously removed].
+    const int index_before_any_removals;
+
+    // The index of the WebContents at the time it is being removed. If multiple
+    // tabs are being simultaneously removed, the index reflects previously
+    // removed tabs in this batch.
+    const int index_at_time_of_removal;
+
+    TabStripModelChange::RemoveReason remove_reason;
+
+    // The |contents| associated optional SessionID, used as key for
+    // ClosedTabCache. We only cache |contents| if |remove_reason| is kCached.
+    absl::optional<SessionID> id;
+  };
+
   static constexpr int kNoTab = -1;
 
   // Construct a TabStripModel with a delegate to help it do certain things
@@ -603,24 +647,25 @@
   FRIEND_TEST_ALL_PREFIXES(TabStripModelTest, GetIndicesClosedByCommand);
 
   class WebContentsData;
-  struct DetachedWebContents;
   struct DetachNotifications;
 
   // Detaches the WebContents at the specified |index| from this strip. |reason|
   // is used to indicate to observers what is going to happen to the WebContents
   // (i.e. deleted or reinserted into another tab strip). Returns the detached
   // WebContents.
-  std::unique_ptr<content::WebContents> DetachWebContentsWithReasonAt(
-      int index,
-      TabStripModelChange::RemoveReason reason);
+  std::unique_ptr<TabStripModel::DetachedWebContents>
+  DetachWebContentsWithReasonAt(int index,
+                                TabStripModelChange::RemoveReason reason);
 
   // Performs all the work to detach a WebContents instance but avoids sending
   // most notifications. TabClosingAt() and TabDetachedAt() are sent because
   // observers are reliant on the selection model being accurate at the time
   // that TabDetachedAt() is called.
-  std::unique_ptr<content::WebContents> DetachWebContentsImpl(
-      int index,
-      bool create_historical_tab);
+  std::unique_ptr<DetachedWebContents> DetachWebContentsImpl(
+      int index_before_any_removals,
+      int index_at_time_of_removal,
+      bool create_historical_tab,
+      TabStripModelChange::RemoveReason reason);
 
   // We batch send notifications. This has two benefits:
   //   1) This allows us to send the minimal number of necessary notifications.
diff --git a/chrome/browser/ui/tabs/tab_strip_model_delegate.h b/chrome/browser/ui/tabs/tab_strip_model_delegate.h
index d3190c3..548597f 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_delegate.h
+++ b/chrome/browser/ui/tabs/tab_strip_model_delegate.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/sessions/core/session_id.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -151,6 +152,18 @@
 
   // Adds the specified WebContents to read later.
   virtual void AddToReadLater(content::WebContents* web_contents) = 0;
+
+  // Gives the delegate an opportunity to cache (take ownership) of
+  // WebContents before they are destroyed. The delegate takes ownership by way
+  // of using std::move() on the `owned_contents` and resetting `remove_reason`
+  // to kCached. It is expected that any WebContents the delegate takes
+  // ownership of remain valid until the next message is pumped. In other
+  // words, the delegate must not immediately destroy any of the supplied
+  // WebContents.
+  // TODO(https://crbug.com/1234332): Provide active web contents.
+  virtual void CacheWebContents(
+      const std::vector<std::unique_ptr<TabStripModel::DetachedWebContents>>&
+          web_contents) = 0;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.cc b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.cc
index e3fc7381..a9d8caa 100644
--- a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.cc
+++ b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.cc
@@ -97,3 +97,7 @@
 
 void TestTabStripModelDelegate::AddToReadLater(
     content::WebContents* web_contents) {}
+
+void TestTabStripModelDelegate::CacheWebContents(
+    const std::vector<std::unique_ptr<TabStripModel::DetachedWebContents>>&
+        web_contents) {}
diff --git a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
index 3295de93..6ac6266 100644
--- a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
+++ b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
@@ -51,6 +51,9 @@
   bool ShouldDisplayFavicon(content::WebContents* web_contents) const override;
   bool CanReload() const override;
   void AddToReadLater(content::WebContents* web_contents) override;
+  void CacheWebContents(
+      const std::vector<std::unique_ptr<TabStripModel::DetachedWebContents>>&
+          web_contents) override;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TEST_TAB_STRIP_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/views/page_info/accuracy_tip_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/accuracy_tip_bubble_view_browsertest.cc
index 40c62fe..11ce8462 100644
--- a/chrome/browser/ui/views/page_info/accuracy_tip_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/accuracy_tip_bubble_view_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/accuracy_tips/accuracy_service_factory.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/hats/hats_service_factory.h"
@@ -29,6 +30,7 @@
 #include "components/accuracy_tips/accuracy_service.h"
 #include "components/accuracy_tips/accuracy_tip_interaction.h"
 #include "components/accuracy_tips/features.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "components/site_engagement/content/site_engagement_score.h"
 #include "components/site_engagement/content/site_engagement_service.h"
@@ -61,12 +63,16 @@
 
   void SetUp() override {
     ASSERT_TRUE(embedded_test_server()->Start());
-    const base::FieldTrialParams accuraty_tips_params = {
+    const base::FieldTrialParams accuracy_tips_params = {
         {accuracy_tips::features::kSampleUrl.name, GetUrl("badurl.com").spec()},
         {accuracy_tips::features::kNumIgnorePrompts.name, "1"}};
+    const base::FieldTrialParams accuracy_survey_params = {
+        {accuracy_tips::features::kMinPromptCountRequiredForSurvey.name, "2"},
+        {"probability", "1.000"}};
     feature_list_.InitWithFeaturesAndParameters(
-        {{safe_browsing::kAccuracyTipsFeature, accuraty_tips_params},
-         {accuracy_tips::features::kAccuracyTipsSurveyFeature, {}}},
+        {{safe_browsing::kAccuracyTipsFeature, accuracy_tips_params},
+         {accuracy_tips::features::kAccuracyTipsSurveyFeature,
+          accuracy_survey_params}},
         {});
 
     // Disable "close on deactivation" since there seems to be an issue with
@@ -78,10 +84,6 @@
 
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
-
-    mock_hats_service_ = static_cast<MockHatsService*>(
-        HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            browser()->profile(), base::BindRepeating(&BuildMockHatsService)));
   }
 
   void ClickExtraButton() {
@@ -95,12 +97,10 @@
   }
 
   base::HistogramTester* histogram_tester() { return &histogram_tester_; }
-  MockHatsService* mock_hats_service() { return mock_hats_service_; }
 
  private:
   base::test::ScopedFeatureList feature_list_;
   base::HistogramTester histogram_tester_;
-  MockHatsService* mock_hats_service_ = nullptr;
 };
 
 IN_PROC_BROWSER_TEST_F(AccuracyTipBubbleViewBrowserTest, NoShowOnRegularUrl) {
@@ -236,22 +236,88 @@
 
 IN_PROC_BROWSER_TEST_F(AccuracyTipBubbleViewBrowserTest,
                        SurveyShownAfterShowingTip) {
-  auto* service = AccuracyServiceFactory::GetForProfile(browser()->profile());
-  ui_test_utils::NavigateToURL(browser(), GetUrl("badurl.com"));
-  EXPECT_TRUE(IsUIShowing());
+  auto* tips_service =
+      AccuracyServiceFactory::GetForProfile(browser()->profile());
+  auto* hats_service =
+      HatsServiceFactory::GetForProfile(browser()->profile(), true);
 
   base::SimpleTestClock clock;
   clock.SetNow(base::Time::Now());
-  service->SetClockForTesting(&clock);
-  clock.Advance(accuracy_tips::features::kMinTimeToShowSurvey.Get());
+  tips_service->SetClockForTesting(&clock);
 
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerAccuracyTips, _, _, _, _));
+  for (int i = 0;
+       i < accuracy_tips::features::kMinPromptCountRequiredForSurvey.Get();
+       i++) {
+    clock.Advance(base::TimeDelta::FromDays(7));
+    ui_test_utils::NavigateToURL(browser(), GetUrl("badurl.com"));
+    EXPECT_TRUE(IsUIShowing());
+
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser(), GURL(chrome::kChromeUINewTabURL),
+        WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+  }
+
+  // Enable metrics and set the profile creation time to be old enough to ensure
+  // the survey triggering.
+  bool enable_metrics = true;
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+      &enable_metrics);
+  browser()->profile()->SetCreationTimeForTesting(
+      base::Time::Now() - base::TimeDelta::FromDays(45));
+
+  clock.Advance(accuracy_tips::features::kMinTimeToShowSurvey.Get());
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL),
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
   base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(hats_service->hats_next_dialog_exists_for_testing());
+}
+
+IN_PROC_BROWSER_TEST_F(AccuracyTipBubbleViewBrowserTest,
+                       SurveyNotShownAfterDeletingHistory) {
+  auto* tips_service =
+      AccuracyServiceFactory::GetForProfile(browser()->profile());
+  auto* hats_service =
+      HatsServiceFactory::GetForProfile(browser()->profile(), true);
+
+  base::SimpleTestClock clock;
+  clock.SetNow(base::Time::Now());
+  tips_service->SetClockForTesting(&clock);
+
+  for (int i = 0;
+       i < accuracy_tips::features::kMinPromptCountRequiredForSurvey.Get();
+       i++) {
+    clock.Advance(base::TimeDelta::FromDays(7));
+    ui_test_utils::NavigateToURL(browser(), GetUrl("badurl.com"));
+    EXPECT_TRUE(IsUIShowing());
+
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser(), GURL(chrome::kChromeUINewTabURL),
+        WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+  }
+
+  // Enable metrics and set the profile creation time to be old enough to ensure
+  // the survey triggering.
+  bool enable_metrics = true;
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+      &enable_metrics);
+  browser()->profile()->SetCreationTimeForTesting(
+      base::Time::Now() - base::TimeDelta::FromDays(45));
+
+  // Delete all history...
+  tips_service->OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
+
+  clock.Advance(accuracy_tips::features::kMinTimeToShowSurvey.Get());
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL(chrome::kChromeUINewTabURL),
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+  base::RunLoop().RunUntilIdle();
+  // ...and because of that, a survey won't be shown.
+  EXPECT_FALSE(hats_service->hats_next_dialog_exists_for_testing());
 }
 
 // Render test for accuracy tip ui.
diff --git a/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view.cc b/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view.cc
index 40260dd..6598fa6d 100644
--- a/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
@@ -258,9 +257,6 @@
                              anchor_view,
                              /*auto_dismissable=*/false),
       controller_(PasswordsModelDelegateFromWebContents(web_contents)) {
-  DCHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kEnablePasswordsAccountStorage));
-
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical)
       .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
diff --git a/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view_unittest.cc b/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view_unittest.cc
index 06364d6..609199d 100644
--- a/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/passwords/move_to_account_store_bubble_view_unittest.cc
@@ -4,13 +4,11 @@
 
 #include "chrome/browser/ui/views/passwords/move_to_account_store_bubble_view.h"
 
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/passwords/password_bubble_view_test_base.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/event_target.h"
 #include "ui/events/event_target_iterator.h"
@@ -20,9 +18,6 @@
 class MoveToAccountStoreBubbleViewTest : public PasswordBubbleViewTestBase {
  public:
   MoveToAccountStoreBubbleViewTest() {
-    feature_list_.InitAndEnableFeature(
-        password_manager::features::kEnablePasswordsAccountStorage);
-
     password_manager::PasswordForm pending_password;
     pending_password.url = GURL("www.example.com");
     ON_CALL(*model_delegate_mock(), GetPendingPassword)
@@ -35,7 +30,6 @@
   void TearDown() override;
 
  protected:
-  base::test::ScopedFeatureList feature_list_;
   MoveToAccountStoreBubbleView* view_;
 };
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
index 3bf9ed09..f72fd98 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -35,6 +35,7 @@
 // settings/advanced_settings/advanced_settings_item.js in
 // chrome/browser/resources/print_preview.
 const char kOptionKey[] = "option";
+const char kResetToDefaultKey[] = "reset_to_default";
 const char kSelectCapKey[] = "select_cap";
 const char kSelectString[] = "SELECT";
 const char kTypeKey[] = "type";
@@ -123,7 +124,6 @@
   for (auto capability : caps->DictItems()) {
     const auto& key = capability.first;
     base::Value* value = &capability.second;
-
     base::Value* list_value = nullptr;
     if (value->is_dict())
       list_value = value->FindKeyOfType(kOptionKey, base::Value::Type::LIST);
@@ -155,6 +155,11 @@
     if (value->is_dict()) {
       base::Value option_dict(base::Value::Type::DICTIONARY);
       option_dict.SetKey(kOptionKey, std::move(*list_value));
+      absl::optional<bool> reset_to_default =
+          value->FindBoolKey(kResetToDefaultKey);
+      if (reset_to_default) {
+        option_dict.SetKey(kResetToDefaultKey, base::Value(*reset_to_default));
+      }
       out_caps.SetKey(key, std::move(option_dict));
     } else {
       out_caps.SetKey(key, std::move(*list_value));
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.h b/chrome/browser/ui/webui/print_preview/print_preview_utils.h
index 47de5d4..d64d260 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.h
@@ -21,6 +21,7 @@
 
 // Printer capability setting keys.
 extern const char kOptionKey[];
+extern const char kResetToDefaultKey[];
 extern const char kTypeKey[];
 extern const char kSelectCapKey[];
 extern const char kSelectString[];
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils_unittest.cc
index 3e76c52..7548378 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils_unittest.cc
@@ -22,6 +22,7 @@
 const char kPagesPerSheet[] = "Pages per sheet";
 const char kPaperType[] = "Paper Type";
 const char kPrinter[] = "printer";
+const char kResetToDefault[] = "reset_to_default";
 const char kValue[] = "value";
 const char kVendorCapability[] = "vendor_capability";
 
@@ -306,4 +307,33 @@
   ValidatePrinter(&cdd_out, printer);
 }
 
+bool GetDpiResetToDefault(base::Value cdd) {
+  base::Value* printer =
+      cdd.FindKeyOfType(kPrinter, base::Value::Type::DICTIONARY);
+  base::Value* dpi =
+      printer->FindKeyOfType(kDpi, base::Value::Type::DICTIONARY);
+  absl::optional<bool> reset_to_default = dpi->FindBoolKey(kResetToDefault);
+  EXPECT_TRUE(reset_to_default);
+  return *reset_to_default;
+}
+
+TEST_F(PrintPreviewUtilsTest, CddResetToDefault) {
+  base::DictionaryValue printer = GetCapabilitiesFull();
+  base::Value* dpi_dict =
+      printer.FindKeyOfType(kDpi, base::Value::Type::DICTIONARY);
+
+  base::DictionaryValue cdd;
+  dpi_dict->SetKey(kResetToDefault, base::Value(true));
+  cdd.SetKey(kPrinter, printer.Clone());
+  auto cdd_out = ValidateCddForPrintPreview(cdd.Clone());
+  ValidatePrinter(&cdd_out, printer);
+  EXPECT_TRUE(GetDpiResetToDefault(std::move(cdd_out)));
+
+  dpi_dict->SetKey(kResetToDefault, base::Value(false));
+  cdd.SetKey(kPrinter, printer.Clone());
+  cdd_out = ValidateCddForPrintPreview(std::move(cdd));
+  ValidatePrinter(&cdd_out, printer);
+  EXPECT_FALSE(GetDpiResetToDefault(std::move(cdd_out)));
+}
+
 }  // namespace printing
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index d1067d8..66aed92 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -294,11 +294,6 @@
                               password_manager::features::kPasswordImport));
 
   html_source->AddBoolean(
-      "enableAccountStorage",
-      base::FeatureList::IsEnabled(
-          password_manager::features::kEnablePasswordsAccountStorage));
-
-  html_source->AddBoolean(
       "enableMovingMultiplePasswordsToAccount",
       base::FeatureList::IsEnabled(
           password_manager::features::kEnableMovingMultiplePasswordsToAccount));
diff --git a/chrome/common/chrome_paths_fuchsia.cc b/chrome/common/chrome_paths_fuchsia.cc
index 0491d54..9e2bb171 100644
--- a/chrome/common/chrome_paths_fuchsia.cc
+++ b/chrome/common/chrome_paths_fuchsia.cc
@@ -9,29 +9,39 @@
 #include "chrome/common/chrome_paths.h"
 
 #include "base/files/file_path.h"
+#include "base/fuchsia/file_utils.h"
 #include "base/notreached.h"
 
 namespace chrome {
+namespace {
+
+constexpr char kDocumentsDir[] = "Documents";
+constexpr char kDownloadsDir[] = "Downloads";
+
+}  // namespace
 
 bool GetDefaultUserDataDirectory(base::FilePath* result) {
-  NOTIMPLEMENTED_LOG_ONCE();
-  *result = base::FilePath("/data");
+  *result = base::FilePath(base::kPersistedDataDirectoryPath);
   return true;
 }
 
 void GetUserCacheDirectory(const base::FilePath& profile_dir,
                            base::FilePath* result) {
-  *result = profile_dir;
+  *result = base::FilePath(base::kPersistedCacheDirectoryPath);
 }
 
 bool GetUserDocumentsDirectory(base::FilePath* result) {
-  NOTIMPLEMENTED_LOG_ONCE();
-  return false;
+  if (!GetDefaultUserDataDirectory(result))
+    return false;
+  *result = result->Append(kDocumentsDir);
+  return true;
 }
 
 bool GetUserDownloadsDirectorySafe(base::FilePath* result) {
-  NOTIMPLEMENTED_LOG_ONCE();
-  return false;
+  if (!GetDefaultUserDataDirectory(result))
+    return false;
+  *result = result->Append(kDownloadsDir);
+  return true;
 }
 
 bool GetUserDownloadsDirectory(base::FilePath* result) {
diff --git a/chrome/test/data/webui/print_preview/model_test.js b/chrome/test/data/webui/print_preview/model_test.js
index a73ded4..23b1a88 100644
--- a/chrome/test/data/webui/print_preview/model_test.js
+++ b/chrome/test/data/webui/print_preview/model_test.js
@@ -25,6 +25,7 @@
   GetCloudPrintTicket: 'get cloud print ticket',
   ChangeDestination: 'change destination',
   PrintToGoogleDriveCros: 'print to google drive cros',
+  CddResetToDefault: 'CDD reset_to_default property',
 };
 
 suite(model_test.suiteName, function() {
@@ -548,4 +549,150 @@
     const ticket = model.createPrintTicket(driveDestination, false, false);
     assertTrue(JSON.parse(ticket).printToGoogleDrive);
   });
+
+  /**
+   * Tests the behaviour of the CDD attribute `reset_to_default`, specifically
+   * that when a setting has a default value in CDD and the user selects another
+   * value in the UI:
+   * - if `reset_to_default`=true, the value of the setting will always be reset
+   * to the CDD default.
+   * - if `reset_to_default`=false, the value of the setting will always be read
+   * from the sticky settings.
+   */
+  test(assert(model_test.TestNames.CddResetToDefault), function() {
+    const cddColorEnabled = true;
+    const stickyColorEnabled = false;
+    const cddDuplexEnabled = false;
+    const stickyDuplexEnabled = true;
+    const cddDpi = 200;
+    const stickyDpi = 100;
+    const cddMediaSizeDisplayName = 'CDD_NAME';
+    const stickyMediaSizeDisplayName = 'STICKY_NAME';
+
+    /**
+     * Returns the CDD description of a destination with default values
+     * specified for color, dpi, duplex and media size.
+     * @param {boolean} resetToDefault Whether the settings should
+     * always reset to their default value or not.
+     * @returns {!Cdd} capabilities
+     */
+    const getTestCapabilities = (resetToDefault) => {
+      return {
+        version: '1.0',
+        printer: {
+          color: {
+            option: [
+              {type: 'STANDARD_COLOR', is_default: true},
+              {type: 'STANDARD_MONOCHROME'}
+            ],
+            reset_to_default: resetToDefault
+          },
+          duplex: {
+            option: [
+              {type: 'NO_DUPLEX', is_default: true}, {type: 'LONG_EDGE'},
+              {type: 'SHORT_EDGE'}
+            ],
+            reset_to_default: resetToDefault
+          },
+          dpi: {
+            option: [
+              {
+                horizontal_dpi: cddDpi,
+                vertical_dpi: cddDpi,
+                is_default: true,
+              },
+              {horizontal_dpi: stickyDpi, vertical_dpi: stickyDpi},
+            ],
+            reset_to_default: resetToDefault
+          },
+          media_size: {
+            option: [
+              {
+                name: 'NA_LETTER',
+                width_microns: 215900,
+                height_microns: 279400,
+                is_default: true,
+                custom_display_name: cddMediaSizeDisplayName,
+              },
+              {
+                name: 'CUSTOM',
+                width_microns: 215900,
+                height_microns: 215900,
+                custom_display_name: stickyMediaSizeDisplayName,
+              }
+            ],
+            reset_to_default: resetToDefault
+          }
+        }
+      };
+    };
+    // Sticky settings that contain different values from the default values
+    // returned by `getTestCapabilities`.
+    const stickySettings = {
+      version: 2,
+      isColorEnabled: stickyColorEnabled,
+      isDuplexEnabled: stickyDuplexEnabled,
+      dpi: {horizontal_dpi: stickyDpi, vertical_dpi: stickyDpi},
+      mediaSize: {
+        name: 'CUSTOM',
+        width_microns: 215900,
+        height_microns: 215900,
+        custom_display_name: stickyMediaSizeDisplayName,
+      },
+    };
+
+    const testDestination = new Destination(
+        'FooDevice', DestinationType.LOCAL, DestinationOrigin.EXTENSION,
+        'FooName', DestinationConnectionStatus.ONLINE);
+    testDestination.capabilities =
+        getTestCapabilities(/*resetToDefault=*/ true);
+    initializeModel();
+    model.destination = testDestination;
+    model.setStickySettings(JSON.stringify(stickySettings));
+    model.applyStickySettings();
+    assertEquals(model.settings.color.value, cddColorEnabled);
+    assertEquals(model.settings.duplex.value, cddDuplexEnabled);
+    assertEquals(model.settings.dpi.value.horizontal_dpi, cddDpi);
+    assertEquals(
+        model.settings.mediaSize.value.custom_display_name,
+        cddMediaSizeDisplayName);
+
+    testDestination.capabilities =
+        getTestCapabilities(/*resetToDefault=*/ false);
+    model.destination = testDestination;
+    model.setStickySettings(JSON.stringify(stickySettings));
+    model.applyStickySettings();
+    assertEquals(model.settings.color.value, stickyColorEnabled);
+    assertEquals(model.settings.duplex.value, stickyDuplexEnabled);
+    assertEquals(model.settings.dpi.value.horizontal_dpi, stickyDpi);
+    assertEquals(
+        model.settings.mediaSize.value.custom_display_name,
+        stickyMediaSizeDisplayName);
+
+    const testDestination2 = new Destination(
+        'FooDevice2', DestinationType.LOCAL, DestinationOrigin.EXTENSION,
+        'FooName2', DestinationConnectionStatus.ONLINE);
+    testDestination2.capabilities =
+        getTestCapabilities(/*resetToDefault=*/ true);
+    // Remove the `is_default` attribute from all the settings.
+    delete testDestination2.capabilities.printer.color.option[0].is_default;
+    delete testDestination2.capabilities.printer.duplex.option[0].is_default;
+    delete testDestination2.capabilities.printer.media_size.option[0]
+        .is_default;
+    delete testDestination2.capabilities.printer.dpi.option[0].is_default;
+
+    model.destination = testDestination2;
+
+    // Even if `reset_to_default` is true for all options, the model settings
+    // should have values from the sticky settings because the CDD doesn't
+    // specify default values to reset to.
+    model.setStickySettings(JSON.stringify(stickySettings));
+    model.applyStickySettings();
+    assertEquals(model.settings.color.value, stickyColorEnabled);
+    assertEquals(model.settings.duplex.value, stickyDuplexEnabled);
+    assertEquals(model.settings.dpi.value.horizontal_dpi, stickyDpi);
+    assertEquals(
+        model.settings.mediaSize.value.custom_display_name,
+        stickyMediaSizeDisplayName);
+  });
 });
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
index 5cbebbb..7168b75 100644
--- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -361,6 +361,10 @@
   this.runMochaTest(model_test.TestNames.ChangeDestination);
 });
 
+TEST_F('PrintPreviewModelTest', 'CddResetToDefault', function() {
+  this.runMochaTest(model_test.TestNames.CddResetToDefault);
+});
+
 GEN('#if defined(OS_CHROMEOS)');
 // eslint-disable-next-line no-var
 var PrintPreviewModelTestCros = class extends PrintPreviewTest {
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index de62e41..381a0fd 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -144,7 +144,7 @@
     ":test_about_page_browser_proxy",
 
     #":test_android_info_browser_proxy",
-    ":test_clear_browsing_data_browser_proxy",
+    #":test_clear_browsing_data_browser_proxy",
 
     #":test_extension_control_browser_proxy",
     ":test_hats_browser_proxy",
@@ -281,7 +281,6 @@
 
 js_library("privacy_page_test") {
   deps = [
-    ":test_clear_browsing_data_browser_proxy",
     ":test_hats_browser_proxy",
     ":test_metrics_browser_proxy",
     ":test_privacy_page_browser_proxy",
@@ -480,14 +479,6 @@
   ]
 }
 
-js_library("test_clear_browsing_data_browser_proxy") {
-  deps = [
-    "..:test_browser_proxy",
-    "//chrome/browser/resources/settings:lazy_load",
-    "//ui/webui/resources/js:cr.m",
-  ]
-}
-
 js_library("test_hats_browser_proxy") {
   deps = [
     "..:test_browser_proxy",
diff --git a/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js b/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
index 942aa59..010b467 100644
--- a/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
@@ -15,7 +15,7 @@
 window.history.pushState('object or string', 'Test', routes.PEOPLE.path);
 
 const browserProxy = new TestSyncBrowserProxy();
-SyncBrowserProxyImpl.instance_ = browserProxy;
+SyncBrowserProxyImpl.setInstance(browserProxy);
 
 const settingsUi = document.createElement('settings-ui');
 document.body.appendChild(settingsUi);
diff --git a/chrome/test/data/webui/settings/avatar_icon_test.js b/chrome/test/data/webui/settings/avatar_icon_test.js
index 0069273..05808198 100644
--- a/chrome/test/data/webui/settings/avatar_icon_test.js
+++ b/chrome/test/data/webui/settings/avatar_icon_test.js
@@ -17,7 +17,7 @@
     PolymerTest.clearBody();
 
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
   });
 
   test('avatarOfFirstSignedInAccountIsDisplayed', async function() {
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
index c5f1069..97f946fa 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
@@ -24,7 +24,7 @@
 
   setup(function() {
     const browserProxy = new TestSyncBrowserProxy();
-    settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+    settings.SyncBrowserProxyImpl.setInstance(browserProxy);
 
     PolymerTest.clearBody();
 
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
index c701292..4023b16 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
@@ -25,7 +25,7 @@
 
   setup(function() {
     const browserProxy = new TestSyncBrowserProxy();
-    settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+    settings.SyncBrowserProxyImpl.setInstance(browserProxy);
 
     PolymerTest.clearBody();
     loadTimeData.overrideValues({
diff --git a/chrome/test/data/webui/settings/chromeos/os_people_page_test.js b/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
index 400069c5..0e6e385 100644
--- a/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
@@ -108,7 +108,7 @@
       settings.ProfileInfoBrowserProxyImpl.instance_ = browserProxy;
 
       syncBrowserProxy = new TestSyncBrowserProxy();
-      settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+      settings.SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
       accountManagerBrowserProxy = new TestAccountManagerBrowserProxy();
       settings.AccountManagerBrowserProxyImpl.instance_ =
diff --git a/chrome/test/data/webui/settings/clear_browsing_data_test.js b/chrome/test/data/webui/settings/clear_browsing_data_test.js
index fd209489..0a0e87c 100644
--- a/chrome/test/data/webui/settings/clear_browsing_data_test.js
+++ b/chrome/test/data/webui/settings/clear_browsing_data_test.js
@@ -106,9 +106,9 @@
 
   setup(function() {
     testBrowserProxy = new TestClearBrowsingDataBrowserProxy();
-    ClearBrowsingDataBrowserProxyImpl.instance_ = testBrowserProxy;
+    ClearBrowsingDataBrowserProxyImpl.setInstance(testBrowserProxy);
     testSyncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = testSyncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(testSyncBrowserProxy);
     PolymerTest.clearBody();
     element = document.createElement('settings-clear-browsing-data-dialog');
     element.set('prefs', getClearBrowsingDataPrefs());
@@ -287,7 +287,7 @@
 
   setup(function() {
     testBrowserProxy = new TestClearBrowsingDataBrowserProxy();
-    ClearBrowsingDataBrowserProxyImpl.instance_ = testBrowserProxy;
+    ClearBrowsingDataBrowserProxyImpl.setInstance(testBrowserProxy);
     PolymerTest.clearBody();
     element = document.createElement('settings-clear-browsing-data-dialog');
     element.set('prefs', getClearBrowsingDataPrefs());
@@ -696,7 +696,7 @@
     loadTimeData.overrideValues({installedAppsInCbd: true});
     testBrowserProxy = new TestClearBrowsingDataBrowserProxy();
     testBrowserProxy.setInstalledApps(installedApps);
-    ClearBrowsingDataBrowserProxyImpl.instance_ = testBrowserProxy;
+    ClearBrowsingDataBrowserProxyImpl.setInstance(testBrowserProxy);
     PolymerTest.clearBody();
     element = document.createElement('settings-clear-browsing-data-dialog');
     element.set('prefs', getClearBrowsingDataPrefs());
@@ -725,11 +725,11 @@
         element.shadowRoot.querySelector('installed-app-checkbox');
     assertTrue(!!firstInstalledApp);
     assertEquals(
-        'google.com', firstInstalledApp.installed_app.registerableDomain);
-    assertTrue(firstInstalledApp.installed_app.isChecked);
+        'google.com', firstInstalledApp.installedApp.registerableDomain);
+    assertTrue(firstInstalledApp.installedApp.isChecked);
     // Choose to keep storage for google.com.
     firstInstalledApp.$.checkbox.click();
-    assertFalse(firstInstalledApp.installed_app.isChecked);
+    assertFalse(firstInstalledApp.installedApp.isChecked);
     // Confirm deletion.
     element.$.installedAppsConfirm.click();
     const [dataTypes, timePeriod, apps] =
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index a932f21..b3c26e2a 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -13,7 +13,6 @@
 GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "chrome/common/chrome_features.h"');
 GEN('#include "components/autofill/core/common/autofill_features.h"');
-GEN('#include "components/password_manager/core/common/password_manager_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
 GEN('#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)');
@@ -330,13 +329,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/passwords_device_section_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      enabled: ['password_manager::features::kEnablePasswordsAccountStorage']
-    };
-  }
 };
 
 TEST_F('CrSettingsPasswordsDeviceSectionTest', 'All', function() {
diff --git a/chrome/test/data/webui/settings/on_startup_page_tests.js b/chrome/test/data/webui/settings/on_startup_page_tests.js
index 712c1c1..c4c991c9 100644
--- a/chrome/test/data/webui/settings/on_startup_page_tests.js
+++ b/chrome/test/data/webui/settings/on_startup_page_tests.js
@@ -5,7 +5,7 @@
 // clang-format off
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {OnStartupBrowserProxy, OnStartupBrowserProxyImpl} from 'chrome://settings/settings.js';
+import {OnStartupBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js';
 // clang-format on
 
@@ -85,7 +85,7 @@
 
   setup(function() {
     onStartupBrowserProxy = new TestOnStartupBrowserProxy();
-    OnStartupBrowserProxyImpl.instance_ = onStartupBrowserProxy;
+    OnStartupBrowserProxyImpl.setInstance(onStartupBrowserProxy);
     return initPage();
   });
 
diff --git a/chrome/test/data/webui/settings/password_check_test.js b/chrome/test/data/webui/settings/password_check_test.js
index 89c032f..d0fe33c 100644
--- a/chrome/test/data/webui/settings/password_check_test.js
+++ b/chrome/test/data/webui/settings/password_check_test.js
@@ -216,7 +216,7 @@
 
     // Override the SyncBrowserProxyImpl for testing.
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
     syncBrowserProxy.syncStatus = {signedIn: false};
   });
 
diff --git a/chrome/test/data/webui/settings/passwords_device_section_test.js b/chrome/test/data/webui/settings/passwords_device_section_test.js
index 2355d36..6834232 100644
--- a/chrome/test/data/webui/settings/passwords_device_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_device_section_test.js
@@ -76,7 +76,7 @@
     passwordManager = new TestPasswordManagerProxy();
     PasswordManagerImpl.instance_ = passwordManager;
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
     elementFactory = new PasswordDeviceSectionElementFactory(document);
 
     // The user only enters this page when they are eligible (signed-in but not
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index 2c9570d..4082e0cd 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -305,8 +305,7 @@
 
 /**
  * Simulates user who is eligible and opted-in for account storage. Should be
- * called after the PasswordsSection element is created. The load time value for
- * enableAccountStorage must be overridden separately.
+ * called after the PasswordsSection element is created.
  * @param {TestPasswordManagerProxy} passwordManager
  */
 function simulateAccountStorageUser(passwordManager) {
@@ -1491,9 +1490,6 @@
     // Tests that the opt-in/opt-out buttons appear for signed-in (non-sync)
     // users and that the text content changes accordingly.
     test('changeOptInButtonsBasedOnSignInAndAccountStorageOptIn', function() {
-      // Feature flag enabled.
-      loadTimeData.overrideValues({enableAccountStorage: true});
-
       const passwordsSection =
           elementFactory.createPasswordsSection(passwordManager, [], []);
 
@@ -1534,8 +1530,6 @@
     // Test verifies the the account storage buttons are not shown for custom
     // passphrase users.
     test('accountStorageButonsNotShownForCustomPassphraseUser', function() {
-      loadTimeData.overrideValues({enableAccountStorage: true});
-
       const passwordsSection =
           elementFactory.createPasswordsSection(passwordManager, [], []);
 
@@ -1555,9 +1549,6 @@
     // Test verifies that enabling sync hides the buttons for account storage
     // opt-in/out and the 'device passwords' page.
     test('enablingSyncHidesAccountStorageButtons', function() {
-      // Feature flag enabled.
-      loadTimeData.overrideValues({enableAccountStorage: true});
-
       const passwordsSection =
           elementFactory.createPasswordsSection(passwordManager, [], []);
 
@@ -1577,7 +1568,6 @@
     test('verifyDevicePasswordsButtonVisibility', function() {
       // Set up user eligible to the account-scoped password storage, not
       // opted in and with no device passwords. Button should be hidden.
-      loadTimeData.overrideValues({enableAccountStorage: true});
       const passwordList =
           [createPasswordEntry({fromAccountStore: true, id: 10})];
       const passwordsSection = elementFactory.createPasswordsSection(
@@ -1607,8 +1597,6 @@
     test(
         'passwordRemovalMessageSpecifiesStoreForAccountStorageUsers',
         function() {
-          loadTimeData.overrideValues({enableAccountStorage: true});
-
           const passwordList = [
             createPasswordEntry(
                 {username: 'account', id: 0, fromAccountStore: true}),
@@ -1645,8 +1633,6 @@
     // Clicking the button in the dialog then removes both versions of the
     // password.
     test('verifyPasswordRemoveDialogRemoveBothCopies', async function() {
-      loadTimeData.overrideValues({enableAccountStorage: true});
-
       const accountCopy =
           createPasswordEntry({frontendId: 42, id: 0, fromAccountStore: true});
       const deviceCopy =
@@ -1686,8 +1672,6 @@
     // both on the device and in the account, the PasswordRemoveDialog shows up.
     // The user then chooses to remove only of the copies.
     test('verifyPasswordRemoveDialogRemoveSingleCopy', async function() {
-      loadTimeData.overrideValues({enableAccountStorage: true});
-
       const accountCopy =
           createPasswordEntry({frontendId: 42, id: 0, fromAccountStore: true});
       const deviceCopy =
diff --git a/chrome/test/data/webui/settings/people_page_sync_controls_test.js b/chrome/test/data/webui/settings/people_page_sync_controls_test.js
index c65eaf7..9753eca 100644
--- a/chrome/test/data/webui/settings/people_page_sync_controls_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_controls_test.js
@@ -24,7 +24,7 @@
   setup(async function() {
     setupRouterWithSyncRoutes();
     browserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = browserProxy;
+    SyncBrowserProxyImpl.setInstance(browserProxy);
 
     PolymerTest.clearBody();
     syncControls = document.createElement('settings-sync-controls');
@@ -132,7 +132,7 @@
 
   setup(function() {
     browserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = browserProxy;
+    SyncBrowserProxyImpl.setInstance(browserProxy);
 
     PolymerTest.clearBody();
 
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_interactive_test.js b/chrome/test/data/webui/settings/people_page_sync_page_interactive_test.js
index da9177e..22fd7d1 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_interactive_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_page_interactive_test.js
@@ -19,7 +19,7 @@
   setup(function() {
     setupRouterWithSyncRoutes();
     PolymerTest.clearBody();
-    SyncBrowserProxyImpl.instance_ = new TestSyncBrowserProxy();
+    SyncBrowserProxyImpl.setInstance(new TestSyncBrowserProxy());
     const router = Router.getInstance();
     router.navigateTo(router.getRoutes().SYNC);
     syncPage = document.createElement('settings-sync-page');
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_test.js b/chrome/test/data/webui/settings/people_page_sync_page_test.js
index 423c6ef..33738f8 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_page_test.js
@@ -63,7 +63,7 @@
   setup(async function() {
     setupRouterWithSyncRoutes();
     browserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = browserProxy;
+    SyncBrowserProxyImpl.setInstance(browserProxy);
 
     setupSyncPage();
 
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index fd5fa72..1b6de52be 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -53,7 +53,7 @@
     ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
 
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
     PolymerTest.clearBody();
     peoplePage = document.createElement('settings-people-page');
@@ -100,7 +100,7 @@
       loadTimeData.overrideValues({signinAllowed: false});
 
       syncBrowserProxy = new TestSyncBrowserProxy();
-      SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+      SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
       profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
       ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
@@ -137,7 +137,7 @@
     setup(async function() {
       loadTimeData.overrideValues({signinAllowed: true});
       syncBrowserProxy = new TestSyncBrowserProxy();
-      SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+      SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
       profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
       ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
@@ -412,7 +412,7 @@
 suite('SyncSettings', function() {
   setup(async function() {
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
     profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
     ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
diff --git a/chrome/test/data/webui/settings/people_page_test_cros.js b/chrome/test/data/webui/settings/people_page_test_cros.js
index 7ee29f7..7cbf564 100644
--- a/chrome/test/data/webui/settings/people_page_test_cros.js
+++ b/chrome/test/data/webui/settings/people_page_test_cros.js
@@ -95,7 +95,7 @@
 
   setup(async function() {
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
     profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
     ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
@@ -156,7 +156,7 @@
 
   setup(async function() {
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
     profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
     ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
@@ -210,7 +210,7 @@
 
   setup(async function() {
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
 
     profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
     ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
diff --git a/chrome/test/data/webui/settings/personalization_options_test.js b/chrome/test/data/webui/settings/personalization_options_test.js
index b6990a58..f949cd5 100644
--- a/chrome/test/data/webui/settings/personalization_options_test.js
+++ b/chrome/test/data/webui/settings/personalization_options_test.js
@@ -51,7 +51,7 @@
     testBrowserProxy = new TestPrivacyPageBrowserProxy();
     PrivacyPageBrowserProxyImpl.instance_ = testBrowserProxy;
     syncBrowserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    SyncBrowserProxyImpl.setInstance(syncBrowserProxy);
     buildTestElement();
   });
 
diff --git a/chrome/test/data/webui/settings/privacy_page_test.js b/chrome/test/data/webui/settings/privacy_page_test.js
index 95a8062..0c6efcd 100644
--- a/chrome/test/data/webui/settings/privacy_page_test.js
+++ b/chrome/test/data/webui/settings/privacy_page_test.js
@@ -69,7 +69,6 @@
   /** @type {!SettingsPrivacyPageElement} */
   let page;
 
-  /** @type {!TestClearBrowsingDataBrowserProxy} */
   let testClearBrowsingDataBrowserProxy;
 
   /** @type {!TestSiteSettingsPrefsBrowserProxy}*/
@@ -88,8 +87,8 @@
 
   setup(function() {
     testClearBrowsingDataBrowserProxy = new TestClearBrowsingDataBrowserProxy();
-    ClearBrowsingDataBrowserProxyImpl.instance_ =
-        testClearBrowsingDataBrowserProxy;
+    ClearBrowsingDataBrowserProxyImpl.setInstance(
+        testClearBrowsingDataBrowserProxy);
     const testBrowserProxy = new TestPrivacyPageBrowserProxy();
     PrivacyPageBrowserProxyImpl.instance_ = testBrowserProxy;
     siteSettingsBrowserProxy = new TestSiteSettingsPrefsBrowserProxy();
diff --git a/chrome/test/data/webui/settings/startup_urls_page_test.js b/chrome/test/data/webui/settings/startup_urls_page_test.js
index 0793a592..82ee40a 100644
--- a/chrome/test/data/webui/settings/startup_urls_page_test.js
+++ b/chrome/test/data/webui/settings/startup_urls_page_test.js
@@ -6,7 +6,7 @@
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {EDIT_STARTUP_URL_EVENT, StartupUrlsPageBrowserProxy, StartupUrlsPageBrowserProxyImpl} from 'chrome://settings/settings.js';
+import {EDIT_STARTUP_URL_EVENT, StartupUrlsPageBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js';
 // clang-format on
 
@@ -83,7 +83,7 @@
 
   setup(function() {
     browserProxy = new TestStartupUrlsPageBrowserProxy();
-    StartupUrlsPageBrowserProxyImpl.instance_ = browserProxy;
+    StartupUrlsPageBrowserProxyImpl.setInstance(browserProxy);
     PolymerTest.clearBody();
     dialog = document.createElement('settings-startup-url-dialog');
   });
@@ -209,7 +209,7 @@
 
   setup(function() {
     browserProxy = new TestStartupUrlsPageBrowserProxy();
-    StartupUrlsPageBrowserProxyImpl.instance_ = browserProxy;
+    StartupUrlsPageBrowserProxyImpl.setInstance(browserProxy);
     PolymerTest.clearBody();
     page = document.createElement('settings-startup-urls-page');
     page.prefs = {
@@ -324,7 +324,7 @@
 
   setup(function() {
     browserProxy = new TestStartupUrlsPageBrowserProxy();
-    StartupUrlsPageBrowserProxyImpl.instance_ = browserProxy;
+    StartupUrlsPageBrowserProxyImpl.setInstance(browserProxy);
     PolymerTest.clearBody();
     element = document.createElement('settings-startup-url-entry');
     element.model = createSampleUrlEntry();
diff --git a/chrome/test/data/webui/settings/sync_account_control_test.js b/chrome/test/data/webui/settings/sync_account_control_test.js
index 29b795ae..52e1f42 100644
--- a/chrome/test/data/webui/settings/sync_account_control_test.js
+++ b/chrome/test/data/webui/settings/sync_account_control_test.js
@@ -32,7 +32,7 @@
   setup(async function() {
     setupRouterWithSyncRoutes();
     browserProxy = new TestSyncBrowserProxy();
-    SyncBrowserProxyImpl.instance_ = browserProxy;
+    SyncBrowserProxyImpl.setInstance(browserProxy);
 
     PolymerTest.clearBody();
     testElement = document.createElement('settings-sync-account-control');
diff --git a/chrome/test/data/webui/settings/test_clear_browsing_data_browser_proxy.js b/chrome/test/data/webui/settings/test_clear_browsing_data_browser_proxy.js
index 077ea629..a8398ca 100644
--- a/chrome/test/data/webui/settings/test_clear_browsing_data_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_clear_browsing_data_browser_proxy.js
@@ -4,7 +4,6 @@
 
 // clang-format off
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
-import {ClearBrowsingDataBrowserProxy, InstalledApp} from 'chrome://settings/lazy_load.js';
 
 import {TestBrowserProxy} from '../test_browser_proxy.js';
 
diff --git a/chromeos/components/camera_app_ui/resources/js/init.js b/chromeos/components/camera_app_ui/resources/js/init.js
index a3ec336..522bf631 100644
--- a/chromeos/components/camera_app_ui/resources/js/init.js
+++ b/chromeos/components/camera_app_ui/resources/js/init.js
@@ -15,12 +15,7 @@
 
 document.addEventListener('DOMContentLoaded', async () => {
   const workerPath = '/js/test_bridge.js';
-  // The cast here is a workaround to avoid warning in closure compiler since
-  // it does not have such signature. We need to fix it in upstream.
-  // TODO(crbug.com/980846): Remove the cast once the PR is merged:
-  // https://github.com/google/closure-compiler/pull/3704
-  const sharedWorker =
-      new SharedWorker(workerPath, /** @type {string} */ ({type: 'module'}));
+  const sharedWorker = new SharedWorker(workerPath, {type: 'module'});
   const testBridge = Comlink.wrap(sharedWorker.port);
   const appWindow = await testBridge.bindWindow(window.location.href);
   // TODO(crbug.com/980846): Refactor to use a better way rather than window
diff --git a/chromeos/components/camera_app_ui/resources/tsconfig.json b/chromeos/components/camera_app_ui/resources/tsconfig.json
index 0568750..43f3a004 100644
--- a/chromeos/components/camera_app_ui/resources/tsconfig.json
+++ b/chromeos/components/camera_app_ui/resources/tsconfig.json
@@ -3,7 +3,18 @@
     "allowJs": true,
     "checkJs": true,
     "noEmit": true,
+    "module": "esnext",
     "target": "esnext"
   },
-  "files": ["js/main.js", "js/externs/types.d.ts"]
+  "files": [
+    "js/externs/types.d.ts",
+    "js/init.js",
+    "js/main.js",
+    "js/models/barcode_worker.js",
+    "js/models/mp4_video_processor.js",
+    "js/test_bridge.js",
+    "js/untrusted_ga_helper.js",
+    "js/untrusted_script_loader.js",
+    "js/untrusted_video_processor_helper.js"
+  ]
 }
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index f1e403e..7dc9b3dc 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -57,6 +57,7 @@
     {::onc::client_cert::kClientCertProvisioningProfileId, &kStringSignature},
     {::onc::client_cert::kClientCertRef, &kStringSignature},
     {::onc::client_cert::kClientCertType, &kStringSignature},
+    {::onc::eap::kDomainSuffixMatch, &kStringListSignature},
     {::onc::eap::kIdentity, &kStringSignature},
     {::onc::eap::kInner, &kStringSignature},
     {::onc::eap::kOuter, &kStringSignature},
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc
index 48fab4e..5ca612a73 100644
--- a/chromeos/network/onc/onc_translation_tables.cc
+++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -24,6 +24,7 @@
     {::onc::eap::kAnonymousIdentity, shill::kEapAnonymousIdentityProperty},
     // This field is converted during translation, see onc_translator_*.
     // { ::onc::client_cert::kClientCertPKCS11Id, shill::kEapCertIdProperty },
+    {::onc::eap::kDomainSuffixMatch, shill::kEapDomainSuffixMatchProperty},
     {::onc::eap::kIdentity, shill::kEapIdentityProperty},
     // This field is converted during translation, see onc_translator_*.
     // { ::onc::eap::kInner, shill::kEapPhase2AuthProperty },
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index d7de4bf..7b98770 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-93-4577.22-1628502876-benchmark-93.0.4577.31-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-94-4588.0-1627896981-benchmark-94.0.4601.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 80ee4e2..c1cd165a 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-93-4577.15-1627899156-benchmark-93.0.4577.31-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-94-4577.15-1627898841-benchmark-94.0.4601.0-r1-redacted.afdo.xz
diff --git a/chromeos/strings/chromeos_strings_nl.xtb b/chromeos/strings/chromeos_strings_nl.xtb
index 6cb93047..30c0e87 100644
--- a/chromeos/strings/chromeos_strings_nl.xtb
+++ b/chromeos/strings/chromeos_strings_nl.xtb
@@ -367,9 +367,11 @@
 <translation id="7835501727204647447">CloudReady installeren</translation>
 <translation id="7881066108824108340">DNS</translation>
 <translation id="7882358943899516840">Type provider</translation>
+<translation id="7895471513946376273">Ontdek tools voor tekenen en ontwerpen</translation>
 <translation id="7936303884198020182">Geen naamservers gevonden</translation>
 <translation id="7960831585769876809">Temperatuur</translation>
 <translation id="7994702968232966508">EAP-methode</translation>
+<translation id="8020238979854764615">Er is een fout opgetreden. Probeer het opnieuw door andere afbeeldingen te kiezen.</translation>
 <translation id="802154636333426148">Downloaden mislukt</translation>
 <translation id="8041089156583427627">Feedback sturen</translation>
 <translation id="8075838845814659848">Resterende batterijlading</translation>
diff --git a/chromeos/strings/chromeos_strings_te.xtb b/chromeos/strings/chromeos_strings_te.xtb
index 9586015..53493f4 100644
--- a/chromeos/strings/chromeos_strings_te.xtb
+++ b/chromeos/strings/chromeos_strings_te.xtb
@@ -87,7 +87,7 @@
 <translation id="2789486458103222910">సరే</translation>
 <translation id="2805756323405976993">యాప్స్</translation>
 <translation id="2862104018715411648">ప్రారంభించడానికి మీ డాక్యుమెంట్‌ను స్కానర్ మీద పెట్టి, స్కాన్ చేయిని ఎంచుకోండి</translation>
-<translation id="2872961005593481000">షట్ డౌన్ చెయ్యండి</translation>
+<translation id="2872961005593481000">షట్ డౌన్ చేయండి</translation>
 <translation id="2878387241690264070"><ph name="NUM_SECONDS" /> సెకన్లలో <ph name="RATE" /> డిశ్చార్జ్ చేయబడింది.</translation>
 <translation id="3008341117444806826">రిఫ్రెష్ చేయి</translation>
 <translation id="3009958530611748826">దీనిలో సేవ్ చేయడానికి ఫోల్డర్‌ను ఎంచుకోండి</translation>
diff --git a/chromeos/strings/chromeos_strings_uz.xtb b/chromeos/strings/chromeos_strings_uz.xtb
index 5918f50c..8d4b131 100644
--- a/chromeos/strings/chromeos_strings_uz.xtb
+++ b/chromeos/strings/chromeos_strings_uz.xtb
@@ -367,9 +367,11 @@
 <translation id="7835501727204647447">CloudReady oʻrnatish</translation>
 <translation id="7881066108824108340">DNS</translation>
 <translation id="7882358943899516840">Ta’minot turi</translation>
+<translation id="7895471513946376273">Chizmachilik va dizayn vositalari bilan tanishing</translation>
 <translation id="7936303884198020182">Nom serverlari topilmadi</translation>
 <translation id="7960831585769876809">Harorat</translation>
 <translation id="7994702968232966508">EAP usuli</translation>
+<translation id="8020238979854764615">Xatolik yuz berdi. Boshqa rasmlarni tanlash orqali qaytadan urining.</translation>
 <translation id="802154636333426148">Yuklab olib bo‘lmadi</translation>
 <translation id="8041089156583427627">Fikr-mulohaza</translation>
 <translation id="8075838845814659848">Batareya quvvati</translation>
diff --git a/chromeos/test/data/network/shill_wifi_eap_tls.json b/chromeos/test/data/network/shill_wifi_eap_tls.json
index eff54f7..5fbf8825 100644
--- a/chromeos/test/data/network/shill_wifi_eap_tls.json
+++ b/chromeos/test/data/network/shill_wifi_eap_tls.json
@@ -1,5 +1,6 @@
 {
    "EAP.CertID": "1:123456abcdef",
+   "EAP.DomainSuffixMatch": ["domain1.com", "domain2.com"],
    "EAP.EAP": "TLS",
    "EAP.Identity": "my_identity",
    "EAP.KeyID": "1:123456abcdef",
diff --git a/chromeos/test/data/network/translation_of_shill_wifi_eap_tls.onc b/chromeos/test/data/network/translation_of_shill_wifi_eap_tls.onc
index 803079638..925d7b5 100644
--- a/chromeos/test/data/network/translation_of_shill_wifi_eap_tls.onc
+++ b/chromeos/test/data/network/translation_of_shill_wifi_eap_tls.onc
@@ -9,6 +9,7 @@
     "EAP": {
       "ClientCertType": "PKCS11Id",
       "ClientCertPKCS11Id": "1:123456abcdef",
+      "DomainSuffixMatch": ["domain1.com", "domain2.com"],
       "Outer": "EAP-TLS",
       "Identity": "my_identity",
       "SubjectMatch": "my_subject",
diff --git a/chromeos/test/data/network/wifi_eap_tls.onc b/chromeos/test/data/network/wifi_eap_tls.onc
index 518c1d7..e8dee90 100644
--- a/chromeos/test/data/network/wifi_eap_tls.onc
+++ b/chromeos/test/data/network/wifi_eap_tls.onc
@@ -10,6 +10,7 @@
       "UseSystemCAs": true,
       "ClientCertType": "PKCS11Id",
       "ClientCertPKCS11Id": "1:123456abcdef",
+      "DomainSuffixMatch": ["domain1.com", "domain2.com"],
       "SaveCredentials": true,
       "SubjectMatch": "my_subject",
       "SubjectAlternativeNameMatch":[
diff --git a/components/accuracy_tips/BUILD.gn b/components/accuracy_tips/BUILD.gn
index bdf94017..42aac39f 100644
--- a/components/accuracy_tips/BUILD.gn
+++ b/components/accuracy_tips/BUILD.gn
@@ -20,11 +20,13 @@
 
   deps = [
     "//base",
+    "//components/history/core/browser",
     "//components/keyed_service/core",
     "//components/pref_registry",
     "//components/prefs",
     "//components/safe_browsing/core/browser/db:database_manager",
     "//components/safe_browsing/core/common",
+    "//components/unified_consent",
     "//content/public/browser",
   ]
 }
@@ -44,6 +46,7 @@
     "//components/safe_browsing/core/browser/db:test_database_manager",
     "//components/safe_browsing/core/common",
     "//components/sync_preferences:test_support",
+    "//components/unified_consent",
     "//content/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/accuracy_tips/DEPS b/components/accuracy_tips/DEPS
index 8f2fec0..3fe7f47d 100644
--- a/components/accuracy_tips/DEPS
+++ b/components/accuracy_tips/DEPS
@@ -2,10 +2,11 @@
     "+content/public/common",
     "+content/public/browser",
     "+content/public/test",
+    "+components/history/core/browser",
     "+components/keyed_service/core",
     "+components/safe_browsing/core",
     "+components/pref_registry",
     "+components/prefs",
     "+components/sync_preferences",
+    "+components/unified_consent",
 ]
-
diff --git a/components/accuracy_tips/accuracy_service.cc b/components/accuracy_tips/accuracy_service.cc
index b6ac68b..d8429af 100644
--- a/components/accuracy_tips/accuracy_service.cc
+++ b/components/accuracy_tips/accuracy_service.cc
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/time/time.h"
+#include "base/values.h"
 #include "components/accuracy_tips/accuracy_tip_interaction.h"
 #include "components/accuracy_tips/accuracy_tip_safe_browsing_client.h"
 #include "components/accuracy_tips/accuracy_tip_status.h"
@@ -21,6 +22,8 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/unified_consent/pref_names.h"
+#include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
 namespace accuracy_tips {
@@ -70,6 +73,7 @@
     std::unique_ptr<Delegate> delegate,
     PrefService* pref_service,
     scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> sb_database,
+    history::HistoryService* history_service,
     scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
     scoped_refptr<base::SequencedTaskRunner> io_task_runner)
     : delegate_(std::move(delegate)),
@@ -83,6 +87,9 @@
         std::move(sb_database), std::move(ui_task_runner),
         std::move(io_task_runner));
   }
+  if (history_service) {
+    history_service_observation_.Observe(history_service);
+  }
 }
 
 AccuracyService::~AccuracyService() = default;
@@ -92,6 +99,7 @@
     sb_client_->Shutdown();
     sb_client_ = nullptr;
   }
+  history_service_observation_.Reset();
 }
 
 void AccuracyService::CheckAccuracyStatus(const GURL& url,
@@ -150,6 +158,8 @@
       pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_))
           ->GetSize() >= static_cast<size_t>(features::kNumIgnorePrompts.Get());
 
+  url_for_last_shown_tip_ = web_contents->GetLastCommittedURL();
+
   delegate_->ShowAccuracyTip(
       web_contents, AccuracyTipStatus::kShowAccuracyTip,
       /*show_opt_out=*/show_opt_out,
@@ -159,8 +169,34 @@
 
 void AccuracyService::MaybeShowSurvey() {
   if (CanShowSurvey()) {
-    // TODO(olesiamarukhno): Add passing the actual survey data here.
-    delegate_->ShowSurvey({}, {});
+    auto* interactions_list =
+        pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_));
+    const int last_interaction = interactions_list->GetList().back().GetInt();
+    const bool ukm_enabled = pref_service_->GetBoolean(
+        unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
+    std::string url_parameter_for_hats =
+        ukm_enabled ? url_for_last_shown_tip_.GetOrigin().spec() : "";
+    delegate_->ShowSurvey(
+        {}, {{"Tip shown for URL", url_parameter_for_hats},
+             {"UI interaction", base::NumberToString(last_interaction)}});
+  }
+}
+
+void AccuracyService::OnURLsDeleted(
+    history::HistoryService* history_service,
+    const history::DeletionInfo& deletion_info) {
+  if (deletion_info.time_range().IsValid()) {
+    base::Time last_shown =
+        pref_service_->GetTime(GetLastShownPrefName(disable_ui_));
+    if (last_shown >= deletion_info.time_range().begin() &&
+        last_shown <= deletion_info.time_range().end()) {
+      url_for_last_shown_tip_ = GURL();
+    }
+  } else {
+    if (deletion_info.deleted_urls_origin_map().count(
+            url_for_last_shown_tip_.GetOrigin())) {
+      url_for_last_shown_tip_ = GURL();
+    }
   }
 }
 
@@ -205,9 +241,16 @@
   const bool has_required_time_passed =
       last_shown_delta >= features::kMinTimeToShowSurvey.Get() &&
       last_shown_delta <= features::kMaxTimeToShowSurvey.Get();
-  // TODO(olesiamarukhno): Add checks for prompt count and add saving the shown
-  // prompt count.
-  return has_required_time_passed;
+  if (!has_required_time_passed)
+    return false;
+
+  if (url_for_last_shown_tip_.is_empty() || !url_for_last_shown_tip_.is_valid())
+    return false;
+
+  int interactions_count =
+      pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_))
+          ->GetSize();
+  return interactions_count >= features::kMinPromptCountRequiredForSurvey.Get();
 }
 
 }  // namespace accuracy_tips
diff --git a/components/accuracy_tips/accuracy_service.h b/components/accuracy_tips/accuracy_service.h
index 6491d996..ed8564b 100644
--- a/components/accuracy_tips/accuracy_service.h
+++ b/components/accuracy_tips/accuracy_service.h
@@ -9,11 +9,14 @@
 #include <memory>
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "components/accuracy_tips/accuracy_tip_interaction.h"
 #include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_service_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "url/gurl.h"
 
@@ -41,7 +44,7 @@
 
 // Checks accuracy information on URLs for AccuracyTips.
 // Handles rate-limiting and feature checks.
-class AccuracyService : public KeyedService {
+class AccuracyService : public KeyedService, history::HistoryServiceObserver {
  public:
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
@@ -75,6 +78,7 @@
       std::unique_ptr<Delegate> delegate,
       PrefService* pref_service,
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> sb_database,
+      history::HistoryService* history_service,
       scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
       scoped_refptr<base::SequencedTaskRunner> io_task_runner);
   ~AccuracyService() override;
@@ -100,6 +104,10 @@
   // KeyedService:
   void Shutdown() override;
 
+  // history::HistoryServiceObserver:
+  void OnURLsDeleted(history::HistoryService* history_service,
+                     const history::DeletionInfo& deletion_info) override;
+
   void SetClockForTesting(base::Clock* clock) { clock_ = clock; }
 
  private:
@@ -118,6 +126,7 @@
   PrefService* pref_service_ = nullptr;
   scoped_refptr<AccuracyTipSafeBrowsingClient> sb_client_;
   scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+  GURL url_for_last_shown_tip_;
 
   // Feature params:
   const GURL sample_url_;
@@ -126,6 +135,10 @@
 
   base::Clock* clock_ = base::DefaultClock::GetInstance();
 
+  base::ScopedObservation<history::HistoryService,
+                          history::HistoryServiceObserver>
+      history_service_observation_{this};
+
   base::WeakPtrFactory<AccuracyService> weak_factory_{this};
 };
 
diff --git a/components/accuracy_tips/accuracy_service_unittest.cc b/components/accuracy_tips/accuracy_service_unittest.cc
index 7f5d84a0..16b3d46 100644
--- a/components/accuracy_tips/accuracy_service_unittest.cc
+++ b/components/accuracy_tips/accuracy_service_unittest.cc
@@ -24,6 +24,9 @@
 #include "components/safe_browsing/core/browser/db/test_database_manager.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/unified_consent/pref_names.h"
+#include "components/unified_consent/unified_consent_service.h"
+#include "content/public/test/test_renderer_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -105,14 +108,16 @@
   std::move(callback).Run(AccuracyTipInteraction::kIgnore);
 }
 
-class AccuracyServiceTest : public ::testing::Test {
+class AccuracyServiceTest : public content::RenderViewHostTestHarness {
  protected:
   AccuracyServiceTest() = default;
 
   void SetUp() override {
+    content::RenderViewHostTestHarness::SetUp();
     SetUpFeatureList(feature_list_);
 
     AccuracyService::RegisterProfilePrefs(prefs_.registry());
+    unified_consent::UnifiedConsentService::RegisterPrefs(prefs_.registry());
     auto delegate =
         std::make_unique<testing::StrictMock<MockAccuracyServiceDelegate>>();
     delegate_ = delegate.get();
@@ -120,7 +125,7 @@
 
     sb_database_ = base::MakeRefCounted<MockSafeBrowsingDatabaseManager>();
     service_ = std::make_unique<AccuracyService>(
-        std::move(delegate), &prefs_, sb_database_,
+        std::move(delegate), &prefs_, sb_database_, nullptr,
         base::ThreadTaskRunnerHandle::Get(),
         base::ThreadTaskRunnerHandle::Get());
     clock_.SetNow(base::Time::Now());
@@ -143,6 +148,7 @@
   MockAccuracyServiceDelegate* delegate() { return delegate_; }
   base::SimpleTestClock* clock() { return &clock_; }
   MockSafeBrowsingDatabaseManager* sb_database() { return sb_database_.get(); }
+  sync_preferences::TestingPrefServiceSyncable* prefs() { return &prefs_; }
 
  private:
   virtual void SetUpFeatureList(base::test::ScopedFeatureList& feature_list) {
@@ -151,7 +157,6 @@
         {{features::kSampleUrl.name, "https://sampleurl.com"}});
   }
 
-  base::test::SingleThreadTaskEnvironment environment_;
   base::test::ScopedFeatureList feature_list_;
   sync_preferences::TestingPrefServiceSyncable prefs_;
   base::SimpleTestClock clock_;
@@ -192,26 +197,26 @@
 
 TEST_F(AccuracyServiceTest, ShowUI) {
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _));
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
 }
 
 TEST_F(AccuracyServiceTest, IgnoreButton) {
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, false, _))
       .WillOnce(Invoke(&IgnoreClicked));
   ;
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
   testing::Mock::VerifyAndClearExpectations(delegate());
 
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, false, _))
       .WillOnce(Invoke(&IgnoreClicked));
   ;
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
   testing::Mock::VerifyAndClearExpectations(delegate());
 
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, true, _))
       .WillOnce(Invoke(&LearnMoreClicked));
   ;
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
   testing::Mock::VerifyAndClearExpectations(delegate());
 }
 
@@ -223,7 +228,7 @@
   // Show an accuracy tip.
   EXPECT_EQ(CheckAccuracyStatusSync(url), AccuracyTipStatus::kShowAccuracyTip);
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _));
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
 
   // Future calls will return that the rate limit is active.
   EXPECT_EQ(CheckAccuracyStatusSync(url), AccuracyTipStatus::kRateLimited);
@@ -245,7 +250,7 @@
   // Clicking the opt-out button will disable future accuracy tips.
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _))
       .WillOnce(Invoke(&OptOutClicked));
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
 
   clock()->Advance(base::TimeDelta::FromDays(1));
   EXPECT_EQ(CheckAccuracyStatusSync(url), AccuracyTipStatus::kOptOut);
@@ -273,7 +278,7 @@
     base::HistogramTester t;
     EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _))
         .WillOnce(Invoke(&LearnMoreClicked));
-    service()->MaybeShowAccuracyTip(nullptr);
+    service()->MaybeShowAccuracyTip(web_contents());
     t.ExpectUniqueSample("Privacy.AccuracyTip.AccuracyTipInteraction",
                          AccuracyTipInteraction::kLearnMore, 1);
     t.ExpectBucketCount("Privacy.AccuracyTip.NumDialogsShown", 1, 1);
@@ -286,7 +291,7 @@
     base::HistogramTester t;
     EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _))
         .WillOnce(Invoke(&OptOutClicked));
-    service()->MaybeShowAccuracyTip(nullptr);
+    service()->MaybeShowAccuracyTip(web_contents());
     t.ExpectUniqueSample("Privacy.AccuracyTip.AccuracyTipInteraction",
                          AccuracyTipInteraction::kOptOut, 1);
     t.ExpectBucketCount("Privacy.AccuracyTip.NumDialogsShown", 2, 1);
@@ -307,7 +312,7 @@
 
 TEST_F(AccuracyServiceDisabledUiTest, ShowWithUiDisabled) {
   EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _)).Times(0);
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
 }
 
 TEST_F(AccuracyServiceDisabledUiTest, TimeBetweenPrompts) {
@@ -317,7 +322,7 @@
 
   // Show an accuracy tip.
   EXPECT_EQ(CheckAccuracyStatusSync(url), AccuracyTipStatus::kShowAccuracyTip);
-  service()->MaybeShowAccuracyTip(nullptr);
+  service()->MaybeShowAccuracyTip(web_contents());
 
   // Future calls will return that the rate limit is active.
   EXPECT_EQ(CheckAccuracyStatusSync(url), AccuracyTipStatus::kRateLimited);
@@ -330,36 +335,73 @@
 }
 
 class AccuracyServiceSurveyTest : public AccuracyServiceTest {
+ public:
+  void SetUp() override {
+    AccuracyServiceTest::SetUp();
+    prefs()->SetBoolean(
+        unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
+  }
+
+  void ShowAccuracyTipsEnoughTimes() {
+    NavigateAndCommit(GURL(gurl_));
+    // Before a tip is shown, a survey won't be shown.
+    EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+    service()->MaybeShowSurvey();
+    testing::Mock::VerifyAndClearExpectations(delegate());
+
+    // Show an accuracy tip required number of times.
+    for (int i = 0; i < features::kMinPromptCountRequiredForSurvey.Get(); i++) {
+      EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _))
+          .WillOnce(Invoke(&LearnMoreClicked));
+      service()->MaybeShowAccuracyTip(web_contents());
+
+      // Before the tip was shown the required number of times...
+      if (i < features::kMinPromptCountRequiredForSurvey.Get() - 1) {
+        // ...even though the minimal time has passed...
+        clock()->Advance(features::kMinTimeToShowSurvey.Get());
+        // ...the survey won't be shown yet.
+        EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+        service()->MaybeShowSurvey();
+        testing::Mock::VerifyAndClearExpectations(delegate());
+        clock()->Advance(features::kTimeBetweenPrompts.Get());
+      }
+    }
+  }
+
+ protected:
+  GURL gurl_ = GURL("https://sampleurl.com");
+
  private:
   void SetUpFeatureList(base::test::ScopedFeatureList& feature_list) override {
     const base::FieldTrialParams accuraty_tips_params = {
         {features::kSampleUrl.name, "https://sampleurl.com"}};
+    const base::FieldTrialParams accuraty_survey_params = {
+        {features::kMinPromptCountRequiredForSurvey.name, "2"}};
     feature_list.InitWithFeaturesAndParameters(
         {{safe_browsing::kAccuracyTipsFeature, accuraty_tips_params},
-         {features::kAccuracyTipsSurveyFeature, {}}},
+         {features::kAccuracyTipsSurveyFeature, accuraty_survey_params}},
         {});
   }
 };
 
 TEST_F(AccuracyServiceSurveyTest, SurveyTimeRange) {
-  // Before a tip is shown, a survey won't be shown.
+  ShowAccuracyTipsEnoughTimes();
+
+  // But even after it was shown enough times, need to wait minimal amount of
+  // time to show a survey.
   EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
   service()->MaybeShowSurvey();
   testing::Mock::VerifyAndClearExpectations(delegate());
 
-  // Show an accuracy tip.
-  EXPECT_CALL(*delegate(), ShowAccuracyTip(_, _, _, _));
-  service()->MaybeShowAccuracyTip(nullptr);
-
-  // But even after it was shown, need to wait minimal amount of time to show
-  // a survey.
-  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
-  service()->MaybeShowSurvey();
-  testing::Mock::VerifyAndClearExpectations(delegate());
+  std::map<std::string, std::string> expected_product_specific_data = {
+      {"Tip shown for URL", gurl_.GetOrigin().spec()},
+      {"UI interaction", base::NumberToString(static_cast<int>(
+                             AccuracyTipInteraction::kLearnMore))}};
 
   // After minimal time passed, a survey can be shown.
   clock()->Advance(features::kMinTimeToShowSurvey.Get());
-  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(1);
+  EXPECT_CALL(*delegate(), ShowSurvey(_, expected_product_specific_data))
+      .Times(1);
   service()->MaybeShowSurvey();
   testing::Mock::VerifyAndClearExpectations(delegate());
 
@@ -371,4 +413,106 @@
   testing::Mock::VerifyAndClearExpectations(delegate());
 }
 
+TEST_F(AccuracyServiceSurveyTest, SurveyUkmDisabled) {
+  prefs()->SetBoolean(
+      unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, false);
+
+  ShowAccuracyTipsEnoughTimes();
+
+  // But even after it was shown enough times, need to wait minimal amount of
+  // time to show a survey.
+  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+
+  std::map<std::string, std::string> expected_product_specific_data = {
+      {"Tip shown for URL", ""},
+      {"UI interaction", base::NumberToString(static_cast<int>(
+                             AccuracyTipInteraction::kLearnMore))}};
+
+  // After minimal time passed, a survey can be shown.
+  clock()->Advance(features::kMinTimeToShowSurvey.Get());
+  EXPECT_CALL(*delegate(), ShowSurvey(_, expected_product_specific_data))
+      .Times(1);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+}
+
+TEST_F(AccuracyServiceSurveyTest, DontShowSurveyAfterDeletingAllHistory) {
+  ShowAccuracyTipsEnoughTimes();
+
+  // All history was deleted...
+  service()->OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
+  // ...and even though all other conditions apply, a survey can't be shown
+  // because all history was deleted.
+  clock()->Advance(features::kMinTimeToShowSurvey.Get());
+  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+}
+
+TEST_F(AccuracyServiceSurveyTest, DontShowSurveyAfterDeletingHistoryForUrls) {
+  ShowAccuracyTipsEnoughTimes();
+
+  // History for the origin was deleted...
+  history::DeletionInfo deletion_info = history::DeletionInfo::ForUrls(
+      {history::URLRow(gurl_)}, std::set<GURL>());
+  deletion_info.set_deleted_urls_origin_map({
+      {gurl_.GetOrigin(), {0, base::Time::Now()}},
+  });
+  service()->OnURLsDeleted(nullptr, deletion_info);
+  // ...and even though all other conditions apply, a survey can't be shown
+  // because the relevant history was deleted.
+  clock()->Advance(features::kMinTimeToShowSurvey.Get());
+  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+}
+
+TEST_F(AccuracyServiceSurveyTest,
+       DontShowSurveyAfterDeletingHistoryForTimeRange) {
+  ShowAccuracyTipsEnoughTimes();
+  clock()->Advance(features::kMinTimeToShowSurvey.Get());
+
+  // History deleted for the last day...
+  base::Time begin = clock()->Now() - base::TimeDelta::FromDays(1);
+  base::Time end = clock()->Now();
+  history::DeletionInfo deletion_info(
+      history::DeletionTimeRange(begin, end), false /* is_from_expiration */,
+      {} /* deleted_rows */, {} /* favicon_urls */,
+      absl::nullopt /* restrict_urls */);
+  service()->OnURLsDeleted(nullptr, deletion_info);
+  // ...and even though all other conditions apply, a survey can't be shown
+  // because the relevant history was deleted.
+  EXPECT_CALL(*delegate(), ShowSurvey(_, _)).Times(0);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+}
+
+TEST_F(AccuracyServiceSurveyTest, ShowSurveyAfterDeletingHistoryForOtherUrls) {
+  ShowAccuracyTipsEnoughTimes();
+
+  // History was deleted for URLs that don't include accuracy tip URL.
+  GURL other_gurl = GURL("https://otherurl.com");
+  history::DeletionInfo deletion_info = history::DeletionInfo::ForUrls(
+      {history::URLRow(other_gurl)}, std::set<GURL>());
+  deletion_info.set_deleted_urls_origin_map({
+      {other_gurl.GetOrigin(), {0, base::Time::Now()}},
+  });
+  service()->OnURLsDeleted(nullptr, deletion_info);
+
+  std::map<std::string, std::string> expected_product_specific_data = {
+      {"Tip shown for URL", gurl_.GetOrigin().spec()},
+      {"UI interaction", base::NumberToString(static_cast<int>(
+                             AccuracyTipInteraction::kLearnMore))}};
+
+  // A survey can be shown because history for the accuracy tip URL wasn't
+  // deleted.
+  clock()->Advance(features::kMinTimeToShowSurvey.Get());
+  EXPECT_CALL(*delegate(), ShowSurvey(_, expected_product_specific_data))
+      .Times(1);
+  service()->MaybeShowSurvey();
+  testing::Mock::VerifyAndClearExpectations(delegate());
+}
+
 }  // namespace accuracy_tips
diff --git a/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc b/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc
index 6681731..89e246e 100644
--- a/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc
+++ b/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc
@@ -37,7 +37,7 @@
 class MockAccuracyService : public AccuracyService {
  public:
   MockAccuracyService()
-      : AccuracyService(nullptr, nullptr, nullptr, nullptr, nullptr) {}
+      : AccuracyService(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) {}
   MOCK_METHOD2(CheckAccuracyStatus, void(const GURL&, AccuracyCheckCallback));
   MOCK_METHOD1(MaybeShowAccuracyTip, void(content::WebContents*));
 };
@@ -114,4 +114,4 @@
   std::move(callback).Run(AccuracyTipStatus::kShowAccuracyTip);
 }
 
-}  // namespace accuracy_tips
\ No newline at end of file
+}  // namespace accuracy_tips
diff --git a/components/accuracy_tips/features.cc b/components/accuracy_tips/features.cc
index 1627613..d75c22a 100644
--- a/components/accuracy_tips/features.cc
+++ b/components/accuracy_tips/features.cc
@@ -42,5 +42,8 @@
     &kAccuracyTipsSurveyFeature, "MaxTimeToShowSurvey",
     base::TimeDelta::FromMinutes(30)};
 
+const base::FeatureParam<int> kMinPromptCountRequiredForSurvey{
+    &kAccuracyTipsSurveyFeature, "MinPromptCountRequiredForSurvey", 1};
+
 }  // namespace features
 }  // namespace accuracy_tips
diff --git a/components/accuracy_tips/features.h b/components/accuracy_tips/features.h
index 12fb175..35184a2c 100644
--- a/components/accuracy_tips/features.h
+++ b/components/accuracy_tips/features.h
@@ -43,6 +43,9 @@
 // which we can show a survey.
 extern const base::FeatureParam<base::TimeDelta> kMaxTimeToShowSurvey;
 
+// A minimal count of accuracy tips shown, after which survey might be shown.
+extern const base::FeatureParam<int> kMinPromptCountRequiredForSurvey;
+
 }  // namespace features
 }  // namespace accuracy_tips
 
diff --git a/components/autofill/android/BUILD.gn b/components/autofill/android/BUILD.gn
index 2234539d..a8dd599 100644
--- a/components/autofill/android/BUILD.gn
+++ b/components/autofill/android/BUILD.gn
@@ -46,6 +46,7 @@
     "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
     "//third_party/androidx:androidx_core_core_java",
     "//ui/android:ui_no_recycler_view_java",
+    "//url:gurl_java",
   ]
   sources = [
     "java/src/org/chromium/components/autofill/AutofillDelegate.java",
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
index ed80ce14..9e01038 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
@@ -4,7 +4,10 @@
 
 package org.chromium.components.autofill;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.ui.DropdownItemBase;
+import org.chromium.url.GURL;
 
 /**
  * Autofill suggestion container used to store information needed for each Autofill popup entry.
@@ -20,13 +23,17 @@
     private final boolean mIsMultilineLabel;
     private final boolean mIsBoldLabel;
     private final String mFeatureForIPH;
+    private final GURL mCustomIconUrl;
 
     /**
      * Constructs a Autofill suggestion container.
      *
      * @param label The main label of the Autofill suggestion.
      * @param sublabel The describing sublabel of the Autofill suggestion.
-     * @param itemTag The tag for the autofill suggestion.
+     * @param itemTag The tag for the autofill suggestion. For keyboard accessory, this would be
+     *         displayed as an IPH bubble. For the dropdown, this is shown below the secondary
+     *         text.For example: For credit cards with offers, the item tag is set to indicate that
+     *         the card has some cashback offer associated with it.
      * @param iconId The resource ID for the icon associated with the suggestion, or
      *               {@code DropdownItem.NO_ICON} for no icon.
      * @param isIconAtStart {@code true} if {@code iconId} is displayed before {@code label}.
@@ -36,10 +43,21 @@
      * @param isBoldLabel Whether the label is displayed in {@code Typeface.BOLD}.
      * @param featureForIPH The IPH feature for the autofill suggestion. If present, it'll be
      *         attempted to be shown in the keyboard accessory.
+     *
+     * Use the {@link AutofillSuggestion.Builder} instead.
      */
+    @Deprecated
     public AutofillSuggestion(String label, String sublabel, String itemTag, int iconId,
             boolean isIconAtStart, int suggestionId, boolean isDeletable, boolean isMultilineLabel,
             boolean isBoldLabel, String featureForIPH) {
+        this(label, sublabel, itemTag, iconId, isIconAtStart, suggestionId, isDeletable,
+                isMultilineLabel, isBoldLabel, featureForIPH, /*customIconUrl=*/null);
+    }
+
+    @VisibleForTesting
+    public AutofillSuggestion(String label, String sublabel, String itemTag, int iconId,
+            boolean isIconAtStart, int suggestionId, boolean isDeletable, boolean isMultilineLabel,
+            boolean isBoldLabel, String featureForIPH, GURL customIconUrl) {
         mLabel = label;
         mSublabel = sublabel;
         mItemTag = itemTag;
@@ -50,6 +68,7 @@
         mIsMultilineLabel = isMultilineLabel;
         mIsBoldLabel = isBoldLabel;
         mFeatureForIPH = featureForIPH;
+        mCustomIconUrl = customIconUrl;
     }
 
     @Override
@@ -98,6 +117,11 @@
         return super.isIconAtStart();
     }
 
+    @Override
+    public GURL getCustomIconUrl() {
+        return mCustomIconUrl;
+    }
+
     public int getSuggestionId() {
         return mSuggestionId;
     }
@@ -116,11 +140,47 @@
         return mFeatureForIPH;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof AutofillSuggestion)) {
+            return false;
+        }
+        AutofillSuggestion other = (AutofillSuggestion) o;
+        return this.mLabel.equals(other.mLabel) && this.mSublabel.equals(other.mSublabel)
+                && this.mItemTag.equals(other.mItemTag) && this.mIconId == other.mIconId
+                && this.mIsIconAtStart == other.mIsIconAtStart
+                && this.mSuggestionId == other.mSuggestionId
+                && this.mIsDeletable == other.mIsDeletable
+                && this.mIsMultilineLabel == other.mIsMultilineLabel
+                && this.mIsBoldLabel == other.mIsBoldLabel
+                && this.mFeatureForIPH.equals(other.mFeatureForIPH)
+                && this.mCustomIconUrl.equals(other.mCustomIconUrl);
+    }
+
+    public Builder toBuilder() {
+        return new Builder()
+                .setLabel(mLabel)
+                .setSubLabel(mSublabel)
+                .setItemTag(mItemTag)
+                .setIconId(mIconId)
+                .setIsIconAtStart(mIsIconAtStart)
+                .setSuggestionId(mSuggestionId)
+                .setIsDeletable(mIsDeletable)
+                .setIsMultiLineLabel(mIsMultilineLabel)
+                .setIsBoldLabel(mIsBoldLabel)
+                .setFeatureForIPH(mFeatureForIPH)
+                .setCustomIconUrl(mCustomIconUrl);
+    }
+
     /**
      * Builder for the {@link AutofillSuggestion}.
      */
     public static final class Builder {
         private int mIconId;
+        private GURL mCustomIconUrl;
         private boolean mIsBoldLabel;
         private boolean mIsIconAtStart;
         private boolean mIsDeletable;
@@ -136,6 +196,11 @@
             return this;
         }
 
+        public Builder setCustomIconUrl(GURL customIconUrl) {
+            this.mCustomIconUrl = customIconUrl;
+            return this;
+        }
+
         public Builder setIsBoldLabel(boolean isBoldLabel) {
             this.mIsBoldLabel = isBoldLabel;
             return this;
@@ -184,7 +249,8 @@
         public AutofillSuggestion build() {
             assert !mLabel.isEmpty() : "AutofillSuggestion requires the label to be set.";
             return new AutofillSuggestion(mLabel, mSubLabel, mItemTag, mIconId, mIsIconAtStart,
-                    mSuggestionId, mIsDeletable, mIsMultiLineLabel, mIsBoldLabel, mFeatureForIPH);
+                    mSuggestionId, mIsDeletable, mIsMultiLineLabel, mIsBoldLabel, mFeatureForIPH,
+                    mCustomIconUrl);
         }
     }
 }
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc
index e256070..21a9616 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -250,6 +250,7 @@
     // card is presented in the keyboard accessory.
     suggestion.feature_for_iph =
         feature_engagement::kIPHKeyboardAccessoryPaymentVirtualCardFeature.name;
+    suggestion.custom_icon_url = credit_card.card_art_url();
 #endif  // OS_ANDROID
 
     suggestion.frontend_id = POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY;
diff --git a/components/autofill/core/browser/ui/suggestion.h b/components/autofill/core/browser/ui/suggestion.h
index 5ec2825f..a03ff30 100644
--- a/components/autofill/core/browser/ui/suggestion.h
+++ b/components/autofill/core/browser/ui/suggestion.h
@@ -9,8 +9,9 @@
 
 #include "base/strings/string_piece.h"
 #include "base/types/strong_alias.h"
+#include "build/build_config.h"
 #include "ui/gfx/image/image.h"
-
+#include "url/gurl.h"
 namespace autofill {
 
 struct Suggestion {
@@ -62,6 +63,13 @@
   std::u16string additional_label;
   // Contains an image to display for the suggestion.
   gfx::Image custom_icon;
+
+#if defined(OS_ANDROID)
+  // The url for the custom icon. This is used by android to fetch the image as
+  // android does not support gfx::Image directly.
+  GURL custom_icon_url;
+#endif  // OS_ANDROID
+
   // TODO(crbug.com/1019660): Identify icons with enum instead of strings.
   // If |custom_icon| is empty, the name of the fallback built-in icon.
   std::string icon;
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
index fff9528..2206e9b 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
@@ -208,7 +208,7 @@
 <translation id="6545864417968258051">బ్లూటూత్ స్కానింగ్</translation>
 <translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> బ్లాక్ చేయబడ్డాయి}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> బ్లాక్ చేయబడ్డాయి}}</translation>
 <translation id="6554732001434021288"><ph name="NUM_DAYS" /> రోజుల క్రితం చివరిగా సందర్శించారు</translation>
-<translation id="6561560012278703671">నిశ్శబ్ద సందేశాలను ఉపయోగించండి (మీకు అంతరాయం కలిగించకుండా నోటిఫికేషన్ ప్రాంప్ట్‌లను బ్లాక్ చేస్తుంది)</translation>
+<translation id="6561560012278703671">నిశ్శబ్ద మెసేజ్‌లను ఉపయోగించండి (మీకు అంతరాయం కలిగించకుండా నోటిఫికేషన్ ప్రాంప్ట్‌లను బ్లాక్ చేస్తుంది)</translation>
 <translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
 <translation id="6612358246767739896">రక్షిత కంటెంట్</translation>
 <translation id="662080504995468778">ఇందులోనే ఉంచు</translation>
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
index a6702b0..dc8fe4e 100644
--- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
+++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -24,6 +24,7 @@
     public static final String ANSWER_SUGGESTIONS_UMA_CLIENT_NAME = "AnswerSuggestions";
     public static final String ASSISTANT_DETAILS_UMA_CLIENT_NAME = "AssistantDetails";
     public static final String ASSISTANT_INFO_BOX_UMA_CLIENT_NAME = "AssistantInfoBox";
+    public static final String AUTOFILL_CARD_ART_UMA_CLIENT_NAME = "AutofillCardArt";
     public static final String CRYPTIDS_UMA_CLIENT_NAME = "Cryptids";
     public static final String ENTITY_SUGGESTIONS_UMA_CLIENT_NAME = "EntitySuggestions";
     public static final String FEED_UMA_CLIENT_NAME = "Feed";
diff --git a/components/javascript_dialogs/app_modal_dialog_controller.cc b/components/javascript_dialogs/app_modal_dialog_controller.cc
index b574d8ee..75f27d7 100644
--- a/components/javascript_dialogs/app_modal_dialog_controller.cc
+++ b/components/javascript_dialogs/app_modal_dialog_controller.cc
@@ -74,7 +74,8 @@
     const std::u16string& message_text,
     const std::u16string& default_prompt_text,
     bool display_suppress_checkbox,
-    Type type,
+    bool is_before_unload_dialog,
+    bool is_reload,
     content::JavaScriptDialogManager::DialogClosedCallback callback)
     : title_(title),
       valid_(true),
@@ -85,7 +86,8 @@
       message_text_(EnforceMaxTextSize(message_text)),
       default_prompt_text_(EnforceMaxPromptSize(default_prompt_text)),
       display_suppress_checkbox_(display_suppress_checkbox),
-      type_(type),
+      is_before_unload_dialog_(is_before_unload_dialog),
+      is_reload_(is_reload),
       callback_(std::move(callback)),
       use_override_prompt_text_(false) {}
 
diff --git a/components/javascript_dialogs/app_modal_dialog_controller.h b/components/javascript_dialogs/app_modal_dialog_controller.h
index 304296b..69463ed 100644
--- a/components/javascript_dialogs/app_modal_dialog_controller.h
+++ b/components/javascript_dialogs/app_modal_dialog_controller.h
@@ -34,12 +34,6 @@
  public:
   typedef std::map<void*, ChromeJavaScriptDialogExtraData> ExtraDataMap;
 
-  enum class Type {
-    kJavaScript,
-    kBeforeUnload,
-    kBeforeUnloadReload,
-    kBeforeUnloadQuitOrHide,
-  };
   AppModalDialogController(
       content::WebContents* web_contents,
       ExtraDataMap* extra_data_map,
@@ -48,7 +42,8 @@
       const std::u16string& message_text,
       const std::u16string& default_prompt_text,
       bool display_suppress_checkbox,
-      Type type,
+      bool is_before_unload_dialog,
+      bool is_reload,
       content::JavaScriptDialogManager::DialogClosedCallback callback);
   ~AppModalDialogController();
 
@@ -93,9 +88,8 @@
   std::u16string message_text() const { return message_text_; }
   std::u16string default_prompt_text() const { return default_prompt_text_; }
   bool display_suppress_checkbox() const { return display_suppress_checkbox_; }
-  bool is_before_unload_dialog() const { return type_ != Type::kJavaScript; }
-  bool is_reload() const { return type_ == Type::kBeforeUnloadReload; }
-  Type type() const { return type_; }
+  bool is_before_unload_dialog() const { return is_before_unload_dialog_; }
+  bool is_reload() const { return is_reload_; }
 
  private:
   // Notifies the delegate with the result of the dialog.
@@ -133,7 +127,8 @@
   const std::u16string message_text_;
   const std::u16string default_prompt_text_;
   const bool display_suppress_checkbox_;
-  const Type type_;
+  const bool is_before_unload_dialog_;
+  const bool is_reload_;
 
   content::JavaScriptDialogManager::DialogClosedCallback callback_;
 
diff --git a/components/javascript_dialogs/app_modal_dialog_manager.cc b/components/javascript_dialogs/app_modal_dialog_manager.cc
index b736c9a8..3a2b826 100644
--- a/components/javascript_dialogs/app_modal_dialog_manager.cc
+++ b/components/javascript_dialogs/app_modal_dialog_manager.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/i18n/rtl.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -28,9 +27,6 @@
 
 namespace {
 
-const base::Feature kShowQuitOrHideForBeforeUnloadApp{
-    "ShowQuitOrHideForBeforeUnloadApp", base::FEATURE_DISABLED_BY_DEFAULT};
-
 #if !defined(OS_ANDROID)
 // Keep in sync with kDefaultMessageWidth, but allow some space for the rest of
 // the text.
@@ -178,7 +174,8 @@
       web_contents, &javascript_dialog_extra_data_, dialog_title, dialog_type,
       message_text, default_prompt_text,
       ShouldDisplaySuppressCheckbox(extra_data),
-      AppModalDialogController::Type::kJavaScript,
+      false,  // is_before_unload_dialog
+      false,  // is_reload
       base::BindOnce(&AppModalDialogManager::OnDialogClosed,
                      base::Unretained(this), web_contents,
                      std::move(callback))));
@@ -190,7 +187,7 @@
     bool is_reload,
     DialogClosedCallback callback) {
   RunBeforeUnloadDialogWithOptions(web_contents, render_frame_host, is_reload,
-                                   false, absl::nullopt, std::move(callback));
+                                   false, std::move(callback));
 }
 
 void AppModalDialogManager::RunBeforeUnloadDialogWithOptions(
@@ -198,7 +195,6 @@
     content::RenderFrameHost* render_frame_host,
     bool is_reload,
     bool is_app,
-    absl::optional<std::u16string> app_name,
     DialogClosedCallback callback) {
   ChromeJavaScriptDialogExtraData* extra_data =
       &javascript_dialog_extra_data_[web_contents];
@@ -223,32 +219,17 @@
   // scam websites so the specification was changed.
 
   std::u16string title;
-  std::u16string message =
-      l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE);
-  AppModalDialogController::Type type =
-      is_reload ? AppModalDialogController::Type::kBeforeUnloadReload
-                : AppModalDialogController::Type::kBeforeUnload;
   if (is_app) {
-    if (is_reload) {
-      title = l10n_util::GetStringUTF16(IDS_BEFORERELOAD_APP_MESSAGEBOX_TITLE);
-    } else {
-      if (app_name &&
-          base::FeatureList::IsEnabled(kShowQuitOrHideForBeforeUnloadApp)) {
-        title = l10n_util::GetStringFUTF16(
-            IDS_BEFOREUNLOAD_QUIT_APP_MESSAGEBOX_TITLE, *app_name);
-        message = l10n_util::GetStringUTF16(
-            IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE_WITH_HIDE);
-        type = AppModalDialogController::Type::kBeforeUnloadQuitOrHide;
-      } else {
-        title =
-            l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_APP_MESSAGEBOX_TITLE);
-      }
-    }
+    title = l10n_util::GetStringUTF16(
+        is_reload ? IDS_BEFORERELOAD_APP_MESSAGEBOX_TITLE
+                  : IDS_BEFOREUNLOAD_APP_MESSAGEBOX_TITLE);
   } else {
     title = l10n_util::GetStringUTF16(is_reload
                                           ? IDS_BEFORERELOAD_MESSAGEBOX_TITLE
                                           : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE);
   }
+  const std::u16string message =
+      l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE);
 
   extensions_client_->OnDialogOpened(web_contents);
 
@@ -256,7 +237,9 @@
       web_contents, &javascript_dialog_extra_data_, title,
       content::JAVASCRIPT_DIALOG_TYPE_CONFIRM, message,
       std::u16string(),  // default_prompt_text
-      ShouldDisplaySuppressCheckbox(extra_data), type,
+      ShouldDisplaySuppressCheckbox(extra_data),
+      true,  // is_before_unload_dialog
+      is_reload,
       base::BindOnce(&AppModalDialogManager::OnDialogClosed,
                      base::Unretained(this), web_contents,
                      std::move(callback))));
diff --git a/components/javascript_dialogs/app_modal_dialog_manager.h b/components/javascript_dialogs/app_modal_dialog_manager.h
index 7957728..1fcff0a 100644
--- a/components/javascript_dialogs/app_modal_dialog_manager.h
+++ b/components/javascript_dialogs/app_modal_dialog_manager.h
@@ -13,7 +13,6 @@
 #include "base/memory/singleton.h"
 #include "components/javascript_dialogs/app_modal_dialog_controller.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace javascript_dialogs {
 
@@ -51,7 +50,6 @@
       content::RenderFrameHost* render_frame_host,
       bool is_reload,
       bool is_app,
-      absl::optional<std::u16string> app_name,
       DialogClosedCallback callback);
 
   // content::JavaScriptDialogManager:
diff --git a/components/javascript_dialogs/tab_modal_dialog_manager.cc b/components/javascript_dialogs/tab_modal_dialog_manager.cc
index b183c24..d47ce32 100644
--- a/components/javascript_dialogs/tab_modal_dialog_manager.cc
+++ b/components/javascript_dialogs/tab_modal_dialog_manager.cc
@@ -314,7 +314,7 @@
 
   return GetAppModalDialogManager()->RunBeforeUnloadDialogWithOptions(
       web_contents, render_frame_host, is_reload, delegate_->IsApp(),
-      delegate_->GetAppName(), std::move(callback));
+      std::move(callback));
 }
 
 bool TabModalDialogManager::HandleJavaScriptDialog(
diff --git a/components/javascript_dialogs/tab_modal_dialog_manager_delegate.h b/components/javascript_dialogs/tab_modal_dialog_manager_delegate.h
index d6e3ee63..9b1330c 100644
--- a/components/javascript_dialogs/tab_modal_dialog_manager_delegate.h
+++ b/components/javascript_dialogs/tab_modal_dialog_manager_delegate.h
@@ -10,7 +10,6 @@
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace javascript_dialogs {
 
@@ -48,9 +47,6 @@
 
   // Should return true if this web contents is an app window, such as a PWA.
   virtual bool IsApp() = 0;
-
-  // If `IsApp` returns true, then this returns the app name.
-  virtual absl::optional<std::u16string> GetAppName() = 0;
 };
 
 }  // namespace javascript_dialogs
diff --git a/components/javascript_dialogs_strings.grdp b/components/javascript_dialogs_strings.grdp
index e175be0..fcb4999 100644
--- a/components/javascript_dialogs_strings.grdp
+++ b/components/javascript_dialogs_strings.grdp
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <grit-part>
- 
+
   <!-- JavaScript Dialog Box strings -->
   <message name="IDS_JAVASCRIPT_MESSAGEBOX_TITLE" desc="Title for JavaScript prompt and confirm originating from a webpage">
     <ph name="SITE">$1<ex>http://www.google.com</ex></ph> says
@@ -23,27 +23,15 @@
   <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog.">
     Leave site?
   </message>
-  <message name="IDS_BEFOREUNLOAD_APP_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog for apps.">
+ <message name="IDS_BEFOREUNLOAD_APP_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog for apps.">
     Leave app?
   </message>
-  <message name="IDS_BEFOREUNLOAD_QUIT_APP_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog for apps.">
-    Quit <ph name="APP">$1<ex>Google Chat</ex></ph>?
-  </message>
   <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL" desc="The text on the button which navigates the user away from the page.">
     Leave
   </message>
-  <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_QUIT_BUTTON_LABEL" desc="The text on the button which closes the app window.">
-    Quit
-  </message>
-  <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_HIDE_BUTTON_LABEL" desc="The text on the button which hides the app window.">
-    Hide
-  </message>
   <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE" desc="Body text in a dialog asking the user to confirm that they want to leave or reload a website.">
     Changes you made may not be saved.
   </message>
-  <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE_WITH_HIDE" desc="Body text in a dialog asking the user to confirm that they want to quit a web app, and gives the user the option to hide the app instead.">
-    To continue running this application in the background, hide it.
-  </message>
 
   <!-- "Before Reload" Dialog Box strings (same as "Before Unload" but when reloading rather than unloading the page -->
   <message name="IDS_BEFORERELOAD_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog for reloads.">
diff --git a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_HIDE_BUTTON_LABEL.png.sha1 b/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_HIDE_BUTTON_LABEL.png.sha1
deleted file mode 100644
index 5c3e877..0000000
--- a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_HIDE_BUTTON_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d8113599caa9df1e2f344b4b8b52ef94123ddeb2
\ No newline at end of file
diff --git a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE_WITH_HIDE.png.sha1 b/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE_WITH_HIDE.png.sha1
deleted file mode 100644
index f0db08c..0000000
--- a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE_WITH_HIDE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-97b0433bc7a6e87f29f3266d7b7db864988f51fa
\ No newline at end of file
diff --git a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_QUIT_BUTTON_LABEL.png.sha1 b/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_QUIT_BUTTON_LABEL.png.sha1
deleted file mode 100644
index fbd371a3..0000000
--- a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_MESSAGEBOX_QUIT_BUTTON_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1f42a725bb4447319718ab79585c5ef0d4c0e477
\ No newline at end of file
diff --git a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_QUIT_APP_MESSAGEBOX_TITLE.png.sha1 b/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_QUIT_APP_MESSAGEBOX_TITLE.png.sha1
deleted file mode 100644
index 1fbd58b..0000000
--- a/components/javascript_dialogs_strings_grdp/IDS_BEFOREUNLOAD_QUIT_APP_MESSAGEBOX_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-8c8443727b40a1e1a84067dff6b636e7123c6652
\ No newline at end of file
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md
index c5fa7ad..ecd1cf5 100644
--- a/components/onc/docs/onc_spec.md
+++ b/components/onc/docs/onc_spec.md
@@ -1343,6 +1343,14 @@
 	* WiFi only. A list of alternative subject names to be matched against the
     alternative subject name of an authentication server certificate.
 
+* **DomainSuffixMatch**
+    * (optional) - **array of string**
+    * WiFi only. A list of constraints for the server domain name. If set, the
+      entries will be used as suffix match requirements against the DNS name
+      element(s) of the alternative subject name of an authentication server
+      certificate. When multiple match strings are specified, a match with any one
+      of the values is considered a sufficient match for the server certificate.
+
 * **TLSVersionMax**
     * (optional) - **string**
     * Sets the maximum TLS protocol version used by the OS for EAP.
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc
index 80b9684..8af2d627 100644
--- a/components/onc/onc_constants.cc
+++ b/components/onc/onc_constants.cc
@@ -307,6 +307,7 @@
 namespace eap {
 const char kAnonymousIdentity[] = "AnonymousIdentity";
 const char kAutomatic[] = "Automatic";
+const char kDomainSuffixMatch[] = "DomainSuffixMatch";
 const char kEAP_AKA[] = "EAP-AKA";
 const char kEAP_FAST[] = "EAP-FAST";
 const char kEAP_SIM[] = "EAP-SIM";
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h
index 0e8d41c..4c842d8 100644
--- a/components/onc/onc_constants.h
+++ b/components/onc/onc_constants.h
@@ -319,6 +319,7 @@
 namespace eap {
 ONC_EXPORT extern const char kAnonymousIdentity[];
 ONC_EXPORT extern const char kAutomatic[];
+ONC_EXPORT extern const char kDomainSuffixMatch[];
 ONC_EXPORT extern const char kEAP_AKA[];
 ONC_EXPORT extern const char kEAP_FAST[];
 ONC_EXPORT extern const char kEAP_SIM[];
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 0b95b51..00b1af62 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -66,7 +66,7 @@
 
   <!-- Accuracy Tip strings -->
   <message name="IDS_PAGE_INFO_ACCURACY_TIP_TITLE" desc="Message to display in the page info bubble when the page you are on triggered an accuracy tip.">
-    Is this website accurate?
+    Take a moment to consider accuracy
   </message>
   <message name="IDS_PAGE_INFO_ACCURACY_TIP_LEARN_MORE_BUTTON" desc="Text of button to learn more about inaccurate pages. Shown on the accuracy tip page info bubble.">
     Learn more
diff --git a/components/page_info_strings_grdp/IDS_PAGE_INFO_ACCURACY_TIP_TITLE.png.sha1 b/components/page_info_strings_grdp/IDS_PAGE_INFO_ACCURACY_TIP_TITLE.png.sha1
index bfb8b6c..5570e769 100644
--- a/components/page_info_strings_grdp/IDS_PAGE_INFO_ACCURACY_TIP_TITLE.png.sha1
+++ b/components/page_info_strings_grdp/IDS_PAGE_INFO_ACCURACY_TIP_TITLE.png.sha1
@@ -1 +1 @@
-fc83a4960d9fd91e5b8a5a02b8253709950cc347
\ No newline at end of file
+1706229775a88447796a66b5b471928b66b395fa
\ No newline at end of file
diff --git a/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc b/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
index e441f0f2..608ab7f 100644
--- a/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
+++ b/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "components/autofill/core/common/gaia_id_hash.h"
-#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/mock_password_store_interface.h"
 #include "components/password_manager/core/browser/mock_smart_bubble_stats_store.h"
 #include "components/password_manager/core/browser/password_form.h"
 #include "components/password_manager/core/browser/statistics_table.h"
@@ -52,19 +52,23 @@
   FakePasswordManagerClient() = default;
   ~FakePasswordManagerClient() override = default;
 
-  void set_profile_store(PasswordStore* store) { profile_store_ = store; }
-  void set_account_store(PasswordStore* store) { account_store_ = store; }
+  void set_profile_store(PasswordStoreInterface* store) {
+    profile_store_ = store;
+  }
+  void set_account_store(PasswordStoreInterface* store) {
+    account_store_ = store;
+  }
 
  private:
-  PasswordStore* GetProfilePasswordStore() const override {
+  PasswordStoreInterface* GetProfilePasswordStoreInterface() const override {
     return profile_store_;
   }
-  PasswordStore* GetAccountPasswordStore() const override {
+  PasswordStoreInterface* GetAccountPasswordStoreInterface() const override {
     return account_store_;
   }
 
-  PasswordStore* profile_store_ = nullptr;
-  PasswordStore* account_store_ = nullptr;
+  PasswordStoreInterface* profile_store_ = nullptr;
+  PasswordStoreInterface* account_store_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(FakePasswordManagerClient);
 };
@@ -130,12 +134,10 @@
       : form_digest_(PasswordForm::Scheme::kHtml,
                      kTestHttpURL,
                      GURL(kTestHttpURL)) {
-    profile_mock_store_ = new MockPasswordStore;
-    profile_mock_store_->Init(/*prefs=*/nullptr);
+    profile_mock_store_ = new MockPasswordStoreInterface;
     client_.set_profile_store(profile_mock_store_.get());
 
-    account_mock_store_ = new MockPasswordStore;
-    account_mock_store_->Init(/*prefs=*/nullptr);
+    account_mock_store_ = new MockPasswordStoreInterface;
     client_.set_account_store(account_mock_store_.get());
 
     feature_list_.InitAndEnableFeature(
@@ -144,10 +146,7 @@
         form_digest_, &client_, /*should_migrate_http_passwords=*/false);
   }
 
-  ~MultiStoreFormFetcherTest() override {
-    profile_mock_store_->ShutdownOnUIThread();
-    account_mock_store_->ShutdownOnUIThread();
-  }
+  ~MultiStoreFormFetcherTest() override = default;
 
   void SetUp() override {
     ON_CALL(*profile_mock_store_, GetSmartBubbleStatsStore)
@@ -174,8 +173,8 @@
   PasswordFormDigest form_digest_;
   std::unique_ptr<MultiStoreFormFetcher> form_fetcher_;
   MockConsumer consumer_;
-  scoped_refptr<MockPasswordStore> profile_mock_store_;
-  scoped_refptr<MockPasswordStore> account_mock_store_;
+  scoped_refptr<MockPasswordStoreInterface> profile_mock_store_;
+  scoped_refptr<MockPasswordStoreInterface> account_mock_store_;
   testing::NiceMock<MockSmartBubbleStatsStore> mock_smart_bubble_stats_store;
   FakePasswordManagerClient client_;
 
diff --git a/components/password_manager/core/browser/password_form.cc b/components/password_manager/core/browser/password_form.cc
index 300e2da..4c5de48 100644
--- a/components/password_manager/core/browser/password_form.cc
+++ b/components/password_manager/core/browser/password_form.cc
@@ -249,7 +249,7 @@
   return !password_value.empty() || !new_password_value.empty();
 }
 
-bool PasswordForm::IsInsecureCredential(InsecureType type) {
+bool PasswordForm::IsInsecureCredential(InsecureType type) const {
   return password_issues.find(type) != password_issues.end();
 }
 
diff --git a/components/password_manager/core/browser/password_form.h b/components/password_manager/core/browser/password_form.h
index 821371d..7a424b34 100644
--- a/components/password_manager/core/browser/password_form.h
+++ b/components/password_manager/core/browser/password_form.h
@@ -402,7 +402,7 @@
 
   // Utility method to check whether the form represents an insecure credential
   // of insecure type `type`.
-  bool IsInsecureCredential(InsecureType type);
+  bool IsInsecureCredential(InsecureType type) const;
 
   PasswordForm();
   PasswordForm(const PasswordForm& other);
diff --git a/components/password_manager/core/browser/password_manager_client_helper.cc b/components/password_manager/core/browser/password_manager_client_helper.cc
index 744c220..d063967 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper.cc
@@ -4,14 +4,12 @@
 
 #include "components/password_manager/core/browser/password_manager_client_helper.h"
 
-#include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_feature_manager.h"
 #include "components/password_manager/core/browser/password_form_manager_for_ui.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/password_sync_util.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -22,6 +20,8 @@
 
 namespace {
 
+constexpr int kMaxMoveToAccountOffersForNonOptedInUser = 5;
+
 bool IsPrimaryAccountSignIn(const signin::IdentityManager& identity_manager,
                             const std::u16string& username,
                             const std::string& signon_realm) {
@@ -125,14 +125,9 @@
           submitted_manager.GetPendingCredentials().signon_realm)) {
     return false;
   }
-  int max_move_to_account_offers_for_non_opted_in_user =
-      base::GetFieldTrialParamByFeatureAsInt(
-          features::kEnablePasswordsAccountStorage,
-          features::kMaxMoveToAccountOffersForNonOptedInUser,
-          features::kMaxMoveToAccountOffersForNonOptedInUserDefaultValue);
   return feature_manager->IsOptedInForAccountStorage() ||
          feature_manager->GetMoveOfferedToNonOptedInUserCount() <
-             max_move_to_account_offers_for_non_opted_in_user;
+             kMaxMoveToAccountOffersForNonOptedInUser;
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_client_helper_unittest.cc b/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
index 4c985413..8c5c3c3 100644
--- a/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -217,9 +216,8 @@
 TEST_F(PasswordManagerClientHelperTest,
        NoPromptToMoveForNonOptedInUserIfRefusedTooManyTimes) {
   base::test::ScopedFeatureList account_storage_feature;
-  account_storage_feature.InitAndEnableFeatureWithParameters(
-      features::kEnablePasswordsAccountStorage,
-      {{features::kMaxMoveToAccountOffersForNonOptedInUser, "1"}});
+  account_storage_feature.InitAndEnableFeature(
+      features::kEnablePasswordsAccountStorage);
   ON_CALL(*client()->GetPasswordFeatureManager(),
           ShouldShowAccountStorageBubbleUi)
       .WillByDefault(Return(true));
@@ -236,10 +234,10 @@
   helper()->NotifySuccessfulLoginWithExistingPassword(
       CreateFormManager(&form, /*is_movable=*/true));
 
-  // If the previous move was refused and the max is 1, shouldn't offer anymore.
+  // If the previous 5 moves were refused, shouldn't offer anymore.
   EXPECT_CALL(*client()->GetPasswordFeatureManager(),
               GetMoveOfferedToNonOptedInUserCount)
-      .WillOnce(Return(1));
+      .WillOnce(Return(5));
   EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount).Times(0);
   helper()->NotifySuccessfulLoginWithExistingPassword(
       CreateFormManager(&form, /*is_movable=*/true));
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.cc b/components/password_manager/core/browser/password_manager_metrics_util.cc
index a047b942..07b4fdd 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
 #include "components/autofill/core/common/password_generation_util.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 
 using autofill::password_generation::PasswordGenerationType;
 
@@ -86,9 +85,6 @@
 
 void LogMoveUIDismissalReason(UIDismissalReason reason,
                               PasswordAccountStorageUserState user_state) {
-  DCHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kEnablePasswordsAccountStorage));
-
   base::UmaHistogramEnumeration("PasswordManager.MoveUIDismissalReason", reason,
                                 NUM_UI_RESPONSES);
 
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.cc b/components/password_manager/core/browser/sync/password_model_type_controller.cc
index 81c7b67..690537e 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -70,7 +70,7 @@
   identity_manager_->AddObserver(this);
 
   DCHECK_EQ(
-      !!base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage),
+      base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage),
       !!account_password_store_for_cleanup);
   if (base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage)) {
     // Note: Right now, we're still in the middle of SyncService initialization,
@@ -81,10 +81,6 @@
         FROM_HERE, base::BindOnce(&PasswordModelTypeController::MaybeClearStore,
                                   weak_ptr_factory_.GetWeakPtr(),
                                   account_password_store_for_cleanup));
-  } else {
-    // If the feature flag is disabled, clear any related prefs that might still
-    // be around.
-    features_util::ClearAccountStorageSettingsForAllUsers(pref_service_);
   }
 }
 
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 667446e..36f7f4b 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -522,15 +522,15 @@
       }
 
       // Passwords or insecure credentials aren't identical.
-      // TODO(crbug.com/1230631): Make sure that if a phished entry exists
-      // locally, it is uploaded and merged with the remote password issues.
       if (ConvertToBaseTime(remote_password_specifics.date_created()) <
               local_password_form.date_created ||
           (AreLocalAndRemotePasswordsEqualExcludingIssues(
                remote_password_specifics, local_password_form) &&
-           !remote_password_specifics.has_password_issues())) {
-        // Either the local password is more recent, or they are equal but local
-        // password has security issues - update the processor.
+           local_password_form.IsInsecureCredential(InsecureType::kPhished))) {
+        // Either the local password is more recent, or they are equal but the
+        // local password has been marked as phished. While all other types of
+        // issues are easy to recompute (e.g. via Password Check) phished
+        // entries are only found locally, so persisting them is important.
         change_processor()->Put(
             /*storage_key=*/base::NumberToString(primary_key.value()),
             std::move(local_form_entity_data), metadata_change_list.get());
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 79c29ad..2b8cfa7b 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -1330,13 +1330,15 @@
 }
 
 TEST_F(PasswordSyncBridgeTest,
-       EqualPasswordsDifferentInsecureCredentialsDuringMerge) {
+       ShouldUploadLocalWhenEqualPasswordsAndLocalPhishedDuringMerge) {
   const int kPrimaryKey = 1000;
   // Test that during merge when Passwords are equal but have different
-  // insecure credentials, local data get updated.
+  // insecure credentials, remote data gets updated if the local password
+  // has been marked as phished.
   const std::string kStorageKey = "1000";
+  const std::vector<InsecureType> kLocalIssuesTypes = {InsecureType::kPhished};
   const PasswordForm kForm =
-      MakePasswordFormWithIssues(kSignonRealm1, {InsecureType::kLeaked});
+      MakePasswordFormWithIssues(kSignonRealm1, kLocalIssuesTypes);
   std::vector<InsecureType> kRemoteIssuesTypes = {InsecureType::kReused,
                                                   InsecureType::kWeak};
 
@@ -1346,17 +1348,14 @@
       CreateSpecificsWithSignonRealmAndIssues(kSignonRealm1,
                                               kRemoteIssuesTypes);
 
-  // Test that UpdateLoginSync is invoked with remote insecure credentials.
-  PasswordForm kExpectedIssuesForm =
-      MakePasswordFormWithIssues(kSignonRealm1, kRemoteIssuesTypes);
-  EXPECT_CALL(
-      *mock_password_store_sync(),
-      UpdateLoginSync(
-          FormHasPasswordIssues(kExpectedIssuesForm.password_issues), _));
-
   syncer::EntityChangeList entity_change_list;
   entity_change_list.push_back(syncer::EntityChange::CreateAdd(
       kStorageKey, SpecificsToEntity(specifics)));
+
+  EXPECT_CALL(
+      mock_processor(),
+      Put(kStorageKey, EntityDataHasSecurityIssueTypes(kLocalIssuesTypes), _));
+
   absl::optional<syncer::ModelError> error = bridge()->MergeSyncData(
       bridge()->CreateMetadataChangeList(), std::move(entity_change_list));
   EXPECT_FALSE(error);
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
index 1c370b8..3a9a70b 100644
--- a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
+++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -223,8 +223,8 @@
 
 InsecureCredentialsManager::InsecureCredentialsManager(
     SavedPasswordsPresenter* presenter,
-    scoped_refptr<PasswordStore> profile_store,
-    scoped_refptr<PasswordStore> account_store)
+    scoped_refptr<PasswordStoreInterface> profile_store,
+    scoped_refptr<PasswordStoreInterface> account_store)
     : presenter_(presenter),
       profile_store_(std::move(profile_store)),
       account_store_(std::move(account_store)) {
@@ -394,7 +394,7 @@
   }
 }
 
-PasswordStore& InsecureCredentialsManager::GetStoreFor(
+PasswordStoreInterface& InsecureCredentialsManager::GetStoreFor(
     const PasswordForm& form) {
   return form.IsUsingAccountStore() ? *account_store_ : *profile_store_;
 }
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
index 2545f1d0..542ca4e4 100644
--- a/components/password_manager/core/browser/ui/insecure_credentials_manager.h
+++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -21,7 +21,7 @@
 #include "build/build_config.h"
 #include "components/password_manager/core/browser/insecure_credentials_table.h"
 #include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
-#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_store_interface.h"
 #include "components/password_manager/core/browser/ui/credential_utils.h"
 #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
 #include "url/gurl.h"
@@ -156,8 +156,8 @@
 
   InsecureCredentialsManager(
       SavedPasswordsPresenter* presenter,
-      scoped_refptr<PasswordStore> profile_store,
-      scoped_refptr<PasswordStore> account_store = nullptr);
+      scoped_refptr<PasswordStoreInterface> profile_store,
+      scoped_refptr<PasswordStoreInterface> account_store = nullptr);
   ~InsecureCredentialsManager() override;
 
   void Init();
@@ -224,15 +224,15 @@
 
   // Returns the `profile_store_` or `account_store_` if `form` is stored in the
   // profile store of the account store accordingly.
-  PasswordStore& GetStoreFor(const PasswordForm& form);
+  PasswordStoreInterface& GetStoreFor(const PasswordForm& form);
 
   // A weak handle to the presenter used to join the list of insecure
   // credentials with saved passwords. Needs to outlive this instance.
   SavedPasswordsPresenter* presenter_ = nullptr;
 
   // The password stores containing the insecure credentials.
-  scoped_refptr<PasswordStore> profile_store_;
-  scoped_refptr<PasswordStore> account_store_;
+  scoped_refptr<PasswordStoreInterface> profile_store_;
+  scoped_refptr<PasswordStoreInterface> account_store_;
 
   // Cache of the most recently obtained insecure credentials.
   std::vector<InsecureCredential> insecure_credentials_;
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index fbca5b9..3660601 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -194,14 +194,6 @@
 const char kPasswordChangeInSettingsWithForcedWarningForEverySite[] =
     "should_force_warning_for_every_site_in_settings";
 
-// Number of times the user can refuse an offer to move a password to the
-// account before Chrome stops offering this flow. Only applies to users who
-// haven't gone through the opt-in flow for passwords account storage.
-const char kMaxMoveToAccountOffersForNonOptedInUser[] =
-    "max_move_to_account_offers_for_non_opted_in_user";
-
-const int kMaxMoveToAccountOffersForNonOptedInUserDefaultValue = 5;
-
 }  // namespace features
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 6df9a98..a9da8c1 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -63,10 +63,6 @@
     kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission[];
 extern const char kPasswordChangeInSettingsWithForcedWarningForEverySite[];
 
-// |kEnablePasswordsAccountStorage| variations.
-extern const char kMaxMoveToAccountOffersForNonOptedInUser[];
-extern const int kMaxMoveToAccountOffersForNonOptedInUserDefaultValue;
-
 }  // namespace features
 
 }  // namespace password_manager
diff --git a/components/password_manager/ios/password_suggestion_helper.mm b/components/password_manager/ios/password_suggestion_helper.mm
index f4a70120..e93e97dd 100644
--- a/components/password_manager/ios/password_suggestion_helper.mm
+++ b/components/password_manager/ios/password_suggestion_helper.mm
@@ -39,6 +39,10 @@
   // manager.
   BOOL _sentPasswordFormToPasswordManager;
 
+  // YES indicates that suggestions from the password manager have been
+  // processed.
+  BOOL _processedPasswordSuggestions;
+
   // The completion to inform the caller of -checkIfSuggestionsAvailableForForm:
   // that suggestions are available for a given form and field.
   PasswordSuggestionsAvailableCompletion _suggestionsAvailableCompletion;
@@ -113,7 +117,8 @@
   }
 
   BOOL isPasswordField = [formQuery isOnPasswordField];
-  if (!_sentPasswordFormToPasswordManager && [formQuery hasFocusType]) {
+  if ([formQuery hasFocusType] &&
+      (!_sentPasswordFormToPasswordManager || !_processedPasswordSuggestions)) {
     // Save the callback until fill data is ready.
     _suggestionsAvailableCompletion = ^(const AccountSelectFillData* fillData) {
       completion(!fillData ? NO
@@ -121,8 +126,10 @@
                                  formQuery.uniqueFormID,
                                  formQuery.uniqueFieldID, isPasswordField));
     };
-    // Form extraction is required for this check.
-    [self.delegate suggestionHelperShouldTriggerFormExtraction:self];
+    if (!_sentPasswordFormToPasswordManager) {
+      // Form extraction is required for this check.
+      [self.delegate suggestionHelperShouldTriggerFormExtraction:self];
+    }
     return;
   }
 
@@ -138,11 +145,13 @@
 - (void)resetForNewPage {
   _fillData.Reset();
   _sentPasswordFormToPasswordManager = NO;
+  _processedPasswordSuggestions = NO;
   _suggestionsAvailableCompletion = nil;
 }
 
 - (void)processWithPasswordFormFillData:(const PasswordFormFillData&)formData {
   _fillData.Add(formData);
+  _processedPasswordSuggestions = YES;
 
   if (_suggestionsAvailableCompletion) {
     _suggestionsAvailableCompletion(&_fillData);
@@ -150,6 +159,13 @@
   }
 }
 - (void)processWithNoSavedCredentials {
+  // Only update |_processedPasswordSuggestions| if PasswordManager was
+  // queried for some forms. This is needed to protect against a case when
+  // there are no forms on the pageload and they are added dynamically.
+  if (_sentPasswordFormToPasswordManager) {
+    _processedPasswordSuggestions = YES;
+  }
+
   if (_suggestionsAvailableCompletion) {
     _suggestionsAvailableCompletion(nullptr);
   }
diff --git a/components/policy/test_support/.style.yapf b/components/policy/test_support/.style.yapf
new file mode 100644
index 0000000..c8016337
--- /dev/null
+++ b/components/policy/test_support/.style.yapf
@@ -0,0 +1,4 @@
+[style]
+# Old python files should follow the old style, as mentioned in
+# https://chromium.googlesource.com/chromium/src/+/main/styleguide/python/python.md#our-previous-python-style.
+indent_width = 2
diff --git a/components/policy/test_support/policy_testserver.py b/components/policy/test_support/policy_testserver.py
index 48c9555d..c78fbfd7 100644
--- a/components/policy/test_support/policy_testserver.py
+++ b/components/policy/test_support/policy_testserver.py
@@ -92,6 +92,8 @@
 import device_management_backend_pb2 as dm
 import cloud_policy_pb2 as cp
 import policy_common_definitions_pb2 as cd
+import private_membership_pb2 as psm
+import private_membership_rlwe_pb2 as psm_rlwe
 
 # Policy for extensions is not supported on Android.
 try:
@@ -109,9 +111,9 @@
 # This is currently OK because policy_testserver.py's support for certificate
 # provisioning is only used in Tast test for now.
 try:
-    from OpenSSL import crypto
+  from OpenSSL import crypto
 except ImportError:
-    crypto = None
+  crypto = None
 
 # ASN.1 object identifier for PKCS#1/RSA.
 PKCS1_RSA_OID = b'\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01'
@@ -120,6 +122,10 @@
 # for the register request.
 KIOSK_MACHINE_IDS = [ 'KIOSK' ]
 
+# List of all IDs that will be used to construct PSM ID, and have membership.
+PSM_MEMBERSHIP_SERIAL_NUMBER_IDS = ["111111"]
+PSM_MEMBERSHIP_BRAND_CODES = ["TEST"]
+
 # Dictionary containing base64-encoded policy signing keys plus per-domain
 # signatures. Format is:
 # {
@@ -377,6 +383,9 @@
       response = self.ProcessPolicy(rmsg, request_type)
     elif request_type == 'enterprise_check':
       response = self.ProcessAutoEnrollment(rmsg.auto_enrollment_request)
+    elif request_type == 'enterprise_psm_check':
+      response = self.ProcessPsmAutoEnrollment(
+          rmsg.private_set_membership_request)
     elif request_type == 'device_initial_enrollment_state':
       response = self.ProcessDeviceInitialEnrollmentState(
           rmsg.device_initial_enrollment_state_request)
@@ -702,6 +711,107 @@
     response.auto_enrollment_response.CopyFrom(auto_enrollment_response)
     return (200, response)
 
+  def GetPsmMembershipResponse(self, encrypted_id):
+    """Retrieves the PSM membership for a given encrypted_id.
+
+    Args:
+      encrypted_id: A string which contains an encrypted ID.
+
+    Returns a boolean:
+      1. True, if encrypted_id has a PSM membership.
+      2. False, otherwise.
+    """
+    for serial_number in PSM_MEMBERSHIP_SERIAL_NUMBER_IDS:
+      for brand_code in PSM_MEMBERSHIP_BRAND_CODES:
+        psm_id = '{}/{}'.format(brand_code.encode('hex'), serial_number)
+        if psm_id == encrypted_id:
+          return True
+    return False
+
+  def GetPsmRlweOprfResponse(self, oprf_request):
+    """Retrieves the fake PSM RLWE OPRF response for a given PSM OPRF request.
+
+    Args:
+      oprf_request: A PrivateMembershipRlweOprfRequest proto message.
+
+    Returns:
+    A PrivateMembershipRlweOprfResponse proto message which will include the
+    passed encrypted_id, from the oprf_request, inside the
+    doubly_encrypted_ids field.
+    """
+    oprf_response = psm_rlwe.PrivateMembershipRlweOprfResponse()
+    encrypted_id = psm.DoublyEncryptedId()
+    encrypted_id.queried_encrypted_id = oprf_request.encrypted_ids[0]
+    oprf_response.doubly_encrypted_ids.append(encrypted_id)
+    return oprf_response
+
+  def GetPsmRlweQueryResponse(self, query_request):
+    """Retrieves the fake PSM RLWE query response for a given PSM query request.
+
+    Args:
+      query_request: A PrivateMembershipRlweQueryRequest proto message.
+
+    Returns:
+    A PrivateMembershipRlweQueryResponse proto message which will include the
+    following:
+        1. The first passed encrypted_id, from queried_encrypted_id field,
+        inside PrivateMembershipRlwePirResponse.queried_encrypted_id field.
+        2. The membership response as a signal data inside
+        PirResponse.plaintext_entry_size  field.
+    """
+    query_response = psm_rlwe.PrivateMembershipRlweQueryResponse()
+    encrypted_id = query_request.queries[0].queried_encrypted_id
+    pir_response = psm_rlwe.PrivateMembershipRlwePirResponse()
+    pir_response.queried_encrypted_id = encrypted_id
+    pir_response.pir_response.plaintext_entry_size =\
+        self.GetPsmMembershipResponse(encrypted_id)
+    query_response.pir_responses.append(pir_res)
+    return query_response
+
+  def ProcessPsmAutoEnrollment(self, msg):
+    """Handles an auto-enrollment PSM check request.
+
+    The reply depends on which PSM request phases is received, as follows:
+      1. In case RLWE OPRF request is filled, replies by sending OPRF response
+      that contain the first received encrypted id.
+      2. In case RLWE Query request is filled, replies by sending Query response
+      that contain the first queried encrypted id. Also, sending out a signal
+      data (inside PirResponse.plaintext_entry_size) to indicate whether there
+      is a membership or not, depending on the received encrypted id.
+      3. Otherwise, it will return an error.
+
+    These allow the client to pick the testing scenario it wants to simulate.
+
+    Args:
+      msg: The PrivateSetMembershipRequest message received from the client.
+
+    Returns:
+      A tuple of HTTP status code and response data to send to the client.
+    """
+    psm_response = dm.PrivateSetMembershipResponse()
+
+    rlwe_request = msg.rlwe_request
+
+    if rlwe_request.HasField('oprf_request'):
+      oprf_request = rlwe_request.oprf_request
+      if not len(oprf_request.encrypted_ids):
+        return (400, 'PSM RLWE OPRF request must contains encrypted_ids field')
+      psm_response.rlwe_response.oprf_response.CopyFrom(
+          self.GetPsmRlweOprfResponse(oprf_request))
+    elif rlwe_request.HasField('query_request'):
+      query_request = rlwe_request.query_request
+      if not len(query_request.queries):
+        return (400, 'PSM RLWE query request must contains queries field')
+      psm_response.rlwe_response.query_response.CopyFrom(
+          self.GetPsmRlweQueryResponse(query_request))
+    else:
+      return (400,
+              'PSM RLWE oprf_request, or query_request fields must be filled')
+
+    response = dm.DeviceManagementResponse()
+    response.private_set_membership_response.CopyFrom(psm_response)
+    return (200, response)
+
   def ProcessDeviceInitialEnrollmentState(self, msg):
     """Handles a device initial enrollment state request.
 
diff --git a/components/remote_cocoa/app_shim/alert.mm b/components/remote_cocoa/app_shim/alert.mm
index c04246d..dee0a10 100644
--- a/components/remote_cocoa/app_shim/alert.mm
+++ b/components/remote_cocoa/app_shim/alert.mm
@@ -90,13 +90,7 @@
         [_alert addButtonWithTitle:l10n_util::FixUpWindowsStyleLabel(
                                        *params->secondary_button_text)];
     [other setKeyEquivalent:@"\e"];
-
-    if (params->secondary_button_with_hide_text) {
-      [_alert addButtonWithTitle:l10n_util::FixUpWindowsStyleLabel(
-                                     *params->secondary_button_with_hide_text)];
-    }
   }
-
   if (params->check_box_text) {
     [_alert setShowsSuppressionButton:YES];
     NSString* suppression_title =
@@ -216,10 +210,6 @@
     case NSAlertSecondButtonReturn:  // Cancel
       _alertBridge->SendResultAndDestroy(AlertDisposition::SECONDARY_BUTTON);
       break;
-    case NSAlertThirdButtonReturn:  // Hide
-      _alertBridge->SendResultAndDestroy(AlertDisposition::SECONDARY_BUTTON);
-      [NSApp hide:nil];
-      break;
     case NSModalResponseStop:  // Window was closed underneath us
       _alertBridge->SendResultAndDestroy(AlertDisposition::CLOSE);
       break;
diff --git a/components/remote_cocoa/common/alert.mojom b/components/remote_cocoa/common/alert.mojom
index c323ef7..a544d4a 100644
--- a/components/remote_cocoa/common/alert.mojom
+++ b/components/remote_cocoa/common/alert.mojom
@@ -21,10 +21,6 @@
   // one button for this alert.
   mojo_base.mojom.String16? secondary_button_text;
 
-  // Text for a button that has the same functionality as the secondary button,
-  // but will also hide the NSApplication. If not set, it will not be shown.
-  mojo_base.mojom.String16? secondary_button_with_hide_text;
-
   // Default text for the text field. If not set, then there is no text field
   // for this alert.
   mojo_base.mojom.String16? text_field_text;
diff --git a/components/strings/components_strings_nl.xtb b/components/strings/components_strings_nl.xtb
index 8b98056..4d51798 100644
--- a/components/strings/components_strings_nl.xtb
+++ b/components/strings/components_strings_nl.xtb
@@ -96,6 +96,7 @@
 <translation id="129863573139666797"><ph name="BEGIN_LINK" />Probeer je cookies te wissen<ph name="END_LINK" /></translation>
 <translation id="1301324364792935241">Controleer je instellingen voor beveiligde DNS</translation>
 <translation id="1307966114820526988">Verouderde functies</translation>
+<translation id="1312803275555673949">Door welk bewijs wordt dit bevestigd?</translation>
 <translation id="131405271941274527"><ph name="URL" /> wil informatie sturen en ontvangen als je je telefoon tegen een NFC-apparaat houdt</translation>
 <translation id="1314509827145471431">Rechts inbinden</translation>
 <translation id="1319245136674974084">Niet meer vragen voor deze app</translation>
@@ -483,6 +484,7 @@
 <translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" />. Druk op Tab en vervolgens op Enter om je browsegeschiedenis, cookies, cache en meer te wissen in de Chrome-instellingen.</translation>
 <translation id="2650446666397867134">Toegang tot het bestand is geweigerd</translation>
 <translation id="2653659639078652383">Verzenden</translation>
+<translation id="2659158170294587313">Als je de app op de achtergrond wilt blijven uitvoeren, verberg je deze.</translation>
 <translation id="2660779039299703961">Gebeurtenis</translation>
 <translation id="2664887757054927933">{COUNT,plural, =0{Geen}=1{1 wachtwoord (voor <ph name="DOMAIN_LIST" />)}=2{2 wachtwoorden (voor <ph name="DOMAIN_LIST" />)}other{# wachtwoorden (voor <ph name="DOMAIN_LIST" />)}}</translation>
 <translation id="2666092431469916601">Boven</translation>
@@ -603,6 +605,7 @@
 <translation id="31207688938192855"><ph name="BEGIN_LINK" />Voer Verbindingsdiagnose uit<ph name="END_LINK" />.</translation>
 <translation id="3121994479408824897">Naar <ph name="DOMAIN" /></translation>
 <translation id="3137507986424712703">{COUNT,plural, =0{Geen}=1{inloggegevens voor één account}other{inloggegevens voor # accounts}}</translation>
+<translation id="314433506352260835"><ph name="APP" /> sluiten?</translation>
 <translation id="3145945101586104090">Kan reactie niet decoderen</translation>
 <translation id="3150653042067488994">Tijdelijke serverfout</translation>
 <translation id="3154506275960390542">Deze pagina bevat een formulier dat mogelijk niet beveiligd wordt verzonden. Gegevens die je verzendt, kunnen tijdens de overdracht worden bekeken door anderen of kunnen worden aangepast door een aanvaller om te wijzigen wat de server ontvangt.</translation>
@@ -635,6 +638,7 @@
 <translation id="3240791268468473923">Pagina geopend waarop staat dat er geen overeenkomende inloggegevens zijn voor beveiligde betaling</translation>
 <translation id="3249845759089040423">Groovy</translation>
 <translation id="3252266817569339921">Frans</translation>
+<translation id="3257954757204451555">Van wie heb je deze informatie?</translation>
 <translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om snel een nieuwe afspraak in Google Agenda te maken</translation>
 <translation id="3266793032086590337">Waarde (conflict)</translation>
 <translation id="3268451620468152448">Geopende tabbladen</translation>
@@ -1032,6 +1036,7 @@
 <translation id="455113658016510503">A9</translation>
 <translation id="4558551763791394412">Probeer je extensies uit te zetten.</translation>
 <translation id="4559332380232738994">10x11</translation>
+<translation id="4567686777917670400">Je beheerder kan je browserinstellingen op afstand wijzigen. Activiteit op dit apparaat kan ook buiten Chromium worden beheerd. <ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /></translation>
 <translation id="457875822857220463">Bezorging</translation>
 <translation id="4579056131138995126">Personal (envelop)</translation>
 <translation id="4582204425268416675">Pas verwijderen</translation>
@@ -1523,6 +1528,7 @@
 <translation id="6337534724793800597">Beleid filteren op naam</translation>
 <translation id="6349101878882523185"><ph name="APP_NAME" /> installeren</translation>
 <translation id="6353505687280762741">{COUNT,plural, =0{Geen}=1{1 wachtwoord (voor <ph name="DOMAIN_LIST" />, gesynchroniseerd)}=2{2 wachtwoorden (voor <ph name="DOMAIN_LIST" />, gesynchroniseerd)}other{# wachtwoorden (voor <ph name="DOMAIN_LIST" />, gesynchroniseerd)}}</translation>
+<translation id="6355392890578844978">Deze browser wordt niet beheerd door een bedrijf of andere organisatie. Activiteit op dit apparaat kan buiten Chromium worden beheerd. <ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /></translation>
 <translation id="6358450015545214790">Wat betekent dit?</translation>
 <translation id="6361757823711327522">B7</translation>
 <translation id="6364095313648930329"><ph name="BEGIN_LINK" />Controleer de proxy, firewall en configuratie voor beveiligde DNS<ph name="END_LINK" /></translation>
@@ -1975,6 +1981,7 @@
 <translation id="7961015016161918242">Nooit</translation>
 <translation id="7966803981046576691">Type taakaccount</translation>
 <translation id="79682505114836835">De waarde <ph name="VALUE" /> is een ongeldige hexadecimale kleur.</translation>
+<translation id="7970392640816874403">Wat zeggen andere bronnen?</translation>
 <translation id="7976214039405368314">Te veel verzoeken</translation>
 <translation id="7977538094055660992">Uitvoerapparaat</translation>
 <translation id="7977894662897852582">Edp</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index 6f0807b..b69d6af 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -16,7 +16,7 @@
 <translation id="1036348656032585052">ఆఫ్ చేయి</translation>
 <translation id="1038106730571050514">సూచనలను చూపు</translation>
 <translation id="1038842779957582377">తెలియని పేరు</translation>
-<translation id="1041998700806130099">జాబ్ షీట్ సందేశం</translation>
+<translation id="1041998700806130099">జాబ్ షీట్ మెసేజ్‌</translation>
 <translation id="1048785276086539861">మీరు అదనపు గమనికలను ఎడిట్ చేసినప్పుడు, ఈ డాక్యుమెంట్ సింగిల్ పేజీ వీక్షణకు తిరిగి వస్తుంది</translation>
 <translation id="1050038467049342496">ఇతర యాప్‌లను మూసివేయండి</translation>
 <translation id="1055184225775184556">&amp;జోడించడాన్ని రద్దు చేయి</translation>
@@ -289,7 +289,7 @@
 <translation id="1915697529809968049">CVCకి బదులుగా Touch IDని ఉపయోగించాలా?</translation>
 <translation id="1916770123977586577">ఈ సైట్ విషయంలో మీరు అప్‌డేట్ చేసిన సెట్టింగ్‌లను వర్తింపజేయడానికి, ఈ పేజీని మళ్లీ లోడ్ చేయండి</translation>
 <translation id="1919345977826869612">యాడ్స్</translation>
-<translation id="1919367280705858090">నిర్దిష్ట ఎర్రర్ సందేశానికి సంబంధించిన సహాయం పొందండి</translation>
+<translation id="1919367280705858090">నిర్దిష్ట ఎర్రర్ మెసేజ్‌కు సంబంధించిన సహాయం పొందండి</translation>
 <translation id="192020519938775529">{COUNT,plural, =0{ఏమీ లేవు}=1{1 సైట్}other{# సైట్‌లు}}</translation>
 <translation id="1924727005275031552">కొత్త</translation>
 <translation id="1939175642807587452">నోటిఫికేషన్‌లను పంపడానికి సైట్ అనుమతి అడగవచ్చు</translation>
@@ -536,7 +536,7 @@
 <translation id="2835170189407361413">ఫారమ్‌ను క్లియర్ చేయి</translation>
 <translation id="2839501879576190149">ముందున్న సైట్ నకిలీది</translation>
 <translation id="2850739647070081192">ఆహ్వానం (ఎన్వలప్)</translation>
-<translation id="2856444702002559011">హ్యాకర్‌లు <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> నుండి మీ సమాచారాన్ని దొంగిలించడానికి ప్రయత్నిస్తూ ఉండవచ్చు (ఉదాహరణకు, పాస్‌వర్డ్‌లు, సందేశాలు లేదా క్రెడిట్ కార్డ్‌లు). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2856444702002559011">హ్యాకర్‌లు <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> నుండి మీ సమాచారాన్ని దొంగిలించడానికి ప్రయత్నిస్తూ ఉండవచ్చు (ఉదాహరణకు, పాస్‌వర్డ్‌లు, మెసేజ్‌లు లేదా క్రెడిట్ కార్డ్‌లు). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
 <translation id="2859806420264540918">ఈ సైట్ అనుచితమైన లేదా తప్పుదారి పట్టించే ప్రకటనలను చూపుతుంది.</translation>
 <translation id="287596039013813457">స్నేహపూర్వకమైనది</translation>
 <translation id="2876489322757410363">వెలుపలి అప్లికేషన్ ద్వారా చెల్లించడానికి అజ్ఞాత మోడ్ నుండి నిష్క్రమిస్తోంది. కొనసాగించాలా?</translation>
@@ -988,7 +988,7 @@
 <translation id="4348834659292907206"><ph name="SITE" />కు కనెక్షన్ సురక్షితం కాదు</translation>
 <translation id="4349531505348777662">మీరు మోసపూరితమైన సైట్‌లో మీ పాస్‌వర్డ్‌ను ఎంటర్ చేశారు. మీరు ఈ పాస్‌వర్డ్‌ను ఉపయోగించిన<ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, ఇతర సైట్‌లకు ఇప్పుడే వెళ్లి, మీ పాస్‌వర్డ్‌ను మార్చాల్సిందిగా Chrome సిఫార్సు చేస్తోంది.</translation>
 <translation id="4351060348582610152"><ph name="ORIGIN" /> సమీపంలోని బ్లూటూత్ పరికరాల కోసం స్కాన్ చేయాలనుకుంటోంది. కింది పరికరాలు కనుగొనబడ్డాయి:</translation>
-<translation id="4356973930735388585">ఈ సైట్‌లోని దాడి చేసేవారు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించడం కోసం లేదా తొలగించడం కోసం మీ కంప్యూటర్‌లో ప్రమాదకరమైన ప్రోగ్రామ్‌లను ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు.</translation>
+<translation id="4356973930735388585">ఈ సైట్‌లోని దాడి చేసేవారు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, మెసేజ్‌లు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించడం కోసం లేదా తొలగించడం కోసం మీ కంప్యూటర్‌లో ప్రమాదకరమైన ప్రోగ్రామ్‌లను ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు.</translation>
 <translation id="4358059973562876591">DnsOverHttpsMode విధానానికి సంబంధించి ఏర్పడిన ఎర్రర్ కారణంగా మీరు పేర్కొన్న టెంప్లేట్‌లను వర్తింపజేయడం వీలు కాకపోవచ్చు.</translation>
 <translation id="4358461427845829800">చెల్లింపు పద్ధతులను నిర్వహించండి...</translation>
 <translation id="4359160567981085931">మీరు మోసపూరితమైన సైట్‌లో మీ పాస్‌వర్డ్‌ను ఎంటర్ చేశారు. Chrome సహాయపడగలదు. మీ పాస్‌వర్డ్‌‌ను మార్చి, మీ ఖాతా ప్రమాదంలో ఉండవచ్చని Googleకు తెలియజేయడానికి, 'ఖాతాను సంరక్షించు'ను క్లిక్ చేయండి.</translation>
@@ -1188,7 +1188,7 @@
 <translation id="507130231501693183">మెయిల్‌బాక్స్ 4</translation>
 <translation id="5087286274860437796">ప్రస్తుతం సర్వర్ ప్రమాణపత్రం చెల్లదు.</translation>
 <translation id="5087580092889165836">కార్డ్‌ను జోడించు</translation>
-<translation id="5088142053160410913">ఆపరేటర్‌కు సందేశం పంపు</translation>
+<translation id="5088142053160410913">ఆపరేటర్‌కు మెసేజ్‌ పంపు</translation>
 <translation id="5089810972385038852">రాష్ట్రం</translation>
 <translation id="5093232627742069661">Z-ఫోల్డ్</translation>
 <translation id="5094747076828555589">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రాన్ని Chromium విశ్వసించలేదు. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కు అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
@@ -1350,7 +1350,7 @@
 <translation id="5624120631404540903">పాస్‌వర్డ్‌లను నిర్వహించండి</translation>
 <translation id="5629630648637658800">విధాన సెట్టింగ్‌లను లోడ్ చేయడంలో విఫలమైంది</translation>
 <translation id="5631439013527180824">చెల్లని పరికర నిర్వహణ టోకెన్</translation>
-<translation id="5633066919399395251"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ కంప్యూటర్‌లో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు.<ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="5633066919399395251"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, మెసేజ్‌లు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ కంప్యూటర్‌లో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు.<ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
 <translation id="563324245173044180">మోసపూరిత కంటెంట్ బ్లాక్ చేయబడింది.</translation>
 <translation id="5644090287519800334">1 వైపు ప్రింట్‌లో చిత్రాన్ని X అక్షంలో జరపు</translation>
 <translation id="5645854190134202180">రెండవ షిఫ్ట్</translation>
@@ -1608,7 +1608,7 @@
 <translation id="6626291197371920147">చెల్లుబాటయ్యే కార్డ్ నంబర్‌ను జోడించండి</translation>
 <translation id="6628463337424475685"><ph name="ENGINE" /> శోధన</translation>
 <translation id="6630043285902923878">USB పరికరాలను కనుగొంటోంది...</translation>
-<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ Macలో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, మెసేజ్‌లు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ Macలో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
 <translation id="663260587451432563">JIS B4</translation>
 <translation id="6643016212128521049">క్లియర్ చేయి</translation>
 <translation id="6645291930348198241">కుక్కీలను, సైట్ డేటాను యాక్సెస్ చేయాలనుకుంటోంది.</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index a30a76a..6e5567c 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -96,6 +96,7 @@
 <translation id="129863573139666797"><ph name="BEGIN_LINK" />Cookie-fayllarni tozalab ko‘ring<ph name="END_LINK" /></translation>
 <translation id="1301324364792935241">DNS sozlamalar himoyasini tekshiring</translation>
 <translation id="1307966114820526988">Eskirgan funksiyalar</translation>
+<translation id="1312803275555673949">Buning qaysi isboti bor ekan?</translation>
 <translation id="131405271941274527"><ph name="URL" /> sayti NFC orqali axborot almashinishga ruxsat soʻramoqda</translation>
 <translation id="1314509827145471431">Oʻng chekkasini belgilash</translation>
 <translation id="1319245136674974084">Bu ilova uchun boshqa soʻralmasin</translation>
@@ -485,6 +486,7 @@
 <translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome sozlamalari orqali brauzer tarixi, cookie fayllari, kesh va boshqa maʼlumotlarni tozalash uchun Enter tugmasini bosing</translation>
 <translation id="2650446666397867134">Faylga kirish taqiqlandi</translation>
 <translation id="2653659639078652383">Yuborish</translation>
+<translation id="2659158170294587313">Fonda ishlashda davom etishi uchun bu ilovani berkiting.</translation>
 <translation id="2660779039299703961">Hodisa</translation>
 <translation id="2664887757054927933">{COUNT,plural, =0{Hech qanday}=1{1 ta parol (<ph name="DOMAIN_LIST" /> uchun)}=2{2 ta parol (<ph name="DOMAIN_LIST" /> uchun)}other{# ta parol (<ph name="DOMAIN_LIST" /> uchun)}}</translation>
 <translation id="2666092431469916601">Tepaga</translation>
@@ -605,6 +607,7 @@
 <translation id="31207688938192855"><ph name="BEGIN_LINK" />Aloqa diagnostikasi bilan tekshirib ko‘ring<ph name="END_LINK" /></translation>
 <translation id="3121994479408824897"><ph name="DOMAIN" /> sahifasini ochish</translation>
 <translation id="3137507986424712703">{COUNT,plural, =0{Mavjud emas}=1{1 ta tizimga kirgan hisob axborotlari}other{# ta tizimga kirgan hisob axborotlari}}</translation>
+<translation id="314433506352260835"><ph name="APP" /> ilovasidan chiqasizmi?</translation>
 <translation id="3145945101586104090">Javobni dekodlab bo‘lmadi</translation>
 <translation id="3150653042067488994">Server vaqtinchalik xatosi</translation>
 <translation id="3154506275960390542">Bu sahifada himoyalanmagan forma mavjud. Unga to‘ldiriluvchi axborot boshqalarga ko‘rinishi va firibgarlar tomonidan o‘zgartirilishi mumkin.</translation>
@@ -638,6 +641,7 @@
 <translation id="3240791268468473923">Xavfsiz toʻlov maʼlumotlari ochilgan jadvaldagi maʼlumotlarga mos kelmadi</translation>
 <translation id="3249845759089040423">Jozibali</translation>
 <translation id="3252266817569339921">Fransuzcha</translation>
+<translation id="3257954757204451555">Bu axborot orqasida kim bor?</translation>
 <translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Taqvimda yangi tadbirni tez yaratish uchun avval Tab, keyin Enter tugmasini bosing</translation>
 <translation id="3266793032086590337">Qiymat (ziddiyatli)</translation>
 <translation id="3268451620468152448">Ochiq ichki oynalar</translation>
@@ -1035,6 +1039,7 @@
 <translation id="455113658016510503">A9</translation>
 <translation id="4558551763791394412">Brauzer kengaytmalarini o‘chirib qo‘yib, keyin tekshirib ko‘ring.</translation>
 <translation id="4559332380232738994">10x11</translation>
+<translation id="4567686777917670400">Adminitratoringiz brauzerni masofadan sozlashi mumkin. Bu qurilmadagi amallar Chromium tashqarisidan boshqarilishi mumkin. <ph name="BEGIN_LINK" />Batafsil<ph name="END_LINK" /></translation>
 <translation id="457875822857220463">Yetkazib berish</translation>
 <translation id="4579056131138995126">Personal (Envelope)</translation>
 <translation id="4582204425268416675">Kartani olib tashlash</translation>
@@ -1526,6 +1531,7 @@
 <translation id="6337534724793800597">Qoidalarni nomi bo‘yicha filtrlash</translation>
 <translation id="6349101878882523185"><ph name="APP_NAME" /> ilovasini oʻrnatish</translation>
 <translation id="6353505687280762741">{COUNT,plural, =0{Hech qanday}=1{1 ta parol (<ph name="DOMAIN_LIST" /> uchun, sinxronlandi)}=2{2 ta parol (<ph name="DOMAIN_LIST" /> uchun, sinxronlandi)}other{# ta parol (<ph name="DOMAIN_LIST" /> uchun, sinxronlandi)}}</translation>
+<translation id="6355392890578844978">Bu brauzer kompaniya yoki tashkilot boshqaruvida emas. Bu qurilmadagi amallar Chromiumdan tashqarida boshqarilishi mumkin. <ph name="BEGIN_LINK" />Batafsil<ph name="END_LINK" /></translation>
 <translation id="6358450015545214790">Bu nima degani?</translation>
 <translation id="6361757823711327522">B7</translation>
 <translation id="6364095313648930329"><ph name="BEGIN_LINK" />Proksi-server, himoya devori va DNS sozlamalarini tekshirish<ph name="END_LINK" /></translation>
@@ -1978,6 +1984,7 @@
 <translation id="7961015016161918242">Hech qachon</translation>
 <translation id="7966803981046576691">Vazifa bajarilayotgan hisob turi</translation>
 <translation id="79682505114836835">“<ph name="VALUE" />” qiymati hex formati uchun yaroqsiz.</translation>
+<translation id="7970392640816874403">Boshqa manbalarda nima yozilgan ekan?</translation>
 <translation id="7976214039405368314">Limitdan oshib ketdi</translation>
 <translation id="7977538094055660992">Chiqarish qurilmasi</translation>
 <translation id="7977894662897852582">Edp</translation>
diff --git a/content/browser/conversions/conversion_host_unittest.cc b/content/browser/conversions/conversion_host_unittest.cc
index ef74014..6064187 100644
--- a/content/browser/conversions/conversion_host_unittest.cc
+++ b/content/browser/conversions/conversion_host_unittest.cc
@@ -68,14 +68,19 @@
 
   void SetUp() override {
     RenderViewHostTestHarness::SetUp();
-    static_cast<WebContentsImpl*>(web_contents())
-        ->RemoveReceiverSetForTesting(blink::mojom::ConversionHost::Name_);
 
     conversion_host_ = ConversionHostTestPeer::CreateConversionHost(
         web_contents(), std::make_unique<TestManagerProvider>(&test_manager_));
+    ConversionHost::SetReceiverImplForTesting(conversion_host_.get());
+
     contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
   }
 
+  void TearDown() override {
+    ConversionHost::SetReceiverImplForTesting(nullptr);
+    RenderViewHostTestHarness::TearDown();
+  }
+
   TestWebContents* contents() {
     return static_cast<TestWebContents*>(web_contents());
   }
@@ -477,10 +482,9 @@
 TEST_F(ConversionHostTest, NoManager_NoPerPageConversionMetrics) {
   // Replace the ConversionHost on the WebContents with one that is backed by a
   // null ConversionManager.
-  static_cast<WebContentsImpl*>(web_contents())
-      ->RemoveReceiverSetForTesting(blink::mojom::ConversionHost::Name_);
   conversion_host_ = ConversionHostTestPeer::CreateConversionHost(
       web_contents(), std::make_unique<TestManagerProvider>(nullptr));
+  ConversionHost::SetReceiverImplForTesting(conversion_host_.get());
   contents()->NavigateAndCommit(GURL("https://www.example.com"));
 
   base::HistogramTester histograms;
@@ -519,10 +523,9 @@
 TEST_F(ConversionHostTest, ImpressionWithNoManagerAvilable_NoCrash) {
   // Replace the ConversionHost on the WebContents with one that is backed by a
   // null ConversionManager.
-  static_cast<WebContentsImpl*>(web_contents())
-      ->RemoveReceiverSetForTesting(blink::mojom::ConversionHost::Name_);
   conversion_host_ = ConversionHostTestPeer::CreateConversionHost(
       web_contents(), std::make_unique<TestManagerProvider>(nullptr));
+  ConversionHost::SetReceiverImplForTesting(conversion_host_.get());
 
   auto navigation = NavigationSimulatorImpl::CreateRendererInitiated(
       GURL(kConversionUrl), main_rfh());
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc
index c086114..de9ae85f 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl.cc
@@ -890,6 +890,49 @@
   return result;
 }
 
+FileSystemAccessManagerImpl::WriteLockManager::WriteLockManager() = default;
+
+FileSystemAccessManagerImpl::WriteLockManager::~WriteLockManager() = default;
+
+bool FileSystemAccessManagerImpl::WriteLockManager::AddAccessHandle(
+    const storage::FileSystemURL& url,
+    std::unique_ptr<FileSystemAccessAccessHandleHostImpl> access_handle) {
+  DCHECK(url.type() == storage::kFileSystemTypeTemporary);
+
+  // TODO(fivedots): Verify that there are no active writers for `url`, once we
+  // implement Add/RemoveWriter.
+  auto insert_result =
+      access_handle_receivers_.emplace(url, std::move(access_handle));
+  bool insert_success = insert_result.second;
+  return insert_success;
+}
+
+bool FileSystemAccessManagerImpl::WriteLockManager::AddWriter(
+    const storage::FileSystemURL& url,
+    std::unique_ptr<FileSystemAccessFileWriterImpl> writer) {
+  DCHECK(url.type() == storage::kFileSystemTypeTemporary);
+
+  // TODO(fivedots): implement this method and migrate ownership of writers.
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void FileSystemAccessManagerImpl::WriteLockManager::RemoveAccessHandle(
+    const storage::FileSystemURL& url) {
+  DCHECK(url.type() == storage::kFileSystemTypeTemporary);
+
+  size_t count_removed = access_handle_receivers_.erase(url);
+  DCHECK_EQ(1u, count_removed);
+}
+
+void FileSystemAccessManagerImpl::WriteLockManager::RemoveWriter(
+    const storage::FileSystemURL& url) {
+  DCHECK(url.type() == storage::kFileSystemTypeTemporary);
+
+  // TODO(fivedots): implement this method and migrate ownership of writers.
+  NOTIMPLEMENTED();
+}
+
 mojo::PendingRemote<blink::mojom::FileSystemAccessFileWriter>
 FileSystemAccessManagerImpl::CreateFileWriter(
     const BindingContext& binding_context,
@@ -949,10 +992,9 @@
       std::make_unique<FileSystemAccessAccessHandleHostImpl>(
           this, url, PassKey(), std::move(receiver),
           std::move(file_delegate_receiver));
-  auto insert_result =
-      access_handle_host_receivers_.emplace(url, std::move(access_handle_host));
-  bool insert_success = insert_result.second;
-  if (!insert_success) {
+  auto success =
+      write_lock_manager_.AddAccessHandle(url, std::move(access_handle_host));
+  if (!success) {
     return mojo::NullRemote();
   }
 
@@ -1304,8 +1346,7 @@
     const storage::FileSystemURL& url) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  size_t count_removed = access_handle_host_receivers_.erase(url);
-  DCHECK_EQ(1u, count_removed);
+  write_lock_manager_.RemoveAccessHandle(url);
 }
 
 void FileSystemAccessManagerImpl::RemoveToken(
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h
index b4ed0bf..8bc21a1 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.h
+++ b/content/browser/file_system_access/file_system_access_manager_impl.h
@@ -246,9 +246,9 @@
   // a writer that doesn't exist.
   void RemoveFileWriter(FileSystemAccessFileWriterImpl* writer);
 
-  // Removes the access handle associated with `url` from
-  // `access_handle_host_receivers_`. It is an error to try to remove an access
-  // handle that doesn't exist.
+  // Releases the exclusive lock on `url` and removes the associated access
+  // handle host. It is an error to try to remove an access
+  // handle host that doesn't exist.
   void RemoveAccessHandleHost(const storage::FileSystemURL& url);
 
   // Remove `token` from `transfer_tokens_`. It is an error to try to remove
@@ -375,6 +375,53 @@
       GetEntryFromDataTransferTokenCallback token_resolved_callback,
       FileSystemAccessPermissionContext::HandleType file_type);
 
+  // Owns receivers that have write access to files (i.e., AccessHandleHost and
+  // FileWriter), ensuring that the right locks are taken.
+  //
+  // Adding an access handle takes an exclusive lock, preventing the addition
+  // of other access handles or file writers that operate on the same URL.
+  //
+  // Adding a file writer takes a shared lock, allowing the addition of other
+  // file writers that operate on the same URL, but preventing it for similar
+  // access handles.
+  //
+  // This class should only handle kFileSystemTypeTemporary URLs, since it
+  // relies on a 1-to-1 URL to file mapping.
+  class WriteLockManager {
+   public:
+    WriteLockManager();
+    ~WriteLockManager();
+
+    // Attempts to take an exclusive lock on `url` and takes ownsership of
+    // `access_handle`. Returns true if successful, false otherwise.
+    bool AddAccessHandle(
+        const storage::FileSystemURL& url,
+        std::unique_ptr<FileSystemAccessAccessHandleHostImpl> access_handle);
+    // Attempts to take a shared lock on `url` and takes ownsership of
+    // `writer`. Returns true if successful, false otherwise.
+    bool AddWriter(const storage::FileSystemURL& url,
+                   std::unique_ptr<FileSystemAccessFileWriterImpl> writer);
+    // Releases the exclusive lock on `url` and the ownership over the
+    // associated access handle. It is is a error to call this method if
+    // there is no exclusive lock on the URL.
+    void RemoveAccessHandle(const storage::FileSystemURL& url);
+    // Releases the shared lock on `url` and the ownership over the
+    // associated writer. It is is a error to call this method if
+    // there is no shared lock on the URL.
+    void RemoveWriter(const storage::FileSystemURL& url);
+
+   private:
+    std::map<storage::FileSystemURL,
+             base::flat_set<std::unique_ptr<FileSystemAccessFileWriterImpl>,
+                            base::UniquePtrComparator>,
+             storage::FileSystemURL::Comparator>
+        writer_receivers_;
+    std::map<storage::FileSystemURL,
+             std::unique_ptr<FileSystemAccessAccessHandleHostImpl>,
+             storage::FileSystemURL::Comparator>
+        access_handle_receivers_;
+  };
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   const scoped_refptr<storage::FileSystemContext> context_;
@@ -401,10 +448,7 @@
   base::flat_set<std::unique_ptr<FileSystemAccessFileWriterImpl>,
                  base::UniquePtrComparator>
       writer_receivers_;
-  std::map<storage::FileSystemURL,
-           std::unique_ptr<FileSystemAccessAccessHandleHostImpl>,
-           storage::FileSystemURL::Comparator>
-      access_handle_host_receivers_;
+  WriteLockManager write_lock_manager_;
 
   bool off_the_record_;
 
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index 005972b..55f7c47 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -38,6 +38,7 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/content_mock_cert_verifier.h"
 #include "content/public/test/navigation_handle_observer.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -195,7 +196,9 @@
 class OriginIsolationOptInHeaderTest : public IsolatedOriginTestBase {
  public:
   OriginIsolationOptInHeaderTest()
-      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
+    feature_list_.InitAndEnableFeature(features::kOriginIsolationHeader);
+  }
   ~OriginIsolationOptInHeaderTest() override = default;
 
   OriginIsolationOptInHeaderTest(const OriginIsolationOptInHeaderTest&) =
@@ -211,8 +214,6 @@
     //  --site-per-process isn't the default, such as Android.
     IsolateAllSitesForTesting(command_line);
 
-    feature_list_.InitAndEnableFeature(features::kOriginIsolationHeader);
-
     // Start the HTTPS server here so derived tests can use it if they override
     // SetUpCommandLine().
     https_server()->AddDefaultHandlers(GetTestDataFilePath());
@@ -282,7 +283,40 @@
   std::queue<std::string> content_;
 };
 
-// As in OriginIsolationOptInHeaderTest, but with same-process origin isolation.
+class OriginIsolationPrerenderOptInHeaderTest
+    : public OriginIsolationOptInHeaderTest {
+ public:
+  OriginIsolationPrerenderOptInHeaderTest()
+      : prerender_helper_(base::BindRepeating(
+            &OriginIsolationPrerenderOptInHeaderTest::prerender_web_contents,
+            base::Unretained(this))) {}
+  ~OriginIsolationPrerenderOptInHeaderTest() override = default;
+
+  OriginIsolationPrerenderOptInHeaderTest(
+      const OriginIsolationPrerenderOptInHeaderTest&) = delete;
+  OriginIsolationPrerenderOptInHeaderTest& operator=(
+      const OriginIsolationPrerenderOptInHeaderTest&) = delete;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // This must be called prior to starting the test server.
+    prerender_helper_.SetUp(https_server());
+    OriginIsolationOptInHeaderTest::SetUpCommandLine(command_line);
+  }
+
+  void set_prerender_web_contents(WebContents* web_contents) {
+    prerender_web_contents_ = web_contents;
+  }
+  WebContents* prerender_web_contents() { return prerender_web_contents_; }
+
+ protected:
+  test::PrerenderTestHelper prerender_helper_;
+
+ private:
+  WebContents* prerender_web_contents_;
+};  // class OriginIsolationPrerenderOptInHeaderTest
+
+// As in OriginIsolationOptInHeaderTest, but with same-process origin
+// isolation.
 class SameProcessOriginIsolationOptInHeaderTest
     : public OriginIsolationOptInHeaderTest {
  public:
@@ -512,6 +546,150 @@
   EXPECT_TRUE(ShouldOriginGetOptInIsolation(origin));
 }
 
+// Two tests for basic OAC operation w.r.t. prerendering FrameTrees.
+
+// Basic test to make sure an origin opting-in in a primary FrameTree
+// triggers registration of a non-opting-origin in an existing prerendering
+// Frametree.
+IN_PROC_BROWSER_TEST_F(OriginIsolationPrerenderOptInHeaderTest,
+                       SimplePrerenderSubOriginIsolationTest) {
+  GURL test_url(https_server()->GetURL("foo.com",
+                                       "/cross_site_iframe_factory.html?"
+                                       "foo.com(foo.com)"));
+  // Navigate primary tab to a non-isolated origin.
+  EXPECT_TRUE(NavigateToURL(shell(), test_url));
+  EXPECT_EQ(2u, shell()->web_contents()->GetAllFrames().size());
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  FrameTreeNode* child_frame_node = root->child_at(0);
+
+  // Create prerender tab, load non-isolated "a.foo.com".
+  Shell* prerender_tab = CreateBrowser();
+  EXPECT_TRUE(NavigateToURL(prerender_tab, GURL(https_server()->GetURL(
+                                               "a.foo.com", "/title1.html"))));
+  auto* prerender_web_contents =
+      static_cast<WebContentsImpl*>(prerender_tab->web_contents());
+  set_prerender_web_contents(prerender_web_contents);
+  GURL non_isolated_origin_url(
+      https_server()->GetURL("a.foo.com", "/title2.html"));
+
+  int host_id = prerender_helper_.AddPrerender(non_isolated_origin_url);
+
+  // In primary tab, navigate to an isolated origin.
+  SetHeaderValue("?1");
+  GURL isolated_suborigin_url(
+      https_server()->GetURL("a.foo.com", "/isolate_origin"));
+  EXPECT_TRUE(
+      NavigateToURLFromRenderer(child_frame_node, isolated_suborigin_url));
+  EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
+            child_frame_node->current_frame_host()->GetSiteInstance());
+  EXPECT_TRUE(child_frame_node->current_frame_host()
+                  ->GetSiteInstance()
+                  ->RequiresDedicatedProcess());
+  EXPECT_TRUE(child_frame_node->current_frame_host()
+                  ->GetSiteInstance()
+                  ->GetSiteInfo()
+                  .is_origin_keyed());
+
+  // Verify in prerender tab that "a.foo.com" is registered as a non-isolated
+  // origin. We must get the SiteInstance() to test from the
+  // PrerenderedMainFrameHost() to make sure the opt-out registration has
+  // propagated to the right place.
+  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+  auto* prerender_site_instance_impl = static_cast<SiteInstanceImpl*>(
+      prerender_helper_.GetPrerenderedMainFrameHost(host_id)
+          ->GetSiteInstance());
+  EXPECT_FALSE(policy->ShouldOriginGetOptInIsolation(
+      prerender_site_instance_impl->GetIsolationContext(),
+      url::Origin::Create(non_isolated_origin_url),
+      true /* origin_requests_isolation */));
+
+  // Activate the prerendered page and confirm the non-isolated origin remains
+  // non-isolated.
+  prerender_helper_.NavigatePrimaryPage(non_isolated_origin_url);
+  auto* new_prerender_site_instance_impl = static_cast<SiteInstanceImpl*>(
+      prerender_tab->web_contents()->GetSiteInstance());
+  EXPECT_EQ(prerender_site_instance_impl, new_prerender_site_instance_impl);
+  EXPECT_FALSE(policy->ShouldOriginGetOptInIsolation(
+      new_prerender_site_instance_impl->GetIsolationContext(),
+      url::Origin::Create(non_isolated_origin_url),
+      true /* origin_requests_isolation */));
+  LOG(INFO) << "wjm: Checking DRDP()";
+  EXPECT_FALSE(
+      new_prerender_site_instance_impl->GetSiteInfo().is_origin_keyed());
+  EXPECT_TRUE(new_prerender_site_instance_impl->GetSiteURL() ==
+                  GURL("https://foo.com") ||
+              new_prerender_site_instance_impl->IsDefaultSiteInstance());
+}
+
+// Basic test to make sure an origin opting-in in a prerendering FrameTree
+// triggers registration of a non-opting-origin in an existing primary
+// Frametree.
+IN_PROC_BROWSER_TEST_F(OriginIsolationPrerenderOptInHeaderTest,
+                       SimplePrerenderSubOriginIsolationTest2) {
+  GURL test_url(https_server()->GetURL("foo.com",
+                                       "/cross_site_iframe_factory.html?"
+                                       "foo.com(foo.com)"));
+  EXPECT_TRUE(NavigateToURL(shell(), test_url));
+  EXPECT_EQ(2u, shell()->web_contents()->GetAllFrames().size());
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  FrameTreeNode* child_frame_node = root->child_at(0);
+  // Navigate child frame to a non-isolated origin "a.foo.com".
+  GURL non_isolated_suborigin_url(
+      https_server()->GetURL("a.foo.com", "/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURLFromRenderer(child_frame_node, non_isolated_suborigin_url));
+  EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
+            child_frame_node->current_frame_host()->GetSiteInstance());
+
+  // Create prerender tab, load isolated "a.foo.com".
+  Shell* prerender_tab = CreateBrowser();
+  EXPECT_TRUE(NavigateToURL(prerender_tab, GURL(https_server()->GetURL(
+                                               "a.foo.com", "/title1.html"))));
+  auto* prerender_web_contents =
+      static_cast<WebContentsImpl*>(prerender_tab->web_contents());
+  set_prerender_web_contents(prerender_web_contents);
+  SetHeaderValue("?1");
+  GURL isolated_origin_url(
+      https_server()->GetURL("a.foo.com", "/isolate_origin"));
+
+  int host_id = prerender_helper_.AddPrerender(isolated_origin_url);
+
+  // Verify origin is isolated in the prerender IsolationContext.
+  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+  auto* prerender_site_instance_impl = static_cast<SiteInstanceImpl*>(
+      prerender_helper_.GetPrerenderedMainFrameHost(host_id)
+          ->GetSiteInstance());
+  EXPECT_TRUE(policy->ShouldOriginGetOptInIsolation(
+      prerender_site_instance_impl->GetIsolationContext(),
+      url::Origin::Create(isolated_origin_url),
+      false /* origin_requests_isolation */));
+  EXPECT_TRUE(prerender_site_instance_impl->RequiresDedicatedProcess());
+  EXPECT_TRUE(prerender_site_instance_impl->GetSiteInfo().is_origin_keyed());
+
+  // Verify in original tab that "a.foo.com" is now registered as a non-isolated
+  // origin.
+  auto* primary_site_instance_impl = static_cast<SiteInstanceImpl*>(
+      shell()->web_contents()->GetSiteInstance());
+  EXPECT_FALSE(policy->ShouldOriginGetOptInIsolation(
+      primary_site_instance_impl->GetIsolationContext(),
+      url::Origin::Create(isolated_origin_url),
+      true /* origin_requests_isolation */));
+
+  // Activate the prerendered page and confirm the isolated origin remains
+  // isolated.
+  prerender_helper_.NavigatePrimaryPage(isolated_origin_url);
+  auto* new_prerender_site_instance_impl = static_cast<SiteInstanceImpl*>(
+      prerender_tab->web_contents()->GetSiteInstance());
+  EXPECT_EQ(prerender_site_instance_impl, new_prerender_site_instance_impl);
+  EXPECT_TRUE(policy->ShouldOriginGetOptInIsolation(
+      new_prerender_site_instance_impl->GetIsolationContext(),
+      url::Origin::Create(isolated_origin_url),
+      false /* origin_requests_isolation */));
+  EXPECT_TRUE(prerender_site_instance_impl->RequiresDedicatedProcess());
+  EXPECT_TRUE(
+      new_prerender_site_instance_impl->GetSiteInfo().is_origin_keyed());
+}
+
 // Further tests deep-dive into various scenarios for the isolation opt-ins.
 
 // In this test the sub-origin is isolated because the header requests it. It
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc
index 2336cae0..3b936748 100644
--- a/content/browser/prerender/prerender_host.cc
+++ b/content/browser/prerender/prerender_host.cc
@@ -67,6 +67,30 @@
   std::unique_ptr<StoredPage> page;
 };
 
+bool AreHttpRequestHeadersCompatible(
+    const std::string& potential_activation_headers_str,
+    const std::string& prerender_headers_str) {
+  net::HttpRequestHeaders prerender_headers;
+  prerender_headers.AddHeadersFromString(prerender_headers_str);
+
+  net::HttpRequestHeaders potential_activation_headers;
+  potential_activation_headers.AddHeadersFromString(
+      potential_activation_headers_str);
+
+  // `potential_activation_headers` are observed before the User-Agent override
+  // while `prerender_headers` are observed after. As a workaround, remove
+  // User-Agent matching from consideration so that activation works with
+  // DevTools mobile emulation.
+  // TODO(https://crbug.com/1238578): Adjust when the headers are observed so we
+  // don't need this workaround.
+  prerender_headers.RemoveHeader(net::HttpRequestHeaders::kUserAgent);
+  potential_activation_headers.RemoveHeader(
+      net::HttpRequestHeaders::kUserAgent);
+
+  return prerender_headers.ToString() ==
+         potential_activation_headers.ToString();
+}
+
 }  // namespace
 
 class PrerenderHost::PageHolder : public FrameTree::Delegate,
@@ -168,6 +192,8 @@
 
   WebContents* GetWebContents() { return &web_contents_; }
 
+  FrameTree* GetPrimaryFrameTree() { return web_contents_.GetFrameTree(); }
+
   ActivateResult Activate(NavigationRequest& navigation_request) {
     // There should be no ongoing main-frame navigation during activation.
     // TODO(https://crbug.com/1190644): Make sure sub-frame navigations are
@@ -191,9 +217,10 @@
             .GetEntryWithUniqueID(page->render_frame_host->nav_entry_id())
             ->CloneWithoutSharing(context.get());
 
-    navigation_request.SetPrerenderNavigationEntry(std::move(nav_entry));
+    navigation_request.SetPrerenderActivationNavigationState(
+        std::move(nav_entry), frame_tree_->root()->current_replication_state());
 
-    FrameTree* target_frame_tree = web_contents_.GetFrameTree();
+    FrameTree* target_frame_tree = GetPrimaryFrameTree();
     DCHECK_EQ(target_frame_tree,
               navigation_request.frame_tree_node()->frame_tree());
 
@@ -443,6 +470,41 @@
   return std::move(result.page);
 }
 
+// Ensure that the frame policies are compatible between primary main frame and
+// prerendering main frame:
+// a) primary main frame's pending_frame_policy would normally apply to the new
+// document during its creation. However, for prerendering we can't apply it as
+// the document is already created.
+// b) prerender main frame's pending_frame_policy can't be transferred to the
+// primary main frame, we should not activate if it's non-zero.
+// c) Existing  document can't change the frame_policy it is affected by, so we
+// can't transfer RenderFrameHosts between FrameTreeNodes with different frame
+// policies.
+//
+// Usually frame policy for the main frame is empty as in the most common case a
+// parent document sets a policy on the child iframe.
+bool PrerenderHost::IsFramePolicyCompatibleWithPrimaryFrameTree() {
+  FrameTreeNode* prerender_root_ftn = page_holder_->frame_tree()->root();
+  FrameTreeNode* primary_root_ftn = page_holder_->GetPrimaryFrameTree()->root();
+
+  // Ensure that the pending frame policy is not set on the main frames, as it
+  // is usually set on frames by their parent frames.
+  if (prerender_root_ftn->pending_frame_policy() != blink::FramePolicy()) {
+    return false;
+  }
+
+  if (primary_root_ftn->pending_frame_policy() != blink::FramePolicy()) {
+    return false;
+  }
+
+  if (prerender_root_ftn->current_replication_state().frame_policy !=
+      primary_root_ftn->current_replication_state().frame_policy) {
+    return false;
+  }
+
+  return true;
+}
+
 bool PrerenderHost::AreInitialPrerenderNavigationParamsCompatibleWithNavigation(
     NavigationRequest& navigation_request) {
   // TODO(crbug.com/1181763): compare the rest of the navigation parameters. We
@@ -484,7 +546,8 @@
     return false;
   }
 
-  if (potential_activation.headers != begin_params_->headers) {
+  if (!AreHttpRequestHeadersCompatible(potential_activation.headers,
+                                       begin_params_->headers)) {
     return false;
   }
 
diff --git a/content/browser/prerender/prerender_host.h b/content/browser/prerender/prerender_host.h
index 57f7e07b..0ca56b7 100644
--- a/content/browser/prerender/prerender_host.h
+++ b/content/browser/prerender/prerender_host.h
@@ -114,6 +114,8 @@
   bool AreInitialPrerenderNavigationParamsCompatibleWithNavigation(
       NavigationRequest& navigation_request);
 
+  bool IsFramePolicyCompatibleWithPrimaryFrameTree();
+
   // Returns the main RenderFrameHost of the prerendered page.
   // This must be called after StartPrerendering() and before Activate().
   RenderFrameHostImpl* GetPrerenderedMainFrameHost();
diff --git a/content/browser/prerender/prerender_host_registry.cc b/content/browser/prerender/prerender_host_registry.cc
index efebc78..3386838 100644
--- a/content/browser/prerender/prerender_host_registry.cc
+++ b/content/browser/prerender/prerender_host_registry.cc
@@ -386,6 +386,10 @@
     return RenderFrameHost::kNoFrameTreeNodeId;
   }
 
+  if (!host->IsFramePolicyCompatibleWithPrimaryFrameTree()) {
+    return RenderFrameHost::kNoFrameTreeNodeId;
+  }
+
   return host->frame_tree_node_id();
 }
 
diff --git a/content/browser/prerender/prerender_host_registry_unittest.cc b/content/browser/prerender/prerender_host_registry_unittest.cc
index 0a30e2daa..7c2d7e3 100644
--- a/content/browser/prerender/prerender_host_registry_unittest.cc
+++ b/content/browser/prerender/prerender_host_registry_unittest.cc
@@ -166,27 +166,26 @@
     return render_frame_host;
   }
 
-  // Helper method to test that prerendering activation fails when an individual
-  // NavigationParams parameter value does not match between the initial and
-  // activation navigations. Use setup_callback to set the individual parameter
-  // value that is to be tested.
-  void CheckNotActivatedForParams(
-      base::OnceCallback<void(NavigationSimulatorImpl*)> setup_callback) {
+  // Helper method to test the navigation param matching logic which allows a
+  // prerender host to be used in a potential activation navigation only if its
+  // params match the potential activation navigation params. Use setup_callback
+  // to set the parameters. Returns true if the host was selected as a
+  // potential candidate for activation, and false otherwise.
+  bool CheckIsActivatedForParams(
+      base::OnceCallback<void(NavigationSimulatorImpl*)> setup_callback)
+      WARN_UNUSED_RESULT {
     const GURL kOriginalUrl("https://example.com/");
 
     std::unique_ptr<TestWebContents> web_contents =
         CreateWebContents(kOriginalUrl);
     RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
-    ASSERT_TRUE(render_frame_host);
 
     const GURL kPrerenderingUrl("https://example.com/next");
     auto attributes = blink::mojom::PrerenderAttributes::New();
     attributes->url = kPrerenderingUrl;
 
     PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
-    const int prerender_frame_tree_node_id =
-        registry->CreateAndStartHost(std::move(attributes), *render_frame_host);
-    ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
+    registry->CreateAndStartHost(std::move(attributes), *render_frame_host);
     PrerenderHost* prerender_host =
         registry->FindHostByUrlForTesting(kPrerenderingUrl);
     CommitPrerenderNavigation(*prerender_host);
@@ -194,13 +193,63 @@
     std::unique_ptr<NavigationSimulatorImpl> navigation =
         NavigationSimulatorImpl::CreateRendererInitiated(kPrerenderingUrl,
                                                          render_frame_host);
+    // Set a default referrer policy that matches the initial prerender
+    // navigation.
+    // TODO(falken): Fix NavigationSimulatorImpl to do this itself.
+    navigation->SetReferrer(blink::mojom::Referrer::New(
+        web_contents->GetMainFrame()->GetLastCommittedURL(),
+        network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin));
+
     // Change a parameter to differentiate the activation request from the
     // prerendering request.
     std::move(setup_callback).Run(navigation.get());
     navigation->Start();
     NavigationRequest* navigation_request = navigation->GetNavigationHandle();
-    EXPECT_FALSE(navigation_request->IsPrerenderedPageActivation());
-    EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
+    // Use is_potentially_prerendered_page_activation_for_testing() instead of
+    // IsPrerenderedPageActivation() because the NavigationSimulator does not
+    // proceed past CommitDeferringConditions on potential activations,
+    // so IsPrerenderedPageActivation() will fail with a CHECK because
+    // prerender_frame_tree_node_id_ is not populated.
+    // TODO(https://crbug.com/1239220): Fix NavigationSimulator to wait for
+    // commit deferring conditions as it does throttles.
+    return navigation_request
+        ->is_potentially_prerendered_page_activation_for_testing();
+  }
+
+  // Helper method to perform a prerender activation that includes specialized
+  // handling or setup on the initial prerender navigation via the
+  // setup_callback parameter.
+  void SetupPrerenderAndCommit(
+      base::OnceCallback<void(NavigationSimulatorImpl*)> setup_callback) {
+    const GURL kOriginalUrl("https://example.com/");
+
+    TestWebContents* wc = static_cast<TestWebContents*>(web_contents());
+    wc->NavigateAndCommit(kOriginalUrl);
+    RenderFrameHostImpl* render_frame_host = wc->GetMainFrame();
+    ASSERT_TRUE(render_frame_host);
+
+    const GURL kPrerenderingUrl("https://example.com/next");
+    auto attributes = blink::mojom::PrerenderAttributes::New();
+    attributes->url = kPrerenderingUrl;
+
+    PrerenderHostRegistry* registry = wc->GetPrerenderHostRegistry();
+    const int prerender_frame_tree_node_id =
+        registry->CreateAndStartHost(std::move(attributes), *render_frame_host);
+    ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
+    PrerenderHost* prerender_host =
+        registry->FindNonReservedHostById(prerender_frame_tree_node_id);
+
+    // Complete the initial prerender navigation.
+    FrameTreeNode* ftn =
+        FrameTreeNode::From(prerender_host->GetPrerenderedMainFrameHost());
+    std::unique_ptr<NavigationSimulatorImpl> sim =
+        NavigationSimulatorImpl::CreateFromPendingInFrame(ftn);
+    std::move(setup_callback).Run(sim.get());
+    sim->Commit();
+    EXPECT_TRUE(prerender_host->is_ready_for_activation());
+
+    // Activate the prerendered page.
+    ActivatePrerenderedPage(kPrerenderingUrl, *wc);
   }
 
  private:
@@ -639,159 +688,226 @@
 // These tests change a parameter to differentiate the activation request from
 // the prerendering request.
 
+// A positive test to show that if the navigation params are equal then the
+// prerender host is selected for activation.
+TEST_F(PrerenderHostRegistryTest, SameInitialAndActivationParams) {
+  EXPECT_TRUE(CheckIsActivatedForParams(
+      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
+        // Do not change any params, so activation happens.
+      })));
+}
+
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_InitiatorFrameToken) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         const GURL kOriginalUrl("https://example.com/");
         navigation->SetInitiatorFrame(nullptr);
         navigation->set_initiator_origin(url::Origin::Create(kOriginalUrl));
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_Headers) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
-        navigation->set_request_headers("User-Agent: Test");
-      }));
+        navigation->set_request_headers("X-Foo: Test");
+      })));
+}
+
+// Tests that the User-Agent header is ignored when comparing request headers.
+//
+// TODO(https://crbug.com/1213299): Check the User-Agent header in a way that
+// works with the DevTools override.
+TEST_F(PrerenderHostRegistryTest, UserAgentIsIgnoredForParamMatching) {
+  EXPECT_TRUE(CheckIsActivatedForParams(
+      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
+        navigation->set_request_headers("User-Agent: MyBrowser");
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_LoadFlags) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_load_flags(net::LOAD_ONLY_FROM_CACHE);
-      }));
+      })));
 
   // If the potential activation request requires validation or bypass of the
   // browser cache, the prerendered page should not be activated.
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_load_flags(net::LOAD_VALIDATE_CACHE);
-      }));
-  CheckNotActivatedForParams(
+      })));
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_load_flags(net::LOAD_BYPASS_CACHE);
-      }));
-  CheckNotActivatedForParams(
+      })));
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_load_flags(net::LOAD_DISABLE_CACHE);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_SkipServiceWorker) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_skip_service_worker(true);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_MixedContentContextType) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_mixed_content_context_type(
             blink::mojom::MixedContentContextType::kNotMixedContent);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_IsFormSubmission) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->SetIsFormSubmission(true);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_SearchableFormUrl) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         const GURL kOriginalUrl("https://example.com/");
         navigation->set_searchable_form_url(kOriginalUrl);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationBeginParams_SearchableFormEncoding) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_searchable_form_encoding("Test encoding");
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_InitiatorOrigin) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_initiator_origin(url::Origin());
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_ShouldCheckMainWorldCSP) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_should_check_main_world_csp(
             network::mojom::CSPDisposition::DO_NOT_CHECK);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_HistoryURLForDataURL) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         const GURL kOriginalUrl("https://example.com/");
         navigation->set_history_url_for_data_url(kOriginalUrl);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_Method) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->SetMethod("POST");
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_HrefTranslate) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_href_translate("test");
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_Transition) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->SetTransition(ui::PAGE_TRANSITION_FORM_SUBMIT);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_RequestContextType) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
         navigation->set_request_context_type(
             blink::mojom::RequestContextType::AUDIO);
-      }));
+      })));
 }
 
 TEST_F(PrerenderHostRegistryTest,
        CompareInitialAndActivationCommonParams_ReferrerPolicy) {
-  CheckNotActivatedForParams(
+  EXPECT_FALSE(CheckIsActivatedForParams(
       base::BindLambdaForTesting([&](NavigationSimulatorImpl* navigation) {
         navigation->SetReferrer(blink::mojom::Referrer::New(
             web_contents()->GetMainFrame()->GetLastCommittedURL(),
             network::mojom::ReferrerPolicy::kAlways));
-      }));
+      })));
 }
 
 // End navigation parameter matching tests ---------
 
+// Begin replication state matching tests ----------
+
+TEST_F(PrerenderHostRegistryTest, InsecureRequestPolicyIsSetWhilePrerendering) {
+  SetupPrerenderAndCommit(
+      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
+        navigation->set_insecure_request_policy(
+            blink::mojom::InsecureRequestPolicy::kBlockAllMixedContent);
+      }));
+  EXPECT_EQ(static_cast<TestWebContents*>(web_contents())
+                ->GetMainFrame()
+                ->frame_tree_node()
+                ->current_replication_state()
+                .insecure_request_policy,
+            blink::mojom::InsecureRequestPolicy::kBlockAllMixedContent);
+}
+
+TEST_F(PrerenderHostRegistryTest,
+       InsecureNavigationsSetIsSetWhilePrerendering) {
+  SetupPrerenderAndCommit(
+      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
+        const std::vector<uint32_t> insecure_navigations = {1, 2};
+        navigation->set_insecure_navigations_set(insecure_navigations);
+      }));
+  const std::vector<uint32_t> insecure_navigations = {1, 2};
+  EXPECT_EQ(static_cast<TestWebContents*>(web_contents())
+                ->GetMainFrame()
+                ->frame_tree_node()
+                ->current_replication_state()
+                .insecure_navigations_set,
+            insecure_navigations);
+}
+
+TEST_F(PrerenderHostRegistryTest,
+       HasPotentiallyTrustworthyUniqueOriginIsSetWhilePrerendering) {
+  SetupPrerenderAndCommit(
+      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
+        navigation->set_has_potentially_trustworthy_unique_origin(true);
+      }));
+  EXPECT_TRUE(static_cast<TestWebContents*>(web_contents())
+                  ->GetMainFrame()
+                  ->frame_tree_node()
+                  ->current_replication_state()
+                  .has_potentially_trustworthy_unique_origin);
+}
+
+// End replication state matching tests ------------
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/renderer_host/file_utilities_host_impl.cc b/content/browser/renderer_host/file_utilities_host_impl.cc
index b48f42a..b741c84 100644
--- a/content/browser/renderer_host/file_utilities_host_impl.cc
+++ b/content/browser/renderer_host/file_utilities_host_impl.cc
@@ -13,6 +13,10 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#if defined(OS_MAC)
+#include "base/mac/mac_util.h"
+#endif
+
 namespace content {
 
 FileUtilitiesHostImpl::FileUtilitiesHostImpl(int process_id)
@@ -45,4 +49,20 @@
   }
 }
 
+#if defined(OS_MAC)
+void FileUtilitiesHostImpl::SetLength(base::File file,
+                                      const int64_t length,
+                                      SetLengthCallback callback) {
+  if (base::mac::IsAtLeastOS10_15()) {
+    mojo::ReportBadMessage("SetLength() disabled on this OS.");
+    // No error message is specified as the ReportBadMessage() call should close
+    // the pipe and kill the renderer.
+    std::move(callback).Run(std::move(file), false);
+    return;
+  }
+  bool result = file.SetLength(length);
+  std::move(callback).Run(std::move(file), result);
+}
+#endif  // defined(OS_MAC)
+
 }  // namespace content
diff --git a/content/browser/renderer_host/file_utilities_host_impl.h b/content/browser/renderer_host/file_utilities_host_impl.h
index 75295a8..7ca1c1d 100644
--- a/content/browser/renderer_host/file_utilities_host_impl.h
+++ b/content/browser/renderer_host/file_utilities_host_impl.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_FILE_UTILITIES_HOST_IMPL_H_
 #define CONTENT_BROWSER_RENDERER_HOST_FILE_UTILITIES_HOST_IMPL_H_
 
+#include "build/build_config.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "third_party/blink/public/mojom/file/file_utilities.mojom.h"
 
@@ -24,6 +25,12 @@
   void GetFileInfo(const base::FilePath& path,
                    GetFileInfoCallback callback) override;
 
+#if defined(OS_MAC)
+  void SetLength(base::File file,
+                 const int64_t length,
+                 SetLengthCallback callback) override;
+#endif  // defined(OS_MAC)
+
   const int process_id_;
 };
 
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
index e9ba9287..7f96b53f 100644
--- a/content/browser/renderer_host/frame_tree.cc
+++ b/content/browser/renderer_host/frame_tree.cc
@@ -609,6 +609,9 @@
 void FrameTree::RegisterExistingOriginToPreventOptInIsolation(
     const url::Origin& previously_visited_origin,
     NavigationRequest* navigation_request_to_exclude) {
+  controller().RegisterExistingOriginToPreventOptInIsolation(
+      previously_visited_origin);
+
   std::unordered_set<SiteInstance*> matching_site_instances;
 
   // Be sure to visit all RenderFrameHosts associated with this frame that might
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index f6751a14..b4d827e 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -850,6 +850,11 @@
 
 }  // namespace
 
+NavigationRequest::PrerenderActivationNavigationState::
+    PrerenderActivationNavigationState() = default;
+NavigationRequest::PrerenderActivationNavigationState::
+    ~PrerenderActivationNavigationState() = default;
+
 // static
 std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
     FrameTreeNode* frame_tree_node,
@@ -5849,6 +5854,25 @@
     g_commit_timeout = timeout;
 }
 
+void NavigationRequest::SetPrerenderActivationNavigationState(
+    std::unique_ptr<NavigationEntryImpl> prerender_navigation_entry,
+    const blink::mojom::FrameReplicationState& replication_state) {
+  DCHECK(IsPrerenderedPageActivation());
+  if (!prerender_navigation_state_) {
+    prerender_navigation_state_.emplace();
+  }
+  prerender_navigation_state_->prerender_navigation_entry =
+      std::move(prerender_navigation_entry);
+
+  // Store the replication state of the prerender main frame to copy the
+  // necessary parameters from it during activation commit and compare with the
+  // final replication state after activation to ensure it hasn't changed.
+  // TODO(https://crbug.com/1237091): This will need to be removed when the
+  // Browsing Instance Frame State is implemented.
+  prerender_navigation_state_->prerender_main_frame_replication_state =
+      replication_state;
+}
+
 void NavigationRequest::RemoveRequestHeader(const std::string& header_name) {
   DCHECK(state_ == WILL_REDIRECT_REQUEST);
   removed_request_headers_.push_back(header_name);
@@ -5921,6 +5945,8 @@
 
 mojom::DidCommitProvisionalLoadParamsPtr
 NavigationRequest::MakeDidCommitProvisionalLoadParamsForPrerenderActivation() {
+  DCHECK(IsPrerenderedPageActivation());
+
   // Start with the provisional load parameters shared between all page
   // activation types.
   mojom::DidCommitProvisionalLoadParamsPtr params =
@@ -5934,9 +5960,19 @@
   // Note: |params| are using last commit params as a basis (via
   // TakeLastCommitParams call), which have a page state from the last commit,
   // but the page state might have been updated since the last commit.
-  params->page_state =
-      prerender_navigation_entry_->GetFrameEntry(frame_tree_node())
-          ->page_state();
+  params->page_state = prerender_navigation_state_->prerender_navigation_entry
+                           ->GetFrameEntry(frame_tree_node())
+                           ->page_state();
+
+  // insecure_request_policy field of the replication state is set during the
+  // navigation commit based on DidCommitProvisionalLoadParams. As prerendering
+  // activates existing page, copy its main frame replication state to ensure
+  // that the effective replication state doesn't change after activation.
+  // TODO(crbug.com/1237091): replication state should belong to the Browsing
+  // Instance Frame State.
+  params->insecure_request_policy =
+      prerender_navigation_state_->prerender_main_frame_replication_state
+          .insecure_request_policy;
   return params;
 }
 
@@ -6426,8 +6462,7 @@
                             .value;
   if (coop_value ==
           network::mojom::CrossOriginOpenerPolicyValue::kSameOriginPlusCoep &&
-      !CompatibleWithCrossOriginIsolated(cross_origin_embedder_policy_) &&
-      !anonymous()) {
+      !CompatibleWithCrossOriginIsolated(cross_origin_embedder_policy_)) {
     NOTREACHED();
     base::debug::DumpWithoutCrashing();
     return false;
@@ -6892,7 +6927,8 @@
 
 std::unique_ptr<NavigationEntryImpl>
 NavigationRequest::TakePrerenderNavigationEntry() {
-  return std::move(prerender_navigation_entry_);
+  DCHECK(IsPrerenderedPageActivation());
+  return std::move(prerender_navigation_state_->prerender_navigation_entry);
 }
 
 bool NavigationRequest::IsWaitingForBeforeUnload() {
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 5377ad6..bb1d1ba 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -866,14 +866,20 @@
   // the BackForwardCache or Prerender)
   bool IsPageActivation() const override;
 
-  // See comments for |prerender_navigation_entry_|.
-  void SetPrerenderNavigationEntry(
-      std::unique_ptr<NavigationEntryImpl> prerender_navigation_entry) {
-    prerender_navigation_entry_ = std::move(prerender_navigation_entry);
-  }
+  // Sets state pertaining to prerender activations. This is only called if
+  // this navigation is a prerender activation.
+  void SetPrerenderActivationNavigationState(
+      std::unique_ptr<NavigationEntryImpl> prerender_navigation_entry,
+      const blink::mojom::FrameReplicationState& replication_state);
 
   std::unique_ptr<NavigationEntryImpl> TakePrerenderNavigationEntry();
 
+  // Returns value that is only valid for prerender activation navigations.
+  const blink::mojom::FrameReplicationState&
+  prerender_main_frame_replication_state() {
+    return prerender_navigation_state_->prerender_main_frame_replication_state;
+  }
+
   // Store a console message, which will be sent to the final RenderFrameHost
   // immediately after requesting the navigation to commit.
   //
@@ -1861,11 +1867,27 @@
   // and callers must not query its value before it's been computed.
   absl::optional<int> prerender_frame_tree_node_id_;
 
-  // Used to store a cloned NavigationEntry for activating a prerendered page.
-  // |prerender_navigation_entry_| is cloned and stored in NavigationRequest
-  // when the prerendered page is transferred to the target FrameTree and is
-  // consumed when NavigationController needs a new entry to commit.
-  std::unique_ptr<NavigationEntryImpl> prerender_navigation_entry_;
+  // Contains state pertaining to a prerender activation. This is only used if
+  // this navigation is a prerender activation.
+  struct PrerenderActivationNavigationState {
+    PrerenderActivationNavigationState();
+    ~PrerenderActivationNavigationState();
+
+    // Used to store a cloned NavigationEntry for activating a prerendered page.
+    // |prerender_navigation_entry| is cloned and stored in NavigationRequest
+    // when the prerendered page is transferred to the target FrameTree and is
+    // consumed when NavigationController needs a new entry to commit.
+    std::unique_ptr<NavigationEntryImpl> prerender_navigation_entry;
+
+    // Used to store the FrameReplicationState for the prerendered page prior to
+    // activation. Value is to be used to populate
+    // DidCommitProvisionalLoadParams values and to verify the replication state
+    // after activation.
+    blink::mojom::FrameReplicationState prerender_main_frame_replication_state;
+  };
+
+  absl::optional<PrerenderActivationNavigationState>
+      prerender_navigation_state_;
 
   // The following fields that constitute the ClientSecurityState. This
   // state is used to take security decisions about the request, and later on
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index 18afbe89..45ce7b8 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -1133,6 +1133,10 @@
   RenderProcessHostImpl* rph =
       static_cast<RenderProcessHostImpl*>(rfh->GetProcess());
 
+  // Disable the BackForwardCache to ensure the old process is going to be
+  // released.
+  DisableBackForwardCacheForTesting(shell()->web_contents(),
+                                    BackForwardCache::TEST_ASSUMES_NO_CACHING);
   host_destructions_ = 0;
   process_exits_ = 0;
   Observe(rph);
@@ -1175,6 +1179,11 @@
   RenderProcessHostImpl* rph =
       static_cast<RenderProcessHostImpl*>(rfh->GetProcess());
 
+  // Disable the BackForwardCache to ensure the old process is going to be
+  // released.
+  DisableBackForwardCacheForTesting(shell()->web_contents(),
+                                    BackForwardCache::TEST_ASSUMES_NO_CACHING);
+
   host_destructions_ = 0;
   process_exits_ = 0;
   Observe(rph);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7cbbea19..fe5f353 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -7357,14 +7357,19 @@
     if (web_contents->GetBrowserContext() != GetBrowserContext())
       continue;
 
-    // TODO(https://crbug.com/1170273): Handle multiple controllers (MPArch)
-    web_contents->GetController().RegisterExistingOriginToPreventOptInIsolation(
-        origin);
-    // Walk the frame tree to pick up any frames without FrameNavigationEntries.
+    // Walk the frame trees to notify each one's NavigationController about the
+    // opting-in origin, and also pick up any frames without
+    // FrameNavigationEntries.
     // * Some frames won't have FrameNavigationEntries (Issues 524208, 608402).
     // * Some pending navigations won't have NavigationEntries.
-    web_contents->GetFrameTree()->RegisterExistingOriginToPreventOptInIsolation(
-        origin, navigation_request_to_exclude);
+    web_contents->ForEachFrameTree(base::BindRepeating(
+        [](const url::Origin& origin,
+           NavigationRequest* navigation_request_to_exclude,
+           FrameTree* frame_tree) {
+          frame_tree->RegisterExistingOriginToPreventOptInIsolation(
+              origin, navigation_request_to_exclude);
+        },
+        origin, navigation_request_to_exclude));
   }
 }
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 056bbd4..9a0afdf 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -651,7 +651,7 @@
 // Used to enable API changes for Secure Payment Confirmation.
 // TODO(crbug.com/1228924): Enable by default in M94.
 const base::Feature kSecurePaymentConfirmationAPIV3{
-    "SecurePaymentConfirmationAPIV3", base::FEATURE_DISABLED_BY_DEFAULT};
+    "SecurePaymentConfirmationAPIV3", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Used to control whether to remove the restriction that PaymentCredential in
 // WebAuthn and secure payment confirmation method in PaymentRequest API must
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
index a91bcdb..d7761b5 100644
--- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -93,6 +93,9 @@
 # Flakily hits a DCHECK during shared image creation.
 crbug.com/1188437 [ linux intel display-server-wayland ] GpuProcess_webgl [ RetryOnFailure ]
 
+# Consistently failing on Android FYI Release (NVIDIA Shield TV).
+crbug.com/1238954 [ android android-shield-android-tv ] GpuProcess_visibility [ Skip ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index c26a1a2..b423f9f 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1494,6 +1494,11 @@
                   frame_tree_node_->IsMainFrame())
                : false;
 
+  params->insecure_request_policy = insecure_request_policy_;
+  params->insecure_navigations_set = insecure_navigations_set_;
+  params->has_potentially_trustworthy_unique_origin =
+      has_potentially_trustworthy_unique_origin_;
+
   return params;
 }
 
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 4bae316d..9791ff4 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -207,6 +207,22 @@
     request_context_type_ = request_context_type;
   }
 
+  void set_insecure_request_policy(
+      blink::mojom::InsecureRequestPolicy insecure_request_policy) {
+    insecure_request_policy_ = insecure_request_policy;
+  }
+
+  void set_insecure_navigations_set(
+      const std::vector<uint32_t> insecure_navigations_set) {
+    insecure_navigations_set_ = insecure_navigations_set;
+  }
+
+  void set_has_potentially_trustworthy_unique_origin(
+      bool has_potentially_trustworthy_unique_origin) {
+    has_potentially_trustworthy_unique_origin_ =
+        has_potentially_trustworthy_unique_origin;
+  }
+
  private:
   NavigationSimulatorImpl(const GURL& original_url,
                           bool browser_initiated,
@@ -373,6 +389,10 @@
   std::string href_translate_;
   blink::mojom::RequestContextType request_context_type_ =
       blink::mojom::RequestContextType::LOCATION;
+  blink::mojom::InsecureRequestPolicy insecure_request_policy_ =
+      blink::mojom::InsecureRequestPolicy::kLeaveInsecureRequestsAlone;
+  std::vector<uint32_t> insecure_navigations_set_;
+  bool has_potentially_trustworthy_unique_origin_ = false;
 
   // Any DNS aliases, as read from CNAME records, for the request URL that
   // would be in the network::mojom::URLResponseHead. The alias chain order
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc
index d3ba8fa..20a2399 100644
--- a/fuchsia/engine/browser/frame_impl_browsertest.cc
+++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -1362,7 +1362,9 @@
 #else
 #define MAYBE_SetPageScale SetPageScale
 #endif
-IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_SetPageScale) {
+// TODO(crbug.com/1239135): SetPageScale/ExecuteJavaScript is racey, causing
+// the test to flake.
+IN_PROC_BROWSER_TEST_F(FrameImplTest, DISABLED_SetPageScale) {
   auto frame = cr_fuchsia::FrameForTest::Create(context(), {});
 
   auto view_tokens = scenic::ViewTokenPair::New();
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
index 544aedf..55c519e5 100644
--- a/gin/gin_features.cc
+++ b/gin/gin_features.cc
@@ -99,6 +99,6 @@
 // Enables slow histograms that provide detailed information at increased
 // runtime overheads.
 const base::Feature kV8SlowHistograms{"V8SlowHistograms",
-                                      base::FEATURE_ENABLED_BY_DEFAULT};
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
 }  // namespace features
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index f416a86..6e7261ff 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -382,9 +382,8 @@
     SetV8Flags("--no-short-builtin-calls");
   }
 
-  if (!base::FeatureList::IsEnabled(features::kV8SlowHistograms)) {
-    SetV8Flags("--slow-histograms");
-  }
+  SetV8FlagsIfOverridden(features::kV8SlowHistograms, "--slow-histograms",
+                         "--no-slow-histograms");
 
   if (IsolateHolder::kStrictMode == mode) {
     SetV8Flags("--use_strict");
diff --git a/ios/chrome/app/strings/resources/ios_strings_nl.xtb b/ios/chrome/app/strings/resources/ios_strings_nl.xtb
index e50c021..f3070aff 100644
--- a/ios/chrome/app/strings/resources/ios_strings_nl.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_nl.xtb
@@ -149,6 +149,7 @@
 <translation id="2421004566762153674">Cookies van derden blokkeren</translation>
 <translation id="2421044535038393232">Doorgaan met bewerken</translation>
 <translation id="2435457462613246316">Wachtwoord tonen</translation>
+<translation id="2476359652512522418">Niet geselecteerd</translation>
 <translation id="2497852260688568942">Synchronisatie is uitgezet door je beheerder</translation>
 <translation id="2500374554657206846">Opties voor 'Wachtwoord opslaan'</translation>
 <translation id="2523363575747517183">Deze website probeert herhaaldelijk een andere app te openen.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_te.xtb b/ios/chrome/app/strings/resources/ios_strings_te.xtb
index 1b52116..468c4af 100644
--- a/ios/chrome/app/strings/resources/ios_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_te.xtb
@@ -558,7 +558,7 @@
 <translation id="6434591244308415567">ఎర్రర్ ఏర్పడింది. తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="6439338047467462846">అన్నింటిని అనుమతించు</translation>
 <translation id="6445051938772793705">దేశం</translation>
-<translation id="6445981559479772097">సందేశం పంపబడింది.</translation>
+<translation id="6445981559479772097">మెసేజ్‌ పంపబడింది.</translation>
 <translation id="6447842834002726250">కుక్కీలు</translation>
 <translation id="6453018583485750254">ఎప్పటికీ చెక్ రన్ చేయవద్దు.</translation>
 <translation id="6459307836338400162">గోప్యత, భద్రత అలాగే డేటా సేకరణకు సంబంధించిన మరిన్ని సెట్టింగ్‌ల కోసం, <ph name="BEGIN_LINK" />సింక్<ph name="END_LINK" />, <ph name="BEGIN_LINK" />Google సర్వీస్‌లు<ph name="END_LINK" /> రెండిటినీ చూడండి.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_uz.xtb b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
index 0cc810cb..485f0e7 100644
--- a/ios/chrome/app/strings/resources/ios_strings_uz.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
@@ -149,6 +149,7 @@
 <translation id="2421004566762153674">Tashqi cookie fayllarni bloklash</translation>
 <translation id="2421044535038393232">Tahrirlashda davom etish</translation>
 <translation id="2435457462613246316">Parolni ko‘rsatish</translation>
+<translation id="2476359652512522418">Tanlanmagan.</translation>
 <translation id="2497852260688568942">Sinxronizatsiyani administrator o‘chirib qo‘ygan</translation>
 <translation id="2500374554657206846">Parollarni saqlash taklif qilinishi</translation>
 <translation id="2523363575747517183">Bu sayt tinimsiz boshqa ilovani ochishga urinmoqda.</translation>
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
index e8e3273a..d35e69b 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -39,6 +39,7 @@
 #include "net/http/http_cache.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties.h"
+#include "net/http/transport_security_state.h"
 #include "net/url_request/url_request_job_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/browsing_data/cache_counter.cc b/ios/chrome/browser/browsing_data/cache_counter.cc
index 644220fa..5621c50 100644
--- a/ios/chrome/browser/browsing_data/cache_counter.cc
+++ b/ios/chrome/browser/browsing_data/cache_counter.cc
@@ -11,6 +11,7 @@
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
 #include "net/base/completion_repeating_callback.h"
+#include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
diff --git a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
index f30ec67f..bfdee818 100644
--- a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
+++ b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
@@ -24,6 +24,7 @@
 #include "ios/web/public/test/web_task_environment.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
+#include "net/base/io_buffer.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index fce0ba8..bdaa05a 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -72,6 +72,7 @@
 using autofill::FieldRendererId;
 using password_manager::PasswordForm;
 using autofill::PasswordFormFillData;
+using base::SysUTF16ToNSString;
 using base::SysUTF8ToNSString;
 using FillingAssistance =
     password_manager::PasswordFormMetricsRecorder::FillingAssistance;
@@ -231,6 +232,9 @@
                        generatedPassword:(NSString*)generatedPassword
                        completionHandler:(void (^)())completionHandler;
 
+- (void)didFinishPasswordFormExtraction:(const std::vector<FormData>&)forms
+                        withMaxUniqueID:(uint32_t)maxID;
+
 @end
 
 class PasswordControllerTest : public ChromeWebTest {
@@ -2218,6 +2222,9 @@
 // is not breaking the password generation flow.
 // Verifies the fix for crbug.com/1077271.
 TEST_F(PasswordControllerTest, PasswordGenerationFieldFocus) {
+  ON_CALL(*store_, GetLogins)
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+
   LoadHtml(@"<html><body>"
             "<form name='login_form' id='signup_form'>"
             "  <input type='text' name='username' id='un'>"
@@ -2526,3 +2533,130 @@
   EXPECT_TRUE(form_manager->is_submitted());
   EXPECT_TRUE(form_manager->IsPasswordUpdate());
 }
+
+// Tests the completion handler for suggestions availability is not called
+// until password manager replies with suggestions.
+TEST_F(PasswordControllerTest,
+       WaitForPasswordmanagerResponseToShowSuggestions) {
+  // Simulate that the form is parsed and sent to PasswordManager.
+  FormData form = test_helpers::MakeSimpleFormData();
+  [passwordController_.sharedPasswordController
+      didFinishPasswordFormExtraction:{form}
+                      withMaxUniqueID:5];
+
+  // Simulate user focusing the field in a form before the password store
+  // response is received.
+  FormSuggestionProviderQuery* form_query = [[FormSuggestionProviderQuery alloc]
+      initWithFormName:SysUTF16ToNSString(form.name)
+          uniqueFormID:form.unique_renderer_id
+       fieldIdentifier:SysUTF16ToNSString(form.fields[0].name)
+         uniqueFieldID:form.fields[0].unique_renderer_id
+             fieldType:@"text"
+                  type:@"focus"
+            typedValue:@""
+               frameID:@"frame-id"];
+
+  __block BOOL completion_was_called = NO;
+  [passwordController_.sharedPasswordController
+      checkIfSuggestionsAvailableForForm:form_query
+                             isMainFrame:YES
+                          hasUserGesture:NO
+                                webState:web_state()
+                       completionHandler:^(BOOL suggestionsAvailable) {
+                         completion_was_called = YES;
+                       }];
+
+  // Check that completion handler wasn't called.
+  EXPECT_FALSE(completion_was_called);
+
+  // Receive suggestions from PasswordManager.
+  PasswordFormFillData form_fill_data;
+  test_helpers::SetPasswordFormFillData(
+      form.url.spec(), "", form.unique_renderer_id.value(), "",
+      form.fields[0].unique_renderer_id.value(), "john.doe@gmail.com", "",
+      form.fields[1].unique_renderer_id.value(), "super!secret", nullptr,
+      nullptr, false, &form_fill_data);
+
+  [passwordController_.sharedPasswordController fillPasswordForm:form_fill_data
+                                               completionHandler:nil];
+  // Check that completion handler was called.
+  EXPECT_TRUE(completion_was_called);
+}
+
+// Tests the completion handler for suggestions availability is not called
+// until password manager replies with suggestions.
+TEST_F(PasswordControllerTest,
+       WaitForPasswordmanagerResponseToShowSuggestionsTwoFields) {
+  // Simulate that the form is parsed and sent to PasswordManager.
+  FormData form = test_helpers::MakeSimpleFormData();
+  [passwordController_.sharedPasswordController
+      didFinishPasswordFormExtraction:{form}
+                      withMaxUniqueID:5];
+
+  // Simulate user focusing the field in a form before the password store
+  // response is received.
+  FormSuggestionProviderQuery* form_query1 =
+      [[FormSuggestionProviderQuery alloc]
+          initWithFormName:SysUTF16ToNSString(form.name)
+              uniqueFormID:form.unique_renderer_id
+           fieldIdentifier:SysUTF16ToNSString(form.fields[0].name)
+             uniqueFieldID:form.fields[0].unique_renderer_id
+                 fieldType:@"text"
+                      type:@"focus"
+                typedValue:@""
+                   frameID:@"frame-id"];
+
+  __block BOOL completion_was_called1 = NO;
+  [passwordController_.sharedPasswordController
+      checkIfSuggestionsAvailableForForm:form_query1
+                             isMainFrame:YES
+                          hasUserGesture:NO
+                                webState:web_state()
+                       completionHandler:^(BOOL suggestionsAvailable) {
+                         completion_was_called1 = YES;
+                       }];
+
+  // Check that completion handler wasn't called.
+  EXPECT_FALSE(completion_was_called1);
+
+  // Simulate user focusing another field in a form before the password store
+  // response is received.
+  FormSuggestionProviderQuery* form_query2 =
+      [[FormSuggestionProviderQuery alloc]
+          initWithFormName:SysUTF16ToNSString(form.name)
+              uniqueFormID:form.unique_renderer_id
+           fieldIdentifier:SysUTF16ToNSString(form.fields[1].name)
+             uniqueFieldID:form.fields[1].unique_renderer_id
+                 fieldType:@"password"
+                      type:@"focus"
+                typedValue:@""
+                   frameID:@"frame-id"];
+
+  __block BOOL completion_was_called2 = NO;
+  [passwordController_.sharedPasswordController
+      checkIfSuggestionsAvailableForForm:form_query2
+                             isMainFrame:YES
+                          hasUserGesture:NO
+                                webState:web_state()
+                       completionHandler:^(BOOL suggestionsAvailable) {
+                         completion_was_called2 = YES;
+                       }];
+
+  // Check that completion handler wasn't called.
+  EXPECT_FALSE(completion_was_called2);
+
+  // Receive suggestions from PasswordManager.
+  PasswordFormFillData form_fill_data;
+  test_helpers::SetPasswordFormFillData(
+      form.url.spec(), "", form.unique_renderer_id.value(), "",
+      form.fields[0].unique_renderer_id.value(), "john.doe@gmail.com", "",
+      form.fields[1].unique_renderer_id.value(), "super!secret", nullptr,
+      nullptr, false, &form_fill_data);
+
+  [passwordController_.sharedPasswordController fillPasswordForm:form_fill_data
+                                               completionHandler:nil];
+
+  // Check that completion handler was called for the second form query.
+  EXPECT_FALSE(completion_was_called1);
+  EXPECT_TRUE(completion_was_called2);
+}
diff --git a/ios/chrome/browser/policy/reporting/profile_report_generator_ios_unittest.mm b/ios/chrome/browser/policy/reporting/profile_report_generator_ios_unittest.mm
index 38d530b..9d70bc2 100644
--- a/ios/chrome/browser/policy/reporting/profile_report_generator_ios_unittest.mm
+++ b/ios/chrome/browser/policy/reporting/profile_report_generator_ios_unittest.mm
@@ -23,6 +23,8 @@
 #include "ios/chrome/browser/policy/reporting/reporting_delegate_factory_ios.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
 #include "ios/chrome/test/testing_application_context.h"
 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
@@ -60,6 +62,10 @@
 
     authentication_service_ =
         AuthenticationServiceFactory::GetForBrowserState(browser_state.get());
+    account_manager_service_ =
+        ChromeAccountManagerServiceFactory::GetForBrowserState(
+            browser_state.get());
+
     scoped_browser_state_manager_ =
         std::make_unique<IOSChromeScopedTestingChromeBrowserStateManager>(
             std::make_unique<TestChromeBrowserStateManager>(
@@ -90,11 +96,10 @@
   }
 
   void SignIn() {
-    ios::FakeChromeIdentityService* identityService =
+    ios::FakeChromeIdentityService* identity_service =
         ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-    identityService->AddIdentities(@[ base::SysUTF8ToNSString(kAccount) ]);
-    ChromeIdentity* identity =
-        [identityService->GetAllIdentities(nullptr) firstObject];
+    identity_service->AddIdentities(@[ base::SysUTF8ToNSString(kAccount) ]);
+    ChromeIdentity* identity = account_manager_service_->GetDefaultIdentity();
     authentication_service_->SignIn(identity);
   }
 
@@ -126,6 +131,7 @@
   std::unique_ptr<IOSChromeScopedTestingChromeBrowserStateManager>
       scoped_browser_state_manager_;
   AuthenticationService* authentication_service_;
+  ChromeAccountManagerService* account_manager_service_;
 };
 
 TEST_F(ProfileReportGeneratorIOSTest, UnsignedInProfile) {
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm b/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm
index 23e41b6..98b30a2 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm
@@ -17,6 +17,8 @@
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h"
 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
 #include "ios/web/public/test/web_task_environment.h"
@@ -51,10 +53,15 @@
     ios::FakeChromeIdentityService* identityService =
         ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
     identityService->AddIdentities(@[ @"identity1", @"identity2" ]);
+
+    ChromeAccountManagerService* account_manager_service =
+        ChromeAccountManagerServiceFactory::GetForBrowserState(
+            browser_state_.get());
     NSArray<ChromeIdentity*>* identities =
-        identityService->GetAllIdentities(nullptr);
+        account_manager_service->GetAllIdentities();
     identity1_ = identities[0];
     identity2_ = identities[1];
+
     sign_in_completion_ = ^(BOOL success) {
       finished_ = true;
       signed_in_success_ = success;
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
index bd00af8..554e098 100644
--- a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
@@ -14,6 +14,8 @@
 #import "ios/chrome/browser/signin/authentication_service_delegate_fake.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_mock.h"
 #include "ios/chrome/test/block_cleanup_test.h"
@@ -33,9 +35,9 @@
 
   void SetUp() override {
     BlockCleanupTest::SetUp();
-    ios::FakeChromeIdentityService* identity_service =
+    identity_service_ =
         ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-    identity_service->AddIdentities(@[ @"identity1" ]);
+    identity_service_->AddIdentities(@[ @"identity1" ]);
 
     TestChromeBrowserState::Builder builder;
     builder.AddTestingFactory(
@@ -48,10 +50,12 @@
     AuthenticationServiceFactory::CreateAndInitializeForBrowserState(
         browser_state_.get(),
         std::make_unique<AuthenticationServiceDelegateFake>());
+    ChromeAccountManagerService* account_manager_service =
+        ChromeAccountManagerServiceFactory::GetForBrowserState(
+            browser_state_.get());
     AuthenticationService* auth_service =
         AuthenticationServiceFactory::GetForBrowserState(browser_state_.get());
-    auth_service->SignIn(
-        [identity_service->GetAllIdentities(nullptr) firstObject]);
+    auth_service->SignIn(account_manager_service->GetDefaultIdentity());
   }
 
  protected:
@@ -61,6 +65,7 @@
   std::unique_ptr<TestChromeBrowserState> browser_state_;
   variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
       variations::VariationsIdsProvider::Mode::kUseSignedInState};
+  ios::FakeChromeIdentityService* identity_service_;
 };
 
 // Tests that the signed in accounts view shouldn't be presented when the
@@ -75,10 +80,8 @@
 // have changed.
 TEST_F(SignedInAccountsViewControllerTest,
        ShouldBePresentedForBrowserStateNecessary) {
-  ios::FakeChromeIdentityService* identity_service =
-      ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-  identity_service->AddIdentities(@[ @"identity2" ]);
-  identity_service->FireChromeIdentityReload();
+  identity_service_->AddIdentities(@[ @"identity2" ]);
+  identity_service_->FireChromeIdentityReload();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE([SignedInAccountsViewController
       shouldBePresentedForBrowserState:browser_state_.get()]);
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_sheet/consistency_sheet_slide_transition_animator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_sheet/consistency_sheet_slide_transition_animator.mm
index 1acbf79..e7d73cf 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_sheet/consistency_sheet_slide_transition_animator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_sheet/consistency_sheet_slide_transition_animator.mm
@@ -98,6 +98,7 @@
 
   // Restore frame to pre-layout value before triggering animations.
   self.navigationController.view.frame = viewControllerFrame;
+  [self.navigationController didUpdateControllerViewFrame];
   NSTimeInterval duration = [self transitionDuration:transitionContext];
   void (^animations)() = ^() {
     [UIView addKeyframeWithRelativeStartTime:.0
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm b/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
index 106e078..2dc2a8d 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
@@ -45,6 +45,9 @@
         base::BindRepeating(
             &AuthenticationServiceFake::CreateAuthenticationService));
     chrome_browser_state_ = builder.Build();
+    account_manager_service_ =
+        ChromeAccountManagerServiceFactory::GetForBrowserState(
+            chrome_browser_state_.get());
   }
 
   void TearDown() override {
@@ -69,6 +72,7 @@
  protected:
   web::WebTaskEnvironment task_environment_;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+  ChromeAccountManagerService* account_manager_service_;
 };
 
 // Should show the sign-in upgrade for the first time.
@@ -85,10 +89,7 @@
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_1_0));
 }
@@ -99,10 +100,7 @@
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
   const base::Version version_1_1("1.1");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_1_1));
 }
@@ -113,10 +111,7 @@
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
   const base::Version version_1_2("1.2");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_1_2));
 }
@@ -127,10 +122,7 @@
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
   const base::Version version_2_0("2.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_2_0));
 }
@@ -141,10 +133,7 @@
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
   const base::Version version_3_0("3.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_3_0));
 }
@@ -159,14 +148,8 @@
   const base::Version version_1_0("1.0");
   const base::Version version_3_0("3.0");
   const base::Version version_5_0("5.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_3_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_3_0);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_5_0));
 }
@@ -180,14 +163,8 @@
   const base::Version version_1_0("1.0");
   const base::Version version_3_0("3.0");
   const base::Version version_5_0("5.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_3_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_3_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
   EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
@@ -207,17 +184,9 @@
   NSString* newAccountGaiaId = @"foo1";
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ newAccountGaiaId ]);
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_3_0);
-  NSArray* allIdentities =
-      ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
-          ->GetAllIdentities(nullptr);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_3_0);
+  NSArray* allIdentities = account_manager_service_->GetAllIdentities();
   ChromeIdentity* foo1Identity = nil;
   for (ChromeIdentity* identity in allIdentities) {
     if ([identity.userFullName isEqualToString:newAccountGaiaId]) {
@@ -241,14 +210,8 @@
   const base::Version version_1_0("1.0");
   const base::Version version_3_0("3.0");
   const base::Version version_4_0("4.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_3_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_3_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
@@ -263,10 +226,7 @@
 TEST_F(SigninUtilsTest, TestWillNotShowNewAccountUntilTwoVersionBis) {
   const base::Version version_1_0("1.0");
   const base::Version version_2_0("2.0");
-  signin::RecordVersionSeen(
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          chrome_browser_state_.get()),
-      version_1_0);
+  signin::RecordVersionSeen(account_manager_service_, version_1_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
   EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index aceff30..3fa19dc 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -151,8 +151,10 @@
     "//base",
     "//base:i18n",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
+    "//ios/chrome/common/ui/util:dynamic_type_util",
     "//ui/base",
   ]
 }
@@ -227,6 +229,7 @@
     "//ios/chrome/browser/ui/authentication/signin:constants",
     "//ios/chrome/browser/ui/authentication/views:views_constants",
     "//ios/chrome/browser/ui/settings/google_services:constants",
+    "//ios/chrome/common",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/public/provider/chrome/browser/signin:constants",
     "//ios/public/provider/chrome/browser/signin:fake_chrome_identity",
diff --git a/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn b/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
index 6b123f7..26df7d35 100644
--- a/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
@@ -31,6 +31,7 @@
   deps = [
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/elements",
+    "//ios/chrome/browser/ui/first_run:constants",
     "//ios/chrome/browser/ui/first_run:first_run_ui",
     "//ios/chrome/browser/ui/first_run/resources:default_browser_screen_banner",
     "//ios/chrome/browser/ui/table_view/cells:cells_constants",
diff --git a/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
index 4819a03..3af2dc7 100644
--- a/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.h"
 #import "ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.h"
+#import "ios/chrome/browser/ui/first_run/first_run_constants.h"
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
@@ -20,9 +21,6 @@
 // Reuse ID for registering cell class in table views.
 constexpr NSString* kReuseID = @"InstructionTableCell";
 
-NSString* const kBeginBoldTag = @"BEGIN_BOLD[ \t]*";
-NSString* const kEndBoldTag = @"[ \t]*END_BOLD";
-
 }  // namespace
 
 @interface DefaultBrowserScreenViewController () <UITableViewDataSource,
@@ -38,6 +36,8 @@
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
+  self.view.accessibilityIdentifier =
+      first_run::kFirstRunDefaultBrowserScreenAccessibilityIdentifier;
   self.bannerImage = [UIImage imageNamed:@"default_browser_screen_banner"];
   self.titleText =
       l10n_util::GetNSString(IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_TITLE);
@@ -109,8 +109,8 @@
 // Parses a string with an embedded bold part inside, delineated by
 // "BEGIN_BOLD" and "END_BOLD". Returns an attributed string with bold part.
 - (NSAttributedString*)putBoldPartInString:(NSString*)string {
-  StringWithTag parsedString =
-      ParseStringWithTag(string, kBeginBoldTag, kEndBoldTag);
+  StringWithTag parsedString = ParseStringWithTag(
+      string, first_run::kBeginBoldTag, first_run::kEndBoldTag);
 
   NSMutableAttributedString* attributedString =
       [[NSMutableAttributedString alloc] initWithString:parsedString.string];
diff --git a/ios/chrome/browser/ui/first_run/first_run_constants.h b/ios/chrome/browser/ui/first_run/first_run_constants.h
index 1589e06..64a54cf 100644
--- a/ios/chrome/browser/ui/first_run/first_run_constants.h
+++ b/ios/chrome/browser/ui/first_run/first_run_constants.h
@@ -22,6 +22,16 @@
 // The accessibility identifier for the Sync screen shown in first run.
 extern NSString* const kFirstRunSyncScreenAccessibilityIdentifier;
 
+// The accessibility identifier for the Default browser screen shown in first
+// run.
+extern NSString* const kFirstRunDefaultBrowserScreenAccessibilityIdentifier;
+
+// Begin tag used to delimit part of text to put in bold.
+extern NSString* const kBeginBoldTag;
+
+// End tag used to delimit part of text to put in bold.
+extern NSString* const kEndBoldTag;
+
 }  // first_run
 
 #endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/first_run/first_run_constants.mm b/ios/chrome/browser/ui/first_run/first_run_constants.mm
index 1269639a..22fa90d 100644
--- a/ios/chrome/browser/ui/first_run/first_run_constants.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_constants.mm
@@ -22,4 +22,10 @@
 NSString* const kFirstRunSyncScreenAccessibilityIdentifier =
     @"firstRunSyncScreenAccessibilityIdentifier";
 
+NSString* const kFirstRunDefaultBrowserScreenAccessibilityIdentifier =
+    @"firstRunDefaultBrowserScreenAccessibilityIdentifier";
+
+NSString* const kBeginBoldTag = @"BEGIN_BOLD[ \t]*";
+NSString* const kEndBoldTag = @"[ \t]*END_BOLD";
+
 }  // first_run
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
index 6576b61a..42657c3 100644
--- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/first_run/first_run_constants.h"
 #import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_constants.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
+#include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
@@ -25,6 +26,8 @@
 #import "ios/testing/earl_grey/earl_grey_test.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#include "ios/third_party/earl_grey2/src/CommonLib/Matcher/GREYLayoutConstraint.h"  // nogncheck
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -34,6 +37,9 @@
 
 namespace {
 
+NSString* const kScrollViewIdentifier =
+    @"kFirstRunScrollViewAccessibilityIdentifier";
+
 // Returns a matcher for the welcome screen accept button.
 id<GREYMatcher> GetAcceptButton() {
   return grey_allOf(grey_text(l10n_util::GetNSString(
@@ -50,6 +56,16 @@
   return grey_accessibilityLabel(buttonTitle);
 }
 
+// Returns a constraint where the element is below the reference.
+GREYLayoutConstraint* BelowConstraint() {
+  return [GREYLayoutConstraint
+      layoutConstraintWithAttribute:kGREYLayoutAttributeTop
+                          relatedBy:kGREYLayoutRelationGreaterThanOrEqual
+               toReferenceAttribute:kGREYLayoutAttributeBottom
+                         multiplier:1.0
+                           constant:0.0];
+}
+
 }  // namespace
 
 // Test first run stages
@@ -115,6 +131,15 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// Checks that the default browser screen is displayed.
+- (void)verifyDefaultBrowserScreenIsDisplayed {
+  [[EarlGrey
+      selectElementWithMatcher:
+          grey_accessibilityID(
+              first_run::kFirstRunDefaultBrowserScreenAccessibilityIdentifier)]
+      assertWithMatcher:grey_notNil()];
+}
+
 // Checks that none of any FRE's screen is displayed.
 - (void)verifyFREIsDismissed {
   [[EarlGrey selectElementWithMatcher:
@@ -131,13 +156,18 @@
                  grey_accessibilityID(
                      first_run::kFirstRunSyncScreenAccessibilityIdentifier)]
       assertWithMatcher:grey_nil()];
+
+  [[EarlGrey
+      selectElementWithMatcher:
+          grey_accessibilityID(
+              first_run::kFirstRunDefaultBrowserScreenAccessibilityIdentifier)]
+      assertWithMatcher:grey_nil()];
 }
 
 // Scrolls down to |elementMatcher| in the scrollable content of the first run
 // screen.
 - (void)scrollToElementAndAssertVisibility:(id<GREYMatcher>)elementMatcher {
-  id<GREYMatcher> scrollView =
-      grey_accessibilityID(@"kFirstRunScrollViewAccessibilityIdentifier");
+  id<GREYMatcher> scrollView = grey_accessibilityID(kScrollViewIdentifier);
 
   [[[EarlGrey
       selectElementWithMatcher:grey_allOf(elementMatcher,
@@ -186,7 +216,7 @@
 
   [self verifySignInScreenIsDisplayed];
 
-  // Valide the Title text.
+  // Validate the Title text.
   id<GREYMatcher> title =
       grey_text(l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE));
   [self scrollToElementAndAssertVisibility:title];
@@ -197,6 +227,69 @@
   [self scrollToElementAndAssertVisibility:subtitle];
 }
 
+// Checks that the default browser screen is displayed correctly.
+- (void)testDefaultBrowserScreenUI {
+  AppLaunchConfiguration config = self.appConfigurationForTestCase;
+  config.features_enabled.push_back(kEnableFREDefaultBrowserScreen);
+  // Relaunch the app to take the configuration into account.
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+
+  // Go to the default browser screen.
+  [self verifyWelcomeScreenIsDisplayed];
+  [self scrollToElementAndAssertVisibility:GetAcceptButton()];
+  [[EarlGrey selectElementWithMatcher:GetAcceptButton()]
+      performAction:grey_tap()];
+
+  [self verifySignInScreenIsDisplayed];
+  [[EarlGrey
+      selectElementWithMatcher:grey_text(l10n_util::GetNSString(
+                                   IDS_IOS_FIRST_RUN_SIGNIN_DONT_SIGN_IN))]
+      performAction:grey_tap()];
+
+  [self verifyDefaultBrowserScreenIsDisplayed];
+
+  // Validate the Title text.
+  id<GREYMatcher> title = grey_text(
+      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_TITLE));
+  [self scrollToElementAndAssertVisibility:title];
+
+  // Validate the Subtitle text.
+  id<GREYMatcher> subtitle = grey_text(l10n_util::GetNSString(
+      IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SUBTITLE));
+  [self scrollToElementAndAssertVisibility:subtitle];
+
+  // Remove bold tags in instructions.
+  StringWithTag firstInstructionParsed = ParseStringWithTag(
+      l10n_util::GetNSString(
+          IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_FIRST_STEP),
+      first_run::kBeginBoldTag, first_run::kEndBoldTag);
+  StringWithTag secondInstructionParsed = ParseStringWithTag(
+      l10n_util::GetNSString(
+          IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SECOND_STEP),
+      first_run::kBeginBoldTag, first_run::kEndBoldTag);
+  StringWithTag thirdInstructionParsed = ParseStringWithTag(
+      l10n_util::GetNSString(
+          IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_THIRD_STEP),
+      first_run::kBeginBoldTag, first_run::kEndBoldTag);
+
+  // Verify instruction order.
+  id<GREYMatcher> firstInstruction = grey_text(firstInstructionParsed.string);
+  id<GREYMatcher> secondInstruction = grey_text(secondInstructionParsed.string);
+  id<GREYMatcher> thirdInstruction = grey_text(thirdInstructionParsed.string);
+
+  // Scroll to ensure that the third instruction is visible.
+  id<GREYMatcher> scrollViewMatcher =
+      grey_accessibilityID(kScrollViewIdentifier);
+  [[EarlGrey selectElementWithMatcher:thirdInstruction]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 50)
+      onElementWithMatcher:scrollViewMatcher];
+
+  [[EarlGrey selectElementWithMatcher:secondInstruction]
+      assertWithMatcher:grey_layout(@[ BelowConstraint() ], firstInstruction)];
+  [[EarlGrey selectElementWithMatcher:thirdInstruction]
+      assertWithMatcher:grey_layout(@[ BelowConstraint() ], secondInstruction)];
+}
+
 // Navigates to the Terms of Service and back.
 - (void)testTermsAndConditions {
   // Tap on “Terms of Service” on the first screen
diff --git a/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm
index d8e9b78..4c34a1d 100644
--- a/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm
@@ -7,8 +7,10 @@
 #include "base/check.h"
 #include "base/i18n/rtl.h"
 #import "ios/chrome/browser/ui/first_run/highlighted_button.h"
+#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/button_util.h"
+#include "ios/chrome/common/ui/util/dynamic_type_util.h"
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -316,7 +318,7 @@
   // Reset the title font and the learn more text to make sure that they are
   // properly scaled. Nothing will be done for the Read More text if the
   // bottom is reached.
-  [self setTitleFont:self.titleLabel];
+  [self setFontForTitle:self.titleLabel];
   [self setReadMoreText];
 
   // Update the primary button once the layout changes take effect to have the
@@ -394,18 +396,27 @@
   return newImage;
 }
 
+// Determines which font text style to use depending on the device size, the
+// size class and if dynamic type is enabled.
+- (UIFontTextStyle)titleLabelFontTextStyle {
+  BOOL dynamicTypeEnabled = UIContentSizeCategoryIsAccessibilityCategory(
+      self.traitCollection.preferredContentSizeCategory);
+
+  if (!dynamicTypeEnabled) {
+    if (IsRegularXRegularSizeClass(self.traitCollection)) {
+      return UIFontTextStyleTitle1;
+    } else if (!IsSmallDevice()) {
+      return UIFontTextStyleLargeTitle;
+    }
+  }
+  return UIFontTextStyleTitle2;
+}
+
 - (UILabel*)titleLabel {
   if (!_titleLabel) {
     _titleLabel = [[UILabel alloc] init];
     _titleLabel.numberOfLines = 0;
-    [self setTitleFont:_titleLabel];
-    UIFontDescriptor* descriptor = [UIFontDescriptor
-        preferredFontDescriptorWithTextStyle:UIFontTextStyleLargeTitle];
-    UIFont* font = [UIFont systemFontOfSize:descriptor.pointSize
-                                     weight:UIFontWeightBold];
-    UIFontMetrics* fontMetrics =
-        [UIFontMetrics metricsForTextStyle:UIFontTextStyleLargeTitle];
-    _titleLabel.font = [fontMetrics scaledFontForFont:font];
+    [self setFontForTitle:_titleLabel];
     _titleLabel.textColor = [UIColor colorNamed:kTextPrimaryColor];
     _titleLabel.text = self.titleText;
     _titleLabel.textAlignment = NSTextAlignmentCenter;
@@ -416,13 +427,14 @@
   return _titleLabel;
 }
 
-- (void)setTitleFont:(UILabel*)titleLabel {
-  UIFontDescriptor* descriptor = [UIFontDescriptor
-      preferredFontDescriptorWithTextStyle:UIFontTextStyleLargeTitle];
+- (void)setFontForTitle:(UILabel*)titleLabel {
+  UIFontTextStyle textStyle = [self titleLabelFontTextStyle];
+
+  UIFontDescriptor* descriptor =
+      [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle];
   UIFont* font = [UIFont systemFontOfSize:descriptor.pointSize
                                    weight:UIFontWeightBold];
-  UIFontMetrics* fontMetrics =
-      [UIFontMetrics metricsForTextStyle:UIFontTextStyleLargeTitle];
+  UIFontMetrics* fontMetrics = [UIFontMetrics metricsForTextStyle:textStyle];
   titleLabel.font = [fontMetrics scaledFontForFont:font];
 }
 
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 3ddc1ea6..5d16c59 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -145,6 +145,7 @@
 
 - (void)stop {
   [self.recentTabsTableViewController dismissModals];
+  self.recentTabsTableViewController.browser = nil;
   [self.recentTabsNavigationController
       dismissViewControllerAnimated:YES
                          completion:self.completion];
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index afe31856..98cd936 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -29,6 +29,8 @@
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #include "ios/chrome/browser/sync/session_sync_service_factory.h"
+#include "ios/chrome/browser/sync/sync_observer_bridge.h"
+#include "ios/chrome/browser/sync/sync_service_factory.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h"
@@ -126,11 +128,13 @@
 
 @interface RecentTabsTableViewController () <SigninPromoViewConsumer,
                                              SigninPresenter,
+                                             SyncObserverModelBridge,
                                              SyncPresenter,
                                              TableViewURLDragDataSource,
                                              UIContextMenuInteractionDelegate,
                                              UIGestureRecognizerDelegate> {
   std::unique_ptr<synced_sessions::SyncedSessions> _syncedSessions;
+  std::unique_ptr<SyncObserverBridge> _syncObserver;
 }
 // The service that manages the recently closed tabs
 @property(nonatomic, assign) sessions::TabRestoreService* tabRestoreService;
@@ -184,11 +188,11 @@
   self.tableView.sectionFooterHeight = 0.0;
   self.title = l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_RECENT_TABS);
 
-    self.dragDropHandler = [[TableViewURLDragDropHandler alloc] init];
-    self.dragDropHandler.origin = WindowActivityRecentTabsOrigin;
-    self.dragDropHandler.dragDataSource = self;
-    self.tableView.dragDelegate = self.dragDropHandler;
-    self.tableView.dragInteractionEnabled = true;
+  self.dragDropHandler = [[TableViewURLDragDropHandler alloc] init];
+  self.dragDropHandler.origin = WindowActivityRecentTabsOrigin;
+  self.dragDropHandler.dragDataSource = self;
+  self.tableView.dragDelegate = self.dragDropHandler;
+  self.tableView.dragInteractionEnabled = true;
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -208,15 +212,20 @@
 #pragma mark - Setters & Getters
 
 - (void)setBrowser:(Browser*)browser {
-  DCHECK(browser);
   _browser = browser;
-  ChromeBrowserState* browserState = browser->GetBrowserState();
-  // Some RecentTabs services depend on objects not present in the OffTheRecord
-  // BrowserState, in order to prevent crashes set |_browserState| to
-  // |browserState|->OriginalChromeBrowserState. While doing this check if
-  // incognito or not so that pages are loaded accordingly.
-  _browserState = browserState->GetOriginalChromeBrowserState();
-  _incognito = browserState->IsOffTheRecord();
+  if (browser) {
+    ChromeBrowserState* browserState = browser->GetBrowserState();
+    // Some RecentTabs services depend on objects not present in the
+    // OffTheRecord BrowserState, in order to prevent crashes set
+    // |_browserState| to |browserState|->OriginalChromeBrowserState. While
+    // doing this check if incognito or not so that pages are loaded
+    // accordingly.
+    _browserState = browserState->GetOriginalChromeBrowserState();
+    _incognito = browserState->IsOffTheRecord();
+    _syncObserver.reset(new SyncObserverBridge(self, self.syncService));
+  } else {
+    _syncObserver.reset();
+  }
 }
 
 - (WebStateList*)webStateList {
@@ -235,6 +244,34 @@
   [self.tableView reloadData];
 }
 
+- (syncer::SyncService*)syncService {
+  DCHECK(_browserState);
+  return SyncServiceFactory::GetForBrowserState(_browserState);
+}
+
+// Returns YES if the user cannot turn on sync for enterprise policy reasons.
+- (BOOL)isSyncDisabledByAdministrator {
+  DCHECK(self.syncService);
+  return self.syncService->GetDisableReasons().Has(
+      syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
+}
+
+#pragma mark - SyncObserverModelBridge
+
+- (void)onSyncStateChanged {
+  if (self.preventUpdates ||
+      ![self.tableViewModel
+          hasSectionForSectionIdentifier:SectionIdentifierOtherDevices]) {
+    return;
+  }
+
+  [self.tableView
+      performBatchUpdates:^{
+        [self updateOtherDevicesSectionForState:self.sessionState];
+      }
+               completion:nil];
+}
+
 #pragma mark - TableViewModel
 
 - (void)loadModel {
@@ -492,24 +529,19 @@
         [[TableViewDisclosureHeaderFooterItem alloc]
             initWithType:ItemTypeRecentlyClosedHeader];
     header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
+    if (self.isSyncDisabledByAdministrator) {
+      header.disabled = YES;
+      header.subtitleText =
+          l10n_util::GetNSString(IDS_IOS_RECENT_TABS_DISABLED_BY_ORGANIZATION);
+    }
     [model setHeader:header
         forSectionWithIdentifier:SectionIdentifierOtherDevices];
     header.collapsed =
         [self.tableViewModel sectionIsCollapsed:SectionIdentifierOtherDevices];
   }
 
-  if (!signin::IsSigninAllowed(self.browserState->GetPrefs())) {
-    // If sign-in is disabled by policy, don't show an illustration or a sign-in
-    // promo.
-    TableViewTextItem* disabledByOrganizationText =
-        [[TableViewTextItem alloc] initWithType:ItemTypeSigninDisabled];
-    disabledByOrganizationText.text =
-        l10n_util::GetNSString(IDS_IOS_RECENT_TABS_DISABLED_BY_ORGANIZATION);
-    disabledByOrganizationText.textColor =
-        [UIColor colorNamed:kTextSecondaryColor];
-    [self.tableViewModel addItem:disabledByOrganizationText
-         toSectionWithIdentifier:SectionIdentifierOtherDevices];
-  } else {
+  if (!self.isSyncDisabledByAdministrator &&
+      signin::IsSigninAllowed(self.browserState->GetPrefs())) {
     ItemType itemType;
     NSString* itemSubtitle;
     NSString* itemButtonText;
diff --git a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
index 636e7e18..260cb5cb 100644
--- a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
+++ b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
@@ -21,6 +21,8 @@
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service.h"
+#import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #include "ios/chrome/browser/sync/sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
@@ -99,10 +101,14 @@
   ios::FakeChromeIdentityService* identityService =
       ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
   identityService->AddIdentities(@[ @"identity1" ]);
-  ChromeIdentity* identity =
-      [identityService->GetAllIdentities(nullptr) firstObject];
-  AuthenticationServiceFactory::GetForBrowserState(chrome_browser_state_.get())
-      ->SignIn(identity);
+
+  ChromeAccountManagerService* account_manager_service =
+      ChromeAccountManagerServiceFactory::GetForBrowserState(
+          chrome_browser_state_.get());
+  AuthenticationService* auth_service =
+      AuthenticationServiceFactory::GetForBrowserState(
+          chrome_browser_state_.get());
+  auth_service->SignIn(account_manager_service->GetDefaultIdentity());
 }
 
 void PassphraseTableViewControllerTest::SetUpNavigationController(
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index fac5ba4..2ff256b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -737,6 +737,7 @@
   // TODO(crbug.com/845192) : RecentTabsTableViewController behaves like a
   // coordinator and that should be factored out.
   [self.baseViewController.remoteTabsViewController dismissModals];
+  self.baseViewController.remoteTabsViewController.browser = nil;
   [self.remoteTabsMediator disconnect];
   self.remoteTabsMediator = nil;
   [self.actionSheetCoordinator stop];
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h
index 125c02d..d4b4b17 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h
@@ -18,6 +18,8 @@
 @property(nonatomic, readwrite, strong) NSString* subtitleText;
 // Determines the direction of the disclosure view.
 @property(nonatomic, readwrite, assign) BOOL collapsed;
+// Determines if the header is shown has disabled.
+@property(nonatomic, readwrite, assign) BOOL disabled;
 @end
 
 // UITableViewHeaderFooterView that displays a text label, subtitle, and a
@@ -32,6 +34,8 @@
 @property(nonatomic, readwrite, strong) UILabel* titleLabel;
 // Shows the subtitleText of the TableViewDisclosureHeaderFooterItem.
 @property(nonatomic, readwrite, strong) UILabel* subtitleLabel;
+// Determines if the header is shown has disabled.
+@property(nonatomic, readwrite, assign) BOOL disabled;
 // Determines if disclosureImageView should be pointing down or to the right.
 @property(nonatomic, assign) DisclosureDirection disclosureDirection;
 // Color used on the highlight animation.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
index 2096191..85c7bac3 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
@@ -24,9 +24,6 @@
 }
 
 @implementation TableViewDisclosureHeaderFooterItem
-@synthesize subtitleText = _subtitleText;
-@synthesize text = _text;
-@synthesize collapsed = _collapsed;
 
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
@@ -45,17 +42,12 @@
   header.titleLabel.text = self.text;
   header.subtitleLabel.text = self.subtitleText;
   header.subtitleLabel.numberOfLines = 0;
+  header.disabled = self.disabled;
   header.isAccessibilityElement = YES;
   header.accessibilityTraits |= UIAccessibilityTraitButton;
   DisclosureDirection direction =
       self.collapsed ? DisclosureDirectionTrailing : DisclosureDirectionDown;
   [header setInitialDirection:direction];
-  if (styler.headerFooterTitleColor)
-    header.titleLabel.textColor = styler.headerFooterTitleColor;
-  if (styler.headerFooterDetailColor)
-    header.subtitleLabel.textColor = styler.headerFooterDetailColor;
-  if (styler.cellHighlightColor)
-    header.highlightColor = styler.cellHighlightColor;
 }
 
 @end
@@ -73,13 +65,6 @@
 @end
 
 @implementation TableViewDisclosureHeaderFooterView
-@synthesize cellAnimator = _cellAnimator;
-@synthesize cellDefaultBackgroundColor = _cellDefaultBackgroundColor;
-@synthesize disclosureDirection = disclosureDirection;
-@synthesize disclosureImageView = _disclosureImageView;
-@synthesize highlightColor = _highlightColor;
-@synthesize subtitleLabel = _subtitleLabel;
-@synthesize titleLabel = _titleLabel;
 
 - (instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier {
   self = [super initWithReuseIdentifier:reuseIdentifier];
@@ -198,6 +183,16 @@
   [self.cellAnimator startAnimation];
 }
 
+#pragma mark - properties
+
+- (void)setDisabled:(BOOL)disabled {
+  _titleLabel.textColor =
+      disabled ? UIColor.cr_secondaryLabelColor : UIColor.cr_labelColor;
+  _disclosureImageView.image =
+      disabled ? nil : [UIImage imageNamed:@"table_view_cell_chevron"];
+  _disabled = disabled;
+}
+
 #pragma mark - internal methods
 
 - (void)addAnimationHighlightToAnimator {
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
index afabd32..bf10d70 100644
--- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
+++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
@@ -24,7 +24,7 @@
 #endif
 
 const CGFloat kTableViewSeparatorInset = 16;
-const CGFloat kTableViewSeparatorInsetWithIcon = 56;
+const CGFloat kTableViewSeparatorInsetWithIcon = 60;
 
 @interface ChromeTableViewController ()
 // The loading displayed by [self startLoadingIndicatorWithLoadingMessage:].
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_nl.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_nl.xtb
index 21fa3a976..70a4f07 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_nl.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_nl.xtb
@@ -1,12 +1,14 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="nl">
+<translation id="1196785757634502276">Je hebt al een wachtwoord voor <ph name="USERNAME" /> opgeslagen op <ph name="WEBSITE" />. Wil je het vervangen?</translation>
 <translation id="1276428923064733819">Kopiëren</translation>
 <translation id="1614914292771557551">Je wachtwoord wordt opgeslagen in je Google-account (<ph name="EMAIL" />) als je teruggaat naar Chrome</translation>
 <translation id="1706288056912586527">Wachtwoord tonen</translation>
 <translation id="1977167321677356409">Wachtwoord</translation>
 <translation id="2712586044587587728">Je Chrome-wachtwoorden zijn beschikbaar voor gebruik in andere apps. Je kunt dit op elk moment uitzetten in de app Instellingen.</translation>
 <translation id="3580107423202590938">Geen Chrome-wachtwoorden</translation>
+<translation id="368844171100841558">Vervangen</translation>
 <translation id="3753678329684433031">Chrome-wachtwoord automatisch invullen</translation>
 <translation id="3789385946721385622">Gebruikersnaam</translation>
 <translation id="4064278913989596727">Help</translation>
@@ -36,6 +38,7 @@
 <translation id="8219905600827687498">Voorgestelde wachtwoorden</translation>
 <translation id="8300526662653766176">Een toegangscode instellen</translation>
 <translation id="8332511935157148552">Geen wachtwoorden gevonden</translation>
+<translation id="8486024683491936104">Wachtwoord vervangen?</translation>
 <translation id="8503813439785031346">Gebruikersnaam</translation>
 <translation id="8518521100965196752">Als je wachtwoorden wilt gebruiken, moet je eerst een toegangscode instellen op je apparaat.</translation>
 <translation id="8877181643142698531">URL</translation>
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
index a73eb33..9d0f19f 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
@@ -1,12 +1,14 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="uz">
+<translation id="1196785757634502276"><ph name="WEBSITE" /> saytidagi <ph name="USERNAME" /> paroli allaqachon saqlangan. Almashtirilsinmi?</translation>
 <translation id="1276428923064733819">Nusxalash</translation>
 <translation id="1614914292771557551">Chrome brauzeriga qaytsangiz, parolingiz Google hisobingizga (<ph name="EMAIL" />) saqlanadi</translation>
 <translation id="1706288056912586527">Parolni ochish</translation>
 <translation id="1977167321677356409">Parol</translation>
 <translation id="2712586044587587728">Chrome parollaringizdan boshqa ilovalarda foydalanish mumkin. Buni Sozlamalar ilovasi orqali istalgan vaqtda faolsizlantirish mumkin.</translation>
 <translation id="3580107423202590938">Hech qanday Chrome paroli topilmadi</translation>
+<translation id="368844171100841558">Almashtirish</translation>
 <translation id="3753678329684433031">Chromeda parollarning avtomatik kiritilishi</translation>
 <translation id="3789385946721385622">Foydalanuvchi nomi</translation>
 <translation id="4064278913989596727">Yordam</translation>
@@ -36,6 +38,7 @@
 <translation id="8219905600827687498">Tavsiya etilgan parollar</translation>
 <translation id="8300526662653766176">Maxfiy kodni belgilang</translation>
 <translation id="8332511935157148552">Hech qanday parol topilmadi</translation>
+<translation id="8486024683491936104">Parol yangilansinmi?</translation>
 <translation id="8503813439785031346">Foydalanuvchi nomi</translation>
 <translation id="8518521100965196752">Parollarni ishlatish uchun qurilmangizni maxfiy kod bilan qulflang.</translation>
 <translation id="8877181643142698531">URL</translation>
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index 086ec71..d846cd0 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -49,6 +49,7 @@
 #include "net/http/http_auth_preferences.h"
 #include "net/http/http_network_layer.h"
 #include "net/http/http_server_properties.h"
+#include "net/http/transport_security_state.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_event_type.h"
 #include "net/proxy_resolution/pac_file_fetcher_impl.h"
diff --git a/testing/buildbot/filters/fuchsia.views_unittests.filter b/testing/buildbot/filters/fuchsia.views_unittests.filter
index 37c5f9f..f54774f 100644
--- a/testing/buildbot/filters/fuchsia.views_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.views_unittests.filter
@@ -12,6 +12,8 @@
 -TextfieldTest.DragAndDrop_InitiateDrag
 -TextfieldTest.DragAndDrop_ToTheLeft
 -TextfieldTest.DragAndDrop_ToTheRight
+-TextfieldTest.DropCallbackRun
+-TextfieldTest.DropCallbackCancelled
 
 # TODO(crbug.com/1231516): This test require handling capture in
 # ui::ScenicWindow
diff --git a/third_party/android_build_tools/aapt2/README.chromium b/third_party/android_build_tools/aapt2/README.chromium
index ae240211..fae3c4f 100644
--- a/third_party/android_build_tools/aapt2/README.chromium
+++ b/third_party/android_build_tools/aapt2/README.chromium
@@ -1,6 +1,6 @@
 Name: Android SDK tool aapt2
 Short name: aapt2
-Version: unknown
+Version: 7.0.0-beta03-7147631
 URL:  https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/${Version}/aapt2-${Version}-linux.jar
 Security Critical: no
 License: Apache Version 2.0
@@ -29,4 +29,4 @@
     * We mostly care about the string after @.
 
 Local Modifications:
-Fetched prebuilt from go/aapt2-6466991 (version not yet published to maven).
+None
diff --git a/third_party/blink/common/frame/frame_policy.cc b/third_party/blink/common/frame/frame_policy.cc
index 2746e057..862ddbc 100644
--- a/third_party/blink/common/frame/frame_policy.cc
+++ b/third_party/blink/common/frame/frame_policy.cc
@@ -24,4 +24,15 @@
 
 FramePolicy::~FramePolicy() = default;
 
+bool operator==(const FramePolicy& lhs, const FramePolicy& rhs) {
+  return (lhs.sandbox_flags == rhs.sandbox_flags) &&
+         (lhs.container_policy == rhs.container_policy) &&
+         (lhs.required_document_policy == rhs.required_document_policy) &&
+         (lhs.is_fenced == rhs.is_fenced);
+}
+
+bool operator!=(const FramePolicy& lhs, const FramePolicy& rhs) {
+  return !(lhs == rhs);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/public/common/frame/frame_policy.h b/third_party/blink/public/common/frame/frame_policy.h
index d57d79b..45d8a86b 100644
--- a/third_party/blink/public/common/frame/frame_policy.h
+++ b/third_party/blink/public/common/frame/frame_policy.h
@@ -57,6 +57,11 @@
   bool is_fenced = false;
 };
 
+bool BLINK_COMMON_EXPORT operator==(const FramePolicy& lhs,
+                                    const FramePolicy& rhs);
+bool BLINK_COMMON_EXPORT operator!=(const FramePolicy& lhs,
+                                    const FramePolicy& rhs);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_POLICY_H_
diff --git a/third_party/blink/public/mojom/file/file_utilities.mojom b/third_party/blink/public/mojom/file/file_utilities.mojom
index a894971..4f564a4 100644
--- a/third_party/blink/public/mojom/file/file_utilities.mojom
+++ b/third_party/blink/public/mojom/file/file_utilities.mojom
@@ -4,6 +4,7 @@
 
 module blink.mojom;
 
+import "mojo/public/mojom/base/file.mojom";
 import "mojo/public/mojom/base/file_info.mojom";
 import "mojo/public/mojom/base/file_path.mojom";
 
@@ -12,4 +13,32 @@
   [Sync]
   GetFileInfo(mojo_base.mojom.FilePath path) => (
       mojo_base.mojom.FileInfo? result);
+
+  // Extends or truncates a previously opened file on macOS < 10.15.
+  //
+  // `result` is true if base::File::SetLength() succeeded, otherwise false.
+  //
+  // Calls ReportBadMessage() on macOS 10.15+. Disabled on other OSes.
+  //
+  // This call is a workaround for a sandboxing limitation in macOS < 10.15 that
+  // results in ftruncate() to fail when called from (sandboxed) renderers.
+  // On modern macOS versions, the renderer calls ftruncate() directly instead
+  // of using this call. The sandboxing issue is discussed at
+  // https://crbug.com/1084565.
+  //
+  // The rendererer passes the file handle to the backend. This could have been
+  // avoided by having NativeIOFileHost always store a dup()ed handle for the
+  // file. This alternative was rejected in order to avoid reasoning about the
+  // effects of having multiple file handles pointing to the same file.
+  //
+  // A compromised renderer may use this call with an arbitrary file handle.
+  // This is not considered a significant attack surface because renderers on
+  // macOS 10.15+ and all other OSes are able to call ftruncate() on any file
+  // handle they have.
+  //
+  // By the same reasoning above (renderers on most OSes can call ftruncate()
+  // directly), this call returns unsanitized base::File::Error information.
+  [EnableIf=is_mac]
+  SetLength(mojo_base.mojom.File backing_file, int64 length) =>
+  (mojo_base.mojom.File backing_file, bool result);
 };
diff --git a/third_party/blink/public/strings/translations/blink_strings_te.xtb b/third_party/blink/public/strings/translations/blink_strings_te.xtb
index 5c72b15..fd71149 100644
--- a/third_party/blink/public/strings/translations/blink_strings_te.xtb
+++ b/third_party/blink/public/strings/translations/blink_strings_te.xtb
@@ -5,7 +5,7 @@
 <translation id="10623998915015855">టోగుల్ బటన్</translation>
 <translation id="1088086359088493902">సెకన్లు</translation>
 <translation id="1142001580032786438">వారం పికర్‌ను చూపుతుంది</translation>
-<translation id="1171774979989969504">దయచేసి ఇమెయిల్ చిరునామాను ఎంటర్ చెయ్యండి.</translation>
+<translation id="1171774979989969504">దయచేసి ఇమెయిల్ చిరునామాను ఎంటర్ చేయండి.</translation>
 <translation id="1178581264944972037">పాజ్ చేయి</translation>
 <translation id="1188858454923323853">బహుమానపూర్వకం</translation>
 <translation id="1206619573307042055">marquee</translation>
diff --git a/third_party/blink/renderer/core/app_history/app_history.cc b/third_party/blink/renderer/core/app_history/app_history.cc
index f555718..6167d79 100644
--- a/third_party/blink/renderer/core/app_history/app_history.cc
+++ b/third_party/blink/renderer/core/app_history/app_history.cc
@@ -426,17 +426,16 @@
   if (key == current()->key())
     return ScriptPromise::CastUndefined(script_state);
 
-  if (AppHistoryApiNavigation* previous_navigation =
-          ongoing_traversals_.DeprecatedAtOrEmptyValue(key)) {
-    return previous_navigation->returned_promise->Promise();
+  auto previous_navigation = ongoing_traversals_.find(key);
+  if (previous_navigation != ongoing_traversals_.end()) {
+    return previous_navigation->value->returned_promise->Promise();
   }
 
   AppHistoryApiNavigation* ongoing_navigation =
       MakeGarbageCollected<AppHistoryApiNavigation>(script_state, options, key);
   ongoing_traversals_.insert(key, ongoing_navigation);
 
-  AppHistoryEntry* destination =
-      entries_[keys_to_indices_.DeprecatedAtOrEmptyValue(key)];
+  AppHistoryEntry* destination = entries_[keys_to_indices_.at(key)];
 
   // TODO(japhet): We will fire the navigate event for same-document navigations
   // at commit time, but not cross-document. This should probably move to a more
@@ -574,8 +573,8 @@
 
   AppHistoryApiNavigation* navigation = nullptr;
   if (destination_item && !destination_item->GetAppHistoryKey().IsNull()) {
-    navigation = ongoing_traversals_.DeprecatedAtOrEmptyValue(
-        destination_item->GetAppHistoryKey());
+    auto iter = ongoing_traversals_.find(destination_item->GetAppHistoryKey());
+    navigation = iter == ongoing_traversals_.end() ? nullptr : iter->value;
   } else {
     navigation = ongoing_non_traversal_navigation_;
   }
@@ -594,9 +593,10 @@
           destination_state);
   if (type == WebFrameLoadType::kBackForward) {
     const String& key = destination_item->GetAppHistoryKey();
-    destination->SetTraverseProperties(
-        key, destination_item->GetAppHistoryId(),
-        keys_to_indices_.DeprecatedAtOrEmptyValue(key));
+    auto iter = keys_to_indices_.find(key);
+    int index = iter == keys_to_indices_.end() ? 0 : iter->value;
+    destination->SetTraverseProperties(key, destination_item->GetAppHistoryId(),
+                                       index);
   }
   init->setDestination(destination);
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 3027631..d3e45ea 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -484,7 +484,8 @@
     const QualifiedName& name) {
   ExplicitlySetAttrElementsMap* element_attribute_map =
       element->GetDocument().GetExplicitlySetAttrElementsMap(element);
-  return element_attribute_map->DeprecatedAtOrEmptyValue(name);
+  return element_attribute_map->Contains(name) ? element_attribute_map->at(name)
+                                               : nullptr;
 }
 
 // Checks that the given element |candidate| is a descendant of
@@ -868,7 +869,8 @@
   // run the synchronization steps which modify the map invalidating any
   // outstanding iterators.
   HeapLinkedHashSet<WeakMember<Element>>* stored_elements =
-      element_attribute_map->DeprecatedAtOrEmptyValue(name);
+      element_attribute_map->Contains(name) ? element_attribute_map->at(name)
+                                            : nullptr;
   if (!stored_elements) {
     stored_elements =
         MakeGarbageCollected<HeapLinkedHashSet<WeakMember<Element>>>();
diff --git a/third_party/blink/renderer/core/dom/id_target_observer_registry.cc b/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
index c15940a9..7517b76 100644
--- a/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
+++ b/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
@@ -63,7 +63,8 @@
   DCHECK(!id.IsEmpty());
   DCHECK(!registry_.IsEmpty());
 
-  notifying_observers_in_set_ = registry_.DeprecatedAtOrEmptyValue(id.Impl());
+  if (registry_.Contains(id.Impl()))
+    notifying_observers_in_set_ = registry_.at(id.Impl());
   if (!notifying_observers_in_set_)
     return;
 
@@ -81,10 +82,9 @@
 }
 
 bool IdTargetObserverRegistry::HasObservers(const AtomicString& id) const {
-  if (id.IsEmpty() || registry_.IsEmpty())
+  if (id.IsEmpty() || registry_.IsEmpty() || !registry_.Contains(id.Impl()))
     return false;
-  ObserverSet* set = registry_.DeprecatedAtOrEmptyValue(id.Impl());
-  return set && !set->IsEmpty();
+  return !registry_.at(id.Impl())->IsEmpty();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/node_lists_node_data.h b/third_party/blink/renderer/core/dom/node_lists_node_data.h
index 3478fff9..52ba9da 100644
--- a/third_party/blink/renderer/core/dom/node_lists_node_data.h
+++ b/third_party/blink/renderer/core/dom/node_lists_node_data.h
@@ -112,9 +112,11 @@
 
   template <typename T>
   T* Cached(CollectionType collection_type) {
-    return static_cast<T*>(
-        atomic_name_caches_.DeprecatedAtOrEmptyValue(NamedNodeListKey(
-            collection_type, CSSSelector::UniversalSelectorAtom())));
+    auto key =
+        NamedNodeListKey(collection_type, CSSSelector::UniversalSelectorAtom());
+    return static_cast<T*>(atomic_name_caches_.Contains(key)
+                               ? atomic_name_caches_.at(key)
+                               : nullptr);
   }
 
   TagCollectionNS* AddCache(ContainerNode& node,
diff --git a/third_party/blink/renderer/core/dom/nth_index_cache.cc b/third_party/blink/renderer/core/dom/nth_index_cache.cc
index e8498c2e..a5ab816 100644
--- a/third_party/blink/renderer/core/dom/nth_index_cache.cc
+++ b/third_party/blink/renderer/core/dom/nth_index_cache.cc
@@ -83,9 +83,9 @@
     return 1;
   NthIndexCache* nth_index_cache = element.GetDocument().GetNthIndexCache();
   NthIndexData* nth_index_data = nullptr;
-  if (nth_index_cache && nth_index_cache->parent_map_) {
-    nth_index_data = nth_index_cache->parent_map_->DeprecatedAtOrEmptyValue(
-        element.parentNode());
+  if (nth_index_cache && nth_index_cache->parent_map_ &&
+      nth_index_cache->parent_map_->Contains(element.parentNode())) {
+    nth_index_data = nth_index_cache->parent_map_->at(element.parentNode());
   }
   if (nth_index_data)
     return nth_index_data->NthIndex(element);
@@ -100,9 +100,9 @@
     return 1;
   NthIndexCache* nth_index_cache = element.GetDocument().GetNthIndexCache();
   NthIndexData* nth_index_data = nullptr;
-  if (nth_index_cache && nth_index_cache->parent_map_) {
-    nth_index_data = nth_index_cache->parent_map_->DeprecatedAtOrEmptyValue(
-        element.parentNode());
+  if (nth_index_cache && nth_index_cache->parent_map_ &&
+      nth_index_cache->parent_map_->Contains(element.parentNode())) {
+    nth_index_data = nth_index_cache->parent_map_->at(element.parentNode());
   }
   if (nth_index_data)
     return nth_index_data->NthLastIndex(element);
@@ -116,9 +116,11 @@
   DCHECK(element.parentNode());
   if (!parent_map_for_type_)
     return nullptr;
-  if (const IndexByType* map = parent_map_for_type_->DeprecatedAtOrEmptyValue(
-          element.parentNode())) {
-    return map->DeprecatedAtOrEmptyValue(element.tagName());
+  const IndexByType* map = parent_map_for_type_->Contains(element.parentNode())
+                               ? parent_map_for_type_->at(element.parentNode())
+                               : nullptr;
+  if (map && map->Contains(element.tagName())) {
+    return map->at(element.tagName());
   }
   return nullptr;
 }
diff --git a/third_party/blink/renderer/core/dom/processing_instruction.cc b/third_party/blink/renderer/core/dom/processing_instruction.cc
index cc51fe2..3be9397 100644
--- a/third_party/blink/renderer/core/dom/processing_instruction.cc
+++ b/third_party/blink/renderer/core/dom/processing_instruction.cc
@@ -120,12 +120,12 @@
   if (!is_css_ && !is_xsl_)
     return false;
 
-  href = attrs.DeprecatedAtOrEmptyValue("href");
-  charset = attrs.DeprecatedAtOrEmptyValue("charset");
-  String alternate = attrs.DeprecatedAtOrEmptyValue("alternate");
+  href = attrs.Contains("href") ? attrs.at("href") : "";
+  charset = attrs.Contains("charset") ? attrs.at("charset") : "";
+  String alternate = attrs.Contains("alternate") ? attrs.at("alternate") : "";
   alternate_ = alternate == "yes";
-  title_ = attrs.DeprecatedAtOrEmptyValue("title");
-  media_ = attrs.DeprecatedAtOrEmptyValue("media");
+  title_ = attrs.Contains("title") ? attrs.at("title") : "";
+  media_ = attrs.Contains("media") ? attrs.at("media") : "";
 
   return !alternate_ || !title_.IsEmpty();
 }
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_map.cc b/third_party/blink/renderer/core/dom/tree_ordered_map.cc
index 2c03a1ec..2484d29 100644
--- a/third_party/blink/renderer/core/dom/tree_ordered_map.cc
+++ b/third_party/blink/renderer/core/dom/tree_ordered_map.cc
@@ -115,10 +115,9 @@
                                     const TreeScope& scope) const {
   DCHECK(key);
 
-  MapEntry* entry = map_.DeprecatedAtOrEmptyValue(key);
-  if (!entry)
+  if (!map_.Contains(key))
     return nullptr;
-
+  MapEntry* entry = map_.at(key);
   DCHECK(entry->count);
   if (entry->element)
     return entry->element;
@@ -197,9 +196,9 @@
 
 Element* TreeOrderedMap::GetCachedFirstElementWithoutAccessingNodeTree(
     const AtomicString& key) {
-  MapEntry* entry = map_.DeprecatedAtOrEmptyValue(key);
-  if (!entry)
+  if (!map_.Contains(key))
     return nullptr;
+  MapEntry* entry = map_.at(key);
   DCHECK(entry->count);
   return entry->element;
 }
diff --git a/third_party/blink/renderer/core/dom/weak_identifier_map.h b/third_party/blink/renderer/core/dom/weak_identifier_map.h
index 8ff0cb2..245893ee 100644
--- a/third_party/blink/renderer/core/dom/weak_identifier_map.h
+++ b/third_party/blink/renderer/core/dom/weak_identifier_map.h
@@ -28,13 +28,14 @@
   }
 
   static IdentifierType Identifier(T* object) {
-    IdentifierType result =
-        Instance().object_to_identifier_.DeprecatedAtOrEmptyValue(object);
+    IdentifierType result;
 
-    if (WTF::IsHashTraitsEmptyValue<HashTraits<IdentifierType>>(result)) {
+    if (!Instance().object_to_identifier_.Contains(object)) {
       do {
         result = Next();
       } while (!LIKELY(Instance().Put(object, result)));
+    } else {
+      result = Instance().object_to_identifier_.at(object);
     }
     return result;
   }
@@ -44,8 +45,9 @@
   }
 
   static T* Lookup(IdentifierType identifier) {
-    return Instance().identifier_to_object_.DeprecatedAtOrEmptyValue(
-        identifier);
+    return Instance().identifier_to_object_.Contains(identifier)
+               ? Instance().identifier_to_object_.at(identifier)
+               : nullptr;
   }
 
   static void NotifyObjectDestroyed(T* object) {
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.cc b/third_party/blink/renderer/core/layout/layout_replaced.cc
index 5223b31a..f925567 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -645,9 +645,9 @@
   // intrinsic ratio but no intrinsic size. In order to maintain aspect ratio,
   // the intrinsic size for SVG might be faked from the aspect ratio,
   // see SVGImage::containerSize().
-  LayoutSize intrinsic_size =
-      overridden_intrinsic_size ? *overridden_intrinsic_size : IntrinsicSize();
-  if (!intrinsic_size.Width() || !intrinsic_size.Height())
+  PhysicalSize intrinsic_size(
+      overridden_intrinsic_size ? *overridden_intrinsic_size : IntrinsicSize());
+  if (intrinsic_size.IsEmpty())
     return content_rect;
 
   PhysicalSize scaled_intrinsic_size(intrinsic_size);
@@ -664,9 +664,9 @@
     case EObjectFit::kContain:
     case EObjectFit::kCover:
       final_rect.size = final_rect.size.FitToAspectRatio(
-          scaled_intrinsic_size, object_fit == EObjectFit::kCover
-                                     ? kAspectRatioFitGrow
-                                     : kAspectRatioFitShrink);
+          intrinsic_size, object_fit == EObjectFit::kCover
+                              ? kAspectRatioFitGrow
+                              : kAspectRatioFitShrink);
       if (object_fit != EObjectFit::kScaleDown ||
           final_rect.Width() <= scaled_intrinsic_size.width)
         break;
diff --git a/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc b/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc
index ceacd700..4370c653 100644
--- a/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/resource_loader_code_cache_test.cc
@@ -88,18 +88,39 @@
     response_.SetHttpStatusCode(200);
   }
 
-  std::vector<uint8_t> MakeSerializedCodeCacheData() {
+  static const size_t kSha256Bytes = 256 / 8;
+
+  std::vector<uint8_t> MakeSerializedCodeCacheData(
+      base::span<uint8_t> data,
+      absl::optional<String> source_text = {},
+      uint32_t data_type_id = 0,
+      CachedMetadataHandler::CachedMetadataType outer_type =
+          CachedMetadataHandler::kSingleEntryWithHash,
+      CachedMetadataHandler::CachedMetadataType inner_type =
+          CachedMetadataHandler::kSingleEntry) {
     const size_t kCachedMetadataTypeSize = sizeof(uint32_t);
-    const size_t kSha256Bytes = 256 / 8;
-    const size_t kDataSize =
-        kCachedMetadataTypeSize + kSha256Bytes + kCachedMetaDataStart + 1;
-    std::vector<uint8_t> data(kDataSize);
-    *reinterpret_cast<uint32_t*>(&data[0]) =
-        CachedMetadataHandler::kSingleEntryWithHash;
+    const size_t kSerializedDataSize = kCachedMetadataTypeSize + kSha256Bytes +
+                                       kCachedMetaDataStart + data.size();
+    std::vector<uint8_t> serialized_data(kSerializedDataSize);
+    *reinterpret_cast<uint32_t*>(&serialized_data[0]) = outer_type;
+    if (source_text.has_value()) {
+      DigestValue hash;
+      CHECK(ComputeDigest(kHashAlgorithmSha256,
+                          static_cast<const char*>(source_text->Bytes()),
+                          source_text->CharactersSizeInBytes(), hash));
+      CHECK_EQ(hash.size(), kSha256Bytes);
+      memcpy(&serialized_data[kCachedMetadataTypeSize], hash.data(),
+             kSha256Bytes);
+    }
     *reinterpret_cast<uint32_t*>(
-        &data[kCachedMetadataTypeSize + kSha256Bytes]) =
-        CachedMetadataHandler::kSingleEntry;
-    return data;
+        &serialized_data[kCachedMetadataTypeSize + kSha256Bytes]) = inner_type;
+    *reinterpret_cast<uint32_t*>(
+        &serialized_data[kCachedMetadataTypeSize + kSha256Bytes +
+                         kCacheDataTypeStart]) = data_type_id;
+    memcpy(&serialized_data[kCachedMetadataTypeSize + kSha256Bytes +
+                            kCachedMetaDataStart],
+           data.data(), data.size());
+    return serialized_data;
   }
 
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
@@ -150,18 +171,23 @@
   // Nothing has changed yet because the code cache hasn't yet responded.
   EXPECT_FALSE(resource_->CodeCacheSize());
 
-  controller_->Respond(base::Time(),
-                       mojo_base::BigBuffer(MakeSerializedCodeCacheData()));
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  controller_->Respond(
+      base::Time(),
+      mojo_base::BigBuffer(MakeSerializedCodeCacheData(cache_data)));
 
   // Code cache data was present.
-  EXPECT_TRUE(resource_->CodeCacheSize());
+  EXPECT_EQ(resource_->CodeCacheSize(),
+            cache_data.size() + kCachedMetaDataStart);
 }
 
 TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullResponseSecond) {
   CommonSetup();
 
-  controller_->Respond(base::Time(),
-                       mojo_base::BigBuffer(MakeSerializedCodeCacheData()));
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  controller_->Respond(
+      base::Time(),
+      mojo_base::BigBuffer(MakeSerializedCodeCacheData(cache_data)));
 
   // Nothing has changed yet because the content response hasn't arrived yet.
   EXPECT_FALSE(resource_->CodeCacheSize());
@@ -169,14 +195,17 @@
   loader_->DidReceiveResponse(WrappedResourceResponse(response_));
 
   // Code cache data was present.
-  EXPECT_TRUE(resource_->CodeCacheSize());
+  EXPECT_EQ(resource_->CodeCacheSize(),
+            cache_data.size() + kCachedMetaDataStart);
 }
 
 TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheFullHttpsScheme) {
   CommonSetup("https://www.example.com/");
 
-  controller_->Respond(base::Time(),
-                       mojo_base::BigBuffer(MakeSerializedCodeCacheData()));
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  controller_->Respond(
+      base::Time(),
+      mojo_base::BigBuffer(MakeSerializedCodeCacheData(cache_data)));
 
   // Nothing has changed yet because the content response hasn't arrived yet.
   EXPECT_FALSE(resource_->CodeCacheSize());
@@ -188,5 +217,107 @@
   EXPECT_FALSE(resource_->CodeCacheSize());
 }
 
+TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheInvalidOuterType) {
+  CommonSetup();
+
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  controller_->Respond(
+      base::Time(),
+      mojo_base::BigBuffer(MakeSerializedCodeCacheData(
+          cache_data, {}, 0, CachedMetadataHandler::kSingleEntry)));
+
+  // Nothing has changed yet because the content response hasn't arrived yet.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+
+  loader_->DidReceiveResponse(WrappedResourceResponse(response_));
+
+  // The serialized metadata was rejected due to an invalid outer type.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+}
+
+TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheInvalidInnerType) {
+  CommonSetup();
+
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  controller_->Respond(
+      base::Time(),
+      mojo_base::BigBuffer(MakeSerializedCodeCacheData(
+          cache_data, {}, 0, CachedMetadataHandler::kSingleEntryWithHash,
+          CachedMetadataHandler::kSourceKeyedMap)));
+
+  // Nothing has changed yet because the content response hasn't arrived yet.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+
+  loader_->DidReceiveResponse(WrappedResourceResponse(response_));
+
+  // The serialized metadata was rejected due to an invalid inner type.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+}
+
+TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheHashCheckSuccess) {
+  CommonSetup();
+
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  String source_text("alert('hello world');");
+  controller_->Respond(
+      base::Time(), mojo_base::BigBuffer(
+                        MakeSerializedCodeCacheData(cache_data, source_text)));
+
+  // Nothing has changed yet because the content response hasn't arrived yet.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+
+  loader_->DidReceiveResponse(WrappedResourceResponse(response_));
+
+  // Code cache data was present.
+  EXPECT_EQ(resource_->CodeCacheSize(),
+            cache_data.size() + kCachedMetaDataStart);
+
+  // Make sure the following steps don't try to do anything too fancy.
+  resource_->CacheHandler()->DisableSendToPlatformForTesting();
+
+  // Successful check.
+  resource_->CacheHandler()->Check(nullptr, ParkableString(source_text.Impl()));
+
+  // Now the metadata can be accessed.
+  scoped_refptr<CachedMetadata> cached_metadata =
+      resource_->CacheHandler()->GetCachedMetadata(0);
+  EXPECT_EQ(cached_metadata->size(), cache_data.size());
+  EXPECT_EQ(*(cached_metadata->Data() + 2), cache_data[2]);
+
+  // But trying to load the metadata with the wrong data_type_id fails.
+  EXPECT_FALSE(resource_->CacheHandler()->GetCachedMetadata(4));
+}
+
+TEST_F(ResourceLoaderCodeCacheTest, WebUICodeCacheHashCheckFailure) {
+  CommonSetup();
+
+  std::vector<uint8_t> cache_data{2, 3, 4, 5, 6};
+  String source_text("alert('hello world');");
+  controller_->Respond(
+      base::Time(), mojo_base::BigBuffer(
+                        MakeSerializedCodeCacheData(cache_data, source_text)));
+
+  // Nothing has changed yet because the content response hasn't arrived yet.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+
+  loader_->DidReceiveResponse(WrappedResourceResponse(response_));
+
+  // Code cache data was present.
+  EXPECT_EQ(resource_->CodeCacheSize(),
+            cache_data.size() + kCachedMetaDataStart);
+
+  // Make sure the following steps don't try to do anything too fancy.
+  resource_->CacheHandler()->DisableSendToPlatformForTesting();
+
+  // Failed check: source text is different.
+  String source_text_2("alert('improved program');");
+  resource_->CacheHandler()->Check(nullptr,
+                                   ParkableString(source_text_2.Impl()));
+
+  // The metadata has been cleared.
+  EXPECT_FALSE(resource_->CodeCacheSize());
+  EXPECT_FALSE(resource_->CacheHandler()->GetCachedMetadata(0));
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
index c6a498f..8d8ed83 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -24,6 +24,8 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "cc/animation/animation_host.h"
+#include "cc/animation/scroll_offset_animations.h"
 #include "cc/base/features.h"
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/layers/scrollbar_layer_base.h"
@@ -1987,8 +1989,9 @@
 
   EXPECT_EQ(gfx::ScrollOffset(), CurrentScrollOffset(element_id));
 
-  // Simulate a direct scroll update out of document lifecycle update.
-  scroller->scrollTo(0, 200);
+  // Simulate an anchoring scroll update out of document lifecycle update.
+  scrollable_area->SetScrollOffset(blink::ScrollOffset(0, 200),
+                                   mojom::blink::ScrollType::kAnchoring);
   EXPECT_EQ(FloatPoint(0, 200), scrollable_area->ScrollPosition());
   EXPECT_EQ(gfx::ScrollOffset(0, 200), CurrentScrollOffset(element_id));
 
@@ -2000,6 +2003,15 @@
   RootCcLayer()->layer_tree_host()->ApplyCompositorChanges(&commit_data);
   EXPECT_EQ(FloatPoint(0, 210), scrollable_area->ScrollPosition());
   EXPECT_EQ(gfx::ScrollOffset(0, 210), CurrentScrollOffset(element_id));
+
+  // Simulate a programmatic scroll update out of document lifecycle update.
+  scroller->scrollTo(0, 200);
+  RootCcLayer()->layer_tree_host()->ApplyCompositorChanges(&commit_data);
+
+  // The programmatic scroll is prioritized over the impl-side update.
+  EXPECT_EQ(FloatPoint(0, 200), scrollable_area->ScrollPosition());
+  ForceFullCompositingUpdate();
+  EXPECT_EQ(gfx::ScrollOffset(0, 200), CurrentScrollOffset(element_id));
 }
 
 TEST_P(ScrollingTest, ThumbInvalidatesLayer) {
@@ -2026,6 +2038,25 @@
   }
 }
 
+TEST_P(ScrollingTest, ProgrammaticScrollCancelsImplAnimation) {
+  LoadHTML(R"HTML(
+    <div id='scroller' style='overflow: scroll; width: 100px; height: 100px'>
+      <div style='height: 1000px'></div>
+    </div>
+  )HTML");
+  ForceFullCompositingUpdate();
+
+  auto* scroller = GetFrame()->GetDocument()->getElementById("scroller");
+  auto* scrollable_area = scroller->GetLayoutBox()->GetScrollableArea();
+  auto& scroll_offset_animations =
+      scrollable_area->GetCompositorAnimationHost()->scroll_offset_animations();
+  cc::ElementId element_id = scrollable_area->GetScrollElementId();
+
+  EXPECT_FALSE(scroll_offset_animations.HasPendingCancelUpdate(element_id));
+  scroller->scrollTo(0, 200);
+  EXPECT_TRUE(scroll_offset_animations.HasPendingCancelUpdate(element_id));
+}
+
 class UnifiedScrollingSimTest : public SimTest, public PaintTestConfigurations {
  public:
   UnifiedScrollingSimTest() : scroll_unification_enabled_(true) {}
diff --git a/third_party/blink/renderer/core/script/pending_import_map.cc b/third_party/blink/renderer/core/script/pending_import_map.cc
index 7e82197f..ce7d534 100644
--- a/third_party/blink/renderer/core/script/pending_import_map.cc
+++ b/third_party/blink/renderer/core/script/pending_import_map.cc
@@ -18,18 +18,15 @@
                                                  const String& import_map_text,
                                                  const KURL& base_url) {
   ExecutionContext* context = element.GetExecutionContext();
-  ScriptState* script_state =
-      ToScriptStateForMainWorld(To<LocalDOMWindow>(context)->GetFrame());
 
   absl::optional<ImportMapError> error_to_rethrow;
   ImportMap* import_map =
       ImportMap::Parse(import_map_text, base_url, *context, &error_to_rethrow);
   return MakeGarbageCollected<PendingImportMap>(
-      script_state, element, import_map, std::move(error_to_rethrow), *context);
+      element, import_map, std::move(error_to_rethrow), *context);
 }
 
 PendingImportMap::PendingImportMap(
-    ScriptState* script_state,
     ScriptElementBase& element,
     ImportMap* import_map,
     absl::optional<ImportMapError> error_to_rethrow,
diff --git a/third_party/blink/renderer/core/script/pending_import_map.h b/third_party/blink/renderer/core/script/pending_import_map.h
index 79bbe8e..2bc92bca 100644
--- a/third_party/blink/renderer/core/script/pending_import_map.h
+++ b/third_party/blink/renderer/core/script/pending_import_map.h
@@ -40,8 +40,7 @@
                                         const String& import_map_text,
                                         const KURL& base_url);
 
-  PendingImportMap(ScriptState* script_state,
-                   ScriptElementBase&,
+  PendingImportMap(ScriptElementBase&,
                    ImportMap*,
                    absl::optional<ImportMapError> error_to_rethrow,
                    const ExecutionContext& original_context);
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
index 97e5b4a1..12b7ce0 100644
--- a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
+++ b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.cc
@@ -19,12 +19,7 @@
 
 namespace blink {
 
-ScrollAnimatorCompositorCoordinator::ScrollAnimatorCompositorCoordinator()
-    : element_id_(),
-      run_state_(RunState::kIdle),
-      impl_only_animation_takeover_(false),
-      compositor_animation_id_(0),
-      compositor_animation_group_id_(0) {
+ScrollAnimatorCompositorCoordinator::ScrollAnimatorCompositorCoordinator() {
   compositor_animation_ = CompositorAnimation::Create();
   DCHECK(compositor_animation_);
   compositor_animation_->SetAnimationDelegate(this);
@@ -97,6 +92,8 @@
 void ScrollAnimatorCompositorCoordinator::CancelAnimation() {
   switch (run_state_) {
     case RunState::kIdle:
+      CancelImplOnlyScrollOffsetAnimation();
+      break;
     case RunState::kWaitingToCancelOnCompositor:
     case RunState::kPostAnimationCleanup:
       break;
@@ -326,6 +323,24 @@
   GetScrollableArea()->RegisterForAnimation();
 }
 
+void ScrollAnimatorCompositorCoordinator::
+    CancelImplOnlyScrollOffsetAnimation() {
+  auto* scrollable_area = GetScrollableArea();
+  DCHECK(scrollable_area);
+
+  if (!scrollable_area->ScrollAnimatorEnabled())
+    return;
+
+  cc::AnimationHost* host = scrollable_area->GetCompositorAnimationHost();
+  if (!host)
+    return;
+
+  CompositorElementId element_id = scrollable_area->GetScrollElementId();
+  DCHECK(element_id);
+
+  host->scroll_offset_animations().AddCancelUpdate(element_id);
+}
+
 String ScrollAnimatorCompositorCoordinator::RunStateAsText() const {
   switch (run_state_) {
     case RunState::kIdle:
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
index ccaaf91e..40e7b8e 100644
--- a/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
+++ b/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
@@ -178,7 +178,7 @@
   // The element id to which the compositor animation is attached when
   // the animation is present.
   CompositorElementId element_id_;
-  RunState run_state_;
+  RunState run_state_ = RunState::kIdle;
   int compositor_animation_id() const { return compositor_animation_id_; }
 
   // An adjustment to the scroll offset on the main thread that may affect
@@ -188,7 +188,7 @@
   // If set to true, sends a cc::ScrollOffsetAnimationUpdate to cc which will
   // abort the impl-only scroll offset animation and continue it on main
   // thread.
-  bool impl_only_animation_takeover_;
+  bool impl_only_animation_takeover_ = false;
 
  private:
   CompositorElementId GetScrollElementId() const;
@@ -198,8 +198,10 @@
   // DocumentLifecycle::LifecycleState::CompositingClean.
   void TakeOverImplOnlyScrollOffsetAnimation();
 
-  int compositor_animation_id_;
-  int compositor_animation_group_id_;
+  void CancelImplOnlyScrollOffsetAnimation();
+
+  int compositor_animation_id_ = 0;
+  int compositor_animation_group_id_ = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
index 56d3a75..60306154 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
@@ -6,7 +6,6 @@
 
 #include "base/files/file_error_or.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -15,6 +14,11 @@
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
+#if defined(OS_MAC)
+#include "base/mac/mac_util.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#endif
+
 namespace blink {
 
 FileSystemAccessFileDelegate* FileSystemAccessFileDelegate::Create(
@@ -29,8 +33,14 @@
     ExecutionContext* context,
     base::File backing_file,
     base::PassKey<FileSystemAccessFileDelegate>)
-    : backing_file_(std::move(backing_file)),
-      task_runner_(context->GetTaskRunner(TaskType::kMiscPlatformAPI)) {}
+    :
+#if defined(OS_MAC)
+      context_(context),
+      file_utilities_host_(context),
+#endif  // defined(OS_MAC)
+      backing_file_(std::move(backing_file)),
+      task_runner_(context->GetTaskRunner(TaskType::kMiscPlatformAPI)) {
+}
 
 base::FileErrorOr<int> FileSystemAccessRegularFileDelegate::Read(
     int64_t offset,
@@ -101,6 +111,24 @@
     return;
   }
 
+#if defined(OS_MAC)
+  // On macOS < 10.15, a sandboxing limitation causes failures in ftruncate()
+  // syscalls issued from renderers. For this reason, base::File::SetLength()
+  // fails in the renderer. We work around this problem by calling ftruncate()
+  // in the browser process. See https://crbug.com/1084565.
+  if (!base::mac::IsAtLeastOS10_15()) {
+    if (!file_utilities_host_.is_bound()) {
+      context_->GetBrowserInterfaceBroker().GetInterface(
+          file_utilities_host_.BindNewPipeAndPassReceiver(task_runner_));
+    }
+    file_utilities_host_->SetLength(
+        std::move(backing_file_), length,
+        WTF::Bind(&FileSystemAccessRegularFileDelegate::DidSetLengthMac,
+                  WrapPersistent(this), std::move(callback)));
+    return;
+  }
+#endif  // defined(OS_MAC)
+
   auto wrapped_callback =
       CrossThreadOnceFunction<void(bool)>(std::move(callback));
 
@@ -124,6 +152,16 @@
       CrossThreadBindOnce(std::move(wrapped_callback), std::move(result)));
 }
 
+#if defined(OS_MAC)
+void FileSystemAccessRegularFileDelegate::DidSetLengthMac(
+    base::OnceCallback<void(bool)> callback,
+    base::File file,
+    bool result) {
+  backing_file_ = std::move(file);
+  std::move(callback).Run(result);
+}
+
+#endif  // defined(OS_MAC)
 void FileSystemAccessRegularFileDelegate::Flush(
     base::OnceCallback<void(bool)> callback) {
   auto wrapped_callback =
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
index eaf79eb..914abe6 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
@@ -8,12 +8,18 @@
 #include "base/files/file.h"
 #include "base/files/file_error_or.h"
 #include "base/types/pass_key.h"
+#include "build/build_config.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/file_system_access/file_system_access_file_delegate.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
+#if defined(OS_MAC)
+#include "third_party/blink/public/mojom/file/file_utilities.mojom-blink.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#endif  // defined(OS_MAC)
+
 namespace blink {
 
 // Non-incognito implementation of the FileSystemAccessFileDelegate. This class
@@ -33,6 +39,14 @@
   FileSystemAccessRegularFileDelegate& operator=(
       const FileSystemAccessRegularFileDelegate&) = delete;
 
+  void Trace(Visitor* visitor) const override {
+    FileSystemAccessFileDelegate::Trace(visitor);
+#if defined(OS_MAC)
+    visitor->Trace(context_);
+    visitor->Trace(file_utilities_host_);
+#endif  // defined(OS_MAC)
+  }
+
   base::FileErrorOr<int> Read(int64_t offset,
                               base::span<uint8_t> data) override;
   base::FileErrorOr<int> Write(int64_t offset,
@@ -68,6 +82,18 @@
       CrossThreadOnceClosure wrapped_callback,
       scoped_refptr<base::SequencedTaskRunner> task_runner);
 
+#if defined(OS_MAC)
+  void DidSetLengthMac(base::OnceCallback<void(bool)> callback,
+                       base::File file,
+                       bool result);
+
+  // We need the FileUtilitiesHost only on Mac, where we have to execute
+  // base::File::SetLength on the browser process, see crbug.com/1084565.
+  // We need the context_ to create the instance of FileUtilitiesHost lazily.
+  Member<ExecutionContext> context_;
+  HeapMojoRemote<mojom::blink::FileUtilitiesHost> file_utilities_host_;
+#endif  // defined(OS_MAC)
+
   // The file on disk backing the parent FileSystemFileHandle.
   base::File backing_file_;
 
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
index 22228a0..0ca78782 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.cc
@@ -14,10 +14,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
-#if defined(OS_MAC)
-#include "base/mac/mac_util.h"
-#endif
-
 namespace blink {
 
 FileSystemSyncAccessHandle::FileSystemSyncAccessHandle(
@@ -191,20 +187,6 @@
     ScriptState* script_state,
     uint64_t size,
     ExceptionState& exception_state) {
-#if defined(OS_MAC)
-  // On macOS < 10.15, a sandboxing limitation causes failures in ftruncate()
-  // syscalls issued from renderers. For this reason, base::File::SetLength()
-  // fails in the renderer.
-  // TODO: Work around this problem by calling ftruncate() in the browser
-  // process. See crbug.com/1084565.
-  if (!base::mac::IsAtLeastOS10_15()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kNotSupportedError,
-        "FileSystemSyncAccessHandle.truncate is not yet supported on MacOS");
-    return ScriptPromise();
-  }
-#endif  // defined(OS_MAC)
-
   if (is_closed_) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "The file was already closed");
diff --git a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
index df8a6f50..cc72f94 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
+++ b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
@@ -49,14 +49,14 @@
 HRTFDatabaseLoader::CreateAndLoadAsynchronouslyIfNecessary(float sample_rate) {
   DCHECK(IsMainThread());
 
-  scoped_refptr<HRTFDatabaseLoader> loader =
-      GetLoaderMap().DeprecatedAtOrEmptyValue(sample_rate);
-  if (loader) {
+  if (GetLoaderMap().Contains(sample_rate)) {
+    scoped_refptr<HRTFDatabaseLoader> loader = GetLoaderMap().at(sample_rate);
     DCHECK_EQ(sample_rate, loader->DatabaseSampleRate());
     return loader;
   }
 
-  loader = base::AdoptRef(new HRTFDatabaseLoader(sample_rate));
+  scoped_refptr<HRTFDatabaseLoader> loader =
+      base::AdoptRef(new HRTFDatabaseLoader(sample_rate));
   GetLoaderMap().insert(sample_rate, loader.get());
   loader->LoadAsynchronously();
   return loader;
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
index 5429aa4a..ee814fd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
@@ -33,7 +33,7 @@
 
 constexpr size_t kDefaultMaxBufferedBodyBytesPerRequest = 100 * 1000;
 constexpr base::TimeDelta kGracePeriodToFinishLoadingWhileInBackForwardCache =
-    base::TimeDelta::FromSeconds(15);
+    base::TimeDelta::FromSeconds(60);
 
 }  // namespace
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index cb642241..f8569c78 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1763,6 +1763,7 @@
 crbug.com/987138 [ Win ] media/controls/doubletap-to-jump-forwards.html [ Pass Timeout ]
 crbug.com/867532 [ Linux ] http/tests/workers/worker-usecounter.html [ Pass Timeout ]
 crbug.com/1002377 external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Pass Timeout ]
+crbug.com/1002377 external/wpt/service-workers/service-worker/update-bytecheck-cors-import.https.html [ Pass Timeout ]
 crbug.com/805756 external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Pass Timeout ]
 crbug.com/666993 [ Debug ] external/wpt/requestidlecallback/callback-idle-periods.html [ Pass Timeout ]
 
@@ -4398,7 +4399,6 @@
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html [ Crash Failure Pass Timeout ]
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-z-index.html [ Crash Failure Pass Timeout ]
 crbug.com/757165 [ Win ] http/tests/devtools/console/console-filter-test.js [ Skip ]
-crbug.com/757165 [ Win ] http/tests/devtools/console/console-links-in-errors-with-trace.js [ Skip ]
 crbug.com/757165 [ Win ] http/tests/misc/client-hints-accept-meta-preloader.html [ Skip ]
 crbug.com/757165 [ Win ] paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child.html [ Skip ]
 crbug.com/757165 [ Win ] paint/invalidation/filters/filter-repaint-on-accelerated-layer.html [ Skip ]
@@ -5284,6 +5284,303 @@
 crbug.com/1207342 http/tests/devtools/editor/text-editor-home-button.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/editor/text-editor-smart-braces.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/editor/text-editor-word-jumps.js [ Failure Pass Timeout ]
+crbug.com/1207342 http/tests/devtools/inspect-iframe-from-different-domain.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/template-content-inspect-crash.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/classes-pane-widget.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/copy-styles.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-delete-inline-style.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-img-tooltip.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-panel-reload-assert.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-panel-selection-after-delete.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-panel-selection-on-refresh.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-panel-styles.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-save-to-temp-var.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/elements-treeoutline-copy.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/hide-shortcut.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/inline-style-title.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/inspect-mode-after-profiling.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/inspect-mode-shadow-text.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/inspect-pointer-events-none.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/inspect-pseudo-element.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/node-reselect-on-append-child.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/reveal-whitespace-text-node.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/selected-element-changes-execution-context.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/css-variables/defined-css-variables.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/css-variables/resolve-css-variables.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/css-variables/resolve-inherited-css-variables.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/blur-while-edit-as-html.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/edit-after-model-changed.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/edit-style-attribute.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/edit-trimmed-attribute-value.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/set-outer-html-2.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/set-outer-html-body.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/set-outer-html-for-xhtml.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/set-outer-html-whitespace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/set-outer-html.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/switch-panels-while-editing-as-html.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/undo-set-outer-html-2.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/edit/undo-set-outer-html.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/highlight/highlight-dom-updates.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/shadow/inspect-deep-shadow-element.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/shadow/reveal-shadow-dom-node.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/cancel-upon-invalid-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/edit-css-with-source-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/import-added-through-js-crash.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/selector-line-deprecated.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/show-all-properties.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/styles-mouse-test.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/styles-parse-invalid-properties.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/styles-redirected-css.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/undo-after-cancelled-editing.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/undo-change-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/undo-property-toggle.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/undo-set-selector-text.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/up-down-numerics-and-colors.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/updates-during-dom-traversal.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/updates-throttled.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles/url-multiple-collapsing.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/add-new-rule-invalid-selector.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/add-new-rule-keyboard.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/case-sensitive-suggestions.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/color-aware-property-value-edit.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/commit-selector-mark-matching.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/commit-selector.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/cssom-media-insert-crash.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/disable-property-workingcopy-update.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/dynamic-style-tag.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/edit-inspector-stylesheet.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/edit-media-text.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/edit-name-with-trimmed-value.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/edit-value-inside-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/edit-value-with-trimmed-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/empty-background-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-1/filter-matched-styles.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/add-import-rule.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/cssom-shorthand-important.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/inactive-properties-with-variables.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/inactive-properties.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/inherited-mixed-case-properties.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/inject-stylesheet.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/keyframes-rules.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/lazy-computed-style.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/media-emulation.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/media-queries.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/media-using-same-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/metrics-box-sizing.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/page-reload-update-sidebar.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/parse-comments.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/parse-declaration-unterminated-comment.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/parse-declaration-with-quote.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/parse-utf8-bom.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/paste-property.js [ Crash Failure Pass Timeout ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/perform-undo-perform-of-mergable-action.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-2/region-style-crash.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/computed-properties-retain-expanded.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/selector-list.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/shadow-dom-rules.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/simple-selector.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/style-autocomplete-swatches.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/style-autocomplete.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Failure Pass Timeout ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-add-invalid-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-add-new-rule-to-stylesheet.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-cancel-editing.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-commit-editing.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-cssom-important-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-disable-then-change.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-disable-then-delete.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-disable-then-enable.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-3/styles-variables.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/cssom-constructed.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/cssom-insert-rule.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/do-not-rebuild-styles-on-every-change.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/style-update-during-selector-edit.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-edit-property-after-invalid-rule.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-edit-slow-completions.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-grid-template.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-iframe.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-inherited-same-source.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-keyframes-cssom-injected.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-keyframes-display-none.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-keyframes.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-overloaded-shorthand.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-overriden-properties.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-properties-overload.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-source-lines-inline.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-source-lines-recovery.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-source-lines.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-update-links-1.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-update-links-2.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-update-links-3.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-update-links-4.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-url-linkify.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/styles-with-spaces-in-sourceURL.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/svg-style.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/undo-add-property.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/elements/styles-4/undo-add-rule-crash.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console-cd.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console-document-write-from-external-script-logging.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console-show-all-messages.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console-xhr-logging-async.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/device-orientation-success.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/file-reader-with-network-panel.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/inspect-element.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/sourcemap-section-warning.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/a11y-axe-core/console/console-error-a11y-test.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/alert-toString-exception.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/command-line-api-getEventListeners.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/command-line-api.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-Object-overwritten.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-assert.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-bad-stacktrace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-bind-fake.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-clear-function.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-clear.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-command-clear.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-control-characters.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-copy-treeoutline.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-copy-truncated-text.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-custom-formatters.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-dir-deprecated.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-dir-primitives.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-dirxml.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-edit-property-value.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-blocked.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-exception-report.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-fake.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-global.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-object-literal.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-scoped.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-syntax-error.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-throw.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval-undefined-override.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-eval.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-expand-removed-node.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-export.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-external-array.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-filter-level-test.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-focus.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-array-prototype.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-broken-unicode.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-classes.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-collections.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-es6-2.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-es6-symbols-error.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-performance.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-style-allowed.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-format-style.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-group-click.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-group-similar.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-history-contains-requested-text.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-last-result.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-linkify-relative-links.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-links-in-errors-with-trace.js [ Skip ]
+crbug.com/1207342 http/tests/devtools/console/console-links-on-messages-before-inspection.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-before-inspector-open.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-custom-elements.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-document-proto.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-eval-syntax-error.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-in-xhtml.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-linkify-links.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-linkify-stack-in-errors.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-short-hand-method.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-side-effects.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-syntax-error.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-toString-object.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-without-console.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-log-wrapped-in-framework.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-memory-equals-console-memory.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-message-contains-async-stack.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-message-format.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-message-from-inline-with-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-message-from-script-inside-svg.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-native-function.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-nested-group.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-object-constructor-name.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-on-paint-worklet.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-originating-command.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-pins.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-preserve-log-x-process-navigation.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-preserve-log.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-prompt-keyboard.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-proxy.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-repeat-count.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-save-to-temp-var.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-script-with-same-url.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-smart-enter.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-stack-overflow.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-substituted.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-tainted-globals.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-tests.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-time.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-timestamp.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-top-level-await.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-trace-arguments.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-trace-in-eval.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-trace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-trim-long-traces.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-trim-long-urls.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-truncate-long-messages.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-uncaught-exception-in-eval.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-uncaught-exception.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-uncaught-promise-in-worker.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-uncaught-promise.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-viewport-control.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-viewport-indices.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-viewport-selection.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-worker-nested-imports-syntax-error.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-xml-document.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/console-xpath.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/exception-objects.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/function-name-in-console-message-stack.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/only-one-deprecation-warning.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/shadow-element.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-clicking-messages.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-key-expand.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-key-links.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-stick-to-bottom-expand-object.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console/viewport-testing/console-stick-to-bottom-with-large-prompt.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/console-sidebar/console-filter-sidebar.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/csp/csp-inline-warning-contains-stacktrace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/database-data.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/database-structure.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/database-version-number.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/transaction-promise-console.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/runtime/runtime-es6-setSymbolPropertyValue.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/runtime/runtime-setPropertyValue.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/service-workers/lazy-addeventlisteners.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/sources/inspect-function.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/database-table-name-excaping.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/a11y-axe-core/application-panel/websql-console-a11y-test.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-iframe-idb.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-on-navigation.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/application-panel/resources-panel-websql.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/background-services/background-service-grid.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/background-services/background-services-panel.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/database-names.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/delete-entry.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/resources-panel.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/track-valid-origin.js [ Failure Pass ]
+crbug.com/1207342 http/tests/devtools/indexeddb/upgrade-events.js [ Failure Pass ]
 
 
 # First party DevTools issues only work in the first-party-sets virtual suite
@@ -5579,7 +5876,6 @@
 # Sheriff 2019-03-28
 crbug.com/946890 external/wpt/html/semantics/embedded-content/media-elements/location-of-the-media-resource/currentSrc.html [ Crash Failure Pass ]
 crbug.com/946711 [ Release ] http/tests/devtools/editor/text-editor-search-switch-editor.js [ Crash Failure Pass Timeout ]
-crbug.com/946712 [ Release ] http/tests/devtools/elements/styles-2/paste-property.js [ Crash Pass Timeout ]
 
 ### external/wpt/fetch/sec-metadata/
 crbug.com/947023 external/wpt/fetch/sec-metadata/font.tentative.https.sub.html [ Failure Pass ]
@@ -5601,7 +5897,6 @@
 # Sheriff 2019-04-17
 crbug.com/953591 [ Win ] fast/forms/datalist/input-appearance-range-with-transform.html [ Failure Pass ]
 crbug.com/953591 [ Win ] transforms/matrix-02.html [ Failure Pass ]
-crbug.com/938884 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ]
 
 # Sheriff 2019-04-18
 crbug.com/954297 [ Win ] http/tests/devtools/oopif/oopif-presentation-console-messages.js [ Crash Pass Timeout ]
@@ -6708,7 +7003,6 @@
 crbug.com/1179219 external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-currentSrc.html [ Failure ]
 
 # Sheriff 2021-02-18
-crbug.com/1179772 [ Win7 ] http/tests/devtools/console/console-preserve-log-x-process-navigation.js [ Failure Pass ]
 crbug.com/1179857 [ Linux ] http/tests/inspector-protocol/dom/dom-getFrameOwner.js [ Failure Pass ]
 crbug.com/1179905 [ Linux ] fast/multicol/nested-very-tall-inside-short-crash.html [ Failure Pass ]
 
@@ -7396,18 +7690,11 @@
 crbug.com/1218431 external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-flush.https.tentative.worker.html [ Skip ]
 crbug.com/1218431 virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-flush.https.tentative.worker.html [ Pass ]
 crbug.com/1218431 external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Skip ]
-crbug.com/1218431 [ Win ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Pass ]
-crbug.com/1218431 [ Linux ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Pass ]
-crbug.com/1218431 [ Fuchsia ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Pass ]
+crbug.com/1218431 virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Pass ]
 crbug.com/1218431 external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-getSize.https.tentative.worker.html [ Skip ]
 crbug.com/1218431 virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-getSize.https.tentative.worker.html [ Pass ]
 crbug.com/1218431 external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Skip ]
-crbug.com/1218431 [ Win ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Pass ]
-crbug.com/1218431 [ Linux ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Pass ]
-crbug.com/1218431 [ Fuchsia ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Pass ]
-# Mac below 10.15 is not implemented yet.
-crbug.com/1218431 [ Mac ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-close.https.tentative.worker.html [ Failure Pass ]
-crbug.com/1218431 [ Mac ] virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Failure Pass ]
+crbug.com/1218431 virtual/file-system-access-access-handle/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Pass ]
 
 # Sheriff 2021-06-30
 crbug.com/1216587 [ Win7 ] accessibility/scroll-window-sends-notification.html [ Failure Pass ]
@@ -7468,8 +7755,8 @@
 crbug.com/996511 virtual/plz-service-worker/external/wpt/service-workers/service-worker/getregistrations.https.html [ Crash Failure Pass Skip Timeout ]
 crbug.com/996511 virtual/plz-service-worker/http/tests/inspector-protocol/fetch/fetch-cors-preflight-sw.js [ Crash Failure Pass Skip Timeout ]
 
-# Expected to time out.
-crbug.com/1218540 storage/shared_storage/unimplemented-worklet-operations.html [ Timeout ]
+# Expected to time out, but NOT crash.
+crbug.com/1218540 storage/shared_storage/unimplemented-worklet-operations.html [ Crash Timeout ]
 
 # Sheriff 2021-07-14
 crbug.com/1229039 [ Linux ] external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Pass Timeout ]
@@ -7574,18 +7861,17 @@
 crbug.com/1237132 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-pattern-over-gradient.html [ Pass Timeout ]
 crbug.com/1178292 [ Mac ] fast/mediacapturefromelement/CanvasCaptureMediaStream-set-size-too-large.html [ Pass Timeout ]
 
-# Sheriff 2021-08-09
-crbug.com/1237909 [ Linux ] external/wpt/webrtc-svc/RTCRtpParameters-scalability.html [ Failure Pass Crash ]
-
 # Sheriff 2021-08-10
 crbug.com/1238266 [ Mac ] virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemSyncAccessHandle-truncate.https.tentative.worker.html [ Pass Failure ]
 crbug.com/1233840 external/wpt/html/cross-origin-opener-policy/historical/coep-navigate-popup-unsafe-inherit.https.html [ Pass Timeout ]
 crbug.com/1230534 external/wpt/webrtc/simulcast/basic.https.html [ Pass Timeout ]
 crbug.com/1230534 external/wpt/webrtc/simulcast/setParameters-active.https.html [ Failure Pass Timeout ]
-crbug.com/1237909 [ Mac ] external/wpt/webrtc-svc/RTCRtpParameters-scalability.html [ Pass Timeout ]
 
 # Sheriff 2021-08-12
 crbug.com/1237640 http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Pass Timeout ]
+crbug.com/1239175 http/tests/navigation/same-and-different-back.html [ Failure Pass ]
+crbug.com/1239164 http/tests/inspector-protocol/network/navigate-iframe-in2in.js [ Failure Pass ]
+crbug.com/1192932 http/tests/inspector-protocol/network/xhr-interception.js [ Failure Pass ]
 crbug.com/1238845 [ Win ] external/wpt/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html [ Failure Pass ]
 crbug.com/1238845 [ Mac ] external/wpt/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html [ Failure Pass ]
 crbug.com/1238845 [ Win ] external/wpt/css/css-highlight-api/painting/custom-highlight-painting-invalidation-002.html [ Failure Pass ]
@@ -7599,3 +7885,6 @@
 crbug.com/1238845 [ Win ] external/wpt/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html [ Failure Pass ]
 crbug.com/1238845 [ Mac ] external/wpt/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html [ Failure Pass ]
 crbug.com/1192215 external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html [ Failure Pass ]
+crbug.com/1237909 external/wpt/webrtc-svc/RTCRtpParameters-scalability.html [ Crash Failure Pass Timeout ]
+crbug.com/1239161 external/wpt/html/semantics/links/links-created-by-a-and-area-elements/htmlanchorelement_noopener.html [ Failure Pass ]
+crbug.com/1239139 virtual/prerender/wpt_internal/prerender/restriction-prompt-by-before-unload.html [ Crash Pass ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index 7113c95..d338154 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -49,13 +49,6 @@
 ### Tests that might be passing now.
 ###
 
-# Only on Mac Intel
-[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="depth32float";aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="Creation";layerCount=7;nonPowerOfTwo=true;canaryOnCreation=true;* [ Failure ]
-[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="depth32float";aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="StoreOpClear";layerCount=1;nonPowerOfTwo=false;canaryOnCreation=false;* [ Failure ]
-[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="depth32float";aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="StoreOpClear";layerCount=7;canaryOnCreation=false;* [ Failure ]
-[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="r8unorm";aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="StoreOpClear";layerCount=1;nonPowerOfTwo=false;canaryOnCreation=false;* [ Failure ]
-[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="rg8unorm";aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="StoreOpClear";layerCount=1;nonPowerOfTwo=false;canaryOnCreation=false;* [ Failure ]
-
 ###
 ### Untriaged timeouts
 ###
@@ -168,6 +161,7 @@
 crbug.com/dawn/690 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_copy_depth_stencil:format="depth16unorm";* [ Failure ]
 crbug.com/dawn/690 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="stencil8";* [ Failure ]
 crbug.com/dawn/690 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="depth16unorm";* [ Failure ]
+crbug.com/dawn/690 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,copyTextureToTexture:copy_stencil_aspect:format="stencil8";* [ Failure ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createTexture:zero_size:dimension="1d";* [ Failure ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createTexture:mipLevelCount,bound_check:dimension="1d";* [ Failure ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createTexture:mipLevelCount,format:format="depth16unorm";* [ Failure ]
@@ -246,12 +240,18 @@
 ### Mac (Metal) specific
 ###
 
-# Stencil textures with more than one mip level are disabled on Metal
+# Depth/stencil textures with multiple mip levels don't clear properly on Mac Intel. (By default they are disabled behind disallow_unsafe_apis.)
 crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_aspect:format="depth24plus-stencil8";* [ Failure ]
-crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_upload_to_stencil_aspect:stencilFormat="depth24plus-stencil8";mipLevel=2;* [ Failure ]
-crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_copy_depth_stencil:format="depth24plus-stencil8";mipLevel=2;* [ Failure ]
-crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_upload_to_stencil_aspect:stencilFormat="depth24plus-stencil8";mipLevel=2;* [ Failure ]
-crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="depth24plus-stencil8";mipLevel=2;* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_upload_to_stencil_aspect:stencilFormat="depth24plus-stencil8";* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:offsets_and_sizes_copy_depth_stencil:format="depth24plus-stencil8";* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_upload_to_stencil_aspect:stencilFormat="depth24plus-stencil8";* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,command_buffer,image_copy:rowsPerImage_and_bytesPerRow_depth_stencil:format="depth24plus-stencil8";* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:format="depth32float";mipLevelCount=5;canaryOnCreation=true;* [ Failure ]
+crbug.com/dawn/838 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:format="depth32float";mipLevelCount=5;uninitializeMethod="StoreOpClear";* [ Failure ]
+
+# r8unorm/rg8unorm with multiple mip levels don't clear properly on Mac Intel.
+crbug.com/dawn/1071 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:format="r8unorm";mipLevelCount=5;uninitializeMethod="StoreOpClear";* [ Failure ]
+crbug.com/dawn/1071 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:format="rg8unorm";mipLevelCount=5;uninitializeMethod="StoreOpClear";* [ Failure ]
 
 crbug.com/tint/993 [ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:shader,execution,robust_access:linear_memory:storageClass="workgroup";* [ Failure ]
 # Timeout + compilation failure
@@ -315,3 +315,6 @@
 
 # (NVIDIA-only) Test times out. Issue with hardware decoding?
 crbug.com/1238241 [ Win ] wpt_internal/webgpu/cts.html?q=webgpu:web_platform,external_texture,video:importExternalTexture,sample:* [ Skip ]
+
+# (Intel-only) Unexpected result. Possibly due to using dst-alpha on an attachment with no alpha channel.
+crbug.com/dawn/1063 [ Win ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count,blend:* [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt
new file mode 100644
index 0000000..1011609
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt
@@ -0,0 +1,22 @@
+This is a testharness.js-based test.
+PASS Local non-secure context can fetch local subresource.
+PASS Local non-secure context can fetch private subresource.
+PASS Local non-secure context can fetch public subresource.
+PASS Private non-secure context cannot fetch local subresource.
+PASS Private non-secure context can fetch private subresource.
+PASS Private non-secure context can fetch public subresource.
+PASS Public non-secure context cannot fetch local subresource.
+PASS Public non-secure context cannot fetch private subresource.
+PASS Public non-secure context can fetch public subresource.
+PASS Treat-as-public-address non-secure context cannot fetch local subresource.
+PASS Treat-as-public-address non-secure context cannot fetch private subresource.
+PASS Treat-as-public-address non-secure context can fetch public subresource.
+PASS Private HTTPS non-secure context cannot fetch local subresource.
+PASS Public HTTPS non-secure context cannot fetch local subresource.
+PASS Public HTTPS non-secure context cannot fetch private subresource.
+PASS Local non-secure context can open connection to ws://localhost.
+FAIL Private non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
+FAIL Public non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
+FAIL Treat-as-public non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
index 8e55559..6b2b6be 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
@@ -139,3 +139,50 @@
   },
   expected: kFetchTestResult.failure,
 }), "Public HTTPS non-secure context cannot fetch private subresource.");
+
+// These tests verify that websocket connections behave similarly to fetches.
+
+promise_test(t => websocketTest(t, {
+  source: {
+    port: kPorts.httpLocal,
+  },
+  target: {
+    protocol: "ws:",
+    port: kPorts.wsLocal,
+  },
+  expected: kWebsocketTestResult.success,
+}), "Local non-secure context can open connection to ws://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    port: kPorts.httpPrivate,
+  },
+  target: {
+    protocol: "ws:",
+    port: kPorts.wsLocal,
+  },
+  expected: kWebsocketTestResult.failure,
+}), "Private non-secure context cannot open connection to ws://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    port: kPorts.httpPublic,
+  },
+  target: {
+    protocol: "ws:",
+    port: kPorts.wsLocal,
+  },
+  expected: kWebsocketTestResult.failure,
+}), "Public non-secure context cannot open connection to ws://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    port: kPorts.httpLocal,
+    treatAsPublicAddress: true,
+  },
+  target: {
+    protocol: "ws:",
+    port: kPorts.wsLocal,
+  },
+  expected: kWebsocketTestResult.failure,
+}), "Treat-as-public non-secure context cannot open connection to ws://localhost.");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/ports.sub.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/ports.sub.js
index 52919db..fb3f0ad 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/ports.sub.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/ports.sub.js
@@ -6,4 +6,6 @@
   httpsLocal:   {{ports[https][0]}},
   httpsPrivate: {{ports[https-private][0]}},
   httpsPublic:  {{ports[https-public][0]}},
+  wsLocal:      {{ports[ws][0]}},
+  wssLocal:     {{ports[wss][0]}},
 };
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/socket-opener.html b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/socket-opener.html
new file mode 100644
index 0000000..48d2721
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/socket-opener.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebSocket Opener</title>
+<script>
+  window.addEventListener("message", function (event) {
+    const socket = new WebSocket(event.data);
+
+    socket.onopen = () => {
+      parent.postMessage("open", "*");
+    };
+    socket.onclose = (evt) => {
+      parent.postMessage(`close: code ${evt.code}`, "*");
+    };
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
index 54177d5..16494bf 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
@@ -32,40 +32,46 @@
   });
 };
 
+const kTreatAsPublicAddressSuffix =
+      "?pipe=header(Content-Security-Policy,treat-as-public-address)";
+
 // Resolves a URL relative to the current location, returning an absolute URL.
 //
 // `url` specifies the relative URL, e.g. "foo.html" or "http://foo.example".
-// `options.protocol` and `options.port`, if defined, override the respective
-// properties of the returned URL object.
+// `options`, if defined, should have the following shape:
+//
+//   {
+//     // Optional. Overrides the protocol of the returned URL.
+//     protocol,
+//
+//     // Optional. Overrides the port of the returned URL.
+//     port,
+//
+//     // Optional boolean. If defined and true, the returned URL path is altered
+//     // such that the response is served with a `treat-as-public-address` CSP
+//     // directive.
+//     treatAsPublicAddress,
+//   }
+//
 function resolveUrl(url, options) {
   const result = new URL(url, window.location);
   if (options === undefined) {
     return result;
   }
 
-  const { port, protocol } = options;
+  const { port, protocol, treatAsPublicAddress } = options;
   if (port !== undefined) {
     result.port = port;
   }
   if (protocol !== undefined) {
     result.protocol = protocol;
   }
-
-  return result;
-}
-
-const kDefaultSourcePath = "resources/fetcher.html";
-
-const kTreatAsPublicAddressSuffix =
-      "?pipe=header(Content-Security-Policy,treat-as-public-address)";
-
-function sourceUrl({ protocol, port, treatAsPublicAddress }) {
-  let path = kDefaultSourcePath;
   if (treatAsPublicAddress) {
-    path += kTreatAsPublicAddressSuffix;
+    result.searchParams.append(
+        "pipe", "header(Content-Security-Policy,treat-as-public-address)");
   }
 
-  return resolveUrl(path, { protocol, port });
+  return result;
 }
 
 const kFetchTestResult = {
@@ -78,43 +84,47 @@
 // Main argument shape:
 //
 //   {
-//     // Optional.
-//     source: {  // Optional, all fields optional.
-//       // Optional. The protocol of the URL of the initiator document.
-//       protocol,
+//     // Optional. Options for `resolveUrl()` when computing the source URL.
+//     source,
 //
-//       // Optional. The port of the URL of the initiator document.
-//       port,
+//     // Optional. Options for `resolveUrl()` when computing the target URL.
+//     target,
 //
-//       // Optional. If true, the initiator document sets the
-//       // `treat-as-public-address` CSP directive.
-//       treatAsPublicAddress,
-//     },
-//
-//     // Optional.
-//     target: {
-//       // The protocol of the URL of the target subresource.
-//       protocol,
-//
-//       // The port of the URL of the target subresource.
-//       port,
-//     },
-//
-//     // Required. The expected result of the fetch. Can be:
-//     // - `true` for a successful fetch
-//     // - `false` for a successful opaque fetch
-//     // - a string representation of an exception for a failed fetch
+//     // Required. One of the values in `kFetchTestResult`.
 //     expected,
 //   }
 //
 async function fetchTest(t, { source, target, expected }) {
-  if (source === undefined) {
-    source = {};
-  }
-  const iframe = await appendIframe(t, document, sourceUrl(source));
+  const sourceUrl = resolveUrl("resources/fetcher.html", source);
+  const iframe = await appendIframe(t, document, sourceUrl);
 
   const targetUrl = resolveUrl("/common/blank-with-cors.html", target);
   const reply = futureMessage();
   iframe.contentWindow.postMessage(targetUrl.href, "*");
   assert_equals(await reply, expected);
 }
+
+const kWebsocketTestResult = {
+  success: "open",
+
+  // The code is a best guess. It is not yet entirely specified, so it may need
+  // to be changed in the future based on implementation experience.
+  failure: "close: code 1006",
+};
+
+// Runs a websocket test. Attempts to open a websocket from `source` (in an
+// iframe) to `target`, then checks that the result is as `expected`.
+//
+// Argument shape is same as for `fetchTest`, except for the following:
+//
+//   `expected` should be one of the values in `kWebsocketTestResult`.
+//
+async function websocketTest(t, { source, target, expected }) {
+  const sourceUrl = resolveUrl("resources/socket-opener.html", source);
+  const iframe = await appendIframe(t, document, sourceUrl);
+
+  const targetUrl = resolveUrl("/echo", target);
+  const reply = futureMessage();
+  iframe.contentWindow.postMessage(targetUrl.href, "*");
+  assert_equals(await reply, expected);
+}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
index 889c3e0d..1218700 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
@@ -98,3 +98,54 @@
   target: { port: kPorts.httpsPublic },
   expected: kFetchTestResult.success,
 }), "Treat-as-public-address secure context can fetch public subresource.");
+
+// These tests verify that websocket connections behave similarly to fetches.
+
+promise_test(t => websocketTest(t, {
+  source: {
+    protocol: "https:",
+    port: kPorts.httpsLocal,
+  },
+  target: {
+    protocol: "wss:",
+    port: kPorts.wssLocal,
+  },
+  expected: kWebsocketTestResult.success,
+}), "Local secure context can open connection to wss://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    protocol: "https:",
+    port: kPorts.httpsPrivate,
+  },
+  target: {
+    protocol: "wss:",
+    port: kPorts.wssLocal,
+  },
+  expected: kWebsocketTestResult.success,
+}), "Private secure context can open connection to wss://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    protocol: "https:",
+    port: kPorts.httpsPublic,
+  },
+  target: {
+    protocol: "wss:",
+    port: kPorts.wssLocal,
+  },
+  expected: kWebsocketTestResult.success,
+}), "Public secure context can open connection to wss://localhost.");
+
+promise_test(t => websocketTest(t, {
+  source: {
+    protocol: "https:",
+    port: kPorts.httpsLocal,
+    treatAsPublicAddress: true,
+  },
+  target: {
+    protocol: "wss:",
+    port: kPorts.wssLocal,
+  },
+  expected: kWebsocketTestResult.success,
+}), "Treat-as-public secure context can open connection to wss://localhost.");
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cross-origin-isolated.tentative.window.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cross-origin-isolated.tentative.window.js
deleted file mode 100644
index 8ab0e710..0000000
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cross-origin-isolated.tentative.window.js
+++ /dev/null
@@ -1,112 +0,0 @@
-// META: script=/common/get-host-info.sub.js
-// META: script=/common/utils.js
-// META: script=../credentialless/resources/common.js
-// META: script=../credentialless/resources/dispatcher.js
-// META: timeout=long
-
-const same_origin = get_host_info().HTTPS_ORIGIN;
-const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
-
-const CROSS_ORIGIN_ISOLATED = "true";
-const NOT_CROSS_ORIGIN_ISOLATED = "false";
-const BLOCKED = "blocked";
-
-// Vary the headers of a parent and its anonymous iframe. Determine in which
-// cases the anonymous iframe gets the cross-origin-isolated capability.
-const crossOriginIsolatedTest = (description, params) => {
-  const default_params = {
-    parent_origin: same_origin,
-    parent_headers: '',
-    parent_allow: '',
-    child_origin: same_origin,
-    child_headers: '',
-    child_state: NOT_CROSS_ORIGIN_ISOLATED,
-  };
-  params = {...default_params, ...params};
-
-  promise_test_parallel(async test => {
-    // Create the parent.
-    const parent_token = token();
-    const parent_url = params.parent_origin + executor_path +
-        params.parent_headers + `&uuid=${parent_token}`;
-    const parent = window.open(parent_url)
-    add_completion_callback(() => parent.close());
-
-    // Create its anonymous iframe.
-    const child_token = token();
-    const child_url = params.child_origin + executor_path +
-        params.child_headers + `&uuid=${child_token}`;
-    send(parent_token, `
-      const iframe = document.createElement("iframe");
-      iframe.src = "${child_url}";
-      iframe.anonymous = true;
-      iframe.allow="${params.parent_allow}";
-      document.body.appendChild(iframe);
-    `);
-
-    // Check child's cross-origin isolation state.
-    const this_token = token();
-    send(child_token, `
-      send("${this_token}", window.crossOriginIsolated);
-    `);
-
-    test.step_timeout(() => {
-      send(this_token, 'blocked');
-    }, 3000);
-
-    assert_equals(await receive(this_token), params.child_state);
-  }, description);
-};
-
-crossOriginIsolatedTest("Basic", {
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Basic + child cross_origin", {
-  child_origin: cross_origin,
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Parent coep_require-corp", {
-  parent_headers: coep_require_corp,
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Parent coep_require-corp + cross_origin", {
-  parent_headers: coep_require_corp,
-  child_origin: cross_origin,
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Parent COI", {
-  parent_headers: coop_same_origin + coep_require_corp,
-  child_state: CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Parent COI + child cross-origin", {
-  parent_headers: coop_same_origin + coep_require_corp,
-  child_origin: cross_origin,
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest("Parent COI + child cross-origin COEP/CORP", {
-  parent_headers: coop_same_origin + coep_require_corp,
-  child_headers: coep_require_corp + corp_cross_origin,
-  child_origin: cross_origin,
-  child_state: NOT_CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest('Parent COI allow + child cross_origin', {
-  parent_headers: coop_same_origin + coep_require_corp,
-  parent_allow: 'cross-origin-isolated',
-  child_origin: cross_origin,
-  child_state: CROSS_ORIGIN_ISOLATED,
-});
-
-crossOriginIsolatedTest('Parent COI allow + child cross-origin COEP/CORP', {
-  parent_headers: coop_same_origin + coep_require_corp,
-  parent_allow: 'cross-origin-isolated',
-  child_headers: coep_require_corp + corp_cross_origin,
-  child_origin: cross_origin,
-  child_state: CROSS_ORIGIN_ISOLATED,
-});
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
index 77f52779..5289a52 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
@@ -698,6 +698,8 @@
 <meta name=variant content='?q=webgpu:api,operation,render_pass,storeOp:render_pass_store_op,depth_stencil_attachment_only:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pass,storeop2:storeOp_controls_whether_1x1_drawn_quad_is_stored:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pipeline,culling_tests:culling:*'>
+<meta name=variant content='?q=webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count:*'>
+<meta name=variant content='?q=webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count,blend:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pipeline,primitive_topology:basic:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pipeline,primitive_topology:unaligned_vertex_count:*'>
 <meta name=variant content='?q=webgpu:api,operation,rendering,basic:clear:*'>
@@ -1322,6 +1324,8 @@
 <meta name=variant content='?q=webgpu:api,validation,createBindGroup:minBindingSize:*'>
 <meta name=variant content='?q=webgpu:api,validation,createBindGroup:buffer,resource_state:*'>
 <meta name=variant content='?q=webgpu:api,validation,createBindGroup:texture,resource_state:*'>
+<meta name=variant content='?q=webgpu:api,validation,createBindGroup:bind_group_layout,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,createBindGroup:binding_resources,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:duplicate_bindings:*'>
 <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:visibility:*'>
 <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:multisampled_validation:*'>
@@ -1332,12 +1336,19 @@
 <meta name=variant content='?q=webgpu:api,validation,createComputePipeline:shader_module_must_be_valid:*'>
 <meta name=variant content='?q=webgpu:api,validation,createComputePipeline:shader_module_stage_must_be_compute:*'>
 <meta name=variant content='?q=webgpu:api,validation,createComputePipeline:enrty_point_name_must_match:*'>
+<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:pipeline_layout,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:shader_module,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:number_of_dynamic_buffers_exceeds_the_maximum_value:*'>
 <meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:number_of_bind_group_layouts_exceeds_the_maximum_value:*'>
+<meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:bind_group_layouts,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:basic_use_of_createRenderPipeline:*'>
 <meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:at_least_one_color_state_is_required:*'>
 <meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:color_formats_must_be_renderable:*'>
 <meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:sample_count_must_be_valid:*'>
+<meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:pipeline_output_targets:*'>
+<meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:pipeline_output_targets,blend:*'>
+<meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:pipeline_layout,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:shader_module,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,createSampler:lodMinAndMaxClamp:*'>
 <meta name=variant content='?q=webgpu:api,validation,createSampler:maxAnisotropy:*'>
 <meta name=variant content='?q=webgpu:api,validation,createTexture:zero_size:*'>
@@ -1368,13 +1379,19 @@
 <meta name=variant content='?q=webgpu:api,validation,createView:mip_levels:*'>
 <meta name=variant content='?q=webgpu:api,validation,createView:cube_faces_square:*'>
 <meta name=variant content='?q=webgpu:api,validation,createView:texture_state:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,beginRenderPass:color_attachments,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,beginRenderPass:depth_stencil_attachment,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,beginRenderPass:occlusion_query_set,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,buffer_texture_copies:depth_stencil_format,copy_usage_and_aspect:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,buffer_texture_copies:depth_stencil_format,copy_buffer_size:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,buffer_texture_copies:depth_stencil_format,copy_buffer_offset:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:set_pipeline:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:pipeline,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:dispatch_sizes:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:indirect_dispatch_buffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:indirect_dispatch_buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:copy_with_invalid_buffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:buffer_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:copy_size_alignment:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:copy_offset_alignment:*'>
@@ -1382,6 +1399,7 @@
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:copy_out_of_bounds:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyBufferToBuffer:copy_within_same_buffer:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyTextureToTexture:copy_with_invalid_texture:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyTextureToTexture:texture,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyTextureToTexture:mipmap_level:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyTextureToTexture:texture_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,copyTextureToTexture:sample_count:*'>
@@ -1418,22 +1436,27 @@
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,dynamic_state:setBlendConstant:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,dynamic_state:setStencilReference:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,indirect_draw:indirect_buffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,indirect_draw:indirect_buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,indirect_draw:indirect_buffer_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,indirect_draw:indirect_offset_alignment:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,indirect_draw:indirect_offset_oob:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:index_buffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:index_buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:index_buffer_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_alignment:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_and_size_oob:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setPipeline:invalid_pipeline:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setPipeline:pipeline,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:slot:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_alignment:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_and_size_oob:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,state_tracking:vertex_buffers_inherit_from_previous_pipeline:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,render,state_tracking:vertex_buffers_do_not_inherit_between_render_passes:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,setBindGroup:state_and_binding_index:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,setBindGroup:bind_group,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,setBindGroup:dynamic_offsets_passed_but_not_expected:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,setBindGroup:dynamic_offsets_match_expectations_in_pass_encoder:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,setBindGroup:u32array_start_and_length:*'>
@@ -1447,10 +1470,13 @@
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,general:occlusion_query,query_index:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,general:timestamp_query,query_type_and_index:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,general:timestamp_query,invalid_query_set:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,queries,general:timestamp_query,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,resolveQuerySet:resolveQuerySet,invalid_queryset_and_destination_buffer:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,resolveQuerySet:resolveQuerySet,first_query_and_query_count:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,resolveQuerySet:resolveQuerySet,destination_buffer_usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,queries,resolveQuerySet:resolveQuerySet,destination_offset:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,queries,resolveQuerySet:query_set_buffer,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,render_bundle:render_bundles,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,error_scope:simple_case_where_the_error_scope_catches_an_error:*'>
 <meta name=variant content='?q=webgpu:api,validation,error_scope:errors_bubble_to_the_parent_scope_if_not_handled_by_the_current_scope:*'>
 <meta name=variant content='?q=webgpu:api,validation,error_scope:if_an_error_scope_matches_an_error_it_does_not_bubble_to_the_parent_scope:*'>
@@ -1616,6 +1642,8 @@
 <meta name=variant content='?q=webgpu:api,validation,image_copy,layout_related:bound_on_bytes_per_row:*'>
 <meta name=variant content='?q=webgpu:api,validation,image_copy,layout_related:bound_on_offset:*'>
 <meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:valid:*'>
+<meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:texture,device_mismatch:*'>
+<meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:sample_count:*'>
 <meta name=variant content='?q=webgpu:api,validation,image_copy,texture_related:mip_level:*'>
@@ -1638,6 +1666,7 @@
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:source_image,crossOrigin:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:source_imageBitmap,state:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:destination_texture,state:*'>
+<meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:destination_texture,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:destination_texture,dimension:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:destination_texture,usage:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:destination_texture,sample_count:*'>
@@ -1649,8 +1678,10 @@
 <meta name=variant content='?q=webgpu:api,validation,queue,destroyed,query_set:beginOcclusionQuery:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,destroyed,query_set:writeTimestamp:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,destroyed,query_set:resolveQuerySet:*'>
+<meta name=variant content='?q=webgpu:api,validation,queue,submit:command_buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,writeBuffer:ranges:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,writeBuffer:usages:*'>
+<meta name=variant content='?q=webgpu:api,validation,queue,writeBuffer:buffer,device_mismatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,render_pass,resolve:resolve_attachment:*'>
 <meta name=variant content='?q=webgpu:api,validation,render_pass,storeOp:store_op_and_read_only:*'>
 <meta name=variant content='?q=webgpu:api,validation,render_pass_descriptor:a_render_pass_with_only_one_color_is_ok:*'>
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index cee8fd9..3087450 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -139,6 +139,7 @@
 src/webgpu/api/operation/render_pipeline/alpha_to_coverage.spec.ts
 src/webgpu/api/operation/render_pipeline/culling_tests.spec.ts
 src/webgpu/api/operation/render_pipeline/entry_point_name.spec.ts
+src/webgpu/api/operation/render_pipeline/pipeline_output_targets.spec.ts
 src/webgpu/api/operation/render_pipeline/primitive_topology.spec.ts
 src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts
 src/webgpu/api/operation/rendering/basic.spec.ts
@@ -216,6 +217,7 @@
 src/webgpu/api/validation/query_set/create.spec.ts
 src/webgpu/api/validation/query_set/destroy.spec.ts
 src/webgpu/api/validation/queue/buffer_mapped.spec.ts
+src/webgpu/api/validation/queue/submit.spec.ts
 src/webgpu/api/validation/queue/writeBuffer.spec.ts
 src/webgpu/util/create_elements.ts
 src/webgpu/api/validation/queue/copyToTexture/CopyExternalImageToTexture.spec.ts
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index fe913cd..45e1c16 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -46775,6 +46775,8 @@
   <int value="-2058656447" label="ContextualSearchUrlActions:enabled"/>
   <int value="-2056351013" label="AutofillUpdatedCardUnmaskPromptUi:enabled"/>
   <int value="-2056198604" label="InterestFeedV2Hearts:disabled"/>
+  <int value="-2054871630"
+      label="PasswordsAccountStorageRevisedOptInFlow:enabled"/>
   <int value="-2054612904" label="BuiltInModuleInfra:enabled"/>
   <int value="-2053860791" label="XGEOVisibleNetworks:enabled"/>
   <int value="-2048927838" label="AutoplayWhitelistSettings:enabled"/>
@@ -46836,6 +46838,8 @@
   <int value="-2012449550" label="OmniboxMostVisitedTiles:enabled"/>
   <int value="-2012266745"
       label="OmniboxLocalZeroSuggestFrecencyRanking:disabled"/>
+  <int value="-2011908446"
+      label="PasswordsAccountStorageRevisedOptInFlow:disabled"/>
   <int value="-2011532551" label="SignedExchangeSubresourcePrefetch:disabled"/>
   <int value="-2011428140" label="RelatedSearchesAlternateUx:disabled"/>
   <int value="-2010634516" label="OmniboxLocalEntitySuggestions:disabled"/>
@@ -47203,6 +47207,7 @@
   <int value="-1731997767" label="SharingHubDesktopAppMenu:enabled"/>
   <int value="-1731267886" label="AutofillEnableStickyPaymentsBubble:enabled"/>
   <int value="-1731149013" label="AndroidMessagesIntegration:enabled"/>
+  <int value="-1730755478" label="ClosedTabCache:disabled"/>
   <int value="-1729926412" label="enable-webusb-notifications"/>
   <int value="-1729808721" label="SubresourceRedirect:enabled"/>
   <int value="-1728605240" label="UseXpsForPrintingFromPdf:enabled"/>
@@ -50652,6 +50657,7 @@
   <int value="1062357243" label="remember-cert-error-decisions"/>
   <int value="1064288458" label="OfflineRecentPages:enabled"/>
   <int value="1065547630" label="EnableInputNoiseCancellationUi:disabled"/>
+  <int value="1065553214" label="ClosedTabCache:enabled"/>
   <int value="1067618884" label="enable-experimental-input-view-features"/>
   <int value="1067990299" label="enable-ui-devtools"/>
   <int value="1069325321" label="CrostiniGpuSupport:enabled"/>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index e9f8093..dab256b 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -4144,7 +4144,7 @@
 
 <histogram
     name="Extensions.{ExtensionSource}ForceInstalledFailureManifestInvalidErrorDetail2"
-    enum="ManifestInvalidError" expires_after="2021-09-19">
+    enum="ManifestInvalidError" expires_after="2022-02-01">
   <owner>swapnilgupta@google.com</owner>
   <owner>burunduk@chromium.org</owner>
   <owner>managed-devices@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/image/histograms.xml b/tools/metrics/histograms/metadata/image/histograms.xml
index f155aa84..004a79c 100644
--- a/tools/metrics/histograms/metadata/image/histograms.xml
+++ b/tools/metrics/histograms/metadata/image/histograms.xml
@@ -46,6 +46,9 @@
       summary="Showing cache patterns only for AnswerSuggestions."/>
   <variant name=".AssistantDetails"
       summary="Showing cache patterns only for AssistantDetails."/>
+  <variant name=".AutofillCardArt"
+      summary="Show customized card-art image for credit card suggestions on
+               Android."/>
   <variant name=".AutofillImageFetcher"
       summary="Show customized card art image for credit card."/>
   <variant name=".ContextualSuggestions"
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 7ebba1c9..6b33a16 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -17,8 +17,8 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "linux": {
-            "hash": "5ac0292f3b6531e8428ccefcf5318e457b12ab6c",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/b34dc62800c061e62c78039a60b9efd9786ede89/trace_processor_shell"
+            "hash": "f5cfa6d6c5c869b45c48d523322f4a3f061aceb2",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/f73e19a324498c7896ddb2e082fad8cb4607545d/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItem.java b/ui/android/java/src/org/chromium/ui/DropdownItem.java
index f7906e9..96ed065 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItem.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItem.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui;
 
+import org.chromium.url.GURL;
+
 /**
  * Dropdown item interface used to access all the information needed to show the item.
  */
@@ -24,10 +26,17 @@
      */
     String getItemTag();
     /**
-     * Returns the drawable id of the icon that should be shown in the dropdown, or NO_ICON.
+     * Returns the drawable id of the icon that should be shown in the dropdown, or NO_ICON. Note:
+     * If the getCustomIconUrl() is present, then it'll be preferred over the drawable id returned
+     * by getIconId().
      */
     int getIconId();
     /**
+     * Returns the url for the icon to be downloaded. If present, the downloaded icon should be
+     * preferred over the resource id returned by getIconId().
+     */
+    GURL getCustomIconUrl();
+    /**
      * Returns true if the item should be enabled in the dropdown.
      */
     boolean isEnabled();
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
index 708ca0a..dbeef81 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui;
 
+import org.chromium.url.GURL;
+
 /**
  * Base implementation of DropdownItem which is used to get default settings to
  * show the item.
@@ -73,4 +75,9 @@
     public int getIconMarginResId() {
         return R.dimen.dropdown_icon_margin;
     }
+
+    @Override
+    public GURL getCustomIconUrl() {
+        return null;
+    }
 }
diff --git a/ui/chromeos/translations/ui_chromeos_strings_te.xtb b/ui/chromeos/translations/ui_chromeos_strings_te.xtb
index b016cae8..2cbbf8b 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_te.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_te.xtb
@@ -76,7 +76,7 @@
 <translation id="1661867754829461514">PIN లేదు</translation>
 <translation id="166439687370499867">షేర్ చేసిన నెట్‌వర్క్ కాన్ఫిగరేషన్‌లను మార్చడం అనుమతించబడదు</translation>
 <translation id="1665611772925418501">ఫైల్‌ను సవరించడం సాధ్యపడదు.</translation>
-<translation id="1673103856845176271">భద్రతా కారణాల దృష్ట్యా ఫైల్‌ను ప్రాప్యత చేయడం సాధ్యపడదు.</translation>
+<translation id="1673103856845176271">భద్రతా కారణాల దృష్ట్యా ఫైల్‌ను యాక్సెస్‌ చేయడం సాధ్యపడదు.</translation>
 <translation id="169515659049020177">Shift</translation>
 <translation id="1722487484194605434"><ph name="NUMBER_OF_ITEMS" /> అంశాలను జిప్ చేస్తోంది...</translation>
 <translation id="1722687688096767818">ప్రొఫైల్‌ను జోడిస్తోంది...</translation>
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index 22302ee..4ca73682 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -390,7 +390,12 @@
   float whole = 0;
   additional_scale_ = std::modf(scale, &whole);
   for (const auto& display : display_list_.displays()) {
-    OnOutputAddedOrUpdated(display.id(), display.bounds(),
+    // display::bounds returns bounds in dip while OnOutputAddedOrUpdated
+    // expects them to be in px. Translate using current scale factor of the
+    // display.
+    OnOutputAddedOrUpdated(display.id(),
+                           gfx::ScaleToEnclosedRect(
+                               display.bounds(), display.device_scale_factor()),
                            display.device_scale_factor(),
                            RotationToWaylandTransform(display.rotation()));
   }
diff --git a/ui/strings/translations/ui_strings_te.xtb b/ui/strings/translations/ui_strings_te.xtb
index f159008..4d9fe211 100644
--- a/ui/strings/translations/ui_strings_te.xtb
+++ b/ui/strings/translations/ui_strings_te.xtb
@@ -250,7 +250,7 @@
 <translation id="8331626408530291785">పైకి స్క్రోల్ చేయి</translation>
 <translation id="8352146631962686268">{YEARS,plural, =1{1 సంవత్సరం}other{# సంవత్సరాలు}}</translation>
 <translation id="838869780401515933">తనిఖీ చేయి</translation>
-<translation id="8393700583063109961">సందేశాన్ని పంపండి</translation>
+<translation id="8393700583063109961">మెసేజ్‌ను పంపండి</translation>
 <translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation>
 <translation id="8458811141851741261">{YEARS,plural, =1{1సం}other{#సం}}</translation>
 <translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE" /> ఫైల్ (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation>
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index a0a0fe58..d2c32364 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -940,43 +941,29 @@
 }
 
 DragOperation Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
+  auto cb = GetDropCallback(event);
+  ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
+  std::move(cb).Run(event, output_drag_op);
+  return output_drag_op;
+}
+
+views::View::DropCallback Textfield::GetDropCallback(
+    const ui::DropTargetEvent& event) {
   DCHECK(CanDrop(event.data()));
+
   drop_cursor_visible_ = false;
 
   if (controller_) {
-    DragOperation drag_operation = controller_->OnDrop(event);
-    if (drag_operation != DragOperation::kNone)
-      return drag_operation;
+    auto cb = controller_->GetDropCallback(event);
+    if (!cb.is_null())
+      return cb;
   }
 
-  gfx::RenderText* render_text = GetRenderText();
   DCHECK(!initiating_drag_ ||
-         !render_text->IsPointInSelection(event.location()));
-  OnBeforeUserAction();
-  skip_input_method_cancel_composition_ = true;
+         !GetRenderText()->IsPointInSelection(event.location()));
 
-  gfx::SelectionModel drop_destination_model =
-      render_text->FindCursorPosition(event.location());
-  std::u16string new_text;
-  event.data().GetString(&new_text);
-
-  // Delete the current selection for a drag and drop within this view.
-  const bool move = initiating_drag_ && !event.IsControlDown() &&
-                    event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
-  if (move) {
-    // Adjust the drop destination if it is on or after the current selection.
-    size_t pos = drop_destination_model.caret_pos();
-    pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
-    model_->DeletePrimarySelectionAndInsertTextAt(new_text, pos);
-  } else {
-    model_->MoveCursorTo(drop_destination_model);
-    // Drop always inserts text even if the textfield is not in insert mode.
-    model_->InsertText(new_text);
-  }
-  skip_input_method_cancel_composition_ = false;
-  UpdateAfterChange(TextChangeType::kUserTriggered, true);
-  OnAfterUserAction();
-  return move ? DragOperation::kMove : DragOperation::kCopy;
+  return base::BindOnce(&Textfield::DropDraggedText,
+                        drop_weak_ptr_factory_.GetWeakPtr());
 }
 
 void Textfield::OnDragDone() {
@@ -1125,6 +1112,7 @@
 
 void Textfield::OnTextChanged() {
   OnPropertyChanged(&model_ + kTextfieldText, kPropertyEffectsPaint);
+  drop_weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2638,6 +2626,39 @@
     GetInputMethod()->OnTextInputTypeChanged(this);
 }
 
+void Textfield::DropDraggedText(const ui::DropTargetEvent& event,
+                                ui::mojom::DragOperation& output_drag_op) {
+  DCHECK(CanDrop(event.data()));
+
+  gfx::RenderText* render_text = GetRenderText();
+
+  OnBeforeUserAction();
+  skip_input_method_cancel_composition_ = true;
+
+  gfx::SelectionModel drop_destination_model =
+      render_text->FindCursorPosition(event.location());
+  std::u16string new_text;
+  event.data().GetString(&new_text);
+
+  // Delete the current selection for a drag and drop within this view.
+  const bool move = initiating_drag_ && !event.IsControlDown() &&
+                    event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
+  if (move) {
+    // Adjust the drop destination if it is on or after the current selection.
+    size_t pos = drop_destination_model.caret_pos();
+    pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
+    model_->DeletePrimarySelectionAndInsertTextAt(new_text, pos);
+  } else {
+    model_->MoveCursorTo(drop_destination_model);
+    // Drop always inserts text even if the textfield is not in insert mode.
+    model_->InsertText(new_text);
+  }
+  skip_input_method_cancel_composition_ = false;
+  UpdateAfterChange(TextChangeType::kUserTriggered, true);
+  OnAfterUserAction();
+  output_drag_op = move ? DragOperation::kMove : DragOperation::kCopy;
+}
+
 BEGIN_METADATA(Textfield, View)
 ADD_PROPERTY_METADATA(bool, ReadOnly)
 ADD_PROPERTY_METADATA(std::u16string, Text)
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index af165933..3d8c7cb 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -340,6 +340,8 @@
   void OnDragExited() override;
   ui::mojom::DragOperation OnPerformDrop(
       const ui::DropTargetEvent& event) override;
+  views::View::DropCallback GetDropCallback(
+      const ui::DropTargetEvent& event) override;
   void OnDragDone() override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
@@ -635,6 +637,10 @@
 
   void OnEnabledChanged();
 
+  // Drops the dragged text.
+  void DropDraggedText(const ui::DropTargetEvent& event,
+                       ui::mojom::DragOperation& output_drag_op);
+
   // The text model.
   std::unique_ptr<TextfieldModel> model_;
 
@@ -775,6 +781,9 @@
 
   // Used to bind callback functions to this object.
   base::WeakPtrFactory<Textfield> weak_ptr_factory_{this};
+
+  // Used to bind drop callback functions to this object.
+  base::WeakPtrFactory<Textfield> drop_weak_ptr_factory_{this};
 };
 
 BEGIN_VIEW_BUILDER(VIEWS_EXPORT, Textfield, View)
diff --git a/ui/views/controls/textfield/textfield_controller.cc b/ui/views/controls/textfield/textfield_controller.cc
index fbb10d6..54dcabd 100644
--- a/ui/views/controls/textfield/textfield_controller.cc
+++ b/ui/views/controls/textfield/textfield_controller.cc
@@ -33,7 +33,7 @@
 
 views::View::DropCallback TextfieldController::GetDropCallback(
     const ui::DropTargetEvent& event) {
-  return base::DoNothing();
+  return base::NullCallback();
 }
 
 }  // namespace views
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index dd3059a..598b334 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -2120,6 +2120,86 @@
   EXPECT_EQ(u"h worlellod", textfield_->GetText());
 }
 
+TEST_F(TextfieldTest, DropCallbackRun) {
+  InitTextfield();
+  textfield_->SetText(u"hello world");
+  const int cursor_y = GetCursorYForTesting();
+
+  std::u16string string;
+  ui::OSExchangeData data;
+  int formats = 0;
+  int operations = 0;
+  std::set<ui::ClipboardFormatType> format_types;
+
+  // Start dragging "hello".
+  textfield_->SetSelectedRange(gfx::Range(0, 5));
+  gfx::Point point(GetCursorPositionX(3), cursor_y);
+  MoveMouseTo(point);
+  PressLeftMouseButton();
+  EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, point, gfx::Point()));
+  operations = textfield_->GetDragOperationsForView(textfield_, point);
+  EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+            operations);
+  textfield_->WriteDragDataForView(nullptr, point, &data);
+  EXPECT_TRUE(data.GetString(&string));
+  EXPECT_EQ(textfield_->GetSelectedText(), string);
+  EXPECT_TRUE(textfield_->GetDropFormats(&formats, &format_types));
+  EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+  EXPECT_TRUE(format_types.empty());
+
+  // Drop "hello" after "d".
+  EXPECT_TRUE(textfield_->CanDrop(data));
+  gfx::PointF drop_point(GetCursorPositionX(11), cursor_y);
+  ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
+  EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+  ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
+  auto cb = textfield_->GetDropCallback(drop_a);
+  std::move(cb).Run(drop_a, output_drag_op);
+  EXPECT_EQ(ui::mojom::DragOperation::kMove, output_drag_op);
+  EXPECT_EQ(u" worldhello", textfield_->GetText());
+}
+
+TEST_F(TextfieldTest, DropCallbackCancelled) {
+  InitTextfield();
+  textfield_->SetText(u"hello world");
+  const int cursor_y = GetCursorYForTesting();
+
+  std::u16string string;
+  ui::OSExchangeData data;
+  int formats = 0;
+  int operations = 0;
+  std::set<ui::ClipboardFormatType> format_types;
+
+  // Start dragging "hello".
+  textfield_->SetSelectedRange(gfx::Range(0, 5));
+  gfx::Point point(GetCursorPositionX(3), cursor_y);
+  MoveMouseTo(point);
+  PressLeftMouseButton();
+  EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, point, gfx::Point()));
+  operations = textfield_->GetDragOperationsForView(textfield_, point);
+  EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+            operations);
+  textfield_->WriteDragDataForView(nullptr, point, &data);
+  EXPECT_TRUE(data.GetString(&string));
+  EXPECT_EQ(textfield_->GetSelectedText(), string);
+  EXPECT_TRUE(textfield_->GetDropFormats(&formats, &format_types));
+  EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+  EXPECT_TRUE(format_types.empty());
+
+  // Drop "hello" after "d". The drop callback should do nothing because
+  // `textfield_` is mutated before the callback is run.
+  EXPECT_TRUE(textfield_->CanDrop(data));
+  gfx::PointF drop_point(GetCursorPositionX(11), cursor_y);
+  ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
+  EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+  ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
+  auto cb = textfield_->GetDropCallback(drop_a);
+  textfield_->AppendText(u"new text");
+  std::move(cb).Run(drop_a, output_drag_op);
+  EXPECT_EQ(ui::mojom::DragOperation::kNone, output_drag_op);
+  EXPECT_EQ(u"hello worldnew text", textfield_->GetText());
+}
+
 TEST_F(TextfieldTest, DragAndDrop_Canceled) {
   InitTextfield();
   textfield_->SetText(u"hello world");
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 323a92d..8414586 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -1293,9 +1293,12 @@
 
 aura::client::DragDropDelegate::DropCallback
 DesktopNativeWidgetAura::GetDropCallback(const ui::DropTargetEvent& event) {
-  // TODO(crbug.com/1197505): Return drop callback.
-  NOTREACHED();
-  return base::NullCallback();
+  DCHECK(drop_helper_);
+  if (ShouldActivate())
+    Activate();
+
+  return drop_helper_->GetDropCallback(event.data(), event.location(),
+                                       last_drop_operation_);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/widget/drop_helper.cc b/ui/views/widget/drop_helper.cc
index ce8f2d7..207276d 100644
--- a/ui/views/widget/drop_helper.cc
+++ b/ui/views/widget/drop_helper.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <set>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -14,6 +15,7 @@
 #include "build/build_config.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
+#include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
 namespace views {
@@ -102,7 +104,7 @@
   return drop_view->OnPerformDrop(drop_event);
 }
 
-View::DropCallback DropHelper::GetDropCallback(
+DropHelper::DropCallback DropHelper::GetDropCallback(
     const OSExchangeData& data,
     const gfx::Point& root_view_location,
     int drag_operation) {
@@ -121,7 +123,15 @@
   View::ConvertPointToTarget(root_view, drop_view, &view_location);
   ui::DropTargetEvent drop_event(data, gfx::PointF(view_location),
                                  gfx::PointF(view_location), drag_operation);
-  return drop_view->GetDropCallback(drop_event);
+
+  auto drop_view_cb = drop_view->GetDropCallback(drop_event);
+  return base::BindOnce(
+      [](View::DropCallback drop_cb, const ui::DropTargetEvent& event,
+         std::unique_ptr<ui::OSExchangeData> data,
+         ui::mojom::DragOperation& output_drag_op) {
+        std::move(drop_cb).Run(event, output_drag_op);
+      },
+      std::move(drop_view_cb));
 }
 
 View* DropHelper::CalculateTargetView(const gfx::Point& root_view_location,
diff --git a/ui/views/widget/drop_helper.h b/ui/views/widget/drop_helper.h
index f361de1..d991dc1 100644
--- a/ui/views/widget/drop_helper.h
+++ b/ui/views/widget/drop_helper.h
@@ -5,6 +5,7 @@
 #ifndef UI_VIEWS_WIDGET_DROP_HELPER_H_
 #define UI_VIEWS_WIDGET_DROP_HELPER_H_
 
+#include <memory>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
@@ -32,6 +33,11 @@
 // then either OnDragExit or OnDrop when the drop is done.
 class VIEWS_EXPORT DropHelper {
  public:
+  using DropCallback =
+      base::OnceCallback<void(const ui::DropTargetEvent& event,
+                              std::unique_ptr<ui::OSExchangeData> data,
+                              ui::mojom::DragOperation& output_drag_op)>;
+
   explicit DropHelper(View* root_view);
   ~DropHelper();
 
@@ -76,9 +82,9 @@
 
   // Invoked when the user drops data on the root view during a drag and drop
   // operation, but the drop is held because of DataTransferPolicController.
-  View::DropCallback GetDropCallback(const OSExchangeData& data,
-                                     const gfx::Point& root_view_location,
-                                     int drag_operation);
+  DropCallback GetDropCallback(const OSExchangeData& data,
+                               const gfx::Point& root_view_location,
+                               int drag_operation);
 
   // Calculates the target view for a drop given the specified location in
   // the coordinate system of the rootview. This tries to avoid continually
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 944ccba..c2ca1c6 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -1113,9 +1113,9 @@
 
 aura::client::DragDropDelegate::DropCallback NativeWidgetAura::GetDropCallback(
     const ui::DropTargetEvent& event) {
-  // TODO(crbug.com/1197506): Return async drop callback function.
-  NOTIMPLEMENTED();
-  return base::NullCallback();
+  DCHECK(drop_helper_);
+  return drop_helper_->GetDropCallback(event.data(), event.location(),
+                                       last_drop_operation_);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index 7d7c0d2..4b155ecd 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -146,6 +146,7 @@
   "cr_elements/cr_radio_button/cr_radio_button_behavior.m.d.ts",
   "cr_elements/cr_radio_button/cr_radio_button.m.d.ts",
   "cr_elements/cr_radio_group/cr_radio_group.m.d.ts",
+  "cr_elements/cr_scrollable_behavior.m.d.ts",
   "cr_elements/cr_search_field/cr_search_field_behavior.d.ts",
   "cr_elements/cr_toast/cr_toast_manager.d.ts",
   "cr_elements/cr_toast/cr_toast.d.ts",
@@ -202,7 +203,6 @@
     "$root_dir/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.d.ts",
     "$root_dir/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.d.ts",
     "$root_dir/cr_elements/cr_radio_button/cr_radio_button_style_css.m.d.ts",
-    "$root_dir/cr_elements/cr_scrollable_behavior.m.d.ts",
     "$root_dir/cr_elements/cr_slider/cr_slider.d.ts",
     "$root_dir/cr_elements/cr_splitter/cr_splitter.d.ts",
     "$root_dir/cr_elements/cr_toolbar/cr_toolbar.d.ts",
@@ -278,7 +278,6 @@
     "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js",
     "cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js",
     "cr_elements/cr_radio_button/cr_radio_button_style_css.m.js",
-    "cr_elements/cr_scrollable_behavior.m.js",
     "cr_elements/cr_search_field/cr_search_field.js",
     "cr_elements/cr_slider/cr_slider.js",
     "cr_elements/cr_splitter/cr_splitter.js",
diff --git a/ui/webui/resources/cr_elements/cr_scrollable_behavior.m.d.ts b/ui/webui/resources/cr_elements/cr_scrollable_behavior.m.d.ts
new file mode 100644
index 0000000..7b35319f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_scrollable_behavior.m.d.ts
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export {CrScrollableBehavior};
+
+interface CrScrollableBehavior {
+  updateScrollableContents(): void;
+  requestUpdateScroll(): void;
+}
+
+declare const CrScrollableBehavior: object;
diff --git a/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.cc b/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.cc
index fbf7438..7d14976 100644
--- a/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.cc
+++ b/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.cc
@@ -50,9 +50,4 @@
   return false;
 }
 
-absl::optional<std::u16string>
-JavaScriptTabModalDialogManagerDelegateAndroid::GetAppName() {
-  return absl::nullopt;
-}
-
 }  // namespace weblayer
diff --git a/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h b/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h
index d1a8c90..46264f0 100644
--- a/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h
+++ b/weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h
@@ -38,7 +38,6 @@
   void SetTabNeedsAttention(bool attention) override;
   bool IsWebContentsForemost() override;
   bool IsApp() override;
-  absl::optional<std::u16string> GetAppName() override;
 
  private:
   content::WebContents* web_contents_;