diff --git a/DEPS b/DEPS
index db06dff..43459cf 100644
--- a/DEPS
+++ b/DEPS
@@ -177,7 +177,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:91769f0e2541d15de294dfc780205e98b49f7431',
+  'luci_go': 'git_revision:36e8e9c8430a6e943284844bacde2b4acb7c1c49',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -209,7 +209,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6100cd8c1aa0779f133c6067a40c1749e6c9b5a4',
+  'skia_revision': 'bdadfc16dffbb144a607f8580f9b10b554c745e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -221,7 +221,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '78fb9314e71bb0a51ba018ae3d8bae774f74ba9c',
+  'angle_revision': '8707d2404672ca90b9135d5c7f94b2df8e2c1d34',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -256,11 +256,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '01c5602dc3e493d34ada24da50ebf5d411277be1',
+  'nacl_revision': '772b2e54c00a242bfed0ec2c7b865813ca98598e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '2f62d8e075656e6b5fb597e681ba4b2b8296900c',
+  'freetype_revision': '967a34eee3fd34f496366ed1283ab5268d23690a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -268,7 +268,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '4c34478b28497acfce02b8a544fed4ae20526336',
+  'harfbuzz_revision': 'b37f03f16b39d397a626f097858e9ae550234ca0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'c92267a4b7d8617db43e59a78051963313b20bd1',
+  'catapult_revision': '98fd7ff368b6f03ad93dc1ebf9e1c5635071f73b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -288,7 +288,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': 'b7b6d993d87f25972a1ab1aa7274377782ef4e47',
+  'devtools_frontend_revision': 'a0dce6da2f3040e925ae84bfba373b12970220be',
   # 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.
@@ -961,7 +961,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '68a81d40157b67aaf937483f2c3b4692e8b109ff',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '03c08d485ec82f0f9c0e78bab4f6d1dc1539b80d',
       'condition': 'checkout_linux',
   },
 
@@ -1349,7 +1349,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5dfd4bdd5b10dc62ae2c6d021573bb889efaf056',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a4d450e81e396a2688a422bcb789dbc82ba67537',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1446,7 +1446,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'fdba2677f32812e823c54d214fe54c73e60b5163',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'aa4563370444e604995ff5fba93e25858f266b79',
 
   'src/third_party/r8': {
       'packages': [
@@ -1534,9 +1534,9 @@
   },
 
   'src/third_party/usrsctp/usrsctplib':
-    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '0bd8b8110bc1a388649e504de1e673114e91013f',
+    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'acfce46e428cc084b4bd0164e1b019261a8dbeda',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@aa612f42d9e203fe7253e099e3287d4cee80a996',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@d3354ebca4609f9557c2a63da2a8529555e857b6',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a',
@@ -1563,7 +1563,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '239db71432f4e4fe1f6192a7d54717701ef84f66',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c6fb22f9d339fc9c3844885844b4a822e77447de',
+    Var('webrtc_git') + '/src.git' + '@' + 'f33f7a2ada62eca8e07c5f4844d809845d2057fc',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1624,7 +1624,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@88e8ade584e962502de1cd77bad4129ffb076e21',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@18f6a66b6a1a78515a7dd1c0a5d160f41533648d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 5eafdc6..9857cd8 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2336,6 +2336,7 @@
                     r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
                     r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
                     r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
+                    r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
                     r"^headless[\\/]app[\\/]headless_shell\.cc$",
                     r"^ipc[\\/]ipc_logging\.cc$",
                     r"^native_client_sdk[\\/]",
diff --git a/WATCHLISTS b/WATCHLISTS
index 58951021..075f7fba 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2125,7 +2125,6 @@
     'autoclick': ['katie+watch@chromium.org'],
     'autofill': ['anthonyvd+autofillwatch@chromium.org',
                  'ftirelo+autofillwatch@chromium.org',
-                 'mathp+autofillwatch@chromium.org',
                  'rogerm+autofillwatch@chromium.org',
                  'tmartino+autofillwatch@chromium.org'],
     'autofill_assistant': ['autofill_assistant+watch@google.com'],
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 03aad08..c581110 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -377,6 +377,11 @@
 const base::Feature kFilesZipUnpack{"FilesZipUnpack",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables or disables handle of `closeView` message from Gaia. The message is
+// supposed to end the flow.
+const base::Feature kGaiaCloseViewMessage{"GaiaCloseViewMessage",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the Gaia reauth endpoint with deleted user customization page.
 const base::Feature kGaiaReauthEndpoint{"GaiaReauthEndpoint",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
@@ -846,6 +851,10 @@
   return base::FeatureList::IsEnabled(kFamilyLinkOnSchoolDevice);
 }
 
+bool IsGaiaCloseViewMessageEnabled() {
+  return base::FeatureList::IsEnabled(kGaiaCloseViewMessage);
+}
+
 bool IsGaiaReauthEndpointEnabled() {
   return base::FeatureList::IsEnabled(kGaiaReauthEndpoint);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 4ef07ce..ad04d4d7 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -187,6 +187,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kHandwritingGestureEditing;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kGaiaCloseViewMessage;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kGaiaReauthEndpoint;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kGamepadVibration;
@@ -371,6 +373,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWAEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWAResizingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFamilyLinkOnSchoolDeviceEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaCloseViewMessageEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaReauthEndpointEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsImeSandboxEnabled();
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index 646f0dd..4163a46f 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">আপনার ডিভাইসগুলি একসাথে আরও ভাল কাজ করে</translation>
 <translation id="1119348796022671382">আপনার ইন্টারফেসে হালকা রং প্রয়োগ করতে 'থিমযুক্ত কালার' মোড ওয়ালপেপার থেকে রং নিয়ে ব্যবহার করে।</translation>
 <translation id="112308213915226829">তাককে স্বয়ংক্রিয়ভাবে লুকান</translation>
+<translation id="1148499908455722006"><ph name="USER_NAME" />-এর জন্য অ্যাকাউন্টের তথ্য সহ ডায়ালগ খুলুন</translation>
 <translation id="1153356358378277386">যুক্ত করা ডিভাইসগুলি</translation>
 <translation id="1165712434476988950">আপটেড প্রয়োগ করতে ডিভাইস রিস্টার্ট করুন।</translation>
 <translation id="1175572348579024023">স্ক্রল করুন</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">সময় শেষ হয়ে গেছে · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">প্রিভিউ দেখুন</translation>
 <translation id="4578906031062871102">'সেটিংস' মেনু খোলা হয়েছে</translation>
+<translation id="4581047786858252841">মাইক্রোফোন চালু করা হয়েছে</translation>
 <translation id="4585337515783392668">অজানা ডিভাইসে কাস্ট করা বন্ধ করুন</translation>
+<translation id="4587299710837179226">মাইক্রোফোন বন্ধ করা আছে</translation>
 <translation id="4596144739579517758">ডার্ক থিম বন্ধ আছে</translation>
 <translation id="4611292653554630842">লগ-ইন করুন</translation>
 <translation id="4623167406982293031">অ্যাকাউন্ট যাচাই করুন</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">স্ক্রিন শেয়ার করা থামাবেন?</translation>
 <translation id="5779721926447984944">পিন করা ফাইল</translation>
 <translation id="5790085346892983794">সফল</translation>
+<translation id="5805809050170488595"><ph name="NETWORK_NAME" /> চালু করতে ক্লিক করুন</translation>
 <translation id="5820394555380036790">Chromium OS</translation>
 <translation id="5825969630400862129">কানেক্ট করা ডিভাইসের সেটিংস</translation>
 <translation id="5837036133683224804"><ph name="RECEIVER_NAME" />-এ <ph name="ROUTE_TITLE" /> বন্ধ করুন</translation>
diff --git a/ash/strings/ash_strings_en-GB.xtb b/ash/strings/ash_strings_en-GB.xtb
index 9440532d..a29416c 100644
--- a/ash/strings/ash_strings_en-GB.xtb
+++ b/ash/strings/ash_strings_en-GB.xtb
@@ -140,6 +140,7 @@
 <translation id="2079504693865562705">Hide apps in shelf</translation>
 <translation id="2083190527011054446">Good night <ph name="GIVEN_NAME" />,</translation>
 <translation id="209965399369889474">Not connected to network</translation>
+<translation id="2108303511227308752">The Alt + backspace keyboard shortcut has changed. To use the delete key, press the <ph name="LAUNCHER_KEY_NAME" /> key + backspace.</translation>
 <translation id="2126242104232412123">New desk</translation>
 <translation id="2127372758936585790">Low-power charger</translation>
 <translation id="2132302418721800944">Record full screen</translation>
@@ -367,6 +368,7 @@
 <translation id="4021716437419160885">Scroll down</translation>
 <translation id="4028481283645788203">Password required for more security</translation>
 <translation id="4032485810211612751"><ph name="HOURS" />:<ph name="MINUTES" />:<ph name="SECONDS" /></translation>
+<translation id="403337028234783023">The <ph name="LAUNCHER_KEY_NAME" /> + number keyboard shortcut has changed. To use the F-keys, press the <ph name="LAUNCHER_KEY_NAME" /> key + a key on the top row.</translation>
 <translation id="4042660782729322247">You're sharing your screen</translation>
 <translation id="4057003836560082631">Browser tab <ph name="INDEX" /> of <ph name="TOTAL_COUNT" />. <ph name="SITE_TITLE" />, <ph name="SITE_URL" /></translation>
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{Off for an app}other{Off for # apps}}</translation>
@@ -392,6 +394,7 @@
 <translation id="425364040945105958">No SIM</translation>
 <translation id="4261870227682513959">Show notification settings. Notifications are off</translation>
 <translation id="4269883910223712419">The admin of this device has the ability to:</translation>
+<translation id="4274537685965975248">The Ctrl + Alt + down arrow keyboard shortcut has changed. To use the End key, press the <ph name="LAUNCHER_KEY_NAME" /> key + right arrow.</translation>
 <translation id="4279490309300973883">Mirroring</translation>
 <translation id="4285498937028063278">Unpin</translation>
 <translation id="4294319844246081198">Good morning <ph name="GIVEN_NAME" />,</translation>
@@ -400,6 +403,7 @@
 <translation id="4303223480529385476">Expand status area</translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4321776623976362024">You pressed the keyboard shortcut for high contrast. Do you want to turn it on?</translation>
+<translation id="4322742403972824594">The Ctrl + Alt + up arrow keyboard shortcut has changed. To use the Home key, press the <ph name="LAUNCHER_KEY_NAME" /> key + left arrow.</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="4333628967105022692">Lacros is not supported while multiple users are signed in.</translation>
 <translation id="4338109981321384717">Magnifying glass</translation>
@@ -417,6 +421,7 @@
 <translation id="4445159312344259901">Sign in to unlock</translation>
 <translation id="4449692009715125625">{NUM_NOTIFICATIONS,plural, =1{1 important notification}other{# important notifications}}</translation>
 <translation id="4450893287417543264">Don't show again</translation>
+<translation id="4451374464530248585">The Alt + down arrow keyboard shortcut has changed. To use the page down key, press the <ph name="LAUNCHER_KEY_NAME" /> key + down arrow.</translation>
 <translation id="445864333228800152">Good evening,</translation>
 <translation id="4458688154122353284">Stop screen recording</translation>
 <translation id="4472575034687746823">Get started</translation>
@@ -708,6 +713,7 @@
 <translation id="6919251195245069855">Couldn’t recognise your smart card. Try again.</translation>
 <translation id="6945221475159498467">Select</translation>
 <translation id="6961121602502368900">Silence phone is not available on work profile</translation>
+<translation id="6961840794482373852">The Alt + up arrow keyboard shortcut has changed. To use the page up key, press the <ph name="LAUNCHER_KEY_NAME" /> key + up arrow.</translation>
 <translation id="6965382102122355670">OK</translation>
 <translation id="6972754398087986839">Get started</translation>
 <translation id="6981982820502123353">Accessibility</translation>
diff --git a/ash/strings/ash_strings_ko.xtb b/ash/strings/ash_strings_ko.xtb
index c919e39..6f65bc8 100644
--- a/ash/strings/ash_strings_ko.xtb
+++ b/ash/strings/ash_strings_ko.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">기기가 연결되면 더욱 원활하게 작동합니다</translation>
 <translation id="1119348796022671382">테마 색상 모드는 배경화면에서 추출한 색상을 사용하여 인터페이스에 부드럽게 반영합니다.</translation>
 <translation id="112308213915226829">실행기 자동 숨김</translation>
+<translation id="1148499908455722006"><ph name="USER_NAME" /> 정보 대화상자 열기</translation>
 <translation id="1153356358378277386">페어링된 기기</translation>
 <translation id="1165712434476988950">업데이트를 적용하려면 기기를 다시 시작해야 합니다.</translation>
 <translation id="1175572348579024023">스크롤</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">타이머 종료 · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">미리보기 표시</translation>
 <translation id="4578906031062871102">설정 메뉴가 열림</translation>
+<translation id="4581047786858252841">마이크 켜짐</translation>
 <translation id="4585337515783392668">알 수 없는 수신기에 전송 중지</translation>
+<translation id="4587299710837179226">마이크 꺼짐</translation>
 <translation id="4596144739579517758">어두운 테마가 꺼져 있습니다.</translation>
 <translation id="4611292653554630842">로그인</translation>
 <translation id="4623167406982293031">계정을 인증하세요.</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">화면 공유를 중단하시겠습니까?</translation>
 <translation id="5779721926447984944">고정된 파일</translation>
 <translation id="5790085346892983794">완료</translation>
+<translation id="5805809050170488595">클릭하여 <ph name="NETWORK_NAME" /> 활성화</translation>
 <translation id="5820394555380036790">Chromium OS</translation>
 <translation id="5825969630400862129">연결된 기기 설정</translation>
 <translation id="5837036133683224804"><ph name="RECEIVER_NAME" />에서 <ph name="ROUTE_TITLE" /> 중지</translation>
diff --git a/ash/strings/ash_strings_lo.xtb b/ash/strings/ash_strings_lo.xtb
index 491bf9c..97476f4 100644
--- a/ash/strings/ash_strings_lo.xtb
+++ b/ash/strings/ash_strings_lo.xtb
@@ -140,6 +140,7 @@
 <translation id="2079504693865562705">ເຊື່ອງແອັບໃນຖ້ານ</translation>
 <translation id="2083190527011054446">ຝັນດີ <ph name="GIVEN_NAME" />,</translation>
 <translation id="209965399369889474">ບໍ່ເຊື່ອມຕໍ່ກັບເຄືອຂ່າຍ</translation>
+<translation id="2108303511227308752">ຄີລັດ Alt + Backspace ຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ Delete, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + backspace.</translation>
 <translation id="2126242104232412123">ພື້ນທີ່ເຮັດວຽກໃໝ່</translation>
 <translation id="2127372758936585790">ເຄື່ອງສາກໄຟຕໍ່າ</translation>
 <translation id="2132302418721800944">ບັນທຶກໜ້າຈໍເຕັມ</translation>
@@ -367,6 +368,7 @@
 <translation id="4021716437419160885">ເລື່ອນລົງ</translation>
 <translation id="4028481283645788203">ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານເພື່ອຄວາມປອດໄພຍິ່ງຂຶ້ນ</translation>
 <translation id="4032485810211612751"><ph name="HOURS" />:<ph name="MINUTES" />:<ph name="SECONDS" /></translation>
+<translation id="403337028234783023">ຄີລັດ <ph name="LAUNCHER_KEY_NAME" /> + ຕົວເລກຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ F, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + ປຸ່ມໃດໜຶ່ງຢູ່ແຖວເທິງສຸດ.</translation>
 <translation id="4042660782729322247">ທ່ານກຳລັງແບ່ງປັນໜ້າຈໍຂອງທ່ານ</translation>
 <translation id="4057003836560082631">ແຖບໂປຣແກຣມທ່ອງເວັບ <ph name="INDEX" /> ແຖບຈາກທັງໝົດ <ph name="TOTAL_COUNT" />. <ph name="SITE_TITLE" />, <ph name="SITE_URL" /></translation>
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{ປິດສຳລັບໜຶ່ງແອັບ}other{ປິດສຳລັບ # ແອັບ}}</translation>
@@ -392,6 +394,7 @@
 <translation id="425364040945105958">ບໍ່ມີ SIM</translation>
 <translation id="4261870227682513959">ສະແດງການຕັ້ງຄ່າການແຈ້ງເຕືອນ. ການແຈ້ງເຕືອນປິດຢູ່</translation>
 <translation id="4269883910223712419">ຜູ້ເບິ່ງແແຍງລະບົບຂອງອຸປະກອນີ້ສາມາດ:</translation>
+<translation id="4274537685965975248">ຄີລັດ Ctrl + Alt + ລູກສອນລົງຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ End, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + ລູກສອນຂວາ.</translation>
 <translation id="4279490309300973883">ການສ່ອງ</translation>
 <translation id="4285498937028063278">ຖອນໝຸດ</translation>
 <translation id="4294319844246081198">ສະບາຍດີຕອນເຊົ້າ <ph name="GIVEN_NAME" />,</translation>
@@ -400,6 +403,7 @@
 <translation id="4303223480529385476">ຂະຫຍາຍພື້ນທີ່ສະແດງສະຖານະ</translation>
 <translation id="4321179778687042513">Ctrl</translation>
 <translation id="4321776623976362024">ທ່ານໄດ້ກົດປຸ່ມລັດແປ້ນພິມສຳລັບຄວາມຄົມຊັດສູງແລ້ວ. ທ່ານຕ້ອງການເປີດມັນບໍ?</translation>
+<translation id="4322742403972824594">ຄີລັດ Ctrl + Alt + ລູກສອນຂຶ້ນຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ Home, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + ລູກສອນຊ້າຍ.</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="4333628967105022692">ບໍ່ຮອງຮັບ Lacros ໃນເວລາທີ່ມີຜູ້ໃຊ້ຫຼາຍຄົນເຂົ້າສູ່ລະບົບ.</translation>
 <translation id="4338109981321384717">ແວ່ນຂະຫຍາຍ</translation>
@@ -417,6 +421,7 @@
 <translation id="4445159312344259901">ເຂົ້າສູ່ລະບົບເພື່ອປົດລັອກ</translation>
 <translation id="4449692009715125625">{NUM_NOTIFICATIONS,plural, =1{ການແຈ້ງເຕືອນສຳຄັນ 1 ລາຍການ}other{ການແຈ້ງເຕືອນສຳຄັນ # ລາຍການ}}</translation>
 <translation id="4450893287417543264">ຢ່າສະແດງອີກ</translation>
+<translation id="4451374464530248585">ຄີລັດ Alt + ລູກສອນລົງຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ Page Down, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + ລູກສອນລົງ.</translation>
 <translation id="445864333228800152">ສະບາຍດີຕອນແລງ,</translation>
 <translation id="4458688154122353284">ຢຸດການບັນທຶກໜ້າຈໍ</translation>
 <translation id="4472575034687746823">ເລີ່ມຕົ້ນ</translation>
@@ -708,6 +713,7 @@
 <translation id="6919251195245069855">ບໍ່ສາມາດຮັບຮູ້ບັດອັດສະລິຍະຂອງທ່ານໄດ້. ລອງໃໝ່.</translation>
 <translation id="6945221475159498467">ເລືອກ</translation>
 <translation id="6961121602502368900">ປິດສຽງໂທລະສັບບໍ່ສາມາດໃຊ້ໄດ້ໃນໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ</translation>
+<translation id="6961840794482373852">ຄີລັດ Alt + ລູກສອນຂຶ້ນຖືກປ່ຽນແປງແລ້ວ. ເພື່ອໃຊ້ປຸ່ມ Page Up, ໃຫ້ກົດປຸ່ມ <ph name="LAUNCHER_KEY_NAME" /> + ລູກສອນຂຶ້ນ.</translation>
 <translation id="6965382102122355670">ຕົກລົງ</translation>
 <translation id="6972754398087986839">ເລີ່ມຕົ້ນ</translation>
 <translation id="6981982820502123353">ການເຂົ້າ​​ເຖິງ​ໄດ້</translation>
diff --git a/ash/strings/ash_strings_mn.xtb b/ash/strings/ash_strings_mn.xtb
index fe66ac7..08689c590 100644
--- a/ash/strings/ash_strings_mn.xtb
+++ b/ash/strings/ash_strings_mn.xtb
@@ -500,7 +500,7 @@
 <translation id="5035236842988137213"><ph name="DEVICE_NAME" /> шинэ утсанд холбогдсон байна</translation>
 <translation id="5035389544768382859">Дэлгэцийн тохируулгыг баталгаажуулах</translation>
 <translation id="504465286040788597">Өмнөх догол мөр</translation>
-<translation id="5078796286268621944">PIN код буруу байна</translation>
+<translation id="5078796286268621944">ПИН код буруу байна</translation>
 <translation id="5083553833479578423">Tуслахын бусад онцлогийн түгжээг тайлна уу.</translation>
 <translation id="5136175204352732067">Өөр гар холбосон</translation>
 <translation id="5155897006997040331">Унших хурд</translation>
@@ -549,7 +549,7 @@
 <translation id="558849140439112033">Зураг авах хэсгийг сонгохын тулд чирнэ үү</translation>
 <translation id="5597451508971090205"><ph name="SHORT_WEEKDAY" />, <ph name="DATE" /></translation>
 <translation id="5600837773213129531">Хэлсэн саналыг идэвхгүй болгохын тулд Ctrl + Alt + Z-г дарна уу.</translation>
-<translation id="5601503069213153581">PIN</translation>
+<translation id="5601503069213153581">ПИН</translation>
 <translation id="5619862035903135339">Администраторын бодлого нь дэлгэцийн зураг авахыг идэвхгүй болгодог</translation>
 <translation id="5625955975703555628">LTE+</translation>
 <translation id="5648021990716966815">Микрофоны чихэвчний оролт</translation>
diff --git a/ash/strings/ash_strings_ms.xtb b/ash/strings/ash_strings_ms.xtb
index 5104046..9d039e8 100644
--- a/ash/strings/ash_strings_ms.xtb
+++ b/ash/strings/ash_strings_ms.xtb
@@ -140,6 +140,7 @@
 <translation id="2079504693865562705">Sembunyikan apl dalam rak</translation>
 <translation id="2083190527011054446">Selamat malam <ph name="GIVEN_NAME" />,</translation>
 <translation id="209965399369889474">Tidak bersambung ke rangkaian</translation>
+<translation id="2108303511227308752">Pintasan papan kekunci Alt + Undur Ruang telah berubah. Untuk menggunakan kekunci Delete, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + undur ruang.</translation>
 <translation id="2126242104232412123">Meja baharu</translation>
 <translation id="2127372758936585790">Pengecas berkuasa rendah</translation>
 <translation id="2132302418721800944">Rakam skrin penuh</translation>
@@ -368,6 +369,7 @@
 <translation id="4021716437419160885">Tatal ke bawah</translation>
 <translation id="4028481283645788203">Kata laluan diperlukan untuk meningkatkan keselamatan</translation>
 <translation id="4032485810211612751"><ph name="HOURS" />:<ph name="MINUTES" />:<ph name="SECONDS" /></translation>
+<translation id="403337028234783023">Pintasan papan kekunci <ph name="LAUNCHER_KEY_NAME" /> + Nombor telah berubah. Untuk menggunakan kekunci F, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + salah satu kekunci di baris atas.</translation>
 <translation id="4042660782729322247">Anda berkongsi skrin anda</translation>
 <translation id="4057003836560082631">Tab penyemak imbas <ph name="INDEX" /> daripada <ph name="TOTAL_COUNT" />. <ph name="SITE_TITLE" />, <ph name="SITE_URL" /></translation>
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{Mati, satu apl}other{Mati, # apl}}</translation>
@@ -393,6 +395,7 @@
 <translation id="425364040945105958">Tiada SIM</translation>
 <translation id="4261870227682513959">Tunjukkan tetapan pemberitahuan. Pemberitahuan dimatikan</translation>
 <translation id="4269883910223712419">Pentadbir peranti ini berkeupayaan untuk:</translation>
+<translation id="4274537685965975248">Pintasan papan kekunci Ctrl + Alt + Anak Panah ke Bawah telah berubah. Untuk menggunakan kekunci End, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + Anak Panah ke Kanan.</translation>
 <translation id="4279490309300973883">Pencerminan</translation>
 <translation id="4285498937028063278">Menyahpin</translation>
 <translation id="4294319844246081198">Selamat pagi <ph name="GIVEN_NAME" />,</translation>
@@ -401,6 +404,7 @@
 <translation id="4303223480529385476">Kembangkan area status</translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4321776623976362024">Anda menekan pintasan papan kekunci untuk kontras tinggi. Adakah anda ingin menghidupkannya?</translation>
+<translation id="4322742403972824594">Pintasan papan kekunci Ctrl + Alt + Anak Panah ke Atas telah berubah. Untuk menggunakan kekunci Home, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + Anak Panah ke Kiri.</translation>
 <translation id="4331809312908958774">OS Chrome</translation>
 <translation id="4333628967105022692">Lacros tidak disokong semasa berbilang pengguna dilog masuk.</translation>
 <translation id="4338109981321384717">Kanta pembesar</translation>
@@ -418,6 +422,7 @@
 <translation id="4445159312344259901">Log masuk untuk membuka kunci</translation>
 <translation id="4449692009715125625">{NUM_NOTIFICATIONS,plural, =1{1 pemberitahuan penting}other{# pemberitahuan penting}}</translation>
 <translation id="4450893287417543264">Jangan tunjukkan lagi</translation>
+<translation id="4451374464530248585">Pintasan papan kekunci Alt + Anak Panah ke Bawah telah berubah. Untuk menggunakan kekunci Page Down, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + Anak Panah ke Bawah.</translation>
 <translation id="445864333228800152">Selamat petang,</translation>
 <translation id="4458688154122353284">Hentikan rakaman skrin</translation>
 <translation id="4472575034687746823">Bermula</translation>
@@ -709,6 +714,7 @@
 <translation id="6919251195245069855">Tidak dapat mengecam kad pintar anda. Cuba lagi.</translation>
 <translation id="6945221475159498467">Pilih</translation>
 <translation id="6961121602502368900">Ciri Senyapkan telefon tidak tersedia pada profil kerja</translation>
+<translation id="6961840794482373852">Pintasan papan kekunci Alt + Anak Panah ke Atas telah berubah. Untuk menggunakan kekunci Page Up, tekan kekunci <ph name="LAUNCHER_KEY_NAME" /> + Anak Panah ke Atas.</translation>
 <translation id="6965382102122355670">OK</translation>
 <translation id="6972754398087986839">Bermula</translation>
 <translation id="6981982820502123353">Kebolehcapaian</translation>
diff --git a/ash/strings/ash_strings_pa.xtb b/ash/strings/ash_strings_pa.xtb
index 4a85e12..d47d206b 100644
--- a/ash/strings/ash_strings_pa.xtb
+++ b/ash/strings/ash_strings_pa.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">ਰਲ ਕੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਹੋਰ ਵੀ ਬਿਹਤਰ ਕੰਮ ਕਰਦੇ ਹਨ</translation>
 <translation id="1119348796022671382">ਥੀਮਡ ਰੰਗ ਮੋਡ ਇੰਟਰਫੇਸ ਨੂੰ ਹਲਕਾ ਰੰਗੀਨ ਕਰਨ ਲਈ ਅਜਿਹੇ ਰੰਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ ਜੋ ਤੁਹਾਡੇ ਵਾਲਪੇਪਰ ਤੋਂ ਐਕਸਟ੍ਰੈਕਟ ਕੀਤੇ ਗਏ ਹਨ।</translation>
 <translation id="112308213915226829">ਸ਼ੈਲਫ ਆਟੋਲੁਕਾਓ</translation>
+<translation id="1148499908455722006"><ph name="USER_NAME" /> ਲਈ ਜਾਣਕਾਰੀ ਵਿੰਡੋ ਖੋਲ੍ਹੋ</translation>
 <translation id="1153356358378277386">ਜੋੜਾਬੱਧ ਕੀਤੀਆਂ ਡੀਵਾਈਸਾਂ</translation>
 <translation id="1165712434476988950">ਅੱਪਡੇਟ ਲਾਗੂ ਕਰਨ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।</translation>
 <translation id="1175572348579024023">ਸਕ੍ਰੋਲ</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">ਸਮਾਂ ਸਮਾਪਤ ਹੋਇਆ · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">ਪੂਰਵ-ਝਲਕਾਂ ਦਿਖਾਓ</translation>
 <translation id="4578906031062871102">ਸੈਟਿੰਗ ਮੀਨੂ ਨੂੰ ਖੋਲ੍ਹਿਆ ਗਿਆ</translation>
+<translation id="4581047786858252841">ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਚਾਲੂ ਹੈ</translation>
 <translation id="4585337515783392668">ਕਿਸੇ ਅਗਿਆਤ ਪ੍ਰਾਪਤਕਰਤਾ 'ਤੇ ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ</translation>
+<translation id="4587299710837179226">ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬੰਦ ਹੈ</translation>
 <translation id="4596144739579517758">ਗੂੜ੍ਹਾ ਥੀਮ ਬੰਦ ਹੈ।</translation>
 <translation id="4611292653554630842">ਲੌਗ ਇਨ ਕਰੋ</translation>
 <translation id="4623167406982293031">ਖਾਤੇ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">ਕੀ ਸਕ੍ਰੀਨ ਸ਼ੇਅਰਿੰਗ ਰੋਕਣੀ ਹੈ?</translation>
 <translation id="5779721926447984944">ਪਿੰਨ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ</translation>
 <translation id="5790085346892983794">ਸਫਲਤਾ</translation>
+<translation id="5805809050170488595"><ph name="NETWORK_NAME" /> ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ</translation>
 <translation id="5820394555380036790">Chromium OS</translation>
 <translation id="5825969630400862129">ਕਨੈਕਟ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ</translation>
 <translation id="5837036133683224804"><ph name="RECEIVER_NAME" /> 'ਤੇ <ph name="ROUTE_TITLE" /> ਨੂੰ ਬੰਦ ਕਰੋ</translation>
diff --git a/ash/strings/ash_strings_si.xtb b/ash/strings/ash_strings_si.xtb
index bc61ca5..18f0a63 100644
--- a/ash/strings/ash_strings_si.xtb
+++ b/ash/strings/ash_strings_si.xtb
@@ -140,6 +140,7 @@
 <translation id="2079504693865562705">රාක්කය තුළ යෙදුම් සඟවන්න</translation>
 <translation id="2083190527011054446">සුබ රාත්‍රියක් <ph name="GIVEN_NAME" />,</translation>
 <translation id="209965399369889474">ජාලයට සම්බන්ධ වී නැත</translation>
+<translation id="2108303511227308752">Alt + Backspace යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. Delete යතුර භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + Backspace ඔබන්න.</translation>
 <translation id="2126242104232412123">නව මේසය</translation>
 <translation id="2127372758936585790">බලය අඩු චාජරයකි</translation>
 <translation id="2132302418721800944">පූර්ණ තිරය පටිගත කරන්න</translation>
@@ -367,6 +368,7 @@
 <translation id="4021716437419160885">පහළට අනුචලනය කරන්න</translation>
 <translation id="4028481283645788203">වැඩිපුර ආරක්‍ෂාව සඳහා මුරපදය අවශ්‍යයි</translation>
 <translation id="4032485810211612751"><ph name="HOURS" />:<ph name="MINUTES" />:<ph name="SECONDS" /></translation>
+<translation id="403337028234783023"><ph name="LAUNCHER_KEY_NAME" /> + Number යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. F-යතුරු භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + ඉහළම පේළියේ ඇති යතුරක් ඔබන්න.</translation>
 <translation id="4042660782729322247">ඔබ ඔබේ තිරය බෙදා ගනියි</translation>
 <translation id="4057003836560082631">බ්‍රව්සර් ටැබ් <ph name="TOTAL_COUNT" />කින් <ph name="INDEX" />. <ph name="SITE_TITLE" />, <ph name="SITE_URL" /></translation>
 <translation id="4065525899979931964">{NUM_APPS,plural, =1{යෙදුමකට අක්‍රියයි}one{යෙදුම් #කට අක්‍රියයි}other{යෙදුම් #කට අක්‍රියයි}}</translation>
@@ -392,6 +394,7 @@
 <translation id="425364040945105958">SIM නැත</translation>
 <translation id="4261870227682513959">දැනුම් දීම් සැකසීම් පෙන්වන්න. දැනුම් දීම් ක්‍රියාවිරහිතයි</translation>
 <translation id="4269883910223712419">මෙම උපාංගයේ පරිපාලකයාට මේවා කළ හැක:</translation>
+<translation id="4274537685965975248">Ctrl + Alt + පහළට ඊතලය යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. End යතුර භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + දකුණට ඊතලය ඔබන්න.</translation>
 <translation id="4279490309300973883">ආදර්ශනය කරමින්</translation>
 <translation id="4285498937028063278">ගලවන්න</translation>
 <translation id="4294319844246081198">සුබ උදෑසනක් <ph name="GIVEN_NAME" />,</translation>
@@ -400,6 +403,7 @@
 <translation id="4303223480529385476">තත්ත්ව ප්‍රදේශය දිග හරින්න</translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4321776623976362024">ඔබ අධිවිභේදනය සඳහා යතුරුපුවරු කෙටිමඟ ඔබා ඇත. ඔබට එය සක්‍රීය කළ යුතුද?</translation>
+<translation id="4322742403972824594">Ctrl + Alt + ඉහළට ඊතලය යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. Home යතුර භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + ඉවමට ඊතලය ඔබන්න.</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="4333628967105022692">බහුපරිශීලකයින් පුරා සිටින අතරතුර Lacros සහාය නොදක්වයි.</translation>
 <translation id="4338109981321384717">විශාලක කාචය</translation>
@@ -417,6 +421,7 @@
 <translation id="4445159312344259901">අගුලු හැරීමට පුරන්න</translation>
 <translation id="4449692009715125625">{NUM_NOTIFICATIONS,plural, =1{වැදගත් දැනුම්දීම් 1}one{වැදගත් දැනුම්දීම් #}other{වැදගත් දැනුම්දීම් #}}</translation>
 <translation id="4450893287417543264">නැවත නොපෙන්වන්න</translation>
+<translation id="4451374464530248585">Alt + පහළට ඊතලය යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. Page Down යතුර භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + පහළට ඊතලය ඔබන්න.</translation>
 <translation id="445864333228800152">සුබ සන්ධ්‍යාවක්,</translation>
 <translation id="4458688154122353284">තිරය පටිගත කිරීම නවත්වන්න</translation>
 <translation id="4472575034687746823">අරඹන්න</translation>
@@ -708,6 +713,7 @@
 <translation id="6919251195245069855">ඔබේ ස්මාර්ට් කාඩ්පත හඳුනා ගැනීමට නොහැකි විය. නැවත උත්සාහ කරන්න.</translation>
 <translation id="6945221475159498467">තෝරන්න</translation>
 <translation id="6961121602502368900">කාර්යාල පැතිකඩෙහි දුරකථනය නිහඬ කිරීම ලබා ගත නොහැකිය</translation>
+<translation id="6961840794482373852">Alt + ඉහළට ඊතලය යතුරු පුවරු කෙටි මග වෙනස් වී ඇත. Page Up යතුර භාවිත කිරීමට, <ph name="LAUNCHER_KEY_NAME" /> යතුර + ඉහළට ඊතලය ඔබන්න.</translation>
 <translation id="6965382102122355670">හරි</translation>
 <translation id="6972754398087986839">අරඹන්න</translation>
 <translation id="6981982820502123353">ප්‍රවේශ්‍යතාව</translation>
diff --git a/ash/strings/ash_strings_sq.xtb b/ash/strings/ash_strings_sq.xtb
index 997ae76..ffc008d 100644
--- a/ash/strings/ash_strings_sq.xtb
+++ b/ash/strings/ash_strings_sq.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">Pajisjet e tua punojnë edhe më mirë së bashku</translation>
 <translation id="1119348796022671382">Modaliteti me ngjyra me temë përdor ngjyrat e nxjerra nga imazhi i sfondit për të ngjyrosur lehtë ndërfaqen.</translation>
 <translation id="112308213915226829">Fshih raftin automatikisht</translation>
+<translation id="1148499908455722006">Hap dialogun e informacioneve për <ph name="USER_NAME" /></translation>
 <translation id="1153356358378277386">Pajisjet e çiftuara</translation>
 <translation id="1165712434476988950">Kërkohet rinisja e pajisjes për të zbatuar përditësimin.</translation>
 <translation id="1175572348579024023">Lëviz</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">Koha mbaroi · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">Shfaq paraafishimet</translation>
 <translation id="4578906031062871102">Menyja e "Cilësimeve" u hap</translation>
+<translation id="4581047786858252841">Mikrofoni është aktiv</translation>
 <translation id="4585337515783392668">Ndalo transmetimin në një marrës të panjohur</translation>
+<translation id="4587299710837179226">Mikrofoni është joaktiv</translation>
 <translation id="4596144739579517758">"Tema e errët" është joaktive</translation>
 <translation id="4611292653554630842">Identifikohu</translation>
 <translation id="4623167406982293031">Verifiko llogarinë</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">Dëshiron të ndalosh ndarjen e ekranit?</translation>
 <translation id="5779721926447984944">Skedarët e gozhduar</translation>
 <translation id="5790085346892983794">Me sukses</translation>
+<translation id="5805809050170488595">Kliko për të aktivizuar <ph name="NETWORK_NAME" /></translation>
 <translation id="5820394555380036790">Chromium OS</translation>
 <translation id="5825969630400862129">Cilësimet e pajisjeve të lidhura</translation>
 <translation id="5837036133683224804">Ndalo <ph name="ROUTE_TITLE" /> në <ph name="RECEIVER_NAME" /></translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index 4bb222f8..88eaf6a 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">మీ పరికరాలు కలిసికట్టుగా మరింత బాగా పనిచేస్తాయి</translation>
 <translation id="1119348796022671382">'రూపం ఉన్న రంగు మోడ్'లో ఇంటర్‌ఫేస్‌కు పలుచగా రంగులు అద్దడానికి మీ వాల్‌పేపర్‌లోని రంగులు సంగ్రహించి ఉపయోగించబడతాయి.</translation>
 <translation id="112308213915226829">అరను స్వయంచాలకంగా దాచు</translation>
+<translation id="1148499908455722006"><ph name="USER_NAME" /> కోసం సమాచార డైలాగ్‌ను తెరవండి</translation>
 <translation id="1153356358378277386">జత చేసిన పరికరాలు</translation>
 <translation id="1165712434476988950">అప్‌డేట్‌ను వర్తింపజేయడానికి పరికరాన్ని రీస్టార్ట్ చేయాలి.</translation>
 <translation id="1175572348579024023">స్క్రోల్ చేస్తుంది</translation>
@@ -438,7 +439,9 @@
 <translation id="4577274620589681794">సమయం ముగిసింది · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">ప్రివ్యూలను చూపు</translation>
 <translation id="4578906031062871102">సెట్టింగ్‌ల మెనూ తెరవబడింది</translation>
+<translation id="4581047786858252841">మైక్రోఫోన్ ఆన్‌లో ఉంది</translation>
 <translation id="4585337515783392668">తెలియని రిసీవర్‌లో ప్రసారం చేయడాన్ని ఆపివేయి</translation>
+<translation id="4587299710837179226">మైక్రోఫోన్ ఆఫ్‌లో ఉంది</translation>
 <translation id="4596144739579517758">ముదురు రంగు రూపం ఆఫ్‌లో ఉంది</translation>
 <translation id="4611292653554630842">లాగిన్ చేయండి</translation>
 <translation id="4623167406982293031">ఖాతాను వెరిఫై చేయండి</translation>
@@ -570,6 +573,7 @@
 <translation id="5777841717266010279">స్క్రీన్ భాగస్వామ్యాన్ని ఆపివేయాలా?</translation>
 <translation id="5779721926447984944">పిన్ చేయబడిన ఫైళ్లు</translation>
 <translation id="5790085346892983794">విజయవంతం</translation>
+<translation id="5805809050170488595"><ph name="NETWORK_NAME" />ను యాక్టివేట్ చేయడానికి క్లిక్ చేయండి</translation>
 <translation id="5820394555380036790">Chromium OS</translation>
 <translation id="5825969630400862129">కనెక్ట్ చేయబడిన పరికరాల సెట్టింగ్‌లు</translation>
 <translation id="5837036133683224804"><ph name="RECEIVER_NAME" />లో <ph name="ROUTE_TITLE" /> ఆపివేయి</translation>
diff --git a/ash/strings/ash_strings_vi.xtb b/ash/strings/ash_strings_vi.xtb
index ff142a4b..fe18f79e 100644
--- a/ash/strings/ash_strings_vi.xtb
+++ b/ash/strings/ash_strings_vi.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">Các thiết bị của bạn hoạt động hiệu quả hơn khi kết nối với nhau</translation>
 <translation id="1119348796022671382">Chế độ màu theo giao diện dùng các màu trích xuất từ hình nền để tạo màu nhẹ nhàng cho giao diện.</translation>
 <translation id="112308213915226829">Tự động ẩn kệ</translation>
+<translation id="1148499908455722006">Mở hộp thoại thông tin cho <ph name="USER_NAME" /></translation>
 <translation id="1153356358378277386">Thiết bị đã ghép nối</translation>
 <translation id="1165712434476988950">Bạn cần phải khởi động lại thiết bị để áp dụng bản cập nhật.</translation>
 <translation id="1175572348579024023">Cuộn</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">Hết giờ · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">Hiển thị bản xem trước</translation>
 <translation id="4578906031062871102">Đã mở trình đơn Cài đặt</translation>
+<translation id="4581047786858252841">Micrô đang bật</translation>
 <translation id="4585337515783392668">Dừng truyền trên bộ thu không xác định</translation>
+<translation id="4587299710837179226">Micrô đang tắt</translation>
 <translation id="4596144739579517758">Giao diện tối đang tắt</translation>
 <translation id="4611292653554630842">Đăng nhập</translation>
 <translation id="4623167406982293031">Xác minh tài khoản</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">Bạn muốn dừng chia sẻ màn hình?</translation>
 <translation id="5779721926447984944">Tệp đã ghim</translation>
 <translation id="5790085346892983794">Thành công</translation>
+<translation id="5805809050170488595">Nhấp để kích hoạt <ph name="NETWORK_NAME" /></translation>
 <translation id="5820394555380036790">Hệ điều hành Chromium</translation>
 <translation id="5825969630400862129">Cài đặt thiết bị đã kết nối</translation>
 <translation id="5837036133683224804">Dừng <ph name="ROUTE_TITLE" /> trên <ph name="RECEIVER_NAME" /></translation>
diff --git a/ash/strings/ash_strings_zh-TW.xtb b/ash/strings/ash_strings_zh-TW.xtb
index 5882f6e..37a5da5 100644
--- a/ash/strings/ash_strings_zh-TW.xtb
+++ b/ash/strings/ash_strings_zh-TW.xtb
@@ -21,6 +21,7 @@
 <translation id="1104621072296271835">完成連結可進一步提升裝置效能</translation>
 <translation id="1119348796022671382">主題色彩模式會使用從桌布擷取的色彩,在介面上套用相對應的色調。</translation>
 <translation id="112308213915226829">自動隱藏檔案櫃</translation>
+<translation id="1148499908455722006">開啟「<ph name="USER_NAME" />」的資訊對話方塊</translation>
 <translation id="1153356358378277386">配對裝置</translation>
 <translation id="1165712434476988950">必須重新啟動裝置才能套用更新。</translation>
 <translation id="1175572348579024023">捲動</translation>
@@ -437,7 +438,9 @@
 <translation id="4577274620589681794">時間到 · <ph name="LABEL" /></translation>
 <translation id="4577990005084629481">顯示預覽</translation>
 <translation id="4578906031062871102">已開啟設定選單</translation>
+<translation id="4581047786858252841">麥克風已開啟</translation>
 <translation id="4585337515783392668">停止透過不明接收器投放</translation>
+<translation id="4587299710837179226">麥克風已關閉</translation>
 <translation id="4596144739579517758">深色主題已關閉</translation>
 <translation id="4611292653554630842">登入</translation>
 <translation id="4623167406982293031">驗證帳戶</translation>
@@ -569,6 +572,7 @@
 <translation id="5777841717266010279">停止共用螢幕?</translation>
 <translation id="5779721926447984944">固定的檔案</translation>
 <translation id="5790085346892983794">成功</translation>
+<translation id="5805809050170488595">按一下即可啟動「<ph name="NETWORK_NAME" />」</translation>
 <translation id="5820394555380036790">Chromium 作業系統</translation>
 <translation id="5825969630400862129">設定已連結的裝置</translation>
 <translation id="5837036133683224804">停止透過<ph name="RECEIVER_NAME" />投放「<ph name="ROUTE_TITLE" />」</translation>
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 04d96a0..fc4b56ab 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -42,6 +42,7 @@
 #include "ui/aura/test/test_windows.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/chromeos/mock_input_method_manager.h"
 #include "ui/display/display.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/manager/display_manager.h"
@@ -178,6 +179,15 @@
   command_line_.reset();
 
   AuraTestHelper::TearDown();
+
+  // Cleanup the global state for InputMethodManager, but only if
+  // it was setup by this test helper. This allows tests to implement
+  // their own override, and in that case we shouldn't call Shutdown
+  // otherwise the global state will be deleted twice.
+  if (input_method_manager_) {
+    chromeos::input_method::InputMethodManager::Shutdown();
+    input_method_manager_ = nullptr;
+  }
 }
 
 aura::Window* AshTestHelper::GetContext() {
@@ -213,6 +223,14 @@
 void AshTestHelper::SetUp(InitParams init_params) {
   // This block of objects are conditionally initialized here rather than in the
   // constructor to make it easier for test classes to override them.
+  if (!input_method::InputMethodManager::Get()) {
+    // |input_method_manager_| is not owned and is cleaned up in TearDown()
+    // by calling InputMethodManager::Shutdown().
+    input_method_manager_ =
+        new chromeos::input_method::MockInputMethodManager();
+    input_method::InputMethodManager::Initialize(input_method_manager_);
+  }
+
   if (!bluez::BluezDBusManager::IsInitialized()) {
     bluez_dbus_manager_initializer_ =
         std::make_unique<BluezDBusManagerInitializer>();
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index d182849..1f664cd 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -28,6 +28,12 @@
 class Window;
 }
 
+namespace chromeos {
+namespace input_method {
+class MockInputMethodManager;
+}  // namespace input_method
+}  // namespace chromeos
+
 namespace display {
 class Display;
 }
@@ -153,6 +159,11 @@
       test_keyboard_controller_observer_;
   std::unique_ptr<AmbientAshTestHelper> ambient_ash_test_helper_;
 
+  // InputMethodManager is not owned by this class. It is stored in a
+  // global that is registered via InputMethodManager::Initialize().
+  chromeos::input_method::MockInputMethodManager* input_method_manager_ =
+      nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(AshTestHelper);
 };
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 7ff21a5..4f6f252 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1925,11 +1925,15 @@
         "allocator/partition_allocator/starscan/object_bitmap.h",
         "allocator/partition_allocator/starscan/pcscan.cc",
         "allocator/partition_allocator/starscan/pcscan.h",
+        "allocator/partition_allocator/starscan/pcscan_internal.cc",
+        "allocator/partition_allocator/starscan/pcscan_internal.h",
         "allocator/partition_allocator/starscan/pcscan_scheduling.cc",
         "allocator/partition_allocator/starscan/pcscan_scheduling.h",
         "allocator/partition_allocator/starscan/raceful_worklist.h",
         "allocator/partition_allocator/starscan/stack/stack.cc",
         "allocator/partition_allocator/starscan/stack/stack.h",
+        "allocator/partition_allocator/starscan/stats_collector.cc",
+        "allocator/partition_allocator/starscan/stats_collector.h",
         "allocator/partition_allocator/thread_cache.cc",
         "allocator/partition_allocator/thread_cache.h",
         "allocator/partition_allocator/yield_processor.h",
diff --git a/base/allocator/partition_allocator/random.cc b/base/allocator/partition_allocator/random.cc
index 416d9b81..d0a50e2 100644
--- a/base/allocator/partition_allocator/random.cc
+++ b/base/allocator/partition_allocator/random.cc
@@ -4,70 +4,62 @@
 
 #include "base/allocator/partition_allocator/random.h"
 
-#include "base/lazy_instance.h"
-#include "base/no_destructor.h"
+#include "base/allocator/partition_allocator/partition_lock.h"
 #include "base/rand_util.h"
-#include "base/synchronization/lock.h"
 
 namespace base {
-
 namespace {
 
-LazyInstance<Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+internal::PartitionLock g_lock = {};
 
-Lock& GetLock() {
-  return g_lock.Get();
-}
-
-}  // namespace
-
-// This is the same PRNG as used by tcmalloc for mapping address randomness;
-// see http://burtleburtle.net/bob/rand/smallprng.html.
+// Using XorShift128+, which is simple and widely used. See
+// https://en.wikipedia.org/wiki/Xorshift#xorshift+ for details.
 struct RandomContext {
   bool initialized;
-  uint32_t a;
-  uint32_t b;
-  uint32_t c;
-  uint32_t d;
+
+  uint64_t a;
+  uint64_t b;
 };
 
-static RandomContext g_context GUARDED_BY(GetLock());
+RandomContext g_context GUARDED_BY(g_lock);
 
-namespace {
-
-RandomContext& GetRandomContext() EXCLUSIVE_LOCKS_REQUIRED(GetLock()) {
+RandomContext& GetRandomContext() EXCLUSIVE_LOCKS_REQUIRED(g_lock) {
   if (UNLIKELY(!g_context.initialized)) {
-    const uint64_t r1 = RandUint64();
-    const uint64_t r2 = RandUint64();
-    g_context.a = static_cast<uint32_t>(r1);
-    g_context.b = static_cast<uint32_t>(r1 >> 32);
-    g_context.c = static_cast<uint32_t>(r2);
-    g_context.d = static_cast<uint32_t>(r2 >> 32);
+    g_context.a = RandUint64();
+    g_context.b = RandUint64();
     g_context.initialized = true;
   }
+
   return g_context;
 }
 
 }  // namespace
 
 uint32_t RandomValue() {
-  AutoLock guard(GetLock());
+  internal::ScopedGuard<true> guard(g_lock);
   RandomContext& x = GetRandomContext();
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-  uint32_t e = x.a - rot(x.b, 27);
-  x.a = x.b ^ rot(x.c, 17);
-  x.b = x.c + x.d;
-  x.c = x.d + e;
-  x.d = e + x.a;
-  return x.d;
-#undef rot
+
+  uint64_t t = x.a;
+  const uint64_t s = x.b;
+
+  x.a = s;
+  t ^= t << 23;
+  t ^= t >> 17;
+  t ^= s ^ (s >> 26);
+  x.b = t;
+
+  // The generator usually returns an uint64_t, truncate it.
+  //
+  // It is noted in this paper (https://arxiv.org/abs/1810.05313) that the
+  // lowest 32 bits fail some statistical tests from the Big Crush
+  // suite. Use the higher ones instead.
+  return (t + s) >> 32;
 }
 
 void SetMmapSeedForTesting(uint64_t seed) {
-  AutoLock guard(GetLock());
+  internal::ScopedGuard<true> guard(g_lock);
   RandomContext& x = GetRandomContext();
   x.a = x.b = static_cast<uint32_t>(seed);
-  x.c = x.d = static_cast<uint32_t>(seed >> 32);
   x.initialized = true;
 }
 
diff --git a/base/allocator/partition_allocator/starscan/pcscan.cc b/base/allocator/partition_allocator/starscan/pcscan.cc
index fc640c6..ae75283 100644
--- a/base/allocator/partition_allocator/starscan/pcscan.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan.cc
@@ -1,1722 +1,14 @@
-// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Copyright (c) 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 "base/allocator/partition_allocator/starscan/pcscan.h"
 
-#include <algorithm>
-#include <array>
-#include <chrono>
-#include <condition_variable>
-#include <mutex>
-#include <numeric>
-#include <set>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include "base/allocator/partition_allocator/address_pool_manager.h"
-#include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
-#include "base/allocator/partition_allocator/page_allocator.h"
-#include "base/allocator/partition_allocator/page_allocator_constants.h"
-#include "base/allocator/partition_allocator/partition_address_space.h"
-#include "base/allocator/partition_allocator/partition_alloc.h"
-#include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "base/allocator/partition_allocator/partition_alloc_features.h"
-#include "base/allocator/partition_allocator/partition_page.h"
-#include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
-#include "base/allocator/partition_allocator/starscan/pcscan_scheduling.h"
-#include "base/allocator/partition_allocator/starscan/raceful_worklist.h"
-#include "base/allocator/partition_allocator/starscan/stack/stack.h"
-#include "base/allocator/partition_allocator/thread_cache.h"
-#include "base/compiler_specific.h"
-#include "base/cpu.h"
-#include "base/debug/alias.h"
-#include "base/immediate_crash.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/no_destructor.h"
-#include "base/threading/platform_thread.h"
-#include "base/time/time.h"
-#include "base/trace_event/base_tracing.h"
-#include "build/build_config.h"
-
-#if defined(ARCH_CPU_X86_64)
-// Include order is important, so we disable formatting.
-// clang-format off
-// Including these headers directly should generally be avoided. For the
-// scanning loop, we check at runtime which SIMD extension we can use. Since
-// Chrome is compiled with -msse3 (the minimal requirement), we include the
-// headers directly to make the intrinsics available. Another option could be to
-// use inline assembly, but that would hinder compiler optimization for
-// vectorized instructions.
-#include <immintrin.h>
-#include <smmintrin.h>
-#include <avxintrin.h>
-#include <avx2intrin.h>
-// clang-format on
-#endif
+#include "base/allocator/partition_allocator/starscan/pcscan_internal.h"
 
 namespace base {
 namespace internal {
 
-[[noreturn]] BASE_EXPORT NOINLINE NOT_TAIL_CALLED void DoubleFreeAttempt() {
-  NO_CODE_FOLDING();
-  IMMEDIATE_CRASH();
-}
-
-namespace {
-
-#if DCHECK_IS_ON() && defined(OS_LINUX)
-// Currently, check reentracy only on Linux. On Android TLS is emulated by the
-// runtime lib, which can allocate and therefore cause reentrancy.
-struct ReentrantScannerGuard final {
- public:
-  ReentrantScannerGuard() {
-    PA_CHECK(!guard_);
-    guard_ = true;
-  }
-  ~ReentrantScannerGuard() { guard_ = false; }
-
- private:
-  // Since this variable has hidden visibility (not referenced by other DSOs),
-  // assume that thread_local works on all supported architectures.
-  static thread_local size_t guard_;
-};
-thread_local size_t ReentrantScannerGuard::guard_ = 0;
-#else
-struct [[maybe_unused]] ReentrantScannerGuard final{};
-#endif
-
-#if defined(PA_HAS_64_BITS_POINTERS)
-// Bytemap that represent regions (cards) that contain quarantined objects.
-// A single PCScan cycle consists of the following steps:
-// 1) clearing (memset quarantine + marking cards that contain quarantine);
-// 2) scanning;
-// 3) sweeping (freeing + unmarking cards that contain freed objects).
-// Marking cards on step 1) ensures that the card table stays in the consistent
-// state while scanning. Unmarking on the step 3) ensures that unmarking
-// actually happens (and we don't hit too many false positives).
-class QuarantineCardTable final {
- public:
-  // Avoid the load of the base of the BRP pool.
-  ALWAYS_INLINE static QuarantineCardTable& GetFrom(uintptr_t ptr) {
-    constexpr uintptr_t kBRPPoolMask = PartitionAddressSpace::BRPPoolBaseMask();
-    return *reinterpret_cast<QuarantineCardTable*>(ptr & kBRPPoolMask);
-  }
-
-  ALWAYS_INLINE void Quarantine(uintptr_t begin, size_t size) {
-    return SetImpl(begin, size, true);
-  }
-
-  ALWAYS_INLINE void Unquarantine(uintptr_t begin, size_t size) {
-    return SetImpl(begin, size, false);
-  }
-
-  // Returns whether the card to which |ptr| points to contains quarantined
-  // objects. May return false positives for but should never return false
-  // negatives, as otherwise this breaks security.
-  ALWAYS_INLINE bool IsQuarantined(uintptr_t ptr) const {
-    const size_t byte = Byte(ptr);
-    PA_DCHECK(byte < bytes_.size());
-    return bytes_[byte];
-  }
-
- private:
-  static constexpr size_t kCardSize =
-      AddressPoolManager::kBRPPoolMaxSize / kSuperPageSize;
-  static constexpr size_t kBytes =
-      AddressPoolManager::kBRPPoolMaxSize / kCardSize;
-
-  QuarantineCardTable() = default;
-
-  ALWAYS_INLINE static constexpr size_t Byte(uintptr_t address) {
-    constexpr uintptr_t kBRPPoolMask = PartitionAddressSpace::BRPPoolBaseMask();
-    return (address & ~kBRPPoolMask) / kCardSize;
-  }
-
-  ALWAYS_INLINE void SetImpl(uintptr_t begin, size_t size, bool value) {
-    const size_t byte = Byte(begin);
-    const size_t need_bytes = (size + (kCardSize - 1)) / kCardSize;
-    PA_DCHECK(bytes_.size() >= byte + need_bytes);
-    PA_DCHECK(
-        PartitionAddressSpace::IsInBRPPool(reinterpret_cast<void*>(begin)));
-    for (size_t i = byte; i < byte + need_bytes; ++i)
-      bytes_[i] = value;
-  }
-
-  std::array<bool, kBytes> bytes_;
-};
-static_assert(kSuperPageSize >= sizeof(QuarantineCardTable),
-              "Card table size must be less than kSuperPageSize, since this is "
-              "what is committed");
-#endif
-
-template <typename T>
-using MetadataVector = std::vector<T, MetadataAllocator<T>>;
-template <typename T>
-using MetadataSet = std::set<T, std::less<>, MetadataAllocator<T>>;
-template <typename K, typename V>
-using MetadataHashMap =
-    std::unordered_map<K,
-                       V,
-                       std::hash<K>,
-                       std::equal_to<>,
-                       MetadataAllocator<std::pair<const K, V>>>;
-
-void LogStats(size_t swept_bytes, size_t last_size, size_t new_size) {
-  VLOG(2) << "quarantine size: " << last_size << " -> " << new_size
-          << ", swept bytes: " << swept_bytes
-          << ", survival rate: " << static_cast<double>(new_size) / last_size;
-}
-
-ALWAYS_INLINE uintptr_t GetObjectStartInSuperPage(uintptr_t maybe_ptr,
-                                                  const PCScan::Root& root) {
-  char* allocation_start =
-      GetSlotStartInSuperPage<ThreadSafe>(reinterpret_cast<char*>(maybe_ptr));
-  if (!allocation_start) {
-    // |maybe_ptr| refers to a garbage or is outside of the payload region.
-    return 0;
-  }
-  return reinterpret_cast<uintptr_t>(
-      root.AdjustPointerForExtrasAdd(allocation_start));
-}
-
-enum class Context {
-  // For tasks executed from mutator threads (safepoints).
-  kMutator,
-  // For concurrent scanner tasks.
-  kScanner
-};
-
-#if DCHECK_IS_ON()
-bool IsScannerQuarantineBitmapEmpty(char* super_page, size_t epoch) {
-  auto* bitmap = QuarantineBitmapFromPointer(QuarantineBitmapType::kScanner,
-                                             epoch, super_page);
-  size_t visited = 0;
-  bitmap->Iterate([&visited](auto) { ++visited; });
-  return !visited;
-}
-#endif
-
-#define FOR_ALL_PCSCAN_SCANNER_SCOPES(V) \
-  V(Clear)                               \
-  V(Scan)                                \
-  V(Sweep)                               \
-  V(Overall)
-
-#define FOR_ALL_PCSCAN_MUTATOR_SCOPES(V) \
-  V(Clear)                               \
-  V(ScanStack)                           \
-  V(Scan)                                \
-  V(Overall)
-
-class StatsCollector final {
- public:
-  enum class ScannerId {
-#define DECLARE_ENUM(name) k##name,
-    FOR_ALL_PCSCAN_SCANNER_SCOPES(DECLARE_ENUM)
-#undef DECLARE_ENUM
-        kNumIds,
-  };
-
-  enum class MutatorId {
-#define DECLARE_ENUM(name) k##name,
-    FOR_ALL_PCSCAN_MUTATOR_SCOPES(DECLARE_ENUM)
-#undef DECLARE_ENUM
-        kNumIds,
-  };
-
-  template <Context context>
-  using IdType =
-      std::conditional_t<context == Context::kMutator, MutatorId, ScannerId>;
-
-  // We don't immediately trace events, but instead defer it until scanning is
-  // done. This is needed to avoid unpredictable work that can be done by traces
-  // (e.g. recursive mutex lock).
-  struct DeferredTraceEvent {
-    base::TimeTicks start_time;
-    base::TimeTicks end_time;
-  };
-
-  // Thread-safe hash-map that maps thread id to scanner events. Doesn't
-  // accumulate events, i.e. every event can only be registered once.
-  template <Context context>
-  class DeferredTraceEventMap final {
-   public:
-    using IdType = StatsCollector::IdType<context>;
-    using UnderlyingMap = MetadataHashMap<
-        PlatformThreadId,
-        std::array<DeferredTraceEvent, static_cast<size_t>(IdType::kNumIds)>>;
-
-    void RegisterBeginEventFromCurrentThread(IdType id) {
-      std::lock_guard<std::mutex> lock(mutex_);
-      const auto tid = base::PlatformThread::CurrentId();
-      const auto now = base::TimeTicks::Now();
-      auto& event_array = events_[tid];
-      auto& event = event_array[static_cast<size_t>(id)];
-      PA_DCHECK(event.start_time.is_null());
-      PA_DCHECK(event.end_time.is_null());
-      event.start_time = now;
-    }
-
-    void RegisterEndEventFromCurrentThread(IdType id) {
-      std::lock_guard<std::mutex> lock(mutex_);
-      const auto tid = base::PlatformThread::CurrentId();
-      const auto now = base::TimeTicks::Now();
-      auto& event_array = events_[tid];
-      auto& event = event_array[static_cast<size_t>(id)];
-      PA_DCHECK(!event.start_time.is_null());
-      PA_DCHECK(event.end_time.is_null());
-      event.end_time = now;
-    }
-
-    const UnderlyingMap& get_underlying_map_unsafe() const { return events_; }
-
-   private:
-    std::mutex mutex_;
-    UnderlyingMap events_;
-  };
-
-  template <Context context>
-  class Scope final {
-   public:
-    Scope(StatsCollector& stats, IdType<context> type)
-        : stats_(stats), type_(type) {
-      stats_.RegisterBeginEventFromCurrentThread(type);
-    }
-
-    Scope(const Scope&) = delete;
-    Scope& operator=(const Scope&) = delete;
-
-    ~Scope() { stats_.RegisterEndEventFromCurrentThread(type_); }
-
-   private:
-    StatsCollector& stats_;
-    IdType<context> type_;
-  };
-
-  using ScannerScope = Scope<Context::kScanner>;
-  using MutatorScope = Scope<Context::kMutator>;
-
-  explicit StatsCollector(const char* process_name)
-      : process_name_(process_name) {}
-
-  StatsCollector(const StatsCollector&) = delete;
-  StatsCollector& operator=(const StatsCollector&) = delete;
-
-  void IncreaseSurvivedQuarantineSize(size_t size) {
-    survived_quarantine_size_.fetch_add(size, std::memory_order_relaxed);
-  }
-  size_t survived_quarantine_size() const {
-    return survived_quarantine_size_.load(std::memory_order_relaxed);
-  }
-
-  void IncreaseSweptSize(size_t size) { swept_size_ += size; }
-  size_t swept_size() const { return swept_size_; }
-
-  base::TimeDelta GetOverallTime() const {
-    return GetTimeImpl<Context::kMutator>(mutator_trace_events_,
-                                          MutatorId::kOverall) +
-           GetTimeImpl<Context::kScanner>(scanner_trace_events_,
-                                          ScannerId::kOverall);
-  }
-
-  void ReportTracesAndHists() {
-    ReportTracesAndHistsImpl<Context::kMutator>(mutator_trace_events_);
-    ReportTracesAndHistsImpl<Context::kScanner>(scanner_trace_events_);
-  }
-
- private:
-  using MetadataString =
-      std::basic_string<char, std::char_traits<char>, MetadataAllocator<char>>;
-  static constexpr char kTraceCategory[] = "partition_alloc";
-
-  static constexpr const char* ToTracingString(ScannerId id) {
-    switch (id) {
-      case ScannerId::kClear:
-        return "PCScan.Scanner.Clear";
-      case ScannerId::kScan:
-        return "PCScan.Scanner.Scan";
-      case ScannerId::kSweep:
-        return "PCScan.Scanner.Sweep";
-      case ScannerId::kOverall:
-        return "PCScan.Scanner";
-      case ScannerId::kNumIds:
-        __builtin_unreachable();
-    }
-  }
-
-  static constexpr const char* ToTracingString(MutatorId id) {
-    switch (id) {
-      case MutatorId::kClear:
-        return "PCScan.Mutator.Clear";
-      case MutatorId::kScanStack:
-        return "PCScan.Mutator.ScanStack";
-      case MutatorId::kScan:
-        return "PCScan.Mutator.Scan";
-      case MutatorId::kOverall:
-        return "PCScan.Mutator";
-      case MutatorId::kNumIds:
-        __builtin_unreachable();
-    }
-  }
-
-  MetadataString ToUMAString(ScannerId id) const {
-    PA_DCHECK(process_name_);
-    const MetadataString process_name = process_name_;
-    switch (id) {
-      case ScannerId::kClear:
-        return "PA.PCScan." + process_name + ".Scanner.Clear";
-      case ScannerId::kScan:
-        return "PA.PCScan." + process_name + ".Scanner.Scan";
-      case ScannerId::kSweep:
-        return "PA.PCScan." + process_name + ".Scanner.Sweep";
-      case ScannerId::kOverall:
-        return "PA.PCScan." + process_name + ".Scanner";
-      case ScannerId::kNumIds:
-        __builtin_unreachable();
-    }
-  }
-
-  MetadataString ToUMAString(MutatorId id) const {
-    PA_DCHECK(process_name_);
-    const MetadataString process_name = process_name_;
-    switch (id) {
-      case MutatorId::kClear:
-        return "PA.PCScan." + process_name + ".Mutator.Clear";
-      case MutatorId::kScanStack:
-        return "PA.PCScan." + process_name + ".Mutator.ScanStack";
-      case MutatorId::kScan:
-        return "PA.PCScan." + process_name + ".Mutator.Scan";
-      case MutatorId::kOverall:
-        return "PA.PCScan." + process_name + ".Mutator";
-      case MutatorId::kNumIds:
-        __builtin_unreachable();
-    }
-  }
-
-  void RegisterBeginEventFromCurrentThread(MutatorId id) {
-    mutator_trace_events_.RegisterBeginEventFromCurrentThread(id);
-  }
-  void RegisterEndEventFromCurrentThread(MutatorId id) {
-    mutator_trace_events_.RegisterEndEventFromCurrentThread(id);
-  }
-  void RegisterBeginEventFromCurrentThread(ScannerId id) {
-    scanner_trace_events_.RegisterBeginEventFromCurrentThread(id);
-  }
-  void RegisterEndEventFromCurrentThread(ScannerId id) {
-    scanner_trace_events_.RegisterEndEventFromCurrentThread(id);
-  }
-
-  template <Context context, typename EventMap>
-  base::TimeDelta GetTimeImpl(const EventMap& event_map,
-                              IdType<context> id) const {
-    base::TimeDelta overall;
-    for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
-      const auto& events = tid_and_events.second;
-      const auto& event = events[static_cast<size_t>(id)];
-      overall += (event.end_time - event.start_time);
-    }
-    return overall;
-  }
-
-  template <Context context, typename EventMap>
-  void ReportTracesAndHistsImpl(const EventMap& event_map) {
-    std::array<base::TimeDelta, static_cast<size_t>(IdType<context>::kNumIds)>
-        accumulated_events{};
-    // First, report traces and accumulate each trace scope to report UMA hists.
-    for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
-      const PlatformThreadId tid = tid_and_events.first;
-      // TRACE_EVENT_* macros below drop most parameters when tracing is
-      // disabled at compile time.
-      ignore_result(tid);
-      const auto& events = tid_and_events.second;
-      PA_DCHECK(accumulated_events.size() == events.size());
-      for (size_t id = 0; id < events.size(); ++id) {
-        const auto& event = events[id];
-        TRACE_EVENT_BEGIN(
-            kTraceCategory,
-            perfetto::StaticString(
-                ToTracingString(static_cast<IdType<context>>(id))),
-            perfetto::ThreadTrack::ForThread(tid), event.start_time);
-        TRACE_EVENT_END(kTraceCategory, perfetto::ThreadTrack::ForThread(tid),
-                        event.end_time);
-        accumulated_events[id] += (event.end_time - event.start_time);
-      }
-    }
-    // Report UMA if process_name is set.
-    if (!process_name_)
-      return;
-    for (size_t id = 0; id < accumulated_events.size(); ++id) {
-      if (accumulated_events[id].is_zero())
-        continue;
-      UmaHistogramTimes(ToUMAString(static_cast<IdType<context>>(id)).c_str(),
-                        accumulated_events[id]);
-    }
-  }
-
-  DeferredTraceEventMap<Context::kMutator> mutator_trace_events_;
-  DeferredTraceEventMap<Context::kScanner> scanner_trace_events_;
-
-  std::atomic<size_t> survived_quarantine_size_{0u};
-  size_t swept_size_ = 0u;
-  const char* process_name_ = nullptr;
-};
-
-#undef FOR_ALL_PCSCAN_MUTATOR_SCOPES
-#undef FOR_ALL_PCSCAN_SCANNER_SCOPES
-
-enum class SimdSupport : uint8_t {
-  kUnvectorized,
-  kSSE41,
-  kAVX2,
-  // TODO(bikineev): Add support for Neon.
-};
-
-SimdSupport DetectSimdSupport() {
-  base::CPU cpu;
-  if (cpu.has_avx2())
-    return SimdSupport::kAVX2;
-  if (cpu.has_sse41())
-    return SimdSupport::kSSE41;
-  return SimdSupport::kUnvectorized;
-}
-
-// Internal PCScan singleton. The separation between frontend and backend is
-// needed to keep access to the hot data (quarantine) in the frontend fast,
-// whereas the backend can hold cold data.
-class PCScanInternal final {
- public:
-  using Root = PCScan::Root;
-  using TaskHandle = scoped_refptr<PCScanTask>;
-
-  static constexpr size_t kMaxNumberOfRoots = 8u;
-  class Roots final : private std::array<Root*, kMaxNumberOfRoots> {
-    using Base = std::array<Root*, kMaxNumberOfRoots>;
-
-   public:
-    using typename Base::const_iterator;
-    using typename Base::iterator;
-
-    // Explicitly value-initialize Base{} as otherwise the default
-    // (aggregate) initialization won't be considered as constexpr.
-    constexpr Roots() : Base{} {}
-
-    iterator begin() { return Base::begin(); }
-    const_iterator begin() const { return Base::begin(); }
-
-    iterator end() { return begin() + current_; }
-    const_iterator end() const { return begin() + current_; }
-
-    void Add(Root* root);
-
-    size_t size() const { return current_; }
-
-    void ClearForTesting();  // IN-TEST
-
-   private:
-    size_t current_ = 0u;
-  };
-
-  static PCScanInternal& Instance() {
-    // Since the data that PCScanInternal holds is cold, it's fine to have the
-    // runtime check for thread-safe local static initialization.
-    static base::NoDestructor<PCScanInternal> instance;
-    return *instance;
-  }
-
-  PCScanInternal(const PCScanInternal&) = delete;
-  PCScanInternal& operator=(const PCScanInternal&) = delete;
-
-  void Initialize();
-  bool is_initialized() const { return is_initialized_; }
-
-  TaskHandle CurrentPCScanTask() const {
-    std::lock_guard<std::mutex> lock(current_task_mutex_);
-    return current_task_;
-  }
-  void SetCurrentPCScanTask(TaskHandle task) {
-    std::lock_guard<std::mutex> lock(current_task_mutex_);
-    current_task_ = std::move(task);
-  }
-  void ResetCurrentPCScanTask() {
-    std::lock_guard<std::mutex> lock(current_task_mutex_);
-    current_task_.reset();
-  }
-
-  void RegisterScannableRoot(Root* root);
-  void RegisterNonScannableRoot(Root* root);
-
-  Roots& scannable_roots() { return scannable_roots_; }
-  const Roots& scannable_roots() const { return scannable_roots_; }
-
-  Roots& nonscannable_roots() { return nonscannable_roots_; }
-  const Roots& nonscannable_roots() const { return nonscannable_roots_; }
-
-  void SetProcessName(const char* name);
-  const char* process_name() const { return process_name_; }
-
-  // Get size of all committed pages from scannable and nonscannable roots.
-  size_t CalculateTotalHeapSize() const;
-
-  SimdSupport simd_support() const { return simd_support_; }
-
-  void EnableStackScanning();
-  void DisableStackScanning();
-  bool IsStackScanningEnabled() const;
-
-  void NotifyThreadCreated(void* stack_top);
-  void NotifyThreadDestroyed();
-
-  void* GetCurrentThreadStackTop() const;
-
-  void ClearRootsForTesting();  // IN-TEST
-  void ReinitForTesting();      // IN-TEST
-
- private:
-  using StackTops = MetadataHashMap<PlatformThreadId, void*>;
-
-  friend base::NoDestructor<PCScanInternal>;
-
-  PCScanInternal();
-
-  TaskHandle current_task_;
-  mutable std::mutex current_task_mutex_;
-
-  Roots scannable_roots_{};
-  Roots nonscannable_roots_{};
-
-  bool stack_scanning_enabled_{false};
-  // TLS emulation of stack tops. Since this is guaranteed to go through
-  // non-quarantinable partition, using it from safepoints is safe.
-  StackTops stack_tops_;
-  mutable std::mutex stack_tops_mutex_;
-
-  const char* process_name_ = nullptr;
-  const SimdSupport simd_support_;
-
-  bool is_initialized_ = false;
-};
-
-void PCScanInternal::Roots::Add(Root* root) {
-  PA_CHECK(std::find(begin(), end(), root) == end());
-  (*this)[current_] = root;
-  ++current_;
-  PA_CHECK(current_ != kMaxNumberOfRoots)
-      << "Exceeded number of allowed partition roots";
-}
-
-void PCScanInternal::Roots::ClearForTesting() {
-  std::fill(begin(), end(), nullptr);
-  current_ = 0;
-}
-
-void CommitCardTable() {
-#if defined(PA_HAS_64_BITS_POINTERS)
-  if (features::IsPartitionAllocGigaCageEnabled()) {
-    // First, make sure that GigaCage is initialized.
-    PartitionAddressSpace::Init();
-    // Then, commit the card table.
-    RecommitSystemPages(
-        reinterpret_cast<void*>(PartitionAddressSpace::BRPPoolBase()),
-        sizeof(QuarantineCardTable), PageReadWrite, PageUpdatePermissions);
-  }
-#endif
-}
-
-void CommitQuarantineBitmaps(PCScan::Root& root) {
-  size_t quarantine_bitmaps_size_to_commit = CommittedQuarantineBitmapsSize();
-  for (auto* super_page_extent = root.first_extent; super_page_extent;
-       super_page_extent = super_page_extent->next) {
-    for (char* super_page = super_page_extent->super_page_base;
-         super_page != super_page_extent->super_pages_end;
-         super_page += kSuperPageSize) {
-      RecommitSystemPages(internal::SuperPageQuarantineBitmaps(super_page),
-                          quarantine_bitmaps_size_to_commit, PageReadWrite,
-                          PageUpdatePermissions);
-    }
-  }
-}
-
-PCScanInternal::PCScanInternal() : simd_support_(DetectSimdSupport()) {}
-
-void PCScanInternal::Initialize() {
-  PA_DCHECK(!is_initialized_);
-  CommitCardTable();
-  is_initialized_ = true;
-}
-
-void PCScanInternal::RegisterScannableRoot(Root* root) {
-  PA_DCHECK(is_initialized());
-  PA_DCHECK(root);
-  PA_CHECK(root->IsQuarantineAllowed());
-  typename Root::ScopedGuard guard(root->lock_);
-  if (root->IsScanEnabled())
-    return;
-  PA_CHECK(!root->IsQuarantineEnabled());
-  CommitQuarantineBitmaps(*root);
-  root->scan_mode = Root::ScanMode::kEnabled;
-  root->quarantine_mode = Root::QuarantineMode::kEnabled;
-  scannable_roots_.Add(root);
-}
-
-void PCScanInternal::RegisterNonScannableRoot(Root* root) {
-  PA_DCHECK(is_initialized());
-  PA_DCHECK(root);
-  PA_CHECK(root->IsQuarantineAllowed());
-  typename Root::ScopedGuard guard(root->lock_);
-  if (root->IsQuarantineEnabled())
-    return;
-  CommitQuarantineBitmaps(*root);
-  root->quarantine_mode = Root::QuarantineMode::kEnabled;
-  nonscannable_roots_.Add(root);
-}
-
-void PCScanInternal::SetProcessName(const char* process_name) {
-  PA_DCHECK(is_initialized());
-  PA_DCHECK(process_name);
-  PA_DCHECK(!process_name_);
-  process_name_ = process_name;
-}
-
-size_t PCScanInternal::CalculateTotalHeapSize() const {
-  PA_DCHECK(is_initialized());
-  const auto acc = [](size_t size, Root* root) {
-    return size + root->get_total_size_of_committed_pages();
-  };
-  return std::accumulate(scannable_roots_.begin(), scannable_roots_.end(), 0u,
-                         acc) +
-         std::accumulate(nonscannable_roots_.begin(), nonscannable_roots_.end(),
-                         0u, acc);
-}
-
-void PCScanInternal::EnableStackScanning() {
-  PA_DCHECK(!stack_scanning_enabled_);
-  stack_scanning_enabled_ = true;
-}
-void PCScanInternal::DisableStackScanning() {
-  PA_DCHECK(stack_scanning_enabled_);
-  stack_scanning_enabled_ = false;
-}
-bool PCScanInternal::IsStackScanningEnabled() const {
-  return stack_scanning_enabled_;
-}
-
-void PCScanInternal::NotifyThreadCreated(void* stack_top) {
-  const auto tid = base::PlatformThread::CurrentId();
-  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
-  const auto res = stack_tops_.insert({tid, stack_top});
-  PA_DCHECK(res.second);
-}
-
-void PCScanInternal::NotifyThreadDestroyed() {
-  const auto tid = base::PlatformThread::CurrentId();
-  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
-  PA_DCHECK(1 == stack_tops_.count(tid));
-  stack_tops_.erase(tid);
-}
-
-void* PCScanInternal::GetCurrentThreadStackTop() const {
-  const auto tid = base::PlatformThread::CurrentId();
-  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
-  auto it = stack_tops_.find(tid);
-  return it != stack_tops_.end() ? it->second : nullptr;
-}
-
-void PCScanInternal::ClearRootsForTesting() {
-  // Set all roots as non-scannable and non-quarantinable.
-  for (auto* root : scannable_roots_) {
-    root->scan_mode = Root::ScanMode::kDisabled;
-    root->quarantine_mode = Root::QuarantineMode::kDisabledByDefault;
-  }
-  for (auto* root : nonscannable_roots_) {
-    root->quarantine_mode = Root::QuarantineMode::kDisabledByDefault;
-  }
-  scannable_roots_.ClearForTesting();     // IN-TEST
-  nonscannable_roots_.ClearForTesting();  // IN-TEST
-}
-
-void PCScanInternal::ReinitForTesting() {
-  is_initialized_ = false;
-  Initialize();
-}
-
-class PCScanSnapshot final {
- public:
-  struct ScanArea {
-    ScanArea(uintptr_t* begin, uintptr_t* end) : begin(begin), end(end) {}
-
-    uintptr_t* begin = nullptr;
-    uintptr_t* end = nullptr;
-  };
-
-  // Large scan areas have their slot size recorded which allows to iterate
-  // based on objects, potentially skipping over objects if possible.
-  struct LargeScanArea : public ScanArea {
-    LargeScanArea(uintptr_t* begin, uintptr_t* end, size_t slot_size)
-        : ScanArea(begin, end), slot_size(slot_size) {}
-
-    size_t slot_size = 0;
-  };
-
-  // Worklists that are shared and processed by different scanners.
-  using ScanAreasWorklist = RacefulWorklist<ScanArea>;
-  using LargeScanAreasWorklist = RacefulWorklist<LargeScanArea>;
-  using SuperPagesWorklist = RacefulWorklist<uintptr_t>;
-
-  // BRP pool is guaranteed to have only normal buckets, so everything there
-  // deals in super pages.
-  using SuperPages = MetadataSet<uintptr_t>;
-
-  PCScanSnapshot() = default;
-
-  void EnsureTaken(size_t pcscan_epoch);
-
-  ScanAreasWorklist& scan_areas_worklist() { return scan_areas_worklist_; }
-  LargeScanAreasWorklist& large_scan_areas_worklist() {
-    return large_scan_areas_worklist_;
-  }
-  SuperPagesWorklist& quarantinable_super_pages_worklist() {
-    return super_pages_worklist_;
-  }
-
-  const SuperPages& quarantinable_super_pages() const { return super_pages_; }
-
- private:
-  void Take(size_t pcscan_epoch);
-
-  SuperPages super_pages_;
-
-  ScanAreasWorklist scan_areas_worklist_;
-  LargeScanAreasWorklist large_scan_areas_worklist_;
-  SuperPagesWorklist super_pages_worklist_;
-
-  std::once_flag once_flag_;
-};
-
-void PCScanSnapshot::EnsureTaken(size_t pcscan_epoch) {
-  std::call_once(once_flag_, &PCScanSnapshot::Take, this, pcscan_epoch);
-}
-
-void PCScanSnapshot::Take(size_t pcscan_epoch) {
-  using Root = PartitionRoot<ThreadSafe>;
-  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
-  // Threshold for which bucket size it is worthwhile in checking whether the
-  // object is a quarantined object and can be skipped.
-  static constexpr size_t kLargeScanAreaThreshold = 8192;
-
-  auto& pcscan_internal = PCScanInternal::Instance();
-  for (Root* root : pcscan_internal.scannable_roots()) {
-    typename Root::ScopedGuard guard(root->lock_);
-
-    // Take a snapshot of all super pages and scannable slot spans.
-    // TODO(bikineev): Consider making current_extent lock-free and moving it
-    // to the concurrent thread.
-    for (auto* super_page_extent = root->first_extent; super_page_extent;
-         super_page_extent = super_page_extent->next) {
-      for (char* super_page = super_page_extent->super_page_base;
-           super_page != super_page_extent->super_pages_end;
-           super_page += kSuperPageSize) {
-        // TODO(bikineev): Consider following freelists instead of slot spans.
-        const size_t visited_slot_spans = IterateSlotSpans<ThreadSafe>(
-            super_page, true /*with_quarantine*/,
-            [this](SlotSpan* slot_span) -> bool {
-              if (slot_span->is_empty() || slot_span->is_decommitted()) {
-                return false;
-              }
-              auto* payload_begin = static_cast<uintptr_t*>(
-                  SlotSpan::ToSlotSpanStartPtr(slot_span));
-              size_t provisioned_size = slot_span->GetProvisionedSize();
-              // Free & decommitted slot spans are skipped.
-              PA_DCHECK(provisioned_size > 0);
-              auto* payload_end =
-                  payload_begin + (provisioned_size / sizeof(uintptr_t));
-              if (slot_span->bucket->slot_size >= kLargeScanAreaThreshold) {
-                large_scan_areas_worklist_.Push(
-                    {payload_begin, payload_end, slot_span->bucket->slot_size});
-              } else {
-                scan_areas_worklist_.Push({payload_begin, payload_end});
-              }
-              return true;
-            });
-        // If we haven't visited any slot spans, all the slot spans in the
-        // super-page are either empty or decommitted. This means that all the
-        // objects are freed and there are no quarantined objects.
-        if (LIKELY(visited_slot_spans)) {
-          super_pages_.insert(reinterpret_cast<uintptr_t>(super_page));
-          super_pages_worklist_.Push(reinterpret_cast<uintptr_t>(super_page));
-        } else {
-#if DCHECK_IS_ON()
-          PA_CHECK(IsScannerQuarantineBitmapEmpty(super_page, pcscan_epoch));
-#endif
-        }
-      }
-    }
-  }
-  for (Root* root : pcscan_internal.nonscannable_roots()) {
-    typename Root::ScopedGuard guard(root->lock_);
-    // Take a snapshot of all super pages and nnonscannable slot spans.
-    for (auto* super_page_extent = root->first_extent; super_page_extent;
-         super_page_extent = super_page_extent->next) {
-      for (char* super_page = super_page_extent->super_page_base;
-           super_page != super_page_extent->super_pages_end;
-           super_page += kSuperPageSize) {
-        super_pages_.insert(reinterpret_cast<uintptr_t>(super_page));
-        super_pages_worklist_.Push(reinterpret_cast<uintptr_t>(super_page));
-      }
-    }
-  }
-}
-
-}  // namespace
-
-// This class is responsible for performing the entire PCScan task.
-// TODO(bikineev): Move PCScan algorithm out of PCScanTask.
-class PCScanTask final : public base::RefCountedThreadSafe<PCScanTask>,
-                         public AllocatedOnPCScanMetadataPartition {
- public:
-  // Creates and initializes a PCScan state.
-  explicit PCScanTask(PCScan& pcscan);
-
-  PCScanTask(PCScanTask&&) noexcept = delete;
-  PCScanTask& operator=(PCScanTask&&) noexcept = delete;
-
-  // Execute PCScan from mutator inside safepoint.
-  void RunFromMutator();
-
-  // Execute PCScan from the scanner thread. Must be called only once from the
-  // scanner thread.
-  void RunFromScanner();
-
-  PCScanScheduler& scheduler() const { return pcscan_.scheduler(); }
-
- private:
-  class ScanLoop;
-  class StackVisitor;
-
-  using Root = PCScan::Root;
-  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
-
-  struct GigaCageLookupPolicy {
-    ALWAYS_INLINE bool TestOnHeapPointer(uintptr_t maybe_ptr) const {
-#if defined(PA_HAS_64_BITS_POINTERS)
-#if DCHECK_IS_ON()
-      PA_DCHECK(
-          IsManagedByPartitionAllocBRPPool(reinterpret_cast<void*>(maybe_ptr)));
-#endif
-      return QuarantineCardTable::GetFrom(maybe_ptr).IsQuarantined(maybe_ptr);
-#else   // defined(PA_HAS_64_BITS_POINTERS)
-      return IsManagedByPartitionAllocBRPPool(
-          reinterpret_cast<void*>(maybe_ptr));
-#endif  // defined(PA_HAS_64_BITS_POINTERS)
-    }
-    [[maybe_unused]] const PCScanSnapshot& snapshot;
-  };
-
-  struct NoGigaCageLookupPolicy {
-    ALWAYS_INLINE bool TestOnHeapPointer(uintptr_t maybe_ptr) const {
-      const auto super_page_base = maybe_ptr & kSuperPageBaseMask;
-      const auto& super_pages = snapshot.quarantinable_super_pages();
-      auto it = super_pages.lower_bound(super_page_base);
-      return it != super_pages.end() && *it == super_page_base;
-    }
-    const PCScanSnapshot& snapshot;
-  };
-
-  // This is used:
-  // - to synchronize all scanning threads (mutators and the scanner);
-  // - for the scanner, to transition through the state machine
-  //   (kScheduled -> kScanning (ctor) -> kSweepingAndFinishing (dtor).
-  template <Context context>
-  class SyncScope final {
-   public:
-    explicit SyncScope(PCScanTask& task) : task_(task) {
-      task_.number_of_scanning_threads_.fetch_add(1, std::memory_order_relaxed);
-      if (context == Context::kScanner) {
-        // Publish the change of the state so that the mutators can join
-        // scanning and expect the consistent state.
-        task_.pcscan_.state_.store(PCScan::State::kScanning,
-                                   std::memory_order_release);
-      }
-    }
-    ~SyncScope() {
-      // First, notify other scanning threads that this thread is done.
-      NotifyThreads();
-      if (context == Context::kScanner) {
-        // The scanner thread must wait here until all safepoints leave.
-        // Otherwise, sweeping may free a page that can be accessed by a
-        // descheduled mutator.
-        WaitForOtherThreads();
-      }
-    }
-
-   private:
-    void NotifyThreads() {
-      {
-        // The lock is required as otherwise there is a race between
-        // fetch_sub/notify in the mutator and checking
-        // number_of_scanning_threads_/waiting in the scanner.
-        std::lock_guard<std::mutex> lock(task_.mutex_);
-        task_.number_of_scanning_threads_.fetch_sub(1,
-                                                    std::memory_order_relaxed);
-        {
-          // Notify that scan is done and there is no need to enter
-          // the safepoint. This also helps a mutator to avoid repeating
-          // entering. Since the scanner thread waits for all threads to finish,
-          // there is no ABA problem here. There is technically no need to have
-          // CAS here, since |state_| is under the mutex and can only be changed
-          // here, but we keep it for safety.
-          PCScan::State expected = PCScan::State::kScanning;
-          task_.pcscan_.state_.compare_exchange_strong(
-              expected, PCScan::State::kSweepingAndFinishing,
-              std::memory_order_relaxed, std::memory_order_relaxed);
-        }
-      }
-      task_.condvar_.notify_all();
-    }
-
-    void WaitForOtherThreads() {
-      std::unique_lock<std::mutex> lock(task_.mutex_);
-      task_.condvar_.wait(lock, [this] {
-        return !task_.number_of_scanning_threads_.load(
-            std::memory_order_relaxed);
-      });
-    }
-
-    PCScanTask& task_;
-  };
-
-  friend class base::RefCountedThreadSafe<PCScanTask>;
-  ~PCScanTask() = default;
-
-  template <typename LookupPolicy>
-  ALWAYS_INLINE QuarantineBitmap* TryFindScannerBitmapForPointer(
-      uintptr_t maybe_ptr) const;
-
-  // Lookup and marking functions. Return size of the object if marked or zero
-  // otherwise.
-  template <typename LookupPolicy>
-  ALWAYS_INLINE size_t TryMarkObjectInNormalBuckets(uintptr_t maybe_ptr) const;
-
-  // Scans stack, only called from safepoints.
-  void ScanStack();
-
-  // Scans all registered partitions and marks reachable quarantined objects.
-  void ScanPartitions();
-
-  // Clear quarantined objects and prepare card table for fast lookup
-  void ClearQuarantinedObjectsAndPrepareCardTable();
-
-  // Sweeps (frees) unreachable quarantined entries. Returns the size of swept
-  // objects.
-  void SweepQuarantine();
-
-  // Finishes the scanner (updates limits, UMA, etc).
-  void FinishScanner();
-
-  // Cache the pcscan epoch to avoid the compiler loading the atomic
-  // QuarantineData::epoch_ on each access.
-  const size_t pcscan_epoch_;
-  PCScanSnapshot snapshot_;
-  StatsCollector stats_;
-  // Mutex and codvar that are used to synchronize scanning threads.
-  std::mutex mutex_;
-  std::condition_variable condvar_;
-  std::atomic<size_t> number_of_scanning_threads_{0u};
-  PCScan& pcscan_;
-};
-
-template <typename LookupPolicy>
-ALWAYS_INLINE QuarantineBitmap* PCScanTask::TryFindScannerBitmapForPointer(
-    uintptr_t maybe_ptr) const {
-  // First, check if |maybe_ptr| points to a valid super page or a quarantined
-  // card.
-  LookupPolicy lookup{snapshot_};
-  if (LIKELY(!lookup.TestOnHeapPointer(maybe_ptr)))
-    return nullptr;
-  // Check if we are not pointing to metadata/guard pages.
-  if (!IsWithinSuperPagePayload(reinterpret_cast<char*>(maybe_ptr),
-                                true /*with quarantine*/))
-    return nullptr;
-  // We are certain here that |maybe_ptr| points to the super page payload.
-  return QuarantineBitmapFromPointer(QuarantineBitmapType::kScanner,
-                                     pcscan_epoch_,
-                                     reinterpret_cast<char*>(maybe_ptr));
-}
-
-// Looks up and marks a potential dangling pointer. Returns the size of the slot
-// (which is then accounted as quarantined) or zero if no object is found.
-// For normal bucket super pages, PCScan uses two quarantine bitmaps, the
-// mutator and the scanner one. The former is used by mutators when objects are
-// freed, while the latter is used concurrently by the PCScan thread. The
-// bitmaps are swapped as soon as PCScan is triggered. Once a dangling pointer
-// (which points to an object in the scanner bitmap) is found,
-// TryMarkObjectInNormalBuckets() marks it again in the bitmap and clears
-// from the scanner bitmap. This way, when scanning is done, all uncleared
-// entries in the scanner bitmap correspond to unreachable objects.
-template <typename LookupPolicy>
-ALWAYS_INLINE size_t
-PCScanTask::TryMarkObjectInNormalBuckets(uintptr_t maybe_ptr) const {
-  // TODO(bartekn): Add a "is in normal buckets" DCHECK in the |else| case.
-  using AccessType = QuarantineBitmap::AccessType;
-  // Check if |maybe_ptr| points somewhere to the heap.
-  auto* scanner_bitmap =
-      TryFindScannerBitmapForPointer<LookupPolicy>(maybe_ptr);
-  if (!scanner_bitmap)
-    return 0;
-
-  auto* root =
-      Root::FromPointerInNormalBuckets(reinterpret_cast<char*>(maybe_ptr));
-
-  // Check if pointer was in the quarantine bitmap.
-  const uintptr_t base = GetObjectStartInSuperPage(maybe_ptr, *root);
-  if (!base || !scanner_bitmap->template CheckBit<AccessType::kAtomic>(base))
-    return 0;
-
-  PA_DCHECK((maybe_ptr & kSuperPageBaseMask) == (base & kSuperPageBaseMask));
-
-  auto* target_slot_span =
-      SlotSpan::FromSlotInnerPtr(reinterpret_cast<void*>(base));
-  PA_DCHECK(root == Root::FromSlotSpan(target_slot_span));
-
-  const size_t usable_size = target_slot_span->GetUsableSize(root);
-  // Range check for inner pointers.
-  if (maybe_ptr >= base + usable_size)
-    return 0;
-
-  // Now we are certain that |maybe_ptr| is a dangling pointer. Mark it again in
-  // the mutator bitmap and clear from the scanner bitmap. Note that since
-  // PCScan has exclusive access to the scanner bitmap, we can avoid atomic rmw
-  // operation for it.
-  scanner_bitmap->template ClearBit<AccessType::kAtomic>(base);
-  QuarantineBitmapFromPointer(QuarantineBitmapType::kMutator, pcscan_epoch_,
-                              reinterpret_cast<char*>(base))
-      ->template SetBit<AccessType::kAtomic>(base);
-  return target_slot_span->bucket->slot_size;
-}
-
-void PCScanTask::ClearQuarantinedObjectsAndPrepareCardTable() {
-  using AccessType = QuarantineBitmap::AccessType;
-
-  const bool giga_cage_enabled = features::IsPartitionAllocGigaCageEnabled();
-  PCScanSnapshot::SuperPagesWorklist::RandomizedView super_pages(
-      snapshot_.quarantinable_super_pages_worklist());
-  super_pages.Visit([this, giga_cage_enabled](uintptr_t super_page_base) {
-    auto* bitmap = QuarantineBitmapFromPointer(
-        QuarantineBitmapType::kScanner, pcscan_epoch_,
-        reinterpret_cast<char*>(super_page_base));
-    auto* root = Root::FromSuperPage(reinterpret_cast<char*>(super_page_base));
-    bitmap->template Iterate<AccessType::kNonAtomic>(
-        [root, giga_cage_enabled](uintptr_t ptr) {
-          auto* object = reinterpret_cast<void*>(ptr);
-          auto* slot_span = SlotSpan::FromSlotInnerPtr(object);
-          // Use zero as a zapping value to speed up the fast bailout check in
-          // ScanPartitions.
-          const size_t size = slot_span->GetUsableSize(root);
-          memset(object, 0, size);
-#if defined(PA_HAS_64_BITS_POINTERS)
-          if (giga_cage_enabled) {
-            // Set card(s) for this quarantined object.
-            QuarantineCardTable::GetFrom(ptr).Quarantine(ptr, size);
-          }
-#else
-          (void)giga_cage_enabled;
-#endif
-        });
-  });
-}
-
-// Class used to perform actual scanning. Dispatches at runtime based on
-// supported SIMD extensions.
-class PCScanTask::ScanLoop final {
- public:
-  explicit ScanLoop(const PCScanTask& pcscan_task)
-      : scan_function_(GetScanFunction()),
-        pcscan_task_(pcscan_task)
-#if defined(PA_HAS_64_BITS_POINTERS)
-        ,
-        brp_pool_base_(PartitionAddressSpace::BRPPoolBase())
-#endif
-  {
-  }
-
-  ScanLoop(const ScanLoop&) = delete;
-  ScanLoop& operator=(const ScanLoop&) = delete;
-
-  // Scans a range of addresses and marks reachable quarantined objects. Returns
-  // the size of marked objects. The function race-fully reads the heap and
-  // therefore TSAN is disabled for the dispatch functions.
-  size_t Run(uintptr_t* begin, uintptr_t* end) const {
-    static_assert(alignof(uintptr_t) % alignof(void*) == 0,
-                  "Alignment of uintptr_t must be at least as strict as "
-                  "alignment of a pointer type.");
-    return (this->*scan_function_)(begin, end);
-  }
-
- private:
-  // This is to support polymorphic behavior and to avoid virtual calls.
-  using ScanFunction = size_t (ScanLoop::*)(uintptr_t*, uintptr_t*) const;
-
-  static ScanFunction GetScanFunction() {
-    if (UNLIKELY(!features::IsPartitionAllocGigaCageEnabled())) {
-      return &ScanLoop::RunUnvectorizedNoGigaCage;
-    }
-// We allow vectorization only for 64bit since they require support of the
-// 64bit GigaCage, and only for x86 because a special instruction set is
-// required.
-#if defined(ARCH_CPU_X86_64)
-    const SimdSupport simd = PCScanInternal::Instance().simd_support();
-    if (simd == SimdSupport::kAVX2)
-      return &ScanLoop::RunAVX2;
-    if (simd == SimdSupport::kSSE41)
-      return &ScanLoop::RunSSE4;
-#endif
-    return &ScanLoop::RunUnvectorized;
-  }
-
-#if defined(PA_HAS_64_BITS_POINTERS)
-  ALWAYS_INLINE bool IsInBRPPool(uintptr_t maybe_ptr) const {
-    return (maybe_ptr & PartitionAddressSpace::BRPPoolBaseMask()) ==
-           brp_pool_base_;
-  }
-#endif
-
-#if defined(ARCH_CPU_X86_64)
-  __attribute__((target("sse4.1"))) NO_SANITIZE("thread") size_t
-      RunSSE4(uintptr_t* begin, uintptr_t* end) const {
-    static constexpr size_t kAlignmentRequirement = 16;
-    static constexpr size_t kWordsInVector = 2;
-    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % kAlignmentRequirement));
-    PA_DCHECK(
-        !((reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin)) %
-          kAlignmentRequirement));
-    const __m128i vbase = _mm_set1_epi64x(brp_pool_base_);
-    const __m128i cage_mask =
-        _mm_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask());
-
-    size_t quarantine_size = 0;
-    for (uintptr_t* payload = begin; payload < end; payload += kWordsInVector) {
-      const __m128i maybe_ptrs =
-          _mm_loadu_si128(reinterpret_cast<__m128i*>(payload));
-      const __m128i vand = _mm_and_si128(maybe_ptrs, cage_mask);
-      const __m128i vcmp = _mm_cmpeq_epi64(vand, vbase);
-      const int mask = _mm_movemask_pd(_mm_castsi128_pd(vcmp));
-      if (LIKELY(!mask))
-        continue;
-      // It's important to extract pointers from the already loaded vector to
-      // avoid racing with the mutator.
-      // Once BRP check passes, we know we're dealing with normal buckets.
-      if (mask & 0b01) {
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm_cvtsi128_si64(maybe_ptrs));
-      }
-      if (mask & 0b10) {
-        // Extraction intrinsics for qwords are only supported in SSE4.1, so
-        // instead we reshuffle dwords with pshufd. The mask is used to move the
-        // 4th and 3rd dwords into the second and first position.
-        static constexpr int kSecondWordMask = (3 << 2) | (2 << 0);
-        const __m128i shuffled = _mm_shuffle_epi32(maybe_ptrs, kSecondWordMask);
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm_cvtsi128_si64(shuffled));
-      }
-    }
-    return quarantine_size;
-  }
-
-  __attribute__((target("avx2"))) NO_SANITIZE("thread") size_t
-      RunAVX2(uintptr_t* begin, uintptr_t* end) const {
-    static constexpr size_t kAlignmentRequirement = 32;
-    static constexpr size_t kWordsInVector = 4;
-    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % kAlignmentRequirement));
-    // For AVX2, stick to integer instructions. This brings slightly better
-    // throughput. For example, according to the Intel docs, on Broadwell and
-    // Haswell the CPI of vmovdqa (_mm256_load_si256) is twice smaller (0.25)
-    // than that of vmovapd (_mm256_load_pd).
-    const __m256i vbase = _mm256_set1_epi64x(brp_pool_base_);
-    const __m256i cage_mask =
-        _mm256_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask());
-
-    size_t quarantine_size = 0;
-    uintptr_t* payload = begin;
-    for (; payload < (end - kWordsInVector); payload += kWordsInVector) {
-      const __m256i maybe_ptrs =
-          _mm256_load_si256(reinterpret_cast<__m256i*>(payload));
-      const __m256i vand = _mm256_and_si256(maybe_ptrs, cage_mask);
-      const __m256i vcmp = _mm256_cmpeq_epi64(vand, vbase);
-      const int mask = _mm256_movemask_pd(_mm256_castsi256_pd(vcmp));
-      if (LIKELY(!mask))
-        continue;
-      // It's important to extract pointers from the already loaded vector to
-      // avoid racing with the mutator.
-      // Once BRP check passes, we know we're dealing with normal buckets.
-      if (mask & 0b0001)
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm256_extract_epi64(maybe_ptrs, 0));
-      if (mask & 0b0010)
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm256_extract_epi64(maybe_ptrs, 1));
-      if (mask & 0b0100)
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm256_extract_epi64(maybe_ptrs, 2));
-      if (mask & 0b1000)
-        quarantine_size +=
-            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-                _mm256_extract_epi64(maybe_ptrs, 3));
-    }
-
-    quarantine_size += RunUnvectorized(payload, end);
-    return quarantine_size;
-  }
-#endif  // defined(ARCH_CPU_X86_64)
-
-  ALWAYS_INLINE NO_SANITIZE("thread") size_t
-      RunUnvectorized(uintptr_t* begin, uintptr_t* end) const {
-    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t)));
-    size_t quarantine_size = 0;
-    for (; begin < end; ++begin) {
-      uintptr_t maybe_ptr = *begin;
-#if defined(PA_HAS_64_BITS_POINTERS)
-      // On 64bit architectures, call IsInBRPPool instead of
-      // IsManagedByPartitionAllocBRPPool to avoid redundant loads of
-      // PartitionAddressSpace::brp_pool_base_address_.
-      if (LIKELY(!IsInBRPPool(maybe_ptr)))
-        continue;
-        // Once BRP check passes, we know we're dealing with normal buckets.
-#endif
-      quarantine_size +=
-          pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
-              maybe_ptr);
-    }
-    return quarantine_size;
-  }
-
-  ALWAYS_INLINE NO_SANITIZE("thread") size_t
-      RunUnvectorizedNoGigaCage(uintptr_t* begin, uintptr_t* end) const {
-    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t)));
-    size_t quarantine_size = 0;
-    for (; begin < end; ++begin) {
-      uintptr_t maybe_ptr = *begin;
-      if (!maybe_ptr)
-        continue;
-      quarantine_size +=
-          pcscan_task_.TryMarkObjectInNormalBuckets<NoGigaCageLookupPolicy>(
-              maybe_ptr);
-    }
-    return quarantine_size;
-  }
-
-  const ScanFunction scan_function_;
-  const PCScanTask& pcscan_task_;
-#if defined(PA_HAS_64_BITS_POINTERS)
-  // Keep this a constant so that the compiler can remove redundant loads for
-  // the base of the BRP pool and hoist them out of the loops.
-  const uintptr_t brp_pool_base_;
-#endif
-};
-
-class PCScanTask::StackVisitor final : public internal::StackVisitor {
- public:
-  explicit StackVisitor(const PCScanTask& task) : task_(task) {}
-
-  void VisitStack(uintptr_t* stack_ptr, uintptr_t* stack_top) override {
-    static constexpr size_t kMinimalAlignment = 32;
-    stack_ptr = reinterpret_cast<uintptr_t*>(
-        reinterpret_cast<uintptr_t>(stack_ptr) & ~(kMinimalAlignment - 1));
-    stack_top = reinterpret_cast<uintptr_t*>(
-        (reinterpret_cast<uintptr_t>(stack_top) + kMinimalAlignment - 1) &
-        ~(kMinimalAlignment - 1));
-    PA_CHECK(stack_ptr < stack_top);
-    ScanLoop loop(task_);
-    quarantine_size_ += loop.Run(stack_ptr, stack_top);
-  }
-
-  // Returns size of quarantined objects that are reachable from the current
-  // stack.
-  size_t quarantine_size() const { return quarantine_size_; }
-
- private:
-  const PCScanTask& task_;
-  size_t quarantine_size_ = 0;
-};
-
-PCScanTask::PCScanTask(PCScan& pcscan)
-    : pcscan_epoch_(pcscan.epoch()),
-      stats_(PCScanInternal::Instance().process_name()),
-      pcscan_(pcscan) {}
-
-void PCScanTask::ScanStack() {
-  const auto& pcscan = PCScanInternal::Instance();
-  if (!pcscan.IsStackScanningEnabled())
-    return;
-  // Check if the stack top was registered. It may happen that it's not if the
-  // current allocation happens from pthread trampolines.
-  void* stack_top = pcscan.GetCurrentThreadStackTop();
-  if (UNLIKELY(!stack_top))
-    return;
-
-  Stack stack_scanner(stack_top);
-  StackVisitor visitor(*this);
-  stack_scanner.IteratePointers(&visitor);
-  stats_.IncreaseSurvivedQuarantineSize(visitor.quarantine_size());
-}
-
-void PCScanTask::ScanPartitions() {
-  const ScanLoop scan_loop(*this);
-  // For scanning large areas, it's worthwhile checking whether the range that
-  // is scanned contains quarantined objects.
-  size_t quarantine_size = 0;
-
-  // Scan areas with large slots.
-  PCScanSnapshot::LargeScanAreasWorklist::RandomizedView large_scan_areas(
-      snapshot_.large_scan_areas_worklist());
-  large_scan_areas.Visit([this, &scan_loop, &quarantine_size](auto scan_area) {
-    // The bitmap is (a) always guaranteed to exist and (b) the same for all
-    // objects in a given slot span.
-    // TODO(chromium:1129751): Check mutator bitmap as well if performance
-    // allows.
-    auto* bitmap = QuarantineBitmapFromPointer(
-        QuarantineBitmapType::kScanner, pcscan_epoch_,
-        reinterpret_cast<char*>(scan_area.begin));
-    for (uintptr_t* current_slot = scan_area.begin;
-         current_slot < scan_area.end;
-         current_slot += (scan_area.slot_size / sizeof(uintptr_t))) {
-      // It is okay to skip objects as their payload has been zapped at this
-      // point which means that the pointers no longer retain other objects.
-      if (bitmap->CheckBit(reinterpret_cast<uintptr_t>(current_slot))) {
-        continue;
-      }
-      uintptr_t* current_slot_end =
-          current_slot + (scan_area.slot_size / sizeof(uintptr_t));
-      PA_DCHECK(current_slot_end <= scan_area.end);
-      quarantine_size += scan_loop.Run(current_slot, current_slot_end);
-    }
-  });
-
-  // Scan areas with regular size slots.
-  PCScanSnapshot::ScanAreasWorklist::RandomizedView scan_areas(
-      snapshot_.scan_areas_worklist());
-  scan_areas.Visit([&scan_loop, &quarantine_size](auto scan_area) {
-    quarantine_size += scan_loop.Run(scan_area.begin, scan_area.end);
-  });
-
-  stats_.IncreaseSurvivedQuarantineSize(quarantine_size);
-}
-
-void PCScanTask::SweepQuarantine() {
-  using AccessType = QuarantineBitmap::AccessType;
-
-  const bool giga_cage_enabled = features::IsPartitionAllocGigaCageEnabled();
-  size_t swept_bytes = 0;
-
-  for (uintptr_t super_page : snapshot_.quarantinable_super_pages()) {
-    auto* bitmap = QuarantineBitmapFromPointer(
-        QuarantineBitmapType::kScanner, pcscan_epoch_,
-        reinterpret_cast<char*>(super_page));
-    auto* root = Root::FromSuperPage(reinterpret_cast<char*>(super_page));
-    bitmap->template IterateAndClear<AccessType::kNonAtomic>(
-        [root, giga_cage_enabled, &swept_bytes](uintptr_t ptr) {
-          auto* object = reinterpret_cast<void*>(ptr);
-          auto* slot_span = SlotSpan::FromSlotInnerPtr(object);
-          swept_bytes += slot_span->bucket->slot_size;
-          root->FreeNoHooksImmediate(object, slot_span);
-#if defined(PA_HAS_64_BITS_POINTERS)
-          if (giga_cage_enabled) {
-            // Reset card(s) for this quarantined object. Please note that the
-            // cards may still contain quarantined objects (which were promoted
-            // in this scan cycle), but
-            // ClearQuarantinedObjectsAndFilterSuperPages() will set them again
-            // in the next PCScan cycle.
-            QuarantineCardTable::GetFrom(ptr).Unquarantine(
-                ptr, slot_span->GetUsableSize(root));
-          }
-#else
-          (void)giga_cage_enabled;
-#endif
-        });
-  }
-
-  stats_.IncreaseSweptSize(swept_bytes);
-
-#if defined(PA_THREAD_CACHE_SUPPORTED)
-  // Sweeping potentially frees into the current thread's thread cache. Purge
-  // releases the cache back to the global allocator.
-  auto* current_thread_tcache = ThreadCache::Get();
-  if (ThreadCache::IsValid(current_thread_tcache))
-    current_thread_tcache->Purge();
-#endif  // defined(PA_THREAD_CACHE_SUPPORTED)
-}
-
-void PCScanTask::FinishScanner() {
-  stats_.ReportTracesAndHists();
-  LogStats(
-      stats_.swept_size(),
-      pcscan_.scheduler_.scheduling_backend().GetQuarantineData().last_size,
-      stats_.survived_quarantine_size());
-
-  pcscan_.scheduler_.scheduling_backend().UpdateScheduleAfterScan(
-      stats_.survived_quarantine_size(), stats_.GetOverallTime(),
-      PCScanInternal::Instance().CalculateTotalHeapSize());
-
-  PCScanInternal::Instance().ResetCurrentPCScanTask();
-  // Check that concurrent task can't be scheduled twice.
-  PA_CHECK(pcscan_.state_.exchange(PCScan::State::kNotRunning,
-                                   std::memory_order_acq_rel) ==
-           PCScan::State::kSweepingAndFinishing);
-}
-
-void PCScanTask::RunFromMutator() {
-  ReentrantScannerGuard reentrancy_guard;
-  StatsCollector::MutatorScope overall_scope(
-      stats_, StatsCollector::MutatorId::kOverall);
-  {
-    SyncScope<Context::kMutator> sync_scope(*this);
-    // Mutator might start entering the safepoint while scanning was already
-    // finished.
-    if (!pcscan_.IsJoinable())
-      return;
-    // Take snapshot of partition-alloc heap if not yet taken.
-    snapshot_.EnsureTaken(pcscan_epoch_);
-    {
-      // Clear all quarantined objects and prepare card table.
-      StatsCollector::MutatorScope clear_scope(
-          stats_, StatsCollector::MutatorId::kClear);
-      ClearQuarantinedObjectsAndPrepareCardTable();
-    }
-    {
-      // Scan the thread's stack to find dangling references.
-      StatsCollector::MutatorScope scan_scope(
-          stats_, StatsCollector::MutatorId::kScanStack);
-      ScanStack();
-    }
-    {
-      // Scan heap for dangling references.
-      StatsCollector::MutatorScope scan_scope(stats_,
-                                              StatsCollector::MutatorId::kScan);
-      ScanPartitions();
-    }
-  }
-}
-
-void PCScanTask::RunFromScanner() {
-  ReentrantScannerGuard reentrancy_guard;
-  {
-    StatsCollector::ScannerScope overall_scope(
-        stats_, StatsCollector::ScannerId::kOverall);
-    {
-      SyncScope<Context::kScanner> sync_scope(*this);
-      // Take snapshot of partition-alloc heap.
-      snapshot_.EnsureTaken(pcscan_epoch_);
-      {
-        // Clear all quarantined objects and prepare the card table.
-        StatsCollector::ScannerScope clear_scope(
-            stats_, StatsCollector::ScannerId::kClear);
-        ClearQuarantinedObjectsAndPrepareCardTable();
-      }
-      {
-        // Scan heap for dangling references.
-        StatsCollector::ScannerScope scan_scope(
-            stats_, StatsCollector::ScannerId::kScan);
-        ScanPartitions();
-      }
-    }
-    {
-      // Sweep unreachable quarantined objects.
-      StatsCollector::ScannerScope sweep_scope(
-          stats_, StatsCollector::ScannerId::kSweep);
-      SweepQuarantine();
-    }
-  }
-  FinishScanner();
-}
-
-class PCScan::PCScanThread final {
- public:
-  using TaskHandle = PCScanInternal::TaskHandle;
-
-  static PCScanThread& Instance() {
-    // Lazily instantiate the scanning thread.
-    static base::NoDestructor<PCScanThread> instance;
-    return *instance;
-  }
-
-  void PostTask(TaskHandle task) {
-    {
-      std::lock_guard<std::mutex> lock(mutex_);
-      PA_DCHECK(!posted_task_.get());
-      posted_task_ = std::move(task);
-      wanted_delay_ = TimeDelta();
-    }
-    condvar_.notify_one();
-  }
-
-  void PostDelayedTask(TimeDelta delay) {
-    {
-      std::lock_guard<std::mutex> lock(mutex_);
-      if (posted_task_.get()) {
-        return;
-      }
-      wanted_delay_ = delay;
-    }
-    condvar_.notify_one();
-  }
-
- private:
-  friend class base::NoDestructor<PCScanThread>;
-
-  PCScanThread() {
-    std::thread{[this] {
-      static constexpr const char* kThreadName = "PCScan";
-      // Ideally we should avoid mixing base:: and std:: API for threading, but
-      // this is useful for visualizing the pcscan thread in chrome://tracing.
-      base::PlatformThread::SetName(kThreadName);
-      TaskLoop();
-    }}.detach();
-  }
-
-  // Waits and returns whether the delay should be recomputed.
-  bool Wait(std::unique_lock<std::mutex>& lock) {
-    PA_DCHECK(lock.owns_lock());
-    if (wanted_delay_.is_zero()) {
-      condvar_.wait(lock, [this] {
-        // Re-evaluate if either delay changed, or a task was
-        // enqueued.
-        return !wanted_delay_.is_zero() || posted_task_.get();
-      });
-      // The delay has already been set up and should not be queried again.
-      return false;
-    }
-    condvar_.wait_for(
-        lock, std::chrono::microseconds(wanted_delay_.InMicroseconds()));
-    // If no task has been posted, the delay should be recomputed at this point.
-    return !posted_task_.get();
-  }
-
-  void TaskLoop() {
-    while (true) {
-      TaskHandle current_task;
-      {
-        std::unique_lock<std::mutex> lock(mutex_);
-        // Scheduling.
-        while (!posted_task_.get()) {
-          if (Wait(lock)) {
-            wanted_delay_ =
-                scheduler().scheduling_backend().UpdateDelayedSchedule();
-            if (wanted_delay_.is_zero()) {
-              break;
-            }
-          }
-        }
-        // Differentiate between a posted task and a delayed task schedule.
-        if (posted_task_.get()) {
-          std::swap(current_task, posted_task_);
-          wanted_delay_ = TimeDelta();
-        } else {
-          PA_DCHECK(wanted_delay_.is_zero());
-        }
-      }
-      // Differentiate between a posted task and a delayed task schedule.
-      if (current_task.get()) {
-        current_task->RunFromScanner();
-      } else {
-        PCScan::Instance().PerformScan(PCScan::InvocationMode::kNonBlocking);
-      }
-    }
-  }
-
-  PCScanScheduler& scheduler() const { return PCScan::Instance().scheduler(); }
-
-  std::mutex mutex_;
-  std::condition_variable condvar_;
-  TaskHandle posted_task_;
-  TimeDelta wanted_delay_;
-};
-
-void PCScan::PerformScan(InvocationMode invocation_mode) {
-#if DCHECK_IS_ON()
-  const auto& internal = PCScanInternal::Instance();
-  const auto& scannable_roots = internal.scannable_roots();
-  const auto& nonscannable_roots = internal.nonscannable_roots();
-  PA_DCHECK(internal.is_initialized());
-  PA_DCHECK(scannable_roots.size() > 0);
-  PA_DCHECK(std::all_of(scannable_roots.begin(), scannable_roots.end(),
-                        [](Root* root) { return root->IsScanEnabled(); }));
-  PA_DCHECK(
-      std::all_of(nonscannable_roots.begin(), nonscannable_roots.end(),
-                  [](Root* root) { return root->IsQuarantineEnabled(); }));
-#endif
-
-  {
-    // If scanning is already in progress, bail out.
-    State expected = State::kNotRunning;
-    if (!state_.compare_exchange_strong(expected, State::kScheduled,
-                                        std::memory_order_acq_rel,
-                                        std::memory_order_relaxed))
-      return;
-  }
-
-  scheduler_.scheduling_backend().ScanStarted();
-
-  // Create PCScan task and set it as current.
-  auto task = base::MakeRefCounted<PCScanTask>(*this);
-  PCScanInternal::Instance().SetCurrentPCScanTask(task);
-
-  if (UNLIKELY(invocation_mode == InvocationMode::kScheduleOnlyForTesting)) {
-    // Immediately change the state to enable safepoint testing.
-    state_.store(State::kScanning, std::memory_order_release);
-    return;
-  }
-
-  // Post PCScan task.
-  if (LIKELY(invocation_mode == InvocationMode::kNonBlocking)) {
-    PCScanThread::Instance().PostTask(std::move(task));
-  } else {
-    PA_DCHECK(InvocationMode::kBlocking == invocation_mode ||
-              InvocationMode::kForcedBlocking == invocation_mode);
-    std::move(*task).RunFromScanner();
-  }
-}
-
-void PCScan::PerformScanIfNeeded(InvocationMode invocation_mode) {
-  if (!PCScanInternal::Instance().scannable_roots().size())
-    return;
-  PCScan& instance = Instance();
-  if (invocation_mode == InvocationMode::kForcedBlocking ||
-      instance.scheduler_.scheduling_backend()
-          .GetQuarantineData()
-          .MinimumScanningThresholdReached())
-    instance.PerformScan(invocation_mode);
-}
-
-void PCScan::PerformDelayedScan(TimeDelta delay) {
-  PCScanThread::Instance().PostDelayedTask(delay);
-}
-
-void PCScan::JoinScan() {
-#if !PCSCAN_DISABLE_SAFEPOINTS
-  auto& internal = PCScanInternal::Instance();
-  // Current task can be destroyed by the scanner. Check that it's valid.
-  if (auto current_task = internal.CurrentPCScanTask())
-    current_task->RunFromMutator();
-#endif
-}
-
-void PCScan::FinishScanForTesting() {
-  auto& internal = PCScanInternal::Instance();
-  auto current_task = internal.CurrentPCScanTask();
-  PA_CHECK(current_task.get());
-  current_task->RunFromScanner();
-}
-
 void PCScan::Initialize() {
   PCScanInternal::Instance().Initialize();
 }
@@ -1729,6 +21,22 @@
   PCScanInternal::Instance().RegisterNonScannableRoot(root);
 }
 
+void PCScan::PerformScan(InvocationMode invocation_mode) {
+  PCScanInternal::Instance().PerformScan(invocation_mode);
+}
+
+void PCScan::PerformScanIfNeeded(InvocationMode invocation_mode) {
+  PCScanInternal::Instance().PerformScanIfNeeded(invocation_mode);
+}
+
+void PCScan::PerformDelayedScan(TimeDelta delay) {
+  PCScanInternal::Instance().PerformDelayedScan(delay);
+}
+
+void PCScan::JoinScan() {
+  PCScanInternal::Instance().JoinScan();
+}
+
 void PCScan::SetProcessName(const char* process_name) {
   PCScanInternal::Instance().SetProcessName(process_name);
 }
@@ -1759,6 +67,10 @@
   PCScanInternal::Instance().ReinitForTesting();  // IN-TEST
 }
 
+void PCScan::FinishScanForTesting() {
+  PCScanInternal::Instance().FinishScanForTesting();  // IN-TEST
+}
+
 PCScan PCScan::instance_ PA_CONSTINIT;
 
 }  // namespace internal
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h
index 271f3aa..b748473 100644
--- a/base/allocator/partition_allocator/starscan/pcscan.h
+++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -28,8 +28,6 @@
 namespace base {
 namespace internal {
 
-class PCScanTask;
-
 [[noreturn]] BASE_EXPORT NOINLINE NOT_TAIL_CALLED void DoubleFreeAttempt();
 
 // PCScan (Probabilistic Conservative Scanning) is the algorithm that eliminates
@@ -101,6 +99,7 @@
   class PCScanThread;
   friend class PCScanTask;
   friend class PCScanTest;
+  friend class PCScanInternal;
 
   enum class State : uint8_t {
     // PCScan task is not scheduled.
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.cc b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
new file mode 100644
index 0000000..7e21e5d
--- /dev/null
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
@@ -0,0 +1,1338 @@
+// Copyright (c) 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 "base/allocator/partition_allocator/starscan/pcscan_internal.h"
+
+#include <algorithm>
+#include <array>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <numeric>
+#include <set>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+#include "base/allocator/partition_allocator/address_pool_manager.h"
+#include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
+#include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/allocator/partition_allocator/page_allocator_constants.h"
+#include "base/allocator/partition_allocator/partition_address_space.h"
+#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/allocator/partition_allocator/partition_alloc_check.h"
+#include "base/allocator/partition_allocator/partition_alloc_constants.h"
+#include "base/allocator/partition_allocator/partition_alloc_features.h"
+#include "base/allocator/partition_allocator/partition_page.h"
+#include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
+#include "base/allocator/partition_allocator/starscan/pcscan_scheduling.h"
+#include "base/allocator/partition_allocator/starscan/raceful_worklist.h"
+#include "base/allocator/partition_allocator/starscan/stack/stack.h"
+#include "base/allocator/partition_allocator/starscan/stats_collector.h"
+#include "base/allocator/partition_allocator/thread_cache.h"
+#include "base/compiler_specific.h"
+#include "base/cpu.h"
+#include "base/debug/alias.h"
+#include "base/immediate_crash.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_X86_64)
+// Include order is important, so we disable formatting.
+// clang-format off
+// Including these headers directly should generally be avoided. For the
+// scanning loop, we check at runtime which SIMD extension we can use. Since
+// Chrome is compiled with -msse3 (the minimal requirement), we include the
+// headers directly to make the intrinsics available. Another option could be to
+// use inline assembly, but that would hinder compiler optimization for
+// vectorized instructions.
+#include <immintrin.h>
+#include <smmintrin.h>
+#include <avxintrin.h>
+#include <avx2intrin.h>
+// clang-format on
+#endif
+
+namespace base {
+namespace internal {
+
+[[noreturn]] BASE_EXPORT NOINLINE NOT_TAIL_CALLED void DoubleFreeAttempt() {
+  NO_CODE_FOLDING();
+  IMMEDIATE_CRASH();
+}
+
+namespace {
+
+#if DCHECK_IS_ON() && defined(OS_LINUX)
+// Currently, check reentracy only on Linux. On Android TLS is emulated by the
+// runtime lib, which can allocate and therefore cause reentrancy.
+struct ReentrantScannerGuard final {
+ public:
+  ReentrantScannerGuard() {
+    PA_CHECK(!guard_);
+    guard_ = true;
+  }
+  ~ReentrantScannerGuard() { guard_ = false; }
+
+ private:
+  // Since this variable has hidden visibility (not referenced by other DSOs),
+  // assume that thread_local works on all supported architectures.
+  static thread_local size_t guard_;
+};
+thread_local size_t ReentrantScannerGuard::guard_ = 0;
+#else
+struct [[maybe_unused]] ReentrantScannerGuard final{};
+#endif
+
+#if defined(PA_HAS_64_BITS_POINTERS)
+// Bytemap that represent regions (cards) that contain quarantined objects.
+// A single PCScan cycle consists of the following steps:
+// 1) clearing (memset quarantine + marking cards that contain quarantine);
+// 2) scanning;
+// 3) sweeping (freeing + unmarking cards that contain freed objects).
+// Marking cards on step 1) ensures that the card table stays in the consistent
+// state while scanning. Unmarking on the step 3) ensures that unmarking
+// actually happens (and we don't hit too many false positives).
+class QuarantineCardTable final {
+ public:
+  // Avoid the load of the base of the BRP pool.
+  ALWAYS_INLINE static QuarantineCardTable& GetFrom(uintptr_t ptr) {
+    constexpr uintptr_t kBRPPoolMask = PartitionAddressSpace::BRPPoolBaseMask();
+    return *reinterpret_cast<QuarantineCardTable*>(ptr & kBRPPoolMask);
+  }
+
+  ALWAYS_INLINE void Quarantine(uintptr_t begin, size_t size) {
+    return SetImpl(begin, size, true);
+  }
+
+  ALWAYS_INLINE void Unquarantine(uintptr_t begin, size_t size) {
+    return SetImpl(begin, size, false);
+  }
+
+  // Returns whether the card to which |ptr| points to contains quarantined
+  // objects. May return false positives for but should never return false
+  // negatives, as otherwise this breaks security.
+  ALWAYS_INLINE bool IsQuarantined(uintptr_t ptr) const {
+    const size_t byte = Byte(ptr);
+    PA_DCHECK(byte < bytes_.size());
+    return bytes_[byte];
+  }
+
+ private:
+  static constexpr size_t kCardSize =
+      AddressPoolManager::kBRPPoolMaxSize / kSuperPageSize;
+  static constexpr size_t kBytes =
+      AddressPoolManager::kBRPPoolMaxSize / kCardSize;
+
+  QuarantineCardTable() = default;
+
+  ALWAYS_INLINE static constexpr size_t Byte(uintptr_t address) {
+    constexpr uintptr_t kBRPPoolMask = PartitionAddressSpace::BRPPoolBaseMask();
+    return (address & ~kBRPPoolMask) / kCardSize;
+  }
+
+  ALWAYS_INLINE void SetImpl(uintptr_t begin, size_t size, bool value) {
+    const size_t byte = Byte(begin);
+    const size_t need_bytes = (size + (kCardSize - 1)) / kCardSize;
+    PA_DCHECK(bytes_.size() >= byte + need_bytes);
+    PA_DCHECK(
+        PartitionAddressSpace::IsInBRPPool(reinterpret_cast<void*>(begin)));
+    for (size_t i = byte; i < byte + need_bytes; ++i)
+      bytes_[i] = value;
+  }
+
+  std::array<bool, kBytes> bytes_;
+};
+static_assert(kSuperPageSize >= sizeof(QuarantineCardTable),
+              "Card table size must be less than kSuperPageSize, since this is "
+              "what is committed");
+#endif
+
+template <typename T>
+using MetadataVector = std::vector<T, MetadataAllocator<T>>;
+template <typename T>
+using MetadataSet = std::set<T, std::less<>, MetadataAllocator<T>>;
+template <typename K, typename V>
+using MetadataHashMap =
+    std::unordered_map<K,
+                       V,
+                       std::hash<K>,
+                       std::equal_to<>,
+                       MetadataAllocator<std::pair<const K, V>>>;
+
+void LogStats(size_t swept_bytes, size_t last_size, size_t new_size) {
+  VLOG(2) << "quarantine size: " << last_size << " -> " << new_size
+          << ", swept bytes: " << swept_bytes
+          << ", survival rate: " << static_cast<double>(new_size) / last_size;
+}
+
+ALWAYS_INLINE uintptr_t GetObjectStartInSuperPage(uintptr_t maybe_ptr,
+                                                  const PCScan::Root& root) {
+  char* allocation_start =
+      GetSlotStartInSuperPage<ThreadSafe>(reinterpret_cast<char*>(maybe_ptr));
+  if (!allocation_start) {
+    // |maybe_ptr| refers to a garbage or is outside of the payload region.
+    return 0;
+  }
+  return reinterpret_cast<uintptr_t>(
+      root.AdjustPointerForExtrasAdd(allocation_start));
+}
+
+#if DCHECK_IS_ON()
+bool IsScannerQuarantineBitmapEmpty(char* super_page, size_t epoch) {
+  auto* bitmap = QuarantineBitmapFromPointer(QuarantineBitmapType::kScanner,
+                                             epoch, super_page);
+  size_t visited = 0;
+  bitmap->Iterate([&visited](auto) { ++visited; });
+  return !visited;
+}
+#endif
+
+PCScanInternal::SimdSupport DetectSimdSupport() {
+  base::CPU cpu;
+  if (cpu.has_avx2())
+    return PCScanInternal::SimdSupport::kAVX2;
+  if (cpu.has_sse41())
+    return PCScanInternal::SimdSupport::kSSE41;
+  return PCScanInternal::SimdSupport::kUnvectorized;
+}
+
+void CommitCardTable() {
+#if defined(PA_HAS_64_BITS_POINTERS)
+  if (features::IsPartitionAllocGigaCageEnabled()) {
+    // First, make sure that GigaCage is initialized.
+    PartitionAddressSpace::Init();
+    // Then, commit the card table.
+    RecommitSystemPages(
+        reinterpret_cast<void*>(PartitionAddressSpace::BRPPoolBase()),
+        sizeof(QuarantineCardTable), PageReadWrite, PageUpdatePermissions);
+  }
+#endif
+}
+
+void CommitQuarantineBitmaps(PCScan::Root& root) {
+  size_t quarantine_bitmaps_size_to_commit = CommittedQuarantineBitmapsSize();
+  for (auto* super_page_extent = root.first_extent; super_page_extent;
+       super_page_extent = super_page_extent->next) {
+    for (char* super_page = super_page_extent->super_page_base;
+         super_page != super_page_extent->super_pages_end;
+         super_page += kSuperPageSize) {
+      RecommitSystemPages(internal::SuperPageQuarantineBitmaps(super_page),
+                          quarantine_bitmaps_size_to_commit, PageReadWrite,
+                          PageUpdatePermissions);
+    }
+  }
+}
+
+class PCScanSnapshot final {
+ public:
+  struct ScanArea {
+    ScanArea(uintptr_t* begin, uintptr_t* end) : begin(begin), end(end) {}
+
+    uintptr_t* begin = nullptr;
+    uintptr_t* end = nullptr;
+  };
+
+  // Large scan areas have their slot size recorded which allows to iterate
+  // based on objects, potentially skipping over objects if possible.
+  struct LargeScanArea : public ScanArea {
+    LargeScanArea(uintptr_t* begin, uintptr_t* end, size_t slot_size)
+        : ScanArea(begin, end), slot_size(slot_size) {}
+
+    size_t slot_size = 0;
+  };
+
+  // Worklists that are shared and processed by different scanners.
+  using ScanAreasWorklist = RacefulWorklist<ScanArea>;
+  using LargeScanAreasWorklist = RacefulWorklist<LargeScanArea>;
+  using SuperPagesWorklist = RacefulWorklist<uintptr_t>;
+
+  // BRP pool is guaranteed to have only normal buckets, so everything there
+  // deals in super pages.
+  using SuperPages = MetadataSet<uintptr_t>;
+
+  PCScanSnapshot() = default;
+
+  void EnsureTaken(size_t pcscan_epoch);
+
+  ScanAreasWorklist& scan_areas_worklist() { return scan_areas_worklist_; }
+  LargeScanAreasWorklist& large_scan_areas_worklist() {
+    return large_scan_areas_worklist_;
+  }
+  SuperPagesWorklist& quarantinable_super_pages_worklist() {
+    return super_pages_worklist_;
+  }
+
+  const SuperPages& quarantinable_super_pages() const { return super_pages_; }
+
+ private:
+  void Take(size_t pcscan_epoch);
+
+  SuperPages super_pages_;
+
+  ScanAreasWorklist scan_areas_worklist_;
+  LargeScanAreasWorklist large_scan_areas_worklist_;
+  SuperPagesWorklist super_pages_worklist_;
+
+  std::once_flag once_flag_;
+};
+
+void PCScanSnapshot::EnsureTaken(size_t pcscan_epoch) {
+  std::call_once(once_flag_, &PCScanSnapshot::Take, this, pcscan_epoch);
+}
+
+void PCScanSnapshot::Take(size_t pcscan_epoch) {
+  using Root = PartitionRoot<ThreadSafe>;
+  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
+  // Threshold for which bucket size it is worthwhile in checking whether the
+  // object is a quarantined object and can be skipped.
+  static constexpr size_t kLargeScanAreaThreshold = 8192;
+
+  auto& pcscan_internal = PCScanInternal::Instance();
+  for (Root* root : pcscan_internal.scannable_roots()) {
+    typename Root::ScopedGuard guard(root->lock_);
+
+    // Take a snapshot of all super pages and scannable slot spans.
+    // TODO(bikineev): Consider making current_extent lock-free and moving it
+    // to the concurrent thread.
+    for (auto* super_page_extent = root->first_extent; super_page_extent;
+         super_page_extent = super_page_extent->next) {
+      for (char* super_page = super_page_extent->super_page_base;
+           super_page != super_page_extent->super_pages_end;
+           super_page += kSuperPageSize) {
+        // TODO(bikineev): Consider following freelists instead of slot spans.
+        const size_t visited_slot_spans = IterateSlotSpans<ThreadSafe>(
+            super_page, true /*with_quarantine*/,
+            [this](SlotSpan* slot_span) -> bool {
+              if (slot_span->is_empty() || slot_span->is_decommitted()) {
+                return false;
+              }
+              auto* payload_begin = static_cast<uintptr_t*>(
+                  SlotSpan::ToSlotSpanStartPtr(slot_span));
+              size_t provisioned_size = slot_span->GetProvisionedSize();
+              // Free & decommitted slot spans are skipped.
+              PA_DCHECK(provisioned_size > 0);
+              auto* payload_end =
+                  payload_begin + (provisioned_size / sizeof(uintptr_t));
+              if (slot_span->bucket->slot_size >= kLargeScanAreaThreshold) {
+                large_scan_areas_worklist_.Push(
+                    {payload_begin, payload_end, slot_span->bucket->slot_size});
+              } else {
+                scan_areas_worklist_.Push({payload_begin, payload_end});
+              }
+              return true;
+            });
+        // If we haven't visited any slot spans, all the slot spans in the
+        // super-page are either empty or decommitted. This means that all the
+        // objects are freed and there are no quarantined objects.
+        if (LIKELY(visited_slot_spans)) {
+          super_pages_.insert(reinterpret_cast<uintptr_t>(super_page));
+          super_pages_worklist_.Push(reinterpret_cast<uintptr_t>(super_page));
+        } else {
+#if DCHECK_IS_ON()
+          PA_CHECK(IsScannerQuarantineBitmapEmpty(super_page, pcscan_epoch));
+#endif
+        }
+      }
+    }
+  }
+  for (Root* root : pcscan_internal.nonscannable_roots()) {
+    typename Root::ScopedGuard guard(root->lock_);
+    // Take a snapshot of all super pages and nnonscannable slot spans.
+    for (auto* super_page_extent = root->first_extent; super_page_extent;
+         super_page_extent = super_page_extent->next) {
+      for (char* super_page = super_page_extent->super_page_base;
+           super_page != super_page_extent->super_pages_end;
+           super_page += kSuperPageSize) {
+        super_pages_.insert(reinterpret_cast<uintptr_t>(super_page));
+        super_pages_worklist_.Push(reinterpret_cast<uintptr_t>(super_page));
+      }
+    }
+  }
+}
+
+}  // namespace
+
+// This class is responsible for performing the entire PCScan task.
+// TODO(bikineev): Move PCScan algorithm out of PCScanTask.
+class PCScanTask final : public base::RefCountedThreadSafe<PCScanTask>,
+                         public AllocatedOnPCScanMetadataPartition {
+ public:
+  // Creates and initializes a PCScan state.
+  explicit PCScanTask(PCScan& pcscan);
+
+  PCScanTask(PCScanTask&&) noexcept = delete;
+  PCScanTask& operator=(PCScanTask&&) noexcept = delete;
+
+  // Execute PCScan from mutator inside safepoint.
+  void RunFromMutator();
+
+  // Execute PCScan from the scanner thread. Must be called only once from the
+  // scanner thread.
+  void RunFromScanner();
+
+  PCScanScheduler& scheduler() const { return pcscan_.scheduler(); }
+
+ private:
+  class ScanLoop;
+  class StackVisitor;
+
+  using Root = PCScan::Root;
+  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
+
+  struct GigaCageLookupPolicy {
+    ALWAYS_INLINE bool TestOnHeapPointer(uintptr_t maybe_ptr) const {
+#if defined(PA_HAS_64_BITS_POINTERS)
+#if DCHECK_IS_ON()
+      PA_DCHECK(
+          IsManagedByPartitionAllocBRPPool(reinterpret_cast<void*>(maybe_ptr)));
+#endif
+      return QuarantineCardTable::GetFrom(maybe_ptr).IsQuarantined(maybe_ptr);
+#else   // defined(PA_HAS_64_BITS_POINTERS)
+      return IsManagedByPartitionAllocBRPPool(
+          reinterpret_cast<void*>(maybe_ptr));
+#endif  // defined(PA_HAS_64_BITS_POINTERS)
+    }
+    [[maybe_unused]] const PCScanSnapshot& snapshot;
+  };
+
+  struct NoGigaCageLookupPolicy {
+    ALWAYS_INLINE bool TestOnHeapPointer(uintptr_t maybe_ptr) const {
+      const auto super_page_base = maybe_ptr & kSuperPageBaseMask;
+      const auto& super_pages = snapshot.quarantinable_super_pages();
+      auto it = super_pages.lower_bound(super_page_base);
+      return it != super_pages.end() && *it == super_page_base;
+    }
+    const PCScanSnapshot& snapshot;
+  };
+
+  // This is used:
+  // - to synchronize all scanning threads (mutators and the scanner);
+  // - for the scanner, to transition through the state machine
+  //   (kScheduled -> kScanning (ctor) -> kSweepingAndFinishing (dtor).
+  template <Context context>
+  class SyncScope final {
+   public:
+    explicit SyncScope(PCScanTask& task) : task_(task) {
+      task_.number_of_scanning_threads_.fetch_add(1, std::memory_order_relaxed);
+      if (context == Context::kScanner) {
+        // Publish the change of the state so that the mutators can join
+        // scanning and expect the consistent state.
+        task_.pcscan_.state_.store(PCScan::State::kScanning,
+                                   std::memory_order_release);
+      }
+    }
+    ~SyncScope() {
+      // First, notify other scanning threads that this thread is done.
+      NotifyThreads();
+      if (context == Context::kScanner) {
+        // The scanner thread must wait here until all safepoints leave.
+        // Otherwise, sweeping may free a page that can be accessed by a
+        // descheduled mutator.
+        WaitForOtherThreads();
+      }
+    }
+
+   private:
+    void NotifyThreads() {
+      {
+        // The lock is required as otherwise there is a race between
+        // fetch_sub/notify in the mutator and checking
+        // number_of_scanning_threads_/waiting in the scanner.
+        std::lock_guard<std::mutex> lock(task_.mutex_);
+        task_.number_of_scanning_threads_.fetch_sub(1,
+                                                    std::memory_order_relaxed);
+        {
+          // Notify that scan is done and there is no need to enter
+          // the safepoint. This also helps a mutator to avoid repeating
+          // entering. Since the scanner thread waits for all threads to finish,
+          // there is no ABA problem here. There is technically no need to have
+          // CAS here, since |state_| is under the mutex and can only be changed
+          // here, but we keep it for safety.
+          PCScan::State expected = PCScan::State::kScanning;
+          task_.pcscan_.state_.compare_exchange_strong(
+              expected, PCScan::State::kSweepingAndFinishing,
+              std::memory_order_relaxed, std::memory_order_relaxed);
+        }
+      }
+      task_.condvar_.notify_all();
+    }
+
+    void WaitForOtherThreads() {
+      std::unique_lock<std::mutex> lock(task_.mutex_);
+      task_.condvar_.wait(lock, [this] {
+        return !task_.number_of_scanning_threads_.load(
+            std::memory_order_relaxed);
+      });
+    }
+
+    PCScanTask& task_;
+  };
+
+  friend class base::RefCountedThreadSafe<PCScanTask>;
+  ~PCScanTask() = default;
+
+  template <typename LookupPolicy>
+  ALWAYS_INLINE QuarantineBitmap* TryFindScannerBitmapForPointer(
+      uintptr_t maybe_ptr) const;
+
+  // Lookup and marking functions. Return size of the object if marked or zero
+  // otherwise.
+  template <typename LookupPolicy>
+  ALWAYS_INLINE size_t TryMarkObjectInNormalBuckets(uintptr_t maybe_ptr) const;
+
+  // Scans stack, only called from safepoints.
+  void ScanStack();
+
+  // Scans all registered partitions and marks reachable quarantined objects.
+  void ScanPartitions();
+
+  // Clear quarantined objects and prepare card table for fast lookup
+  void ClearQuarantinedObjectsAndPrepareCardTable();
+
+  // Sweeps (frees) unreachable quarantined entries. Returns the size of swept
+  // objects.
+  void SweepQuarantine();
+
+  // Finishes the scanner (updates limits, UMA, etc).
+  void FinishScanner();
+
+  // Cache the pcscan epoch to avoid the compiler loading the atomic
+  // QuarantineData::epoch_ on each access.
+  const size_t pcscan_epoch_;
+  PCScanSnapshot snapshot_;
+  StatsCollector stats_;
+  // Mutex and codvar that are used to synchronize scanning threads.
+  std::mutex mutex_;
+  std::condition_variable condvar_;
+  std::atomic<size_t> number_of_scanning_threads_{0u};
+  PCScan& pcscan_;
+};
+
+template <typename LookupPolicy>
+ALWAYS_INLINE QuarantineBitmap* PCScanTask::TryFindScannerBitmapForPointer(
+    uintptr_t maybe_ptr) const {
+  // First, check if |maybe_ptr| points to a valid super page or a quarantined
+  // card.
+  LookupPolicy lookup{snapshot_};
+  if (LIKELY(!lookup.TestOnHeapPointer(maybe_ptr)))
+    return nullptr;
+  // Check if we are not pointing to metadata/guard pages.
+  if (!IsWithinSuperPagePayload(reinterpret_cast<char*>(maybe_ptr),
+                                true /*with quarantine*/))
+    return nullptr;
+  // We are certain here that |maybe_ptr| points to the super page payload.
+  return QuarantineBitmapFromPointer(QuarantineBitmapType::kScanner,
+                                     pcscan_epoch_,
+                                     reinterpret_cast<char*>(maybe_ptr));
+}
+
+// Looks up and marks a potential dangling pointer. Returns the size of the slot
+// (which is then accounted as quarantined) or zero if no object is found.
+// For normal bucket super pages, PCScan uses two quarantine bitmaps, the
+// mutator and the scanner one. The former is used by mutators when objects are
+// freed, while the latter is used concurrently by the PCScan thread. The
+// bitmaps are swapped as soon as PCScan is triggered. Once a dangling pointer
+// (which points to an object in the scanner bitmap) is found,
+// TryMarkObjectInNormalBuckets() marks it again in the bitmap and clears
+// from the scanner bitmap. This way, when scanning is done, all uncleared
+// entries in the scanner bitmap correspond to unreachable objects.
+template <typename LookupPolicy>
+ALWAYS_INLINE size_t
+PCScanTask::TryMarkObjectInNormalBuckets(uintptr_t maybe_ptr) const {
+  // TODO(bartekn): Add a "is in normal buckets" DCHECK in the |else| case.
+  using AccessType = QuarantineBitmap::AccessType;
+  // Check if |maybe_ptr| points somewhere to the heap.
+  auto* scanner_bitmap =
+      TryFindScannerBitmapForPointer<LookupPolicy>(maybe_ptr);
+  if (!scanner_bitmap)
+    return 0;
+
+  auto* root =
+      Root::FromPointerInNormalBuckets(reinterpret_cast<char*>(maybe_ptr));
+
+  // Check if pointer was in the quarantine bitmap.
+  const uintptr_t base = GetObjectStartInSuperPage(maybe_ptr, *root);
+  if (!base || !scanner_bitmap->template CheckBit<AccessType::kAtomic>(base))
+    return 0;
+
+  PA_DCHECK((maybe_ptr & kSuperPageBaseMask) == (base & kSuperPageBaseMask));
+
+  auto* target_slot_span =
+      SlotSpan::FromSlotInnerPtr(reinterpret_cast<void*>(base));
+  PA_DCHECK(root == Root::FromSlotSpan(target_slot_span));
+
+  const size_t usable_size = target_slot_span->GetUsableSize(root);
+  // Range check for inner pointers.
+  if (maybe_ptr >= base + usable_size)
+    return 0;
+
+  // Now we are certain that |maybe_ptr| is a dangling pointer. Mark it again in
+  // the mutator bitmap and clear from the scanner bitmap. Note that since
+  // PCScan has exclusive access to the scanner bitmap, we can avoid atomic rmw
+  // operation for it.
+  scanner_bitmap->template ClearBit<AccessType::kAtomic>(base);
+  QuarantineBitmapFromPointer(QuarantineBitmapType::kMutator, pcscan_epoch_,
+                              reinterpret_cast<char*>(base))
+      ->template SetBit<AccessType::kAtomic>(base);
+  return target_slot_span->bucket->slot_size;
+}
+
+void PCScanTask::ClearQuarantinedObjectsAndPrepareCardTable() {
+  using AccessType = QuarantineBitmap::AccessType;
+
+  const bool giga_cage_enabled = features::IsPartitionAllocGigaCageEnabled();
+  PCScanSnapshot::SuperPagesWorklist::RandomizedView super_pages(
+      snapshot_.quarantinable_super_pages_worklist());
+  super_pages.Visit([this, giga_cage_enabled](uintptr_t super_page_base) {
+    auto* bitmap = QuarantineBitmapFromPointer(
+        QuarantineBitmapType::kScanner, pcscan_epoch_,
+        reinterpret_cast<char*>(super_page_base));
+    auto* root = Root::FromSuperPage(reinterpret_cast<char*>(super_page_base));
+    bitmap->template Iterate<AccessType::kNonAtomic>(
+        [root, giga_cage_enabled](uintptr_t ptr) {
+          auto* object = reinterpret_cast<void*>(ptr);
+          auto* slot_span = SlotSpan::FromSlotInnerPtr(object);
+          // Use zero as a zapping value to speed up the fast bailout check in
+          // ScanPartitions.
+          const size_t size = slot_span->GetUsableSize(root);
+          memset(object, 0, size);
+#if defined(PA_HAS_64_BITS_POINTERS)
+          if (giga_cage_enabled) {
+            // Set card(s) for this quarantined object.
+            QuarantineCardTable::GetFrom(ptr).Quarantine(ptr, size);
+          }
+#else
+          (void)giga_cage_enabled;
+#endif
+        });
+  });
+}
+
+// Class used to perform actual scanning. Dispatches at runtime based on
+// supported SIMD extensions.
+class PCScanTask::ScanLoop final {
+ public:
+  explicit ScanLoop(const PCScanTask& pcscan_task)
+      : scan_function_(GetScanFunction()),
+        pcscan_task_(pcscan_task)
+#if defined(PA_HAS_64_BITS_POINTERS)
+        ,
+        brp_pool_base_(PartitionAddressSpace::BRPPoolBase())
+#endif
+  {
+  }
+
+  ScanLoop(const ScanLoop&) = delete;
+  ScanLoop& operator=(const ScanLoop&) = delete;
+
+  // Scans a range of addresses and marks reachable quarantined objects. Returns
+  // the size of marked objects. The function race-fully reads the heap and
+  // therefore TSAN is disabled for the dispatch functions.
+  size_t Run(uintptr_t* begin, uintptr_t* end) const {
+    static_assert(alignof(uintptr_t) % alignof(void*) == 0,
+                  "Alignment of uintptr_t must be at least as strict as "
+                  "alignment of a pointer type.");
+    return (this->*scan_function_)(begin, end);
+  }
+
+ private:
+  // This is to support polymorphic behavior and to avoid virtual calls.
+  using ScanFunction = size_t (ScanLoop::*)(uintptr_t*, uintptr_t*) const;
+
+  static ScanFunction GetScanFunction() {
+    if (UNLIKELY(!features::IsPartitionAllocGigaCageEnabled())) {
+      return &ScanLoop::RunUnvectorizedNoGigaCage;
+    }
+// We allow vectorization only for 64bit since they require support of the
+// 64bit GigaCage, and only for x86 because a special instruction set is
+// required.
+#if defined(ARCH_CPU_X86_64)
+    const PCScanInternal::SimdSupport simd =
+        PCScanInternal::Instance().simd_support();
+    if (simd == PCScanInternal::SimdSupport::kAVX2)
+      return &ScanLoop::RunAVX2;
+    if (simd == PCScanInternal::SimdSupport::kSSE41)
+      return &ScanLoop::RunSSE4;
+#endif
+    return &ScanLoop::RunUnvectorized;
+  }
+
+#if defined(PA_HAS_64_BITS_POINTERS)
+  ALWAYS_INLINE bool IsInBRPPool(uintptr_t maybe_ptr) const {
+    return (maybe_ptr & PartitionAddressSpace::BRPPoolBaseMask()) ==
+           brp_pool_base_;
+  }
+#endif
+
+#if defined(ARCH_CPU_X86_64)
+  __attribute__((target("sse4.1"))) NO_SANITIZE("thread") size_t
+      RunSSE4(uintptr_t* begin, uintptr_t* end) const {
+    static constexpr size_t kAlignmentRequirement = 16;
+    static constexpr size_t kWordsInVector = 2;
+    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % kAlignmentRequirement));
+    PA_DCHECK(
+        !((reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin)) %
+          kAlignmentRequirement));
+    const __m128i vbase = _mm_set1_epi64x(brp_pool_base_);
+    const __m128i cage_mask =
+        _mm_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask());
+
+    size_t quarantine_size = 0;
+    for (uintptr_t* payload = begin; payload < end; payload += kWordsInVector) {
+      const __m128i maybe_ptrs =
+          _mm_loadu_si128(reinterpret_cast<__m128i*>(payload));
+      const __m128i vand = _mm_and_si128(maybe_ptrs, cage_mask);
+      const __m128i vcmp = _mm_cmpeq_epi64(vand, vbase);
+      const int mask = _mm_movemask_pd(_mm_castsi128_pd(vcmp));
+      if (LIKELY(!mask))
+        continue;
+      // It's important to extract pointers from the already loaded vector to
+      // avoid racing with the mutator.
+      // Once BRP check passes, we know we're dealing with normal buckets.
+      if (mask & 0b01) {
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm_cvtsi128_si64(maybe_ptrs));
+      }
+      if (mask & 0b10) {
+        // Extraction intrinsics for qwords are only supported in SSE4.1, so
+        // instead we reshuffle dwords with pshufd. The mask is used to move the
+        // 4th and 3rd dwords into the second and first position.
+        static constexpr int kSecondWordMask = (3 << 2) | (2 << 0);
+        const __m128i shuffled = _mm_shuffle_epi32(maybe_ptrs, kSecondWordMask);
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm_cvtsi128_si64(shuffled));
+      }
+    }
+    return quarantine_size;
+  }
+
+  __attribute__((target("avx2"))) NO_SANITIZE("thread") size_t
+      RunAVX2(uintptr_t* begin, uintptr_t* end) const {
+    static constexpr size_t kAlignmentRequirement = 32;
+    static constexpr size_t kWordsInVector = 4;
+    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % kAlignmentRequirement));
+    // For AVX2, stick to integer instructions. This brings slightly better
+    // throughput. For example, according to the Intel docs, on Broadwell and
+    // Haswell the CPI of vmovdqa (_mm256_load_si256) is twice smaller (0.25)
+    // than that of vmovapd (_mm256_load_pd).
+    const __m256i vbase = _mm256_set1_epi64x(brp_pool_base_);
+    const __m256i cage_mask =
+        _mm256_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask());
+
+    size_t quarantine_size = 0;
+    uintptr_t* payload = begin;
+    for (; payload < (end - kWordsInVector); payload += kWordsInVector) {
+      const __m256i maybe_ptrs =
+          _mm256_load_si256(reinterpret_cast<__m256i*>(payload));
+      const __m256i vand = _mm256_and_si256(maybe_ptrs, cage_mask);
+      const __m256i vcmp = _mm256_cmpeq_epi64(vand, vbase);
+      const int mask = _mm256_movemask_pd(_mm256_castsi256_pd(vcmp));
+      if (LIKELY(!mask))
+        continue;
+      // It's important to extract pointers from the already loaded vector to
+      // avoid racing with the mutator.
+      // Once BRP check passes, we know we're dealing with normal buckets.
+      if (mask & 0b0001)
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm256_extract_epi64(maybe_ptrs, 0));
+      if (mask & 0b0010)
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm256_extract_epi64(maybe_ptrs, 1));
+      if (mask & 0b0100)
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm256_extract_epi64(maybe_ptrs, 2));
+      if (mask & 0b1000)
+        quarantine_size +=
+            pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+                _mm256_extract_epi64(maybe_ptrs, 3));
+    }
+
+    quarantine_size += RunUnvectorized(payload, end);
+    return quarantine_size;
+  }
+#endif  // defined(ARCH_CPU_X86_64)
+
+  ALWAYS_INLINE NO_SANITIZE("thread") size_t
+      RunUnvectorized(uintptr_t* begin, uintptr_t* end) const {
+    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t)));
+    size_t quarantine_size = 0;
+    for (; begin < end; ++begin) {
+      uintptr_t maybe_ptr = *begin;
+#if defined(PA_HAS_64_BITS_POINTERS)
+      // On 64bit architectures, call IsInBRPPool instead of
+      // IsManagedByPartitionAllocBRPPool to avoid redundant loads of
+      // PartitionAddressSpace::brp_pool_base_address_.
+      if (LIKELY(!IsInBRPPool(maybe_ptr)))
+        continue;
+        // Once BRP check passes, we know we're dealing with normal buckets.
+#endif
+      quarantine_size +=
+          pcscan_task_.TryMarkObjectInNormalBuckets<GigaCageLookupPolicy>(
+              maybe_ptr);
+    }
+    return quarantine_size;
+  }
+
+  ALWAYS_INLINE NO_SANITIZE("thread") size_t
+      RunUnvectorizedNoGigaCage(uintptr_t* begin, uintptr_t* end) const {
+    PA_DCHECK(!(reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t)));
+    size_t quarantine_size = 0;
+    for (; begin < end; ++begin) {
+      uintptr_t maybe_ptr = *begin;
+      if (!maybe_ptr)
+        continue;
+      quarantine_size +=
+          pcscan_task_.TryMarkObjectInNormalBuckets<NoGigaCageLookupPolicy>(
+              maybe_ptr);
+    }
+    return quarantine_size;
+  }
+
+  const ScanFunction scan_function_;
+  const PCScanTask& pcscan_task_;
+#if defined(PA_HAS_64_BITS_POINTERS)
+  // Keep this a constant so that the compiler can remove redundant loads for
+  // the base of the BRP pool and hoist them out of the loops.
+  const uintptr_t brp_pool_base_;
+#endif
+};
+
+class PCScanTask::StackVisitor final : public internal::StackVisitor {
+ public:
+  explicit StackVisitor(const PCScanTask& task) : task_(task) {}
+
+  void VisitStack(uintptr_t* stack_ptr, uintptr_t* stack_top) override {
+    static constexpr size_t kMinimalAlignment = 32;
+    stack_ptr = reinterpret_cast<uintptr_t*>(
+        reinterpret_cast<uintptr_t>(stack_ptr) & ~(kMinimalAlignment - 1));
+    stack_top = reinterpret_cast<uintptr_t*>(
+        (reinterpret_cast<uintptr_t>(stack_top) + kMinimalAlignment - 1) &
+        ~(kMinimalAlignment - 1));
+    PA_CHECK(stack_ptr < stack_top);
+    ScanLoop loop(task_);
+    quarantine_size_ += loop.Run(stack_ptr, stack_top);
+  }
+
+  // Returns size of quarantined objects that are reachable from the current
+  // stack.
+  size_t quarantine_size() const { return quarantine_size_; }
+
+ private:
+  const PCScanTask& task_;
+  size_t quarantine_size_ = 0;
+};
+
+PCScanTask::PCScanTask(PCScan& pcscan)
+    : pcscan_epoch_(pcscan.epoch()),
+      stats_(PCScanInternal::Instance().process_name()),
+      pcscan_(pcscan) {}
+
+void PCScanTask::ScanStack() {
+  const auto& pcscan = PCScanInternal::Instance();
+  if (!pcscan.IsStackScanningEnabled())
+    return;
+  // Check if the stack top was registered. It may happen that it's not if the
+  // current allocation happens from pthread trampolines.
+  void* stack_top = pcscan.GetCurrentThreadStackTop();
+  if (UNLIKELY(!stack_top))
+    return;
+
+  Stack stack_scanner(stack_top);
+  StackVisitor visitor(*this);
+  stack_scanner.IteratePointers(&visitor);
+  stats_.IncreaseSurvivedQuarantineSize(visitor.quarantine_size());
+}
+
+void PCScanTask::ScanPartitions() {
+  const ScanLoop scan_loop(*this);
+  // For scanning large areas, it's worthwhile checking whether the range that
+  // is scanned contains quarantined objects.
+  size_t quarantine_size = 0;
+
+  // Scan areas with large slots.
+  PCScanSnapshot::LargeScanAreasWorklist::RandomizedView large_scan_areas(
+      snapshot_.large_scan_areas_worklist());
+  large_scan_areas.Visit([this, &scan_loop, &quarantine_size](auto scan_area) {
+    // The bitmap is (a) always guaranteed to exist and (b) the same for all
+    // objects in a given slot span.
+    // TODO(chromium:1129751): Check mutator bitmap as well if performance
+    // allows.
+    auto* bitmap = QuarantineBitmapFromPointer(
+        QuarantineBitmapType::kScanner, pcscan_epoch_,
+        reinterpret_cast<char*>(scan_area.begin));
+    for (uintptr_t* current_slot = scan_area.begin;
+         current_slot < scan_area.end;
+         current_slot += (scan_area.slot_size / sizeof(uintptr_t))) {
+      // It is okay to skip objects as their payload has been zapped at this
+      // point which means that the pointers no longer retain other objects.
+      if (bitmap->CheckBit(reinterpret_cast<uintptr_t>(current_slot))) {
+        continue;
+      }
+      uintptr_t* current_slot_end =
+          current_slot + (scan_area.slot_size / sizeof(uintptr_t));
+      PA_DCHECK(current_slot_end <= scan_area.end);
+      quarantine_size += scan_loop.Run(current_slot, current_slot_end);
+    }
+  });
+
+  // Scan areas with regular size slots.
+  PCScanSnapshot::ScanAreasWorklist::RandomizedView scan_areas(
+      snapshot_.scan_areas_worklist());
+  scan_areas.Visit([&scan_loop, &quarantine_size](auto scan_area) {
+    quarantine_size += scan_loop.Run(scan_area.begin, scan_area.end);
+  });
+
+  stats_.IncreaseSurvivedQuarantineSize(quarantine_size);
+}
+
+void PCScanTask::SweepQuarantine() {
+  using AccessType = QuarantineBitmap::AccessType;
+
+  const bool giga_cage_enabled = features::IsPartitionAllocGigaCageEnabled();
+  size_t swept_bytes = 0;
+
+  for (uintptr_t super_page : snapshot_.quarantinable_super_pages()) {
+    auto* bitmap = QuarantineBitmapFromPointer(
+        QuarantineBitmapType::kScanner, pcscan_epoch_,
+        reinterpret_cast<char*>(super_page));
+    auto* root = Root::FromSuperPage(reinterpret_cast<char*>(super_page));
+    bitmap->template IterateAndClear<AccessType::kNonAtomic>(
+        [root, giga_cage_enabled, &swept_bytes](uintptr_t ptr) {
+          auto* object = reinterpret_cast<void*>(ptr);
+          auto* slot_span = SlotSpan::FromSlotInnerPtr(object);
+          swept_bytes += slot_span->bucket->slot_size;
+          root->FreeNoHooksImmediate(object, slot_span);
+#if defined(PA_HAS_64_BITS_POINTERS)
+          if (giga_cage_enabled) {
+            // Reset card(s) for this quarantined object. Please note that the
+            // cards may still contain quarantined objects (which were promoted
+            // in this scan cycle), but
+            // ClearQuarantinedObjectsAndFilterSuperPages() will set them again
+            // in the next PCScan cycle.
+            QuarantineCardTable::GetFrom(ptr).Unquarantine(
+                ptr, slot_span->GetUsableSize(root));
+          }
+#else
+          (void)giga_cage_enabled;
+#endif
+        });
+  }
+
+  stats_.IncreaseSweptSize(swept_bytes);
+
+#if defined(PA_THREAD_CACHE_SUPPORTED)
+  // Sweeping potentially frees into the current thread's thread cache. Purge
+  // releases the cache back to the global allocator.
+  auto* current_thread_tcache = ThreadCache::Get();
+  if (ThreadCache::IsValid(current_thread_tcache))
+    current_thread_tcache->Purge();
+#endif  // defined(PA_THREAD_CACHE_SUPPORTED)
+}
+
+void PCScanTask::FinishScanner() {
+  stats_.ReportTracesAndHists();
+  LogStats(
+      stats_.swept_size(),
+      pcscan_.scheduler_.scheduling_backend().GetQuarantineData().last_size,
+      stats_.survived_quarantine_size());
+
+  pcscan_.scheduler_.scheduling_backend().UpdateScheduleAfterScan(
+      stats_.survived_quarantine_size(), stats_.GetOverallTime(),
+      PCScanInternal::Instance().CalculateTotalHeapSize());
+
+  PCScanInternal::Instance().ResetCurrentPCScanTask();
+  // Check that concurrent task can't be scheduled twice.
+  PA_CHECK(pcscan_.state_.exchange(PCScan::State::kNotRunning,
+                                   std::memory_order_acq_rel) ==
+           PCScan::State::kSweepingAndFinishing);
+}
+
+void PCScanTask::RunFromMutator() {
+  ReentrantScannerGuard reentrancy_guard;
+  StatsCollector::MutatorScope overall_scope(
+      stats_, StatsCollector::MutatorId::kOverall);
+  {
+    SyncScope<Context::kMutator> sync_scope(*this);
+    // Mutator might start entering the safepoint while scanning was already
+    // finished.
+    if (!pcscan_.IsJoinable())
+      return;
+    // Take snapshot of partition-alloc heap if not yet taken.
+    snapshot_.EnsureTaken(pcscan_epoch_);
+    {
+      // Clear all quarantined objects and prepare card table.
+      StatsCollector::MutatorScope clear_scope(
+          stats_, StatsCollector::MutatorId::kClear);
+      ClearQuarantinedObjectsAndPrepareCardTable();
+    }
+    {
+      // Scan the thread's stack to find dangling references.
+      StatsCollector::MutatorScope scan_scope(
+          stats_, StatsCollector::MutatorId::kScanStack);
+      ScanStack();
+    }
+    {
+      // Scan heap for dangling references.
+      StatsCollector::MutatorScope scan_scope(stats_,
+                                              StatsCollector::MutatorId::kScan);
+      ScanPartitions();
+    }
+  }
+}
+
+void PCScanTask::RunFromScanner() {
+  ReentrantScannerGuard reentrancy_guard;
+  {
+    StatsCollector::ScannerScope overall_scope(
+        stats_, StatsCollector::ScannerId::kOverall);
+    {
+      SyncScope<Context::kScanner> sync_scope(*this);
+      // Take snapshot of partition-alloc heap.
+      snapshot_.EnsureTaken(pcscan_epoch_);
+      {
+        // Clear all quarantined objects and prepare the card table.
+        StatsCollector::ScannerScope clear_scope(
+            stats_, StatsCollector::ScannerId::kClear);
+        ClearQuarantinedObjectsAndPrepareCardTable();
+      }
+      {
+        // Scan heap for dangling references.
+        StatsCollector::ScannerScope scan_scope(
+            stats_, StatsCollector::ScannerId::kScan);
+        ScanPartitions();
+      }
+    }
+    {
+      // Sweep unreachable quarantined objects.
+      StatsCollector::ScannerScope sweep_scope(
+          stats_, StatsCollector::ScannerId::kSweep);
+      SweepQuarantine();
+    }
+  }
+  FinishScanner();
+}
+
+class PCScan::PCScanThread final {
+ public:
+  using TaskHandle = PCScanInternal::TaskHandle;
+
+  static PCScanThread& Instance() {
+    // Lazily instantiate the scanning thread.
+    static base::NoDestructor<PCScanThread> instance;
+    return *instance;
+  }
+
+  void PostTask(TaskHandle task) {
+    {
+      std::lock_guard<std::mutex> lock(mutex_);
+      PA_DCHECK(!posted_task_.get());
+      posted_task_ = std::move(task);
+      wanted_delay_ = TimeDelta();
+    }
+    condvar_.notify_one();
+  }
+
+  void PostDelayedTask(TimeDelta delay) {
+    {
+      std::lock_guard<std::mutex> lock(mutex_);
+      if (posted_task_.get()) {
+        return;
+      }
+      wanted_delay_ = delay;
+    }
+    condvar_.notify_one();
+  }
+
+ private:
+  friend class base::NoDestructor<PCScanThread>;
+
+  PCScanThread() {
+    std::thread{[this] {
+      static constexpr const char* kThreadName = "PCScan";
+      // Ideally we should avoid mixing base:: and std:: API for threading, but
+      // this is useful for visualizing the pcscan thread in chrome://tracing.
+      base::PlatformThread::SetName(kThreadName);
+      TaskLoop();
+    }}.detach();
+  }
+
+  // Waits and returns whether the delay should be recomputed.
+  bool Wait(std::unique_lock<std::mutex>& lock) {
+    PA_DCHECK(lock.owns_lock());
+    if (wanted_delay_.is_zero()) {
+      condvar_.wait(lock, [this] {
+        // Re-evaluate if either delay changed, or a task was
+        // enqueued.
+        return !wanted_delay_.is_zero() || posted_task_.get();
+      });
+      // The delay has already been set up and should not be queried again.
+      return false;
+    }
+    condvar_.wait_for(
+        lock, std::chrono::microseconds(wanted_delay_.InMicroseconds()));
+    // If no task has been posted, the delay should be recomputed at this point.
+    return !posted_task_.get();
+  }
+
+  void TaskLoop() {
+    while (true) {
+      TaskHandle current_task;
+      {
+        std::unique_lock<std::mutex> lock(mutex_);
+        // Scheduling.
+        while (!posted_task_.get()) {
+          if (Wait(lock)) {
+            wanted_delay_ =
+                scheduler().scheduling_backend().UpdateDelayedSchedule();
+            if (wanted_delay_.is_zero()) {
+              break;
+            }
+          }
+        }
+        // Differentiate between a posted task and a delayed task schedule.
+        if (posted_task_.get()) {
+          std::swap(current_task, posted_task_);
+          wanted_delay_ = TimeDelta();
+        } else {
+          PA_DCHECK(wanted_delay_.is_zero());
+        }
+      }
+      // Differentiate between a posted task and a delayed task schedule.
+      if (current_task.get()) {
+        current_task->RunFromScanner();
+      } else {
+        PCScan::Instance().PerformScan(PCScan::InvocationMode::kNonBlocking);
+      }
+    }
+  }
+
+  PCScanScheduler& scheduler() const { return PCScan::Instance().scheduler(); }
+
+  std::mutex mutex_;
+  std::condition_variable condvar_;
+  TaskHandle posted_task_;
+  TimeDelta wanted_delay_;
+};
+
+void PCScanInternal::Roots::Add(Root* root) {
+  PA_CHECK(std::find(begin(), end(), root) == end());
+  (*this)[current_] = root;
+  ++current_;
+  PA_CHECK(current_ != kMaxNumberOfRoots)
+      << "Exceeded number of allowed partition roots";
+}
+
+void PCScanInternal::Roots::ClearForTesting() {
+  std::fill(begin(), end(), nullptr);
+  current_ = 0;
+}
+
+PCScanInternal::PCScanInternal() : simd_support_(DetectSimdSupport()) {}
+
+PCScanInternal::~PCScanInternal() = default;
+
+void PCScanInternal::Initialize() {
+  PA_DCHECK(!is_initialized_);
+  CommitCardTable();
+  is_initialized_ = true;
+}
+
+void PCScanInternal::PerformScan(PCScan::InvocationMode invocation_mode) {
+#if DCHECK_IS_ON()
+  PA_DCHECK(is_initialized());
+  PA_DCHECK(scannable_roots().size() > 0);
+  PA_DCHECK(std::all_of(scannable_roots().begin(), scannable_roots().end(),
+                        [](Root* root) { return root->IsScanEnabled(); }));
+  PA_DCHECK(
+      std::all_of(nonscannable_roots().begin(), nonscannable_roots().end(),
+                  [](Root* root) { return root->IsQuarantineEnabled(); }));
+#endif
+
+  PCScan& frontend = PCScan::Instance();
+  {
+    // If scanning is already in progress, bail out.
+    PCScan::State expected = PCScan::State::kNotRunning;
+    if (!frontend.state_.compare_exchange_strong(
+            expected, PCScan::State::kScheduled, std::memory_order_acq_rel,
+            std::memory_order_relaxed))
+      return;
+  }
+
+  frontend.scheduler_.scheduling_backend().ScanStarted();
+
+  // Create PCScan task and set it as current.
+  auto task = base::MakeRefCounted<PCScanTask>(frontend);
+  PCScanInternal::Instance().SetCurrentPCScanTask(task);
+
+  if (UNLIKELY(invocation_mode ==
+               PCScan::InvocationMode::kScheduleOnlyForTesting)) {
+    // Immediately change the state to enable safepoint testing.
+    frontend.state_.store(PCScan::State::kScanning, std::memory_order_release);
+    return;
+  }
+
+  // Post PCScan task.
+  if (LIKELY(invocation_mode == PCScan::InvocationMode::kNonBlocking)) {
+    PCScan::PCScanThread::Instance().PostTask(std::move(task));
+  } else {
+    PA_DCHECK(PCScan::InvocationMode::kBlocking == invocation_mode ||
+              PCScan::InvocationMode::kForcedBlocking == invocation_mode);
+    std::move(*task).RunFromScanner();
+  }
+}
+
+void PCScanInternal::PerformScanIfNeeded(
+    PCScan::InvocationMode invocation_mode) {
+  if (!scannable_roots().size())
+    return;
+  PCScan& frontend = PCScan::Instance();
+  if (invocation_mode == PCScan::InvocationMode::kForcedBlocking ||
+      frontend.scheduler_.scheduling_backend()
+          .GetQuarantineData()
+          .MinimumScanningThresholdReached())
+    PerformScan(invocation_mode);
+}
+
+void PCScanInternal::PerformDelayedScan(TimeDelta delay) {
+  PCScan::PCScanThread::Instance().PostDelayedTask(delay);
+}
+
+void PCScanInternal::JoinScan() {
+#if !PCSCAN_DISABLE_SAFEPOINTS
+  // Current task can be destroyed by the scanner. Check that it's valid.
+  if (auto current_task = CurrentPCScanTask())
+    current_task->RunFromMutator();
+#endif
+}
+
+PCScanInternal::TaskHandle PCScanInternal::CurrentPCScanTask() const {
+  std::lock_guard<std::mutex> lock(current_task_mutex_);
+  return current_task_;
+}
+
+void PCScanInternal::SetCurrentPCScanTask(TaskHandle task) {
+  std::lock_guard<std::mutex> lock(current_task_mutex_);
+  current_task_ = std::move(task);
+}
+
+void PCScanInternal::ResetCurrentPCScanTask() {
+  std::lock_guard<std::mutex> lock(current_task_mutex_);
+  current_task_.reset();
+}
+
+void PCScanInternal::RegisterScannableRoot(Root* root) {
+  PA_DCHECK(is_initialized());
+  PA_DCHECK(root);
+  PA_CHECK(root->IsQuarantineAllowed());
+  typename Root::ScopedGuard guard(root->lock_);
+  if (root->IsScanEnabled())
+    return;
+  PA_CHECK(!root->IsQuarantineEnabled());
+  CommitQuarantineBitmaps(*root);
+  root->scan_mode = Root::ScanMode::kEnabled;
+  root->quarantine_mode = Root::QuarantineMode::kEnabled;
+  scannable_roots_.Add(root);
+}
+
+void PCScanInternal::RegisterNonScannableRoot(Root* root) {
+  PA_DCHECK(is_initialized());
+  PA_DCHECK(root);
+  PA_CHECK(root->IsQuarantineAllowed());
+  typename Root::ScopedGuard guard(root->lock_);
+  if (root->IsQuarantineEnabled())
+    return;
+  CommitQuarantineBitmaps(*root);
+  root->quarantine_mode = Root::QuarantineMode::kEnabled;
+  nonscannable_roots_.Add(root);
+}
+
+void PCScanInternal::SetProcessName(const char* process_name) {
+  PA_DCHECK(is_initialized());
+  PA_DCHECK(process_name);
+  PA_DCHECK(!process_name_);
+  process_name_ = process_name;
+}
+
+size_t PCScanInternal::CalculateTotalHeapSize() const {
+  PA_DCHECK(is_initialized());
+  const auto acc = [](size_t size, Root* root) {
+    return size + root->get_total_size_of_committed_pages();
+  };
+  return std::accumulate(scannable_roots_.begin(), scannable_roots_.end(), 0u,
+                         acc) +
+         std::accumulate(nonscannable_roots_.begin(), nonscannable_roots_.end(),
+                         0u, acc);
+}
+
+void PCScanInternal::EnableStackScanning() {
+  PA_DCHECK(!stack_scanning_enabled_);
+  stack_scanning_enabled_ = true;
+}
+void PCScanInternal::DisableStackScanning() {
+  PA_DCHECK(stack_scanning_enabled_);
+  stack_scanning_enabled_ = false;
+}
+bool PCScanInternal::IsStackScanningEnabled() const {
+  return stack_scanning_enabled_;
+}
+
+void PCScanInternal::NotifyThreadCreated(void* stack_top) {
+  const auto tid = base::PlatformThread::CurrentId();
+  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
+  const auto res = stack_tops_.insert({tid, stack_top});
+  PA_DCHECK(res.second);
+}
+
+void PCScanInternal::NotifyThreadDestroyed() {
+  const auto tid = base::PlatformThread::CurrentId();
+  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
+  PA_DCHECK(1 == stack_tops_.count(tid));
+  stack_tops_.erase(tid);
+}
+
+void* PCScanInternal::GetCurrentThreadStackTop() const {
+  const auto tid = base::PlatformThread::CurrentId();
+  std::lock_guard<std::mutex> lock(stack_tops_mutex_);
+  auto it = stack_tops_.find(tid);
+  return it != stack_tops_.end() ? it->second : nullptr;
+}
+
+void PCScanInternal::ClearRootsForTesting() {
+  // Set all roots as non-scannable and non-quarantinable.
+  for (auto* root : scannable_roots_) {
+    root->scan_mode = Root::ScanMode::kDisabled;
+    root->quarantine_mode = Root::QuarantineMode::kDisabledByDefault;
+  }
+  for (auto* root : nonscannable_roots_) {
+    root->quarantine_mode = Root::QuarantineMode::kDisabledByDefault;
+  }
+  scannable_roots_.ClearForTesting();     // IN-TEST
+  nonscannable_roots_.ClearForTesting();  // IN-TEST
+}
+
+void PCScanInternal::ReinitForTesting() {
+  is_initialized_ = false;
+  Initialize();
+}
+
+void PCScanInternal::FinishScanForTesting() {
+  auto current_task = CurrentPCScanTask();
+  PA_CHECK(current_task.get());
+  current_task->RunFromScanner();
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.h b/base/allocator/partition_allocator/starscan/pcscan_internal.h
new file mode 100644
index 0000000..6fddf68
--- /dev/null
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.h
@@ -0,0 +1,153 @@
+// Copyright (c) 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_PCSCAN_INTERNAL_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_PCSCAN_INTERNAL_H_
+
+#include <array>
+#include <unordered_map>
+
+#include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
+#include "base/allocator/partition_allocator/starscan/pcscan.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
+
+namespace base {
+
+namespace internal {
+
+class PCScanTask;
+
+// Internal PCScan singleton. The separation between frontend and backend is
+// needed to keep access to the hot data (quarantine) in the frontend fast,
+// whereas the backend can hold cold data.
+class PCScanInternal final {
+ public:
+  using Root = PCScan::Root;
+  using TaskHandle = scoped_refptr<PCScanTask>;
+
+  enum class SimdSupport : uint8_t {
+    kUnvectorized,
+    kSSE41,
+    kAVX2,
+    // TODO(bikineev): Add support for Neon.
+  };
+
+  static constexpr size_t kMaxNumberOfRoots = 8u;
+  class Roots final : private std::array<Root*, kMaxNumberOfRoots> {
+    using Base = std::array<Root*, kMaxNumberOfRoots>;
+
+   public:
+    using typename Base::const_iterator;
+    using typename Base::iterator;
+
+    // Explicitly value-initialize Base{} as otherwise the default
+    // (aggregate) initialization won't be considered as constexpr.
+    constexpr Roots() : Base{} {}
+
+    iterator begin() { return Base::begin(); }
+    const_iterator begin() const { return Base::begin(); }
+
+    iterator end() { return begin() + current_; }
+    const_iterator end() const { return begin() + current_; }
+
+    void Add(Root* root);
+
+    size_t size() const { return current_; }
+
+    void ClearForTesting();  // IN-TEST
+
+   private:
+    size_t current_ = 0u;
+  };
+
+  static PCScanInternal& Instance() {
+    // Since the data that PCScanInternal holds is cold, it's fine to have the
+    // runtime check for thread-safe local static initialization.
+    static base::NoDestructor<PCScanInternal> instance;
+    return *instance;
+  }
+
+  PCScanInternal(const PCScanInternal&) = delete;
+  PCScanInternal& operator=(const PCScanInternal&) = delete;
+
+  ~PCScanInternal();
+
+  void Initialize();
+  bool is_initialized() const { return is_initialized_; }
+
+  void PerformScan(PCScan::InvocationMode);
+  void PerformScanIfNeeded(PCScan::InvocationMode);
+  void PerformDelayedScan(TimeDelta delay);
+  void JoinScan();
+
+  TaskHandle CurrentPCScanTask() const;
+  void SetCurrentPCScanTask(TaskHandle task);
+  void ResetCurrentPCScanTask();
+
+  void RegisterScannableRoot(Root* root);
+  void RegisterNonScannableRoot(Root* root);
+
+  Roots& scannable_roots() { return scannable_roots_; }
+  const Roots& scannable_roots() const { return scannable_roots_; }
+
+  Roots& nonscannable_roots() { return nonscannable_roots_; }
+  const Roots& nonscannable_roots() const { return nonscannable_roots_; }
+
+  void SetProcessName(const char* name);
+  const char* process_name() const { return process_name_; }
+
+  // Get size of all committed pages from scannable and nonscannable roots.
+  size_t CalculateTotalHeapSize() const;
+
+  SimdSupport simd_support() const { return simd_support_; }
+
+  void EnableStackScanning();
+  void DisableStackScanning();
+  bool IsStackScanningEnabled() const;
+
+  void NotifyThreadCreated(void* stack_top);
+  void NotifyThreadDestroyed();
+
+  void* GetCurrentThreadStackTop() const;
+
+  void ClearRootsForTesting();  // IN-TEST
+  void ReinitForTesting();      // IN-TEST
+  void FinishScanForTesting();  // IN-TEST
+
+ private:
+  friend base::NoDestructor<PCScanInternal>;
+
+  using StackTops = std::unordered_map<
+      PlatformThreadId,
+      void*,
+      std::hash<PlatformThreadId>,
+      std::equal_to<>,
+      MetadataAllocator<std::pair<const PlatformThreadId, void*>>>;
+
+  PCScanInternal();
+
+  TaskHandle current_task_;
+  mutable std::mutex current_task_mutex_;
+
+  Roots scannable_roots_{};
+  Roots nonscannable_roots_{};
+
+  bool stack_scanning_enabled_{false};
+  // TLS emulation of stack tops. Since this is guaranteed to go through
+  // non-quarantinable partition, using it from safepoints is safe.
+  StackTops stack_tops_;
+  mutable std::mutex stack_tops_mutex_;
+
+  const char* process_name_ = nullptr;
+  const SimdSupport simd_support_;
+
+  bool is_initialized_ = false;
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_PCSCAN_INTERNAL_H_
diff --git a/base/allocator/partition_allocator/starscan/stats_collector.cc b/base/allocator/partition_allocator/starscan/stats_collector.cc
new file mode 100644
index 0000000..123dd12
--- /dev/null
+++ b/base/allocator/partition_allocator/starscan/stats_collector.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 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 "base/allocator/partition_allocator/starscan/stats_collector.h"
+
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+StatsCollector::StatsCollector(const char* process_name)
+    : process_name_(process_name) {}
+
+StatsCollector::~StatsCollector() = default;
+
+base::TimeDelta StatsCollector::GetOverallTime() const {
+  return GetTimeImpl<Context::kMutator>(mutator_trace_events_,
+                                        MutatorId::kOverall) +
+         GetTimeImpl<Context::kScanner>(scanner_trace_events_,
+                                        ScannerId::kOverall);
+}
+
+void StatsCollector::ReportTracesAndHists() const {
+  ReportTracesAndHistsImpl<Context::kMutator>(mutator_trace_events_);
+  ReportTracesAndHistsImpl<Context::kScanner>(scanner_trace_events_);
+}
+
+template <Context context>
+base::TimeDelta StatsCollector::GetTimeImpl(
+    const DeferredTraceEventMap<context>& event_map,
+    IdType<context> id) const {
+  base::TimeDelta overall;
+  for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
+    const auto& events = tid_and_events.second;
+    const auto& event = events[static_cast<size_t>(id)];
+    overall += (event.end_time - event.start_time);
+  }
+  return overall;
+}
+
+template <Context context>
+void StatsCollector::ReportTracesAndHistsImpl(
+    const DeferredTraceEventMap<context>& event_map) const {
+  std::array<base::TimeDelta, static_cast<size_t>(IdType<context>::kNumIds)>
+      accumulated_events{};
+  // First, report traces and accumulate each trace scope to report UMA hists.
+  for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
+    const PlatformThreadId tid = tid_and_events.first;
+    // TRACE_EVENT_* macros below drop most parameters when tracing is
+    // disabled at compile time.
+    ignore_result(tid);
+    const auto& events = tid_and_events.second;
+    PA_DCHECK(accumulated_events.size() == events.size());
+    for (size_t id = 0; id < events.size(); ++id) {
+      const auto& event = events[id];
+      TRACE_EVENT_BEGIN(kTraceCategory,
+                        perfetto::StaticString(
+                            ToTracingString(static_cast<IdType<context>>(id))),
+                        perfetto::ThreadTrack::ForThread(tid),
+                        event.start_time);
+      TRACE_EVENT_END(kTraceCategory, perfetto::ThreadTrack::ForThread(tid),
+                      event.end_time);
+      accumulated_events[id] += (event.end_time - event.start_time);
+    }
+  }
+  // Report UMA if process_name is set.
+  if (!process_name_)
+    return;
+  for (size_t id = 0; id < accumulated_events.size(); ++id) {
+    if (accumulated_events[id].is_zero())
+      continue;
+    UmaHistogramTimes(ToUMAString(static_cast<IdType<context>>(id)).c_str(),
+                      accumulated_events[id]);
+  }
+}
+
+template base::TimeDelta StatsCollector::GetTimeImpl(
+    const DeferredTraceEventMap<Context::kMutator>&,
+    IdType<Context::kMutator>) const;
+template base::TimeDelta StatsCollector::GetTimeImpl(
+    const DeferredTraceEventMap<Context::kScanner>&,
+    IdType<Context::kScanner>) const;
+
+template void StatsCollector::ReportTracesAndHistsImpl(
+    const DeferredTraceEventMap<Context::kMutator>&) const;
+template void StatsCollector::ReportTracesAndHistsImpl(
+    const DeferredTraceEventMap<Context::kScanner>&) const;
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/allocator/partition_allocator/starscan/stats_collector.h b/base/allocator/partition_allocator/starscan/stats_collector.h
new file mode 100644
index 0000000..464039bf
--- /dev/null
+++ b/base/allocator/partition_allocator/starscan/stats_collector.h
@@ -0,0 +1,274 @@
+// Copyright (c) 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_STATS_COLLECTOR_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_STATS_COLLECTOR_H_
+
+#include <array>
+#include <atomic>
+#include <mutex>
+#include <type_traits>
+#include <unordered_map>
+
+#include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
+
+namespace base {
+namespace internal {
+
+#define FOR_ALL_PCSCAN_SCANNER_SCOPES(V) \
+  V(Clear)                               \
+  V(Scan)                                \
+  V(Sweep)                               \
+  V(Overall)
+
+#define FOR_ALL_PCSCAN_MUTATOR_SCOPES(V) \
+  V(Clear)                               \
+  V(ScanStack)                           \
+  V(Scan)                                \
+  V(Overall)
+
+enum class Context {
+  // For tasks executed from mutator threads (safepoints).
+  kMutator,
+  // For concurrent scanner tasks.
+  kScanner
+};
+
+class StatsCollector final {
+ public:
+  enum class ScannerId {
+#define DECLARE_ENUM(name) k##name,
+    FOR_ALL_PCSCAN_SCANNER_SCOPES(DECLARE_ENUM)
+#undef DECLARE_ENUM
+        kNumIds,
+  };
+
+  enum class MutatorId {
+#define DECLARE_ENUM(name) k##name,
+    FOR_ALL_PCSCAN_MUTATOR_SCOPES(DECLARE_ENUM)
+#undef DECLARE_ENUM
+        kNumIds,
+  };
+
+  template <Context context>
+  using IdType =
+      std::conditional_t<context == Context::kMutator, MutatorId, ScannerId>;
+
+  // We don't immediately trace events, but instead defer it until scanning is
+  // done. This is needed to avoid unpredictable work that can be done by traces
+  // (e.g. recursive mutex lock).
+  struct DeferredTraceEvent {
+    base::TimeTicks start_time;
+    base::TimeTicks end_time;
+  };
+
+  // Thread-safe hash-map that maps thread id to scanner events. Doesn't
+  // accumulate events, i.e. every event can only be registered once.
+  template <Context context>
+  class DeferredTraceEventMap final {
+   public:
+    using IdType = StatsCollector::IdType<context>;
+    using PerThreadEvents =
+        std::array<DeferredTraceEvent, static_cast<size_t>(IdType::kNumIds)>;
+    using UnderlyingMap = std::unordered_map<
+        PlatformThreadId,
+        PerThreadEvents,
+        std::hash<PlatformThreadId>,
+        std::equal_to<>,
+        MetadataAllocator<std::pair<const PlatformThreadId, PerThreadEvents>>>;
+
+    inline void RegisterBeginEventFromCurrentThread(IdType id);
+    inline void RegisterEndEventFromCurrentThread(IdType id);
+
+    const UnderlyingMap& get_underlying_map_unsafe() const { return events_; }
+
+   private:
+    std::mutex mutex_;
+    UnderlyingMap events_;
+  };
+
+  template <Context context>
+  class Scope final {
+   public:
+    Scope(StatsCollector& stats, IdType<context> type)
+        : stats_(stats), type_(type) {
+      stats_.RegisterBeginEventFromCurrentThread(type);
+    }
+
+    Scope(const Scope&) = delete;
+    Scope& operator=(const Scope&) = delete;
+
+    ~Scope() { stats_.RegisterEndEventFromCurrentThread(type_); }
+
+   private:
+    StatsCollector& stats_;
+    IdType<context> type_;
+  };
+
+  using ScannerScope = Scope<Context::kScanner>;
+  using MutatorScope = Scope<Context::kMutator>;
+
+  explicit StatsCollector(const char* process_name);
+
+  StatsCollector(const StatsCollector&) = delete;
+  StatsCollector& operator=(const StatsCollector&) = delete;
+
+  ~StatsCollector();
+
+  void IncreaseSurvivedQuarantineSize(size_t size) {
+    survived_quarantine_size_.fetch_add(size, std::memory_order_relaxed);
+  }
+  size_t survived_quarantine_size() const {
+    return survived_quarantine_size_.load(std::memory_order_relaxed);
+  }
+
+  void IncreaseSweptSize(size_t size) { swept_size_ += size; }
+  size_t swept_size() const { return swept_size_; }
+
+  base::TimeDelta GetOverallTime() const;
+  void ReportTracesAndHists() const;
+
+ private:
+  using MetadataString =
+      std::basic_string<char, std::char_traits<char>, MetadataAllocator<char>>;
+  static constexpr char kTraceCategory[] = "partition_alloc";
+
+  static constexpr const char* ToTracingString(ScannerId id);
+  static constexpr const char* ToTracingString(MutatorId id);
+
+  MetadataString ToUMAString(ScannerId id) const;
+  MetadataString ToUMAString(MutatorId id) const;
+
+  void RegisterBeginEventFromCurrentThread(MutatorId id) {
+    mutator_trace_events_.RegisterBeginEventFromCurrentThread(id);
+  }
+  void RegisterEndEventFromCurrentThread(MutatorId id) {
+    mutator_trace_events_.RegisterEndEventFromCurrentThread(id);
+  }
+  void RegisterBeginEventFromCurrentThread(ScannerId id) {
+    scanner_trace_events_.RegisterBeginEventFromCurrentThread(id);
+  }
+  void RegisterEndEventFromCurrentThread(ScannerId id) {
+    scanner_trace_events_.RegisterEndEventFromCurrentThread(id);
+  }
+
+  template <Context context>
+  base::TimeDelta GetTimeImpl(const DeferredTraceEventMap<context>& event_map,
+                              IdType<context> id) const;
+
+  template <Context context>
+  void ReportTracesAndHistsImpl(
+      const DeferredTraceEventMap<context>& event_map) const;
+
+  DeferredTraceEventMap<Context::kMutator> mutator_trace_events_;
+  DeferredTraceEventMap<Context::kScanner> scanner_trace_events_;
+
+  std::atomic<size_t> survived_quarantine_size_{0u};
+  size_t swept_size_ = 0u;
+  const char* process_name_ = nullptr;
+};
+
+template <Context context>
+inline void StatsCollector::DeferredTraceEventMap<
+    context>::RegisterBeginEventFromCurrentThread(IdType id) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  const auto tid = base::PlatformThread::CurrentId();
+  const auto now = base::TimeTicks::Now();
+  auto& event_array = events_[tid];
+  auto& event = event_array[static_cast<size_t>(id)];
+  PA_DCHECK(event.start_time.is_null());
+  PA_DCHECK(event.end_time.is_null());
+  event.start_time = now;
+}
+
+template <Context context>
+inline void StatsCollector::DeferredTraceEventMap<
+    context>::RegisterEndEventFromCurrentThread(IdType id) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  const auto tid = base::PlatformThread::CurrentId();
+  const auto now = base::TimeTicks::Now();
+  auto& event_array = events_[tid];
+  auto& event = event_array[static_cast<size_t>(id)];
+  PA_DCHECK(!event.start_time.is_null());
+  PA_DCHECK(event.end_time.is_null());
+  event.end_time = now;
+}
+
+inline constexpr const char* StatsCollector::ToTracingString(ScannerId id) {
+  switch (id) {
+    case ScannerId::kClear:
+      return "PCScan.Scanner.Clear";
+    case ScannerId::kScan:
+      return "PCScan.Scanner.Scan";
+    case ScannerId::kSweep:
+      return "PCScan.Scanner.Sweep";
+    case ScannerId::kOverall:
+      return "PCScan.Scanner";
+    case ScannerId::kNumIds:
+      __builtin_unreachable();
+  }
+}
+
+inline constexpr const char* StatsCollector::ToTracingString(MutatorId id) {
+  switch (id) {
+    case MutatorId::kClear:
+      return "PCScan.Mutator.Clear";
+    case MutatorId::kScanStack:
+      return "PCScan.Mutator.ScanStack";
+    case MutatorId::kScan:
+      return "PCScan.Mutator.Scan";
+    case MutatorId::kOverall:
+      return "PCScan.Mutator";
+    case MutatorId::kNumIds:
+      __builtin_unreachable();
+  }
+}
+
+inline StatsCollector::MetadataString StatsCollector::ToUMAString(
+    ScannerId id) const {
+  PA_DCHECK(process_name_);
+  const MetadataString process_name = process_name_;
+  switch (id) {
+    case ScannerId::kClear:
+      return "PA.PCScan." + process_name + ".Scanner.Clear";
+    case ScannerId::kScan:
+      return "PA.PCScan." + process_name + ".Scanner.Scan";
+    case ScannerId::kSweep:
+      return "PA.PCScan." + process_name + ".Scanner.Sweep";
+    case ScannerId::kOverall:
+      return "PA.PCScan." + process_name + ".Scanner";
+    case ScannerId::kNumIds:
+      __builtin_unreachable();
+  }
+}
+
+inline StatsCollector::MetadataString StatsCollector::ToUMAString(
+    MutatorId id) const {
+  PA_DCHECK(process_name_);
+  const MetadataString process_name = process_name_;
+  switch (id) {
+    case MutatorId::kClear:
+      return "PA.PCScan." + process_name + ".Mutator.Clear";
+    case MutatorId::kScanStack:
+      return "PA.PCScan." + process_name + ".Mutator.ScanStack";
+    case MutatorId::kScan:
+      return "PA.PCScan." + process_name + ".Mutator.Scan";
+    case MutatorId::kOverall:
+      return "PA.PCScan." + process_name + ".Mutator";
+    case MutatorId::kNumIds:
+      __builtin_unreachable();
+  }
+}
+
+#undef FOR_ALL_PCSCAN_MUTATOR_SCOPES
+#undef FOR_ALL_PCSCAN_SCANNER_SCOPES
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_STATS_COLLECTOR_H_
diff --git a/base/feature_list.cc b/base/feature_list.cc
index fa23a691..76a418d 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/feature_list.h"
+#include <string>
 
 // feature_list.h is a widely included header and its size impacts build
 // time. Try not to raise this limit unless necessary. See
@@ -13,9 +14,6 @@
 
 #include <stddef.h>
 
-#include <utility>
-#include <vector>
-
 #include "base/base_paths.h"
 #include "base/base_switches.h"
 #include "base/debug/alias.h"
@@ -533,15 +531,45 @@
 
 FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) {
   DCHECK(initialized_);
-  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
   DCHECK(CheckFeatureIdentity(feature)) << feature.name;
 
-  auto it = overrides_.find(feature.name);
+  return GetAssociatedFieldTrialByFeatureName(feature.name);
+}
+
+const base::FeatureList::OverrideEntry*
+FeatureList::GetOverrideEntryByFeatureName(StringPiece name) {
+  DCHECK(initialized_);
+  DCHECK(IsValidFeatureOrFieldTrialName(std::string(name))) << name;
+
+  auto it = overrides_.find(name);
   if (it != overrides_.end()) {
     const OverrideEntry& entry = it->second;
-    return entry.field_trial;
+    return &entry;
   }
+  return nullptr;
+}
 
+FieldTrial* FeatureList::GetAssociatedFieldTrialByFeatureName(
+    StringPiece name) {
+  DCHECK(initialized_);
+
+  const base::FeatureList::OverrideEntry* entry =
+      GetOverrideEntryByFeatureName(name);
+  if (entry) {
+    return entry->field_trial;
+  }
+  return nullptr;
+}
+
+FieldTrial* FeatureList::GetEnabledFieldTrialByFeatureName(StringPiece name) {
+  DCHECK(initialized_);
+
+  const base::FeatureList::OverrideEntry* entry =
+      GetOverrideEntryByFeatureName(name);
+  if (entry &&
+      entry->overridden_state == base::FeatureList::OVERRIDE_ENABLE_FEATURE) {
+    return entry->field_trial;
+  }
   return nullptr;
 }
 
diff --git a/base/feature_list.h b/base/feature_list.h
index 2f27fc2..f407330 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -225,6 +225,14 @@
   void GetCommandLineFeatureOverrides(std::string* enable_overrides,
                                       std::string* disable_overrides);
 
+  // Returns the field trial associated with the given feature |name|. Used for
+  // getting the FieldTrial without requiring a struct Feature.
+  base::FieldTrial* GetAssociatedFieldTrialByFeatureName(StringPiece name);
+
+  // Get associated field trial for the given feature |name| only if override
+  // enables it.
+  FieldTrial* GetEnabledFieldTrialByFeatureName(StringPiece name);
+
   // Returns whether the given |feature| is enabled. Must only be called after
   // the singleton instance has been registered via SetInstance(). Additionally,
   // a feature with a given name must only have a single corresponding Feature
@@ -313,6 +321,11 @@
     OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial);
   };
 
+  // Returns the override for the field trial associated with the given feature
+  // |name| or null if the feature is not found.
+  const base::FeatureList::OverrideEntry* GetOverrideEntryByFeatureName(
+      StringPiece name);
+
   // Finalizes the initialization state of the FeatureList, so that no further
   // overrides can be registered. This is called by SetInstance() on the
   // singleton feature list that is being registered.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 7cd768c..d598d0a 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-4.20210509.3.1
+4.20210510.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 7cd768c..d598d0a 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-4.20210509.3.1
+4.20210510.1.1
diff --git a/cc/trees/frame_rate_estimator.h b/cc/trees/frame_rate_estimator.h
index 7ea1683..378a217 100644
--- a/cc/trees/frame_rate_estimator.h
+++ b/cc/trees/frame_rate_estimator.h
@@ -20,6 +20,7 @@
   void WillDraw(base::TimeTicks now);
   void NotifyInputEvent();
   base::TimeDelta GetPreferredInterval() const;
+  bool input_priority_mode() const { return input_priority_mode_; }
 
  private:
   void OnExitInputPriorityMode();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 97b0d75f..906fa88 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2529,6 +2529,8 @@
     metadata.preferred_frame_interval = viz::BeginFrameArgs::MaxInterval();
   } else if (mutator_host_->MainThreadAnimationsCount() == 0 &&
              !mutator_host_->HasSmilAnimation() &&
+             mutator_host_->NeedsTickAnimations() &&
+             !frame_rate_estimator_.input_priority_mode() &&
              mutator_host_->MinimumTickInterval() > kMinDelta) {
     // All animations are impl-thread animations that tick at no more than
     // half the default display compositing fps.
@@ -2544,7 +2546,8 @@
     // to general webpages.
     metadata.preferred_frame_interval = kTwiceOfDefaultInterval;
   } else {
-    // There are main-thread or high frequency impl-thread animations.
+    // There are main-thread, high frequency impl-thread animations, or input
+    // events.
     frame_rate_estimator_.WillDraw(CurrentBeginFrameArgs().frame_time);
     metadata.preferred_frame_interval =
         frame_rate_estimator_.GetPreferredInterval();
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 7879d56d..a0c18d32 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1516,6 +1516,14 @@
     if (is_chrome_branded && !is_mac) {
       public_deps = [ ":preinstalled_apps" ]
     }
+
+    if (enable_pak_file_integrity_checks) {
+      files_to_hash = [
+        "resources.pak",
+        "chrome_100_percent.pak",
+        "chrome_200_percent.pak",
+      ]
+    }
   }
 }
 
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index 019e75d..de4a28b 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -309,6 +309,7 @@
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantProgressBarIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPromptNavigationIntegrationTest.java",
+    "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantScreenOrientationHelper.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTabHelperCustomTabTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTabHelperRegularTabTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTextUtilsTest.java",
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 83904fe..be2ed63 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -51,6 +51,7 @@
 import androidx.test.espresso.matcher.ViewMatchers.Visibility;
 import androidx.test.filters.MediumTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -89,6 +90,9 @@
     @Rule
     public CustomTabActivityTestRule mTestRule = new CustomTabActivityTestRule();
 
+    private final AutofillAssistantScreenOrientationHelper<CustomTabActivityTestRule>
+            mScreenOrientationHelper = new AutofillAssistantScreenOrientationHelper<>(mTestRule);
+
     private static final String TEST_PAGE = "/components/test/data/autofill_assistant/html/"
             + "form_target_website.html";
 
@@ -104,9 +108,15 @@
         mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
                 InstrumentationRegistry.getTargetContext(),
                 mTestRule.getTestServer().getURL(TEST_PAGE)));
+        mScreenOrientationHelper.setPortraitOrientation();
         mHelper = new AutofillAssistantCollectUserDataTestHelper();
     }
 
+    @After
+    public void tearDown() {
+        mScreenOrientationHelper.restoreOrientation();
+    }
+
     /**
      * Add a contact with Autofill Assistant UI and fill it into the form.
      */
@@ -192,7 +202,6 @@
      */
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1197105")
     public void testCreateAndEditProfileMultipleTimes() throws Exception {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantScreenOrientationHelper.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantScreenOrientationHelper.java
new file mode 100644
index 0000000..0e5d64f
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantScreenOrientationHelper.java
@@ -0,0 +1,31 @@
+// 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_assistant;
+
+import android.annotation.SuppressLint;
+import android.content.pm.ActivityInfo;
+
+import org.chromium.chrome.test.ChromeActivityTestRule;
+
+class AutofillAssistantScreenOrientationHelper<T extends ChromeActivityTestRule> {
+    private int mOriginalRequestedScreenOrientation;
+    private final T mTestRule;
+
+    AutofillAssistantScreenOrientationHelper(T testRule) {
+        mTestRule = testRule;
+    }
+
+    @SuppressLint("SourceLockedOrientationActivity")
+    public void setPortraitOrientation() {
+        assert mTestRule.getActivity() != null;
+        mOriginalRequestedScreenOrientation = mTestRule.getActivity().getRequestedOrientation();
+        mTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    public void restoreOrientation() {
+        assert mTestRule.getActivity() != null;
+        mTestRule.getActivity().setRequestedOrientation(mOriginalRequestedScreenOrientation);
+    }
+}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java
index f3391427..d556b06 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InChromeTriggeringTest.java
@@ -87,7 +87,7 @@
 
     @Test
     @MediumTest
-    @Features.EnableFeatures("AutofillAssistantInChromeTriggering")
+    @Features.EnableFeatures("AutofillAssistantInTabTriggering")
     public void triggerImplicitlyOnSupportedSite() {
         AutofillAssistantTestServiceRequestSender testServiceRequestSender =
                 new AutofillAssistantTestServiceRequestSender();
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
index a37687ec..eba2479 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
@@ -9,10 +9,8 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
 import org.chromium.chrome.browser.autofill_assistant.metrics.FeatureModuleInstallation;
-import org.chromium.chrome.browser.autofill_assistant.metrics.LiteScriptFinishedState;
 import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding;
 import org.chromium.chrome.browser.autofill_assistant.strings.IntentStrings;
-import org.chromium.components.ukm.UkmRecorder;
 import org.chromium.content_public.browser.WebContents;
 
 /**
@@ -60,25 +58,6 @@
     }
 
     /**
-     * UKM metric. Records the finish of a lite script.
-     *
-     * The events recorded by this call lacks a trigger type. This is appropriate
-     * when the trigger type is not yet known, because the Trigger protos sent by
-     * the server have not been processed yet. If trigger protos are available,
-     * record the metric from C++.
-     */
-    public static void recordLiteScriptFinished(
-            WebContents webContents, @LiteScriptFinishedState int finishedState) {
-        if (!areWebContentsValid(webContents)) {
-            return;
-        }
-        new UkmRecorder.Bridge().recordEventWithIntegerMetric(webContents,
-                /* eventName = */ "AutofillAssistant.LiteScriptFinished",
-                /* metricName = */ "LiteScriptFinished",
-                /* metricValue = */ finishedState);
-    }
-
-    /**
      * Returns whether {@code webContents} are non-null and valid. Invalid
      * webContents will cause a failed DCHECK when attempting to report UKM metrics.
      */
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 93ae7da8..73aba55 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -229,6 +229,7 @@
     @MediumTest
     @Feature({"StartSurface"})
     @CommandLineFlags.Add({BASE_PARAMS + "/single/home_button_on_grid_tab_switcher/false"})
+    @FlakyTest(message = "https://crbug.com/1207306")
     public void testShow_SingleAsHomepage() {
         Assume.assumeFalse("https://crbug.com/1196473",
                 mUseInstantStart && mImmediateReturn
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java
index cf2d667..d7682f7785 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java
@@ -293,6 +293,10 @@
     private void animateOutDialog() {
         if (mDialogInOutAnimator != null || !isShowing()) return;
 
+        if (getCurrentFocus() != null) {
+            KeyboardVisibilityDelegate.getInstance().hideKeyboard(getCurrentFocus());
+        }
+
         Animator dropDown =
                 ObjectAnimator.ofFloat(mLayout, View.TRANSLATION_Y, 0f, mLayout.getHeight());
         Animator fadeOut = ObjectAnimator.ofFloat(mLayout, View.ALPHA, mLayout.getAlpha(), 0f);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
index 8d72b2a7..64e70bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
@@ -49,7 +49,7 @@
 import org.chromium.components.page_info.PageInfoMainController;
 import org.chromium.components.page_info.PageInfoRowView;
 import org.chromium.components.page_info.PageInfoSubpageController;
-import org.chromium.components.page_info.PageInfoView.PageInfoViewParams;
+import org.chromium.components.page_info.PageInfoViewV2;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.url.GURL;
@@ -154,7 +154,7 @@
      */
     @Override
     public void initOfflinePageUiParams(
-            PageInfoViewParams viewParams, Consumer<Runnable> runAfterDismiss) {
+            PageInfoViewV2.Params viewParams, Consumer<Runnable> runAfterDismiss) {
         if (isShowingOfflinePage() && OfflinePageUtils.isConnected()) {
             viewParams.openOnlineButtonClickCallback = () -> {
                 runAfterDismiss.accept(() -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
index 9e962ef..b60301a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
@@ -116,8 +116,6 @@
 
         identityMutator.reloadAllAccountsFromSystemWithPrimaryAccount(CoreAccountInfo.getIdFrom(
                 identityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN)));
-
-        signinManager.maybeRollbackMobileIdentityConsistency();
         return signinManager;
     }
 
@@ -150,25 +148,6 @@
     }
 
     /**
-     * Temporary code to handle rollback for {@link ChromeFeatureList#MOBILE_IDENTITY_CONSISTENCY}.
-     * TODO(https://crbug.com/1065029): Remove when the flag is removed.
-     */
-    private void maybeRollbackMobileIdentityConsistency() {
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) return;
-        // Nothing to do if there's no primary account.
-        if (mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN) == null) return;
-        // Nothing to do if sync is on - this state existed before MobileIdentityConsistency.
-        if (mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SYNC) != null) return;
-
-        Log.w(TAG, "Rolling back MobileIdentityConsistency: signing out.");
-        signOut(SignoutReason.MOBILE_IDENTITY_CONSISTENCY_ROLLBACK);
-        // Since AccountReconcilor currently operates in pre-MICE mode, it doesn't react to
-        // primary account changes when there's no sync consent. Log-out web accounts manually.
-        SigninManagerImplJni.get().logOutAllAccountsForMobileIdentityConsistencyRollback(
-                mNativeSigninManagerAndroid);
-    }
-
-    /**
      * Implements {@link AccountTrackerService.Observer}.
      */
     @Override
@@ -413,8 +392,7 @@
                     AccountUtils.createAccountFromName(mSignInState.mCoreAccountInfo.getEmail()));
             boolean atLeastOneDataTypeSynced =
                     !ProfileSyncService.get().getChosenDataTypes().isEmpty();
-            if (!ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
-                    || atLeastOneDataTypeSynced) {
+            if (atLeastOneDataTypeSynced) {
                 // Turn on sync only when user has at least one data type to sync, this is
                 // consistent with {@link ManageSyncSettings#updataSyncStateFromSelectedModelTypes},
                 // in which we turn off sync we stop sync service when the user toggles off all the
@@ -766,10 +744,6 @@
 
         String getManagementDomain(long nativeSigninManagerAndroid);
 
-        // Temporary code to handle rollback for MobileIdentityConsistency.
-        // TODO(https://crbug.com/1065029): Remove when the flag is removed.
-        void logOutAllAccountsForMobileIdentityConsistencyRollback(long nativeSigninManagerAndroid);
-
         void wipeProfileData(long nativeSigninManagerAndroid, Runnable callback);
 
         void wipeGoogleServiceWorkerCaches(long nativeSigninManagerAndroid, Runnable callback);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsSearchTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsSearchTest.java
index fbf67b8..70ca3ab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsSearchTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsSearchTest.java
@@ -71,6 +71,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.history.HistoryActivity;
 import org.chromium.chrome.browser.history.HistoryManager;
@@ -79,6 +80,7 @@
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
 import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.Date;
@@ -446,10 +448,14 @@
 
     /**
      * Check that the filtered password list persists after the user had inspected a single result.
+     *
+     * TODO(crbug.com/1202907): Move this test to a full integration test which spins up native
+     * and actually has stored passwords.
      */
     @Test
     @SmallTest
     @Feature({"Preferences"})
+    @DisableFeatures({ChromeFeatureList.EDIT_PASSWORDS_IN_SETTINGS})
     public void testSearchResultsPersistAfterEntryInspection() {
         mTestHelper.setPasswordSourceWithMultipleEntries(GREEK_GODS);
         mTestHelper.setPasswordExceptions(new String[] {"http://exclu.de", "http://not-inclu.de"});
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
index ecbf8cc2c..b8969ee 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
@@ -40,6 +40,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.password_check.PasswordCheck;
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
@@ -50,6 +51,7 @@
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.sync.ModelType;
@@ -295,6 +297,7 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
+    @DisableFeatures({ChromeFeatureList.EDIT_PASSWORDS_IN_SETTINGS})
     public void testViewPasswordNoLock() {
         mTestHelper.setPasswordSource(
                 new SavedPasswordEntry("https://example.com", "test user", "password"));
@@ -323,6 +326,7 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
+    @DisableFeatures({ChromeFeatureList.EDIT_PASSWORDS_IN_SETTINGS})
     public void testViewPassword() {
         mTestHelper.setPasswordSource(
                 new SavedPasswordEntry("https://example.com", "test user", "test password"));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerImplTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerImplTest.java
index ad5d0252..a118132 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerImplTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerImplTest.java
@@ -42,13 +42,14 @@
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.components.signin.metrics.SignoutDelete;
 import org.chromium.components.signin.metrics.SignoutReason;
+import org.chromium.components.sync.ModelType;
 
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /** Tests for {@link SigninManagerImpl}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Features.DisableFeatures(
-        {ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY, ChromeFeatureList.DEPRECATE_MENAGERIE_API})
+@Features.DisableFeatures({ChromeFeatureList.DEPRECATE_MENAGERIE_API})
 public class SigninManagerImplTest {
     private static final long NATIVE_SIGNIN_MANAGER = 10001L;
     private static final long NATIVE_IDENTITY_MANAGER = 10002L;
@@ -110,6 +111,7 @@
     @Test
     public void signinAndTurnSyncOn() {
         when(mIdentityMutator.setPrimaryAccount(any(), anyInt())).thenReturn(true);
+        when(mProfileSyncService.getChosenDataTypes()).thenReturn(Set.of(ModelType.BOOKMARKS));
 
         mSigninManager.onFirstRunCheckDone();
 
@@ -333,43 +335,6 @@
     }
 
     @Test
-    public void rollbackWhenMobileIdentityConsistencyIsDisabled() {
-        when(mIdentityManagerNativeMock.getPrimaryAccountInfo(
-                     NATIVE_IDENTITY_MANAGER, ConsentLevel.SIGNIN))
-                .thenReturn(ACCOUNT_INFO);
-
-        mSigninManager = (SigninManagerImpl) SigninManagerImpl.create(
-                NATIVE_SIGNIN_MANAGER, mAccountTrackerService, mIdentityManager, mIdentityMutator);
-
-        // SignedIn state (without sync consent) doesn't exist pre-MobileIdentityConsistency. If the
-        // feature is disabled while in this state, SigninManager ctor should trigger sign-out.
-        verify(mIdentityMutator)
-                .clearPrimaryAccount(SignoutReason.MOBILE_IDENTITY_CONSISTENCY_ROLLBACK,
-                        SignoutDelete.IGNORE_METRIC);
-        verify(mNativeMock)
-                .logOutAllAccountsForMobileIdentityConsistencyRollback(NATIVE_SIGNIN_MANAGER);
-        // This sign-out shouldn't wipe data.
-        verify(mNativeMock, never()).wipeProfileData(anyLong(), any());
-        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
-    }
-
-    @Test
-    @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
-    public void noRollbackWhenMobileIdentityConsistencyIsEnabled() {
-        when(mIdentityManagerNativeMock.getPrimaryAccountInfo(
-                     NATIVE_IDENTITY_MANAGER, ConsentLevel.SIGNIN))
-                .thenReturn(ACCOUNT_INFO);
-
-        mSigninManager = (SigninManagerImpl) SigninManagerImpl.create(
-                NATIVE_SIGNIN_MANAGER, mAccountTrackerService, mIdentityManager, mIdentityMutator);
-        ;
-
-        verify(mIdentityMutator, never()).clearPrimaryAccount(anyInt(), anyInt());
-        verify(mNativeMock, never())
-                .logOutAllAccountsForMobileIdentityConsistencyRollback(anyLong());
-    }
-
-    @Test
     public void callbackNotifiedWhenNoOperationIsInProgress() {
         AtomicInteger callCount = new AtomicInteger(0);
 
diff --git a/chrome/app/resources/chromium_strings_bn.xtb b/chrome/app/resources/chromium_strings_bn.xtb
index 5da2bd1..9bac6b9 100644
--- a/chrome/app/resources/chromium_strings_bn.xtb
+++ b/chrome/app/resources/chromium_strings_bn.xtb
@@ -22,6 +22,7 @@
 <translation id="1911763535808217981">এটি বন্ধ করার মানে হল, আপনি Chromium-এ সাইন-ইন না করে Gmail এর মতো Google সাইটগুলিতে সাইন-ইন করতে পারেন</translation>
 <translation id="1929939181775079593">Chromium সাড়া দিচ্ছে না৷ আবার শুরু করবেন?</translation>
 <translation id="1966382378801805537">Chromium ডিফল্ট ব্রাউজার নির্ধারণ বা সেট করতে পারছে না</translation>
+<translation id="1981611865800294956">&amp;Chromium OS আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="2008474315282236005">এটি এই ডিভাইস থেকে ১টি আইটেম মুছে দেবে। আপনার ডেটা পরে পুনরুদ্ধার করার জন্য, Chromium-এ <ph name="USER_EMAIL" /> হিসেবে সাইন-ইন করুন।</translation>
 <translation id="2020032459870799438">আপনার অন্যান্য পাসওয়ার্ড ডেটার নিরাপত্তা লঙ্ঘন এবং অন্যান্য নিরাপত্তা সংক্রান্ত সমস্যা থেকে সুরক্ষিত কিনা তা চেক করতে <ph name="BEGIN_LINK" />Chromium-এ সাইন-ইন করুন<ph name="END_LINK" />।</translation>
 <translation id="2174178932569897599">Chromium কাস্টমাইজ করুন</translation>
@@ -119,6 +120,7 @@
 <translation id="4788777615168560705">Chromium আপনার পাসওয়ার্ড চেক করতে পারছে না। ২৪ ঘণ্টা পরে আবার চেষ্টা করুন বা <ph name="BEGIN_LINK" />আপনার Google অ্যাকাউন্টে পাসওয়ার্ড চেক করুন<ph name="END_LINK" />।</translation>
 <translation id="479167709087336770">এটি Google সার্চ-এ যে বানান পরীক্ষা করার টুল ব্যবহার করা হয় সেটিই ব্যবহার করে। আপনি ব্রাউজারে যে টেক্সট লেখেন, সেটি Google-এ পাঠানো হয়। সেটিংস থেকে আপনি এটি পরিবর্তন করতে পারেন।</translation>
 <translation id="4888717733111232871">mDNS ট্রাফিকের অনুমতি দিতে Chromium এর জন্য ইনবাউন্ড নিয়ম।</translation>
+<translation id="4893347770495441059">&amp;Chromium আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="4943838377383847465">Chromium পটভূমিতে চলছে৷</translation>
 <translation id="4987820182225656817">অতিথিগণ কোনো কিছুর জন্য অভাব বোধ না করেই Chromium ব্যবহার করতে পারবেন৷</translation>
 <translation id="4994636714258228724">Chromium এর সাথে নিজেকে যোগ করুন</translation>
@@ -272,6 +274,7 @@
 <translation id="91086099826398415">নতুন Chromium ট্যাবে লিঙ্ক খুলুন</translation>
 <translation id="911206726377975832">আপনার ব্রাউজিং ডেটাও মুছে দেবেন?</translation>
 <translation id="9158494823179993217"><ph name="TARGET_URL_HOSTNAME" /> অ্যাক্সেস করতে অন্য ব্রাউজার খোলার জন্য আপনার সিস্টেম অ্যাডমিনিস্ট্রেটর Chromium কনফিগার করেছেন।</translation>
+<translation id="9185526690718004400">&amp;Chromium আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Chromium OS সিস্টেম</translation>
 <translation id="93478295209880648">Chromium সঠিকভাবে কাজ নাও করতে পারে কারণ এটি এখন আর Windows XP বা Windows Vista আর সমর্থিত নয়</translation>
diff --git a/chrome/app/resources/chromium_strings_ko.xtb b/chrome/app/resources/chromium_strings_ko.xtb
index 5dead10..a379d44 100644
--- a/chrome/app/resources/chromium_strings_ko.xtb
+++ b/chrome/app/resources/chromium_strings_ko.xtb
@@ -24,6 +24,7 @@
 <translation id="1911763535808217981">이 기능을 사용 중지하면 Chromium에 로그인하지 않고도 Gmail 등의 Google 사이트에 로그인할 수 있습니다.</translation>
 <translation id="1929939181775079593">Chromium이 응답하지 않습니다. 다시 시작하시겠습니까?</translation>
 <translation id="1966382378801805537">Chromium에서 기본 브라우저를 확인하거나 설정할 수 없습니다.</translation>
+<translation id="1981611865800294956">다시 실행하여 Chromium OS 업데이트</translation>
 <translation id="2008474315282236005">항목 1개가 기기에서 삭제됩니다. 나중에 데이터를 가져오려면 Chromium에 <ph name="USER_EMAIL" />(으)로 로그인하세요.</translation>
 <translation id="2020032459870799438">다른 암호가 정보 유출 및 다른 보안 문제로부터 안전한지 확인하려면 <ph name="BEGIN_LINK" />Chromium에 로그인<ph name="END_LINK" />하세요.</translation>
 <translation id="2174178932569897599">Chromium 맞춤설정</translation>
@@ -121,6 +122,7 @@
 <translation id="4788777615168560705">Chromium에서 비밀번호를 확인할 수 없습니다. 24시간 후에 다시 시도해 보거나 <ph name="BEGIN_LINK" />Google 계정에서 비밀번호를 확인<ph name="END_LINK" />하세요.</translation>
 <translation id="479167709087336770">Google 검색과 동일한 맞춤법 검사기가 사용됩니다. 브라우저에 입력되는 텍스트는 Google로 전송됩니다. 설정에서 언제든지 이 동작을 변경할 수 있습니다.</translation>
 <translation id="4888717733111232871">Chromium이 mDNS 트래픽을 허용하는 인바운드 규칙입니다.</translation>
+<translation id="4893347770495441059">다시 실행하여 Chromium 업데이트</translation>
 <translation id="4943838377383847465">Chromium이 백그라운드 모드로 실행 중입니다.</translation>
 <translation id="4987820182225656817">게스트로 사용 기록을 남기지 않고 Chromium을 사용할 수 있습니다.</translation>
 <translation id="4994636714258228724">Chromium에 본인 추가</translation>
@@ -276,6 +278,7 @@
 <translation id="91086099826398415">새 Chromium 탭에서 링크 열기(&amp;T)</translation>
 <translation id="911206726377975832">인터넷 사용 기록도 삭제하시겠습니까?</translation>
 <translation id="9158494823179993217">시스템 관리자가 <ph name="TARGET_URL_HOSTNAME" /> 액세스를 위해 대체 브라우저를 열도록 Chromium을 구성했습니다.</translation>
+<translation id="9185526690718004400">다시 실행하여 Chromium 업데이트</translation>
 <translation id="9190841055450128916">Chromium(mDNS-In)</translation>
 <translation id="9214764063801632699">Chromium OS 시스템</translation>
 <translation id="93478295209880648">Windows XP 또는 Windows Vista에서 더 이상 Chromium을 지원하지 않으므로 Chromium이 올바르게 작동하지 않을 수 있습니다</translation>
diff --git a/chrome/app/resources/chromium_strings_pa.xtb b/chrome/app/resources/chromium_strings_pa.xtb
index bd6f3e3..fecf1c0 100644
--- a/chrome/app/resources/chromium_strings_pa.xtb
+++ b/chrome/app/resources/chromium_strings_pa.xtb
@@ -24,6 +24,7 @@
 <translation id="1911763535808217981">ਇਸਨੂੰ ਬੰਦ ਕਰਕੇ, ਤੁਸੀਂ Chromium ਵਿੱਚ ਸਾਈਨ-ਇਨ ਕੀਤੇ ਬਿਨਾਂ Gmail ਵਰਗੀਆਂ Google ਸਾਈਟਾਂ 'ਤੇ ਸਾਈਨ-ਇਨ ਕਰ ਸਕਦੇ ਹੋ</translation>
 <translation id="1929939181775079593">Chromium ਜਵਾਬ ਨਹੀਂ ਦੇ ਰਿਹਾ ਹੈ। ਕੀ ਹੁਣ ਰੀਲੌਂਚ ਕਰਨਾ ਹੈ?</translation>
 <translation id="1966382378801805537">Chromium ਪੂਰਵ-ਨਿਰਧਾਰਤ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਪਤਾ ਨਹੀਂ ਲਗਾ ਸਕਦਾ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੈੱਟ ਨਹੀਂ ਕਰ ਸਕਦਾ ਹੈ</translation>
+<translation id="1981611865800294956">&amp;Chromium OS ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="2008474315282236005">ਇਸ ਨਾਲ ਇਸ ਡੀਵਾਈਸ ਤੋਂ 1 ਆਈਟਮ ਮਿਟਾ ਦਿੱਤੀ ਜਾਵੇਗੀ। ਬਾਅਦ ਵਿੱਚ ਆਪਣੇ ਡਾਟੇ ਨੂੰ ਮੁੜ-ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, Chromium 'ਤੇ <ph name="USER_EMAIL" /> ਵਜੋਂ ਸਾਈਨ-ਇਨ ਕਰੋ।</translation>
 <translation id="2020032459870799438">ਇਹ ਜਾਂਚ ਕਰਨ ਲਈ ਕਿ ਤੁਹਾਡੇ ਹੋਰ ਪਾਸਵਰਡ ਡਾਟਾ ਉਲੰਘਣਾਵਾਂ ਅਤੇ ਹੋਰ ਸੁਰੱਖਿਆ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਤੋਂ ਸੁਰੱਖਿਅਤ ਹਨ ਜਾਂ ਨਹੀਂ, <ph name="BEGIN_LINK" />Chromium ਵਿੱਚ ਸਾਈਨ-ਇਨ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="2174178932569897599">Chromium ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ</translation>
@@ -121,6 +122,7 @@
 <translation id="4788777615168560705">Chromium ਤੁਹਾਡੇ ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕਰ ਸਕਦਾ। 24 ਘੰਟਿਆਂ ਬਾਅਦ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ <ph name="BEGIN_LINK" />ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="479167709087336770">ਇਹ Google ਖੋਜ ਵੇਲੇ ਵਰਤੇ ਜਾਣ ਵਾਲੇ ਸਪੈੱਲ-ਚੈਕਰ ਨੂੰ ਹੀ ਵਰਤਦਾ ਹੈ। ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਤੁਹਾਡੇ ਵੱਲੋਂ ਟਾਈਪ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਲਿਖਤ Google ਨੂੰ ਭੇਜੀ ਜਾਵੇਗੀ। ਤੁਸੀਂ ਹਮੇਸ਼ਾਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਸ ਵਤੀਰੇ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।</translation>
 <translation id="4888717733111232871">mDNS ਟ੍ਰੈਫਿਕ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ Chromium ਲਈ ਇਨਬਾਊਂਡ ਨਿਯਮ।</translation>
+<translation id="4893347770495441059">&amp;Chromium ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="4943838377383847465">Chromium ਪਿਛੋਕੜ ਮੋਡ ਵਿੱਚ ਹੈ।</translation>
 <translation id="4987820182225656817">ਮਹਿਮਾਨ ਕੁਝ ਵੀ ਪਿੱਛੇ ਛੱਡੇ ਬਿਨਾਂ Chromium ਵਰਤ ਸਕਦੇ ਹਨ।</translation>
 <translation id="4994636714258228724">ਖੁਦ ਨੂੰ Chromium ਵਿੱਚ ਜੋੜੋ</translation>
@@ -276,6 +278,7 @@
 <translation id="91086099826398415">ਨਵੀਂ Chromium &amp;ਟੈਬ ਵਿੱਚ ਲਿੰਕ ਖੋਲ੍ਹੋ</translation>
 <translation id="911206726377975832">ਕੀ ਤੁਹਾਡਾ ਬ੍ਰਾਊਜ਼ਿੰਗ ਡਾਟਾ ਵੀ ਮਿਟਾਉਣਾ ਹੈ?</translation>
 <translation id="9158494823179993217">ਤੁਹਾਡੇ ਸਿਸਟਮ ਪ੍ਰਸ਼ਾਸਕ ਨੇ <ph name="TARGET_URL_HOSTNAME" /> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਵਾਸਤੇ ਕੋਈ ਵਿਕਲਪਿਕ ਬ੍ਰਾਊਜ਼ਰ ਖੋਲ੍ਹਣ ਲਈ Chromium ਦਾ ਸੰਰੂਪਣ ਕੀਤਾ ਹੈ।</translation>
+<translation id="9185526690718004400">&amp;Chromium ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Chromium OS ਸਿਸਟਮ</translation>
 <translation id="93478295209880648">ਸ਼ਾਇਦ Chromium ਠੀਕ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ ਕਿਉਂਕਿ ਇਹ ਹੁਣ Windows XP ਜਾਂ Windows Vista 'ਤੇ ਕੰਮ ਨਹੀਂ ਕਰਦਾ ਹੈ</translation>
diff --git a/chrome/app/resources/chromium_strings_sq.xtb b/chrome/app/resources/chromium_strings_sq.xtb
index f15c5ef..5ca16212 100644
--- a/chrome/app/resources/chromium_strings_sq.xtb
+++ b/chrome/app/resources/chromium_strings_sq.xtb
@@ -24,6 +24,7 @@
 <translation id="1911763535808217981">Duke çaktivizuar këtë, mund të identifikohesh në sajtet e Google si Gmail pa u identifikuar në Chromium</translation>
 <translation id="1929939181775079593">Chromium nuk përgjigjet. Dëshiron ta hapësh sërish tani?</translation>
 <translation id="1966382378801805537">Chromium nuk mund të përcaktojë ose caktojë shfletuesin e parazgjedhur</translation>
+<translation id="1981611865800294956">Nise përsëri për të përditësuar &amp;Chromium OS</translation>
 <translation id="2008474315282236005">Kjo do të fshijë 1 artikull nga kjo pajisje. Për t'i marrë më vonë të dhënat, identifikohu te Chromium si <ph name="USER_EMAIL" />.</translation>
 <translation id="2020032459870799438">Për të kontrolluar nëse fjalëkalimet e tjera janë të sigurta nga nxjerrjet e paautorizuara të të dhënave dhe probleme të tjera të sigurisë, <ph name="BEGIN_LINK" />identifikohu në Chromium<ph name="END_LINK" />.</translation>
 <translation id="2174178932569897599">Personalizo Chromium</translation>
@@ -121,6 +122,7 @@
 <translation id="4788777615168560705">Chromium nuk mund t'i kontrollojë fjalëkalimet e tua. Provo përsëri pas 24 orësh ose <ph name="BEGIN_LINK" />kontrollo fjalëkalimet në "Llogarinë tënde të Google"<ph name="END_LINK" />.</translation>
 <translation id="479167709087336770">Kjo përdor të njëjtin kontrollues drejtshkrimor që përdoret në kërkimin e Google. Teksti që shkruan në shfletues dërgohet te Google. Mund ta ndryshosh këtë sjellje gjithmonë te cilësimet.</translation>
 <translation id="4888717733111232871">Rregulli hyrës për Chromium për të lejuar trafikun mDNS.</translation>
+<translation id="4893347770495441059">Nise përsëri për të përditësuar &amp;Chromium</translation>
 <translation id="4943838377383847465">Chromium është në modalitetin e sfondit.</translation>
 <translation id="4987820182225656817">Vizitorët mund të përdorin Chromium pa lënë asgjë prapa.</translation>
 <translation id="4994636714258228724">Shtoje veten te Chromium</translation>
@@ -275,6 +277,7 @@
 <translation id="91086099826398415">Hape lidhjen në një &amp;skedë të re të Chromium</translation>
 <translation id="911206726377975832">Të fshihen po ashtu të dhënat e shfletimit?</translation>
 <translation id="9158494823179993217">Administratori i sistemit ka konfiguruar Chromium që të hapë një shfletues alternativ për të pasur qasje te <ph name="TARGET_URL_HOSTNAME" />.</translation>
+<translation id="9185526690718004400">Nise përsëri për të përditësuar &amp;Chromium</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Sistemi Chromium OS</translation>
 <translation id="93478295209880648">Chromium mund të mos funksionojë si duhet sepse nuk mbështetet më në Windows XP ose Windows Vista</translation>
diff --git a/chrome/app/resources/chromium_strings_te.xtb b/chrome/app/resources/chromium_strings_te.xtb
index f97056c9..6b1e81d6 100644
--- a/chrome/app/resources/chromium_strings_te.xtb
+++ b/chrome/app/resources/chromium_strings_te.xtb
@@ -22,6 +22,7 @@
 <translation id="1911763535808217981">దీనిని ఆఫ్ చేయడం ద్వారా, మీరు Chromiumకి సైన్ ఇన్ చేయకుండానే Gmail లాంటి Google సైట్‌లలో సైన్ ఇన్ చేయగలరు</translation>
 <translation id="1929939181775079593">Chromium ప్రతిస్పందించడం లేదు. ఇప్పుడు మళ్లీ ప్రారంభించాలా?</translation>
 <translation id="1966382378801805537">Chromium డిఫాల్ట్ బ్రౌజర్‌ను నిశ్చయించలేదు లేదా సెట్ చేయలేదు</translation>
+<translation id="1981611865800294956">&amp;Chromium OSను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="2008474315282236005">ఇది ఈ పరికరం నుండి 1 అంశాన్ని తొలగిస్తుంది. మీ డేటాను తర్వాత తిరిగి పొందడానికి, Chromiumకు <ph name="USER_EMAIL" /> లాగా సైన్ ఇన్ చేయండి.</translation>
 <translation id="2020032459870799438">డేటా ఉల్లంఘనల నుండి, ఇతర భద్రతా సమస్యల నుండి మీ ఇతర పాస్‌వర్డ్‌లు సురక్షితంగా ఉన్నాయో లేదో చెక్ చేయడానికి, <ph name="BEGIN_LINK" />Chromiumకు సైన్ ఇన్ చేయండి<ph name="END_LINK" />.</translation>
 <translation id="2174178932569897599">Chromiumను అనుకూలంగా మార్చు</translation>
@@ -117,6 +118,7 @@
 <translation id="4788777615168560705">Chromium మీ పాస్‌వర్డ్‌లను చెక్ చేయలేకపోయింది. 24 గంటల తర్వాత మళ్లీ ట్రై చేయండి లేదా <ph name="BEGIN_LINK" />మీ Google ఖాతాలో పాస్‌వర్డ్‌లను చెక్ చేయండి<ph name="END_LINK" />.</translation>
 <translation id="479167709087336770">Google Searchలో ఉపయోగించే స్పెల్ చెకర్‌నే ఇది ఉపయోగిస్తుంది. మీరు బ్రౌజర్‌లో టైప్ చేసే టెక్స్ట్‌ను Googleకు పంపుతుంది. ఈ ఆప్షన్‌ను తర్వాత ఎప్పుడైనా మీరు సెట్టింగ్‌లలో మార్చవచ్చు.</translation>
 <translation id="4888717733111232871">mDNS ట్రాఫిక్‌ను అనుమతించడానికి Chromium ఇన్‌బౌండ్ నియమం.</translation>
+<translation id="4893347770495441059">&amp;Chromiumను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="4943838377383847465">Chromium నేపథ్య మోడ్‌లో ఉంది.</translation>
 <translation id="4987820182225656817">అతిథులు ఎటువంటి చరిత్రను వదలకుండానే Chromiumను ఉపయోగించవచ్చు.</translation>
 <translation id="4994636714258228724">Chromiumకు మిమ్మల్ని జోడించుకోండి</translation>
@@ -270,6 +272,7 @@
 <translation id="91086099826398415">కొత్త Chromium &amp;ట్యాబ్‌లో లింక్‌ని తెరువు</translation>
 <translation id="911206726377975832">మీ బ్రౌజింగ్ డేటాను కూడా తొలగించాలా?</translation>
 <translation id="9158494823179993217"><ph name="TARGET_URL_HOSTNAME" />‌ను యాక్సెస్ చేయడం కోసం ఒక ప్రత్యామ్నాయ బ్రౌజర్‌ను తెరిచే విధంగా Chromiumను మీ సిస్టమ్ నిర్వాహకులు కాన్ఫిగర్ చేశారు.</translation>
+<translation id="9185526690718004400">&amp;Chromiumను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Chromium OS సిస్టమ్</translation>
 <translation id="93478295209880648">Chromiumకి ఇప్పుడు Windows XP లేదా Windows Vistaలో మద్దతు లేనందున ఇది సరిగ్గా పని చేయకపోవచ్చు</translation>
diff --git a/chrome/app/resources/chromium_strings_vi.xtb b/chrome/app/resources/chromium_strings_vi.xtb
index b40aa6b..c257c90 100644
--- a/chrome/app/resources/chromium_strings_vi.xtb
+++ b/chrome/app/resources/chromium_strings_vi.xtb
@@ -22,6 +22,7 @@
 <translation id="1911763535808217981">Bằng việc tắt tính năng này, bạn có thể đăng nhập vào các trang web của Google, chẳng hạn như Gmail mà không cần đăng nhập vào Chromium</translation>
 <translation id="1929939181775079593">Chromium không phản hồi. Chạy lại ngay bây giờ?</translation>
 <translation id="1966382378801805537">Chromium không thể xác định hoặc đặt trình duyệt mặc định</translation>
+<translation id="1981611865800294956">Chạy lại để cập nhật &amp;Chromium OS</translation>
 <translation id="2008474315282236005">Thao tác này sẽ xóa 1 mục khỏi thiết bị này. Để truy xuất dữ liệu của bạn sau, hãy đăng nhập vào Chromium dưới dạng <ph name="USER_EMAIL" />.</translation>
 <translation id="2020032459870799438">Để kiểm tra xem các mật khẩu khác của bạn có bị ảnh hưởng bởi các vụ rò rỉ dữ liệu và sự cố bảo mật khác hay không, hãy <ph name="BEGIN_LINK" />đăng nhập vào Chromium<ph name="END_LINK" />.</translation>
 <translation id="2174178932569897599">Tùy chỉnh Chromium</translation>
@@ -119,6 +120,7 @@
 <translation id="4788777615168560705">Chromium không thể kiểm tra mật khẩu của bạn. Hãy thử lại sau 24 giờ hoặc <ph name="BEGIN_LINK" />kiểm tra các mật khẩu trong Tài khoản Google của bạn<ph name="END_LINK" />.</translation>
 <translation id="479167709087336770">Dịch vụ này sử dụng cùng một trình kiểm tra chính tả dùng trong Google Tìm kiếm. Thông tin bạn nhập vào trình duyệt sẽ được gửi tới Google. Bạn luôn có thể thay đổi hành động này trong phần cài đặt.</translation>
 <translation id="4888717733111232871">Quy tắc kết nối để Chromium cho phép lưu lượng truy cập mDNS.</translation>
+<translation id="4893347770495441059">Chạy lại để cập nhật &amp;Chromium</translation>
 <translation id="4943838377383847465">Chromium đang chạy trong nền.</translation>
 <translation id="4987820182225656817">Khách có thể sử dụng Chromium mà không phải thoát khỏi bất cứ nội dung nào.</translation>
 <translation id="4994636714258228724">Thêm chính bạn vào Chromium</translation>
@@ -274,6 +276,7 @@
 <translation id="91086099826398415">Mở đường liên kết trong thẻ mới của Chromium</translation>
 <translation id="911206726377975832">Bạn cũng muốn xóa dữ liệu duyệt web của mình?</translation>
 <translation id="9158494823179993217">Quản trị viên hệ thống của bạn đã định cấu hình Chromium để mở một trình duyệt thay thế khi truy cập vào <ph name="TARGET_URL_HOSTNAME" />.</translation>
+<translation id="9185526690718004400">Chạy lại để cập nhật &amp;Chromium</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Hệ thống Chromium OS</translation>
 <translation id="93478295209880648">Chromium có thể không hoạt động chính xác do không được hỗ trợ trên Windows XP hoặc Windows Vista nữa</translation>
diff --git a/chrome/app/resources/chromium_strings_zh-TW.xtb b/chrome/app/resources/chromium_strings_zh-TW.xtb
index 9690b6f..01ff25d 100644
--- a/chrome/app/resources/chromium_strings_zh-TW.xtb
+++ b/chrome/app/resources/chromium_strings_zh-TW.xtb
@@ -22,6 +22,7 @@
 <translation id="1911763535808217981">關閉這項功能後,你可以單獨登入 Gmail 等這類 Google 網站,不必同時登入 Chromium</translation>
 <translation id="1929939181775079593">Chromium 沒有回應,要立即重新啟動嗎?</translation>
 <translation id="1966382378801805537">Chromium 無法偵測或設定預設瀏覽器</translation>
+<translation id="1981611865800294956">重新啟動以更新 &amp;Chromium 作業系統</translation>
 <translation id="2008474315282236005">登出後,系統會將 1 個項目從這個裝置上刪除。日後如要重新取得你的資料,請以 <ph name="USER_EMAIL" /> 身分登入 Chromium。</translation>
 <translation id="2020032459870799438">如要檢查你其他的密碼是否因資料侵害事件而遭到外洩,或是否有其他安全性問題,<ph name="BEGIN_LINK" />請登入 Chromium<ph name="END_LINK" />。</translation>
 <translation id="2174178932569897599">自訂 Chromium</translation>
@@ -119,6 +120,7 @@
 <translation id="4788777615168560705">Chromium 無法檢查你的密碼,請於 24 小時後再試,或<ph name="BEGIN_LINK" />檢查 Google 帳戶中的密碼<ph name="END_LINK" />。</translation>
 <translation id="479167709087336770">這會使用與 Google 搜尋相同的拼字檢查工具。系統會將你在瀏覽器中輸入的文字傳送給 Google。你隨時可以在設定中變更這項行為。</translation>
 <translation id="4888717733111232871">允許 mDNS 流量的 Chromium 輸入規則。</translation>
+<translation id="4893347770495441059">重新啟動以更新 &amp;Chromium</translation>
 <translation id="4943838377383847465">Chromium 正在背景模式中執行。</translation>
 <translation id="4987820182225656817">以訪客身分使用 Chromium 不會留下任何記錄。</translation>
 <translation id="4994636714258228724">新增為 Chromium 使用者</translation>
@@ -273,6 +275,7 @@
 <translation id="91086099826398415">在新的 Chromium 分頁中開啟連結(&amp;T)</translation>
 <translation id="911206726377975832">你要一併刪除瀏覽資料嗎?</translation>
 <translation id="9158494823179993217">系統管理員已設定 Chromium 開啟替代瀏覽器來存取 <ph name="TARGET_URL_HOSTNAME" />。</translation>
+<translation id="9185526690718004400">重新啟動以更新 &amp;Chromium</translation>
 <translation id="9190841055450128916">Chromium (mDNS-In)</translation>
 <translation id="9214764063801632699">Chromium 作業系統</translation>
 <translation id="93478295209880648">Chromium 已不適用於 Windows XP 或 Windows Vista,因此可能無法正常運作</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 20502c51..456cb010 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="bn">
 <translation id="1001307489511021749">আপনার Google অ্যাকাউন্ট দিয়ে সাইন-ইন করা সব Chrome OS ডিভাইসে আপনার অ্যাপ, সেটিংস এবং অন্যান্য কাস্টমাইজেশন সিঙ্ক হয়ে যাবে।</translation>
 <translation id="1003088604756913841">নতুন <ph name="APP" /> উইন্ডোতে লিঙ্ক খুলুন</translation>
+<translation id="100323615638474026">ইউএসবি ডিভাইস (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">অ্যাক্সেস করতে পারে এমন সাইট</translation>
 <translation id="1005274289863221750">আপনার মাইক্রোফোন ও ক্যামেরা ব্যবহার করুন</translation>
 <translation id="1005333234656240382">ADB ডিবাগিং চালু করতে চান?</translation>
@@ -574,6 +575,7 @@
 <translation id="1614511179807650956">আপনি হয়ত সমস্ত মোবাইল ডেটা ব্যবহার করে ফেলেছেন৷ আরও ডেটা কিনতে <ph name="NAME" /> অ্যাক্টিভেশন পোর্টালে যান</translation>
 <translation id="161460670679785907">আপনার ফোনটি শনাক্ত করা যায়নি</translation>
 <translation id="1615402009686901181">কোনও গোপনীয় কন্টেন্ট দেখা গেলে অ্যাডমিনিস্ট্রেটরের সেট করা নীতি অনুযায়ী স্ক্রিন ক্যাপচার করার সুবিধা বন্ধ করে দেওয়া হয়</translation>
+<translation id="1615755956145364867">সুরক্ষিত কন্টেন্ট চালানোর জন্য সাইট আপনার অনুমতি চাইতে পারে</translation>
 <translation id="1616206807336925449">এই এক্সটেনশনটির কোনও বিশেষ অনুমতির প্রয়োজন নেই।</translation>
 <translation id="1616298854599875024">এটি একটি শেয়ার করা মডিউল না হওয়ার কারণে <ph name="IMPORT_NAME" /> এক্সটেনশন ইমপোর্ট করা যাচ্ছে না</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{আপনার সংস্থার সুরক্ষা নীতি মেনে চলছে কিনা তা জানতে এই ডেটা চেক করা হচ্ছে…}=1{আপনার সংস্থার সুরক্ষা নীতি মেনে চলছে কিনা তা জানতে এই ফাইল চেক করা হচ্ছে…}one{আপনার সংস্থার সুরক্ষা নীতি মেনে চলছে কিনা তা জানতে এই ফাইলগুলি চেক করা হচ্ছে…}other{আপনার সংস্থার সুরক্ষা নীতি মেনে চলছে কিনা তা জানতে এই ফাইলগুলি চেক করা হচ্ছে…}}</translation>
@@ -768,6 +770,7 @@
 <translation id="1794051631868188691"><ph name="MERCHANT" /> কখনও দেখতে চাই না</translation>
 <translation id="1794791083288629568">এই সমস্যা সমাধানে আমাদের সাহায্য করতে প্রতিবার্তা পাঠান।</translation>
 <translation id="1795214765651529549">ক্লাসিক ব্যবহার করুন</translation>
+<translation id="1796588414813960292">যেসব ফিচার ব্যবহার করার জন্য সাউন্ড প্রয়োজন সেগুলি কাজ করবে না</translation>
 <translation id="1799071797295057738">"<ph name="EXTENSION_NAME" />" এক্সটেনশনটি অটোমেটিক বন্ধ করা হয়েছে।</translation>
 <translation id="1800973090344019061">"<ph name="APP_NAME" />" এক্সটেনশনটি আপনার স্ক্রিনের কন্টেন্ট শেয়ার করতে চায়।</translation>
 <translation id="1802624026913571222">ডিভাইসের কভার বন্ধ করলে স্লিপ মোডে চলে যাবে</translation>
@@ -966,6 +969,7 @@
 <translation id="2007404777272201486">কোনও সমস্যা অভিযোগ করুন...</translation>
 <translation id="2010501376126504057">মানানসই ডিভাইস</translation>
 <translation id="2015232545623037616">PC ও Chromecast একই ওয়াই-ফাই নেটওয়ার্কে আছে</translation>
+<translation id="2016473077102413275">যেসব ফিচার ব্যবহার করার জন্য ছবি প্রয়োজন সেগুলি কাজ করবে না</translation>
 <translation id="2016574333161572915">আপনার Google Meet হার্ডওয়্যার সেট-আপ করার জন্য রেডি</translation>
 <translation id="2017334798163366053">কার্য-সম্পাদনা ডেটা সংগ্রহ বন্ধ করুন</translation>
 <translation id="2018352199541442911">আপনার বাহ্যিক স্টোরেজের ডিভাইসটি এই মুহুর্তে সমর্থিত নয়৷</translation>
@@ -1296,6 +1300,7 @@
 <translation id="2355604387869345912">ইনস্ট্যান্ট টিথারিং চালু করুন</translation>
 <translation id="2356070529366658676">জিজ্ঞাসা করুন</translation>
 <translation id="2357330829548294574"><ph name="USER_NAME" />-কে সরান</translation>
+<translation id="2358561147588818967">সাইট জাভাস্ক্রিপ্ট ব্যবহার করতে পারে</translation>
 <translation id="2359071692152028734">Linux অ্যাপ প্রতিক্রিয়া নাও জানাতে পারে।</translation>
 <translation id="2359345697448000899">টুল মেনুতে এক্সটেনশনে ক্লিক করে আপনার এক্সটেনশনগুলি পরিচালনা করুন৷</translation>
 <translation id="2359556993567737338">ব্লুটুথ ডিভাইস কানেক্ট করুন</translation>
@@ -1472,6 +1477,7 @@
 <translation id="2544853746127077729">নেটওয়ার্কের দ্বারা প্রমাণীকরণ সার্টিফিকেট প্রত্যাখ্যান করা হয়েছে</translation>
 <translation id="2546283357679194313">কুকিজ ও সাইট ডেটা</translation>
 <translation id="2548347166720081527"><ph name="PERMISSION" />-এর অনুমতি দেওয়া হয়েছে</translation>
+<translation id="2548545707296594436">eSIM প্রোফাইল ক্যাশে রিসেট করুন</translation>
 <translation id="2549985041256363841">রেকর্ডিং শুরু করুন</translation>
 <translation id="2550212893339833758">অদলবদল করা মেমরি</translation>
 <translation id="2550596535588364872"><ph name="FILE_NAME" /> খোলার জন্য <ph name="EXTENSION_NAME" />-কে অনুমতি দিন?</translation>
@@ -1664,6 +1670,7 @@
 <translation id="2765217105034171413">ক্ষুদ্র</translation>
 <translation id="2766006623206032690">প্র&amp;তিলেপন করুন ও যান</translation>
 <translation id="2766161002040448006">কোনও অভিভাবককে বলুন</translation>
+<translation id="2767077837043621282">আপনার Chromebook আপডেট করা যায়নি। পরে আবার চেষ্টা করুন।</translation>
 <translation id="2767127727915954024"><ph name="ORIGIN" /> <ph name="FILENAME" /> এডিট করতে পারবে যতক্ষণ না আপনি এই সাইটের জন্য সব ট্যাব বন্ধ করে দিচ্ছেন</translation>
 <translation id="2770465223704140727">তালিকা থেকে সরান</translation>
 <translation id="2770690685823456775">আপনার পাসওয়ার্ড অন্য ফোল্ডারে এক্সপোর্ট করুন</translation>
@@ -1941,6 +1948,7 @@
 <translation id="3060379269883947824">'বাছুন ও শুনুন' চালু করুন</translation>
 <translation id="3060952009917586498">ডিভাইসের ভাষা পরিবর্তন করুন। এখন <ph name="LANGUAGE" /> ভাষায় ডিভাইসটি ব্যবহার করছেন।</translation>
 <translation id="3060987956645097882">আমরা আপনার ফোনে সাথে কানেক্ট করতে পারছি না। আপনার ফোন কাছাকাছি, আনলক অবস্থায় রয়েছে কিনা এবং তাতে ব্লুটুথ আর ওয়াই-ফাই চালু আছে কিনা দেখে নিন।</translation>
+<translation id="3064871050034234884">সাইট সাউন্ড চালাতে পারে</translation>
 <translation id="3065041951436100775">ট্যাব নষ্ট হওয়ার প্রতিক্রিয়া।</translation>
 <translation id="3065522099314259755">কীবোর্ড রিপিট করার লেটেন্সি</translation>
 <translation id="3067198179881736288">অ্যাপ ইনস্টল করবেন?</translation>
@@ -2291,6 +2299,7 @@
 <translation id="3462413494201477527">অ্যাকাউন্ট সেট-আপ বাতিল করবেন?</translation>
 <translation id="3464145797867108663">অফিস প্রোফাইল যোগ করুন</translation>
 <translation id="346431825526753">এটি <ph name="CUSTODIAN_EMAIL" />-এর দ্বারা পরিচালিত বাচ্চাদের জন্য একটি অ্যাকাউন্ট৷</translation>
+<translation id="3465480292013046659">আপডেট ডাউনলোড করার সময় সমস্যা হয়েছে। পরে আবার চেষ্টা করুন।</translation>
 <translation id="3468298837301810372">লেবেল</translation>
 <translation id="3468999815377931311">Android ফোন</translation>
 <translation id="3470442499439619530">এই ব্যবহারকারীকে সরান</translation>
@@ -2322,6 +2331,7 @@
 <translation id="3495496470825196617">চার্জ করার সময় ডিভাইসকে 'নিষ্ক্রিয়' বা 'স্লিপ' স্ট্যাটাসে রাখা</translation>
 <translation id="3495660573538963482">Google অ্যাসিস্ট্যান্ট সেটিংস</translation>
 <translation id="3496213124478423963">জুম কমান</translation>
+<translation id="3497501929010263034"><ph name="VENDOR_NAME" /> থেকে ইউএসবি ডিভাইস (প্রোডাক্ট <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">ডুডল শেয়ার করুন</translation>
 <translation id="3498215018399854026">আমরা এই মুহূর্তে আপনার পিতামাতার সাথে যোগাযোগ করতে পারিনি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷</translation>
 <translation id="3500417806337761827">শেয়ার মাউন্ট করার সময় কোনও সমস্যা হয়েছে। অনেকগুলি SMB শেয়ার আগে থেকেই মাউন্ট করা হয়েছে।</translation>
@@ -2409,6 +2419,7 @@
 <translation id="3600792891314830896">সাউন্ড প্লে করা হয় যে সাইটগুলিতে সেগুলি মিউট করুন</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">নতুন ফিচার উপলভ্য হলেই তা অফার করে</translation>
+<translation id="3602179428782502464">আপনার অ্যাডমিনিস্ট্রেটর এই আপডেট ব্লক করে দিয়েছেন</translation>
 <translation id="3602290021589620013">প্রিভিউ</translation>
 <translation id="3602870520245633055">প্রিন্ট ও স্ক্যান করুন</translation>
 <translation id="3603622770190368340">নেটওয়ার্ক সার্টিফিকেট প্রাপ্ত করুন</translation>
@@ -2418,6 +2429,7 @@
 <translation id="3610369246614755442">ডকিং স্টেশনের ফ্যান সার্ভিসিং করতে হবে</translation>
 <translation id="361106536627977100">ফ্ল্যাশ ডেটা</translation>
 <translation id="3611655097742243705">অ্যাপ ডাউনলোড করতে Play Store দেখুন</translation>
+<translation id="3611658447322220736">সম্প্রতি বন্ধ করা সাইট ডেটা পাঠানো ও গ্রহণ করা শেষ করতে পারে</translation>
 <translation id="3612673635130633812">&lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt; এর দ্বারা ডাউনলোড হয়েছে</translation>
 <translation id="3613134908380545408"><ph name="FOLDER_NAME" /> দেখান</translation>
 <translation id="3613422051106148727">&amp;নতুন ট্যাবে খুলুন</translation>
@@ -2450,6 +2462,7 @@
 <translation id="3639220004740062347">রিডার মোড থেকে বেরিয়ে আসুন</translation>
 <translation id="3640214691812501263"><ph name="USER_NAME" /> এর জন্য "<ph name="EXTENSION_NAME" />" জুড়বেন?</translation>
 <translation id="3640613767643722554">অ্যাসিস্ট্যান্টকে আপনার ভয়েস চিনতে শেখান</translation>
+<translation id="3641456520301071208">সাইট আপনার লোকেশন জানতে চায়</translation>
 <translation id="3645372836428131288">আঙ্গুলের ছাপের বিভিন্ন অংশ ক্যাপচার করতে একটু এদিক-ওদিক সরান৷</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{<ph name="DEVICE_NAME" /> থেকে <ph name="ATTACHMENTS" /> এসেছে}one{<ph name="DEVICE_NAME" /> থেকে <ph name="ATTACHMENTS" /> এসেছে}other{<ph name="DEVICE_NAME" /> থেকে <ph name="ATTACHMENTS" /> এসেছে}}</translation>
 <translation id="3648348069317717750"><ph name="USB_DEVICE_NAME" /> শনাক্ত হয়েছে</translation>
@@ -2492,6 +2505,7 @@
 <translation id="3688526734140524629">চ্যানেল পরিবর্তন করুন</translation>
 <translation id="3688578402379768763">আপ-টু-ডেট</translation>
 <translation id="3688794912214798596">ভাষা পরিবর্তন করুন...</translation>
+<translation id="3690128548376345212"><ph name="NETWORK_COUNT" />টির মধ্যে <ph name="NETWORK_INDEX" /> নম্বর নেটওয়ার্ক, <ph name="NETWORK_NAME" />, চালু করা হয়নি, <ph name="CONNECTION_STATUS" />, সিগন্যাল ক্ষমতা <ph name="SIGNAL_STRENGTH" />%, বিবরণ</translation>
 <translation id="3690369331356918524">আপনার পাসওয়ার্ড কোনও ডেটা নিরাপত্তা লঙ্ঘনের কারণে সর্বজনীনভাবে প্রকাশ হলে তা আপনাকে জানানো হবে</translation>
 <translation id="3691231116639905343">কীবোর্ড অ্যাপ</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> আপনার স্ক্রিন শেয়ার করতে চায়</translation>
@@ -2573,6 +2587,7 @@
 <translation id="3772609330847318323"><ph name="ORIGIN" />-এর জন্য পাসওয়ার্ড আপডেট করুন</translation>
 <translation id="3775432569830822555">SSL সার্ভার সার্টিফিকেট</translation>
 <translation id="3775705724665058594">আপনার ডিভাইসে পাঠান</translation>
+<translation id="3776508619697147021">একাধিক ফাইল অটোমেটিক ডাউনলোড করতে, সাইট অনুমতি চাইতে পারে</translation>
 <translation id="3776796446459804932">এই এক্সটেনশনটি 'Chrome ওয়েব স্টোরে'র নীতি লঙ্ঘন করে৷</translation>
 <translation id="3777483481409781352">সেলুলার ডিভাইস অ্যাক্টিভেট করা যায়নি</translation>
 <translation id="3777806571986431400">এক্সটেনশন চালু করা হয়েছে</translation>
@@ -2873,6 +2888,7 @@
 <translation id="4078738236287221428">আক্রমণাত্মক</translation>
 <translation id="4079140982534148664">উন্নত বানান পরীক্ষা ব্যবহার করুন</translation>
 <translation id="4081242589061676262">ফাইলটি কাস্ট করতে অক্ষম।</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> আপনার ফোনে বিজ্ঞপ্তি পাঠিয়েছে। আপনার পরিচয় কনফার্ম করতে, ফোনে উল্লিখিত ধাপগুলি অনুসরণ করুন।</translation>
 <translation id="4084682180776658562">বুকমার্ক</translation>
 <translation id="4084835346725913160"><ph name="TAB_NAME" /> বন্ধ করুন</translation>
 <translation id="4085270836953633510">কোনও সাইট সিরিয়াল পোর্ট অ্যাক্সেস করতে চাইলে আমাকে জিজ্ঞাসা করুন</translation>
@@ -3034,6 +3050,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{কন্টেন্ট দেখান}one{সব কন্টেন্ট দেখান}other{সব কন্টেন্ট দেখান}}</translation>
 <translation id="4289372044984810120">এখান থেকে আপনার অ্যাকাউন্ট ম্যানেজ করুন। <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">ওভারভিউ</translation>
+<translation id="4290791284969893584">কোনও পৃষ্ঠা বন্ধ করে দিলে, আপনার শুরু করা টাস্ক নাও শেষ হতে পারে</translation>
 <translation id="4295072614469448764">অ্যাপ আপনার টার্মিনালে পাওয়া যায়। আপনার লঞ্চারে একটি আইকনও থাকতে পারে।</translation>
 <translation id="4295839147292213505">আপনার কম্পিউটার থেকে টেক্সট, ইন্টারনেট কানেকশন শেয়ার, কথোপকথনের বিজ্ঞপ্তির উত্তর এবং আপনার ফোনের সাহায্যে <ph name="DEVICE_TYPE" /> আনলক করতে পারবনে।<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">Chrome ও Google Play-তে ওয়েবসাইট, অ্যাপ ও এক্সটেনশনকে আপনার <ph name="USER_EMAIL" /> অ্যাকাউন্ট ব্যবহার করার অনুমতি দিতে আবার সাইন-ইন করুন। আপনি এই অ্যাকাউন্ট সরিয়েও দিতে পারেন। <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
@@ -3230,6 +3247,7 @@
 <translation id="4514610446763173167">ভিডিও চালাতে বা থামানোর জন্য টগল করুন</translation>
 <translation id="451515744433878153">সরান</translation>
 <translation id="4515872537870654449">সার্ভিসিংয়ের জন্য Dell-এর সাথে যোগাযোগ করুন। ফ্যান কাজ না করলে ডকিং স্টেশন বন্ধ হয়ে যাবে।</translation>
+<translation id="4519331665958994620">সাইট আপনার ক্যামেরা ব্যবহার করার অনুমতি চাইতে পারে</translation>
 <translation id="4519935350946509010">কানেকশনে সমস্যা।</translation>
 <translation id="4520385623207007473">কুকিগুলি ব্যবহার করা হচ্ছে</translation>
 <translation id="452039078290142656"><ph name="VENDOR_NAME" /> থেকে অজানা ডিভাইসগুলি</translation>
@@ -3409,6 +3427,7 @@
 <translation id="4694604912444486114">বাঁদর</translation>
 <translation id="4697071790493980729">কোনও ফলাফল পাওয়া যায়নি</translation>
 <translation id="4697551882387947560">যখন ব্রাউজিং সেশন সমাপ্ত হয়</translation>
+<translation id="469838979880025581">সাইট আপনার মাইক্রোফোন ব্যবহার করার অনুমতি চাইতে পারে</translation>
 <translation id="4699172675775169585">ক্যাশে করা ছবি এবং ফাইলগুলি</translation>
 <translation id="4699357559218762027">(স্বয়ংক্রিয়ভাবে- লঞ্চ হয়েছে)</translation>
 <translation id="4701025263201366865">অভিভাবকের সাইন-ইন</translation>
@@ -3591,6 +3610,10 @@
 <translation id="4918086044614829423">স্বীকার</translation>
 <translation id="4921290200821452703">অভিভাবকদের জন্য স্কুল অ্যাকাউন্ট সম্পর্কিত তথ্য</translation>
 <translation id="4921348630401250116">টেক্সট-টু-স্পিচ</translation>
+<translation id="4921809350408880559">আগে Google Drive ব্যবহার করার সময় আপনার অ্যাক্টিভিটির উপর নির্ভর করে আপনাকে সাম্প্রতিক ও সাজেস্ট করা ডকুমেন্ট দেখানো হচ্ছে।
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google Drive কোন ডেটা কেন সংগ্রহ করে তা <ph name="BEGIN_LINK" />এখান<ph name="END_LINK" /> থেকে জানুন।</translation>
 <translation id="49226369361073053">{0,plural, =0{এখনই ডিভাইস আপডেট করুন}=1{১ সেকেন্ডের মধ্যে ডিভাইস আপডেট করুন}one{# সেকেন্ডের মধ্যে ডিভাইস আপডেট করুন}other{# সেকেন্ডের মধ্যে ডিভাইস আপডেট করুন}}</translation>
 <translation id="492299503953721473">Android অ্যাপ্লিকেশানগুলি সরান</translation>
 <translation id="492363500327720082"><ph name="APP_NAME" /> আনইনস্টল করা হচ্ছে...</translation>
@@ -4352,6 +4375,7 @@
 <translation id="5794700615121138172">Linux-এর শেয়ার করা ফোল্ডার</translation>
 <translation id="5794786537412027208">সব Chrome অ্যাপ বন্ধ করুন</translation>
 <translation id="5797070761912323120">সার্চ, বিজ্ঞাপন এবং অন্যান্য Google পরিষেবাকে আপনার মতো করে সাজিয়ে নিতে Google আপনার ইতিহাস ব্যবহার করতে পারে</translation>
+<translation id="5798079537501238810">সাইট, পেমেন্ট হ্যান্ডলার ইনস্টল করতে পারে</translation>
 <translation id="579907812742603813">সুরক্ষিত কন্টেন্ট</translation>
 <translation id="579915268381781820">আপনার নিরাপত্তা কী খুলে নেওয়া হয়েছে।</translation>
 <translation id="5799478978078236781"><ph name="DEVICE_TYPE" /> সংক্রান্ত পরামর্শ, অফার ও আপডেট পান এবং মতামত শেয়ার করুন।</translation>
@@ -4384,6 +4408,7 @@
 <translation id="5833726373896279253">এই সেটিংস কেবল মালিক ঈষত্সংশোধন করতে পারেন:</translation>
 <translation id="5834581999798853053">প্রায় <ph name="TIME" /> মিনিট বাকি</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - ক্যামেরা বা মাইক্রোফোন রেকর্ডিং</translation>
+<translation id="583673505367439042">সাইট আপনার ডিভাইসের ফাইল ও ফোল্ডার এডিট করার অনুমতি চাইতে পারে</translation>
 <translation id="5840680448799937675">সর্বদা ফাইল অফলাইনে শেয়ার করা হবে</translation>
 <translation id="5841270259333717135">ইথারনেট কনফিগার করুন</translation>
 <translation id="5842497610951477805">ব্লুটুথ সক্ষম</translation>
@@ -4433,6 +4458,7 @@
 <translation id="5889282057229379085">ইন্টারমিডিয়েট CAগুলির সর্বাধিক সংখ্যা: <ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">পছন্দের ওয়াই-ফাই নেটওয়ার্ক</translation>
 <translation id="5895138241574237353">পুনর্সূচনা</translation>
+<translation id="5896749729057314184"><ph name="NETWORK_COUNT" />টির মধ্যে <ph name="NETWORK_INDEX" /> নম্বর নেটওয়ার্ক, <ph name="NETWORK_NAME" />, চালু করা হয়নি, সিগন্যাল ক্ষমতা <ph name="SIGNAL_STRENGTH" />%, বিবরণ</translation>
 <translation id="5900302528761731119">Google প্রোফাইল ফটো </translation>
 <translation id="590036993063074298">মিররিং কোয়ালিটির বিবরণ</translation>
 <translation id="5901069264981746702">আপনার আঙুলের ছাপ সংক্রান্ত ডেটা সুরক্ষিতভাবে স্টোর করে রাখা হয় এবং <ph name="DEVICE_TYPE" /> থেকে হারিয়ে যায় না। <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
@@ -4677,6 +4703,7 @@
 <translation id="6155141482566063812">ব্যাকগ্রাউন্ড ট্যাব আপনার স্ক্রিন শেয়ার করছে</translation>
 <translation id="6156323911414505561">বুকমার্ক বার দেখান</translation>
 <translation id="6156863943908443225">স্ক্রিপ্ট  ক্যাশে</translation>
+<translation id="615930144153753547">সাইট ছবি দেখাতে পারে</translation>
 <translation id="6160625263637492097">যাচাইকরণের জন্য সার্টিফিকেট সরবরাহ করুন</translation>
 <translation id="6163363155248589649">&amp;সাধারণ</translation>
 <translation id="6163376401832887457">Kerberos সেটিংস</translation>
@@ -4883,6 +4910,10 @@
 <translation id="6398715114293939307">Google Play স্টোর সরান</translation>
 <translation id="6398765197997659313">পূর্ণ স্ক্রীণ বন্ধ করুন</translation>
 <translation id="6399774419735315745">গুপ্তচর</translation>
+<translation id="6400510847800135340">আগে Google পরিষেবা ব্যবহার করার সময় আপনার অ্যাক্টিভিটির উপর নির্ভর করে আপনাকে এই আইটেম দেখানো হচ্ছে। <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> থেকে আপনি ডেটা দেখতে, মুছে দিতে ও পরিবর্তন করতে পারেন।
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google কোন ডেটা কেন সংগ্রহ করে তা <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" /> থেকে জানুন।</translation>
 <translation id="6404511346730675251">বুকমার্ক সম্পাদনা করুন</translation>
 <translation id="6406303162637086258">ব্রাউজার রিস্টার্ট সিমুলেট করুন</translation>
 <translation id="6406506848690869874">সিঙ্ক</translation>
@@ -4932,6 +4963,7 @@
 <translation id="6452251728599530347"><ph name="PERCENT" /> হয়েছে</translation>
 <translation id="645286928527869380">রেসিপি সম্পর্কিত আইডিয়া</translation>
 <translation id="6452961788130242735">নেটওয়ার্কের সমস্যা বা ভুল রিলম</translation>
+<translation id="6453921811609336127">পরের ইনপুট পদ্ধতিতে পাল্টাতে <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> টিপুন</translation>
 <translation id="6455264371803474013">নির্দিষ্ট সাইটগুলিতে</translation>
 <translation id="6455894534188563617">&amp;নতুন ফোল্ডার</translation>
 <translation id="645705751491738698">জাভাস্ক্রিপ্ট ব্লক করা চালিয়ে যান</translation>
@@ -5057,6 +5089,7 @@
 <translation id="6590458744723262880">ফোল্ডারটির নতুন নাম দিন</translation>
 <translation id="6592267180249644460"><ph name="WEBRTC_LOG_CAPTURE_TIME" /> এ WebRTC লগ ক্যাপচার করা হয়েছে</translation>
 <translation id="6592808042417736307">আপনার আঙ্গুলের ছাপ ক্যাপচার করা হয়েছে</translation>
+<translation id="6593881952206664229">কপিরাইট সহ মিডিয়া নাও চলতে পারে</translation>
 <translation id="6594011207075825276">ক্রমিক সংখ্যা ধরে ধরে ডিভাইস খোঁজা হচ্ছে...</translation>
 <translation id="6595187330192059106">MIDI ডিভাইসগুলি সম্পূর্ণ নিয়ন্ত্রণ করা থেকে <ph name="HOST" />-কে সবসময় ব্লক করুন।</translation>
 <translation id="6596325263575161958">এনক্রিপশন বিকল্পগুলি</translation>
@@ -6014,6 +6047,7 @@
 <translation id="7661451191293163002">একটি নিবন্ধীকরণ সার্টিফিকেট পাওয়া যায়নি।</translation>
 <translation id="7662283695561029522">কনফিগার করতে ট্যাপ করুন</translation>
 <translation id="7663719505383602579">গ্রাহক: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">কীবোর্ড শর্টকাট আছে</translation>
 <translation id="7664620655576155379">অসমর্থিত ব্লুটুথ ডিভাইস: "<ph name="DEVICE_NAME" />"৷</translation>
 <translation id="7665082356120621510">সাইজ সেভ করুন</translation>
 <translation id="7665369617277396874">অ্যাকাউন্ট যোগ করুন</translation>
@@ -6192,6 +6226,7 @@
 <translation id="7835178595033117206">বুকমার্ক সরানো হয়েছে</translation>
 <translation id="7836850009646241041">আপনার নিরাপত্তা কী আবার স্পর্শ করার চেষ্টা করুন</translation>
 <translation id="7837776265184002579">আপনার হোমপেজটি <ph name="URL" />-তে কপি করা হয়েছে।</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{<ph name="DEVICE_NAME" />-এ <ph name="ATTACHMENTS" /> পাঠানো হয়েছে}one{<ph name="DEVICE_NAME" />-এ <ph name="ATTACHMENTS" /> পাঠানো হয়েছে}other{<ph name="DEVICE_NAME" />-এ <ph name="ATTACHMENTS" /> পাঠানো হয়েছে}}</translation>
 <translation id="7839051173341654115">মিডিয়া দেখুন/ব্যাক-আপ নিন</translation>
 <translation id="7839192898639727867">সার্টিফিকেট বিষয় কী আইডি</translation>
 <translation id="7842692330619197998">আপনি যদি নতুন অ্যাকাউন্ট তৈরি করতে চান, তাহলে g.co/ChromeEnterpriseAccount লিঙ্কে যান।</translation>
@@ -6888,6 +6923,7 @@
 <translation id="8633025649649592204">সাম্প্রতিক অ্যাক্টিভিটি</translation>
 <translation id="8635628933471165173">আবার লোড করা হচ্ছে...</translation>
 <translation id="8636284842992792762">এক্সটেনশন চালু করা হচ্ছে...</translation>
+<translation id="8636500887554457830">সাইটকে পপ-আপ পাঠানো বা রিডাইরেক্ট ব্যবহার করার অনুমতি দেবেন না</translation>
 <translation id="8637542770513281060">আপনার কম্পিউটারে একটি নিরাপদ মডিউল আছে, যেটির সাহায্যে Chrome OS-এর বিভিন্ন জটিল নিরাপত্তা বৈশিষ্ট্য ব্যবহার করা হয়। আরও জানতে Chromebook সহায়তা কেন্দ্রে যান: https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">সিস্টেম আপডেট উপলভ্য৷ ডাউনলোড করতে প্রস্তুত হচ্ছে...</translation>
 <translation id="863903787380594467">ভুল পিন দিয়েছেন। আপনি আর <ph name="RETRIES" /> বার চেষ্টা করতে পারবেন।</translation>
@@ -7106,6 +7142,7 @@
 <translation id="8842594465773264717">এই ফিঙ্গারপ্রিন্ট মুছুন</translation>
 <translation id="8845001906332463065">সাহায্য পান</translation>
 <translation id="8846132060409673887">এই কম্পিউটারের প্রস্তুতকারক এবং মডেলটি পড়ুন</translation>
+<translation id="8846163936679269230">eSIM প্রোফাইল রিসেট করুন</translation>
 <translation id="8847523528195140327">ডিভাইসের কভার বন্ধ করলে সাইন-আউট হয়ে যাবে</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">লুকানো আছে</translation>
@@ -7161,6 +7198,7 @@
 <translation id="8898822736010347272">আপনার দেখা কিছু পৃষ্ঠার ইউআরএল, সীমিত সিস্টেম সম্পর্কিত তথ্য এবং কিছু পৃষ্ঠার কন্টেন্ট Google-এর কাছে পাঠান যাতে নতুন ঝুঁকি চিহ্নিত করে ওয়েব ব্যবহারকারীর প্রত্যেককে সুরক্ষিত রাখা যায়।</translation>
 <translation id="8899851313684471736">নতুন &amp;উইন্ডোতে লিঙ্ক খুলুন</translation>
 <translation id="8900413463156971200">মোবাইল নেটওয়ার্ক চালু করুন</translation>
+<translation id="8901994452417867840">প্রোফাইল যোগ করা হয়েছে। এই ডিভাইসের সব ব্যবহারকারী এই কানেকশন ব্যবহার করতে পারবেন।</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> আপনাকে নিজের ডেটার ব্যাকআপ নিয়ে এই <ph name="DEVICE_TYPE" /> আজই ফেরত দিতে বলছে।}one{<ph name="MANAGER" /> আপনাকে নিজের ডেটার ব্যাকআপ নিয়ে এই <ph name="DEVICE_TYPE" /> নির্ধারিত সময়সীমা শেষ হওয়ার আগেই ফেরত দিতে বলছে।}other{<ph name="MANAGER" /> আপনাকে নিজের ডেটার ব্যাকআপ নিয়ে এই <ph name="DEVICE_TYPE" /> নির্ধারিত সময়সীমা শেষ হওয়ার আগেই ফেরত দিতে বলছে।}}</translation>
 <translation id="8902667442496790482">'বাছুন ও শুনুন'-এর সেটিংস খুলুন</translation>
 <translation id="8903263458134414071">সাইন-ইন করার জন্য একটি অ্যাকাউন্ট বেছে নিন</translation>
@@ -7342,6 +7380,7 @@
 <translation id="9094982973264386462">সরান</translation>
 <translation id="9095253524804455615">সরান</translation>
 <translation id="909554839118732438">'ছদ্মবেশী' উইন্ডো বন্ধ করুন</translation>
+<translation id="9100416672768993722">শেষ ব্যবহৃত ইনপুট পদ্ধতিতে পাল্টাতে <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> টিপুন</translation>
 <translation id="9100610230175265781">পাসফ্রেজের প্রয়োজন</translation>
 <translation id="9100765901046053179">উন্নত সেটিংস</translation>
 <translation id="9101691533782776290">অ্যাপ্লিকেশন লঞ্চ করুন</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index f3fe066..0852270 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -62,6 +62,7 @@
 <translation id="1066613507389053689">Chrome OS update required</translation>
 <translation id="1067048845568873861">Created</translation>
 <translation id="1067922213147265141">Other Google services</translation>
+<translation id="1069355737714877171">Remove eSIM profile named <ph name="PROFILE_NAME" /></translation>
 <translation id="1070377999570795893">Another program on your computer added an extension that may change the way Chrome works.
 
 <ph name="EXTENSION_NAME" /></translation>
@@ -357,6 +358,7 @@
 <translation id="138784436342154190">Restore default start-up page?</translation>
 <translation id="1388253969141979417">Allowed to use your microphone</translation>
 <translation id="1388728792929436380"><ph name="DEVICE_TYPE" /> will restart when updates are complete.</translation>
+<translation id="138900021244932468">No profiles were discovered. To set up a new network, scan the QR code using the device camera or enter the activation code provided by your operator.</translation>
 <translation id="139013308650923562">Allowed to use fonts installed on your device</translation>
 <translation id="1390548061267426325">Open as a standard tab</translation>
 <translation id="1393283411312835250">Sun and clouds</translation>
@@ -995,6 +997,7 @@
 You can manage this account’s settings by installing the Family Link app on your device.  We sent you instructions in an email.</translation>
 <translation id="2040460856718599782">Oops!  Something went wrong when trying to authenticate you. Please double-check your sign-in credentials and try again.</translation>
 <translation id="2044014337866019681">Please make sure that you are verifying <ph name="ACCOUNT" /> to unlock the session.</translation>
+<translation id="2044023416777079300">Modem not registered</translation>
 <translation id="204497730941176055">Microsoft certificate template name</translation>
 <translation id="2045117674524495717">Keyboard Shortcut Helper</translation>
 <translation id="2045969484888636535">Continue blocking cookies</translation>
@@ -4098,6 +4101,7 @@
 <translation id="5486261815000869482">Confirm password</translation>
 <translation id="5486275809415469523"><ph name="APP_NAME" /> is sharing your screen with <ph name="TAB_NAME" />.</translation>
 <translation id="5486561344817861625">Simulate browser restart</translation>
+<translation id="5487460042548760727">Rename profile to <ph name="PROFILE_NAME" /></translation>
 <translation id="5487521232677179737">Clear data</translation>
 <translation id="5488093641312826914">'<ph name="COPIED_ITEM_NAME" />' copied</translation>
 <translation id="5488508217173274228">Sync encryption options</translation>
@@ -4839,6 +4843,7 @@
 <translation id="6308937455967653460">Save lin&amp;k as...</translation>
 <translation id="6309443618838462258">Your administrator doesn't allow this input method</translation>
 <translation id="6309510305002439352">Microphone turned off</translation>
+<translation id="6310141306111263820">Couldn't install eSIM profile. For help, please contact your operator.</translation>
 <translation id="6311220991371174222">Cannot start Chrome because something went wrong when opening your profile. Try to restart Chrome.</translation>
 <translation id="6312403991423642364">Unknown network error</translation>
 <translation id="6312567056350025599">{NUM_DAYS,plural, =1{Safety check ran 1 day ago}other{Safety check ran {NUM_DAYS} days ago}}</translation>
@@ -5975,6 +5980,7 @@
 <translation id="7582582252461552277">Prefer this network</translation>
 <translation id="7582844466922312471">Mobile Data</translation>
 <translation id="7583948862126372804">Count</translation>
+<translation id="7586051298768394542">Can't download speech files. Dictation will continue to work by sending your voice to Google.</translation>
 <translation id="7586498138629385861">Chrome will keep running while Chrome Apps are open.</translation>
 <translation id="7589461650300748890">Whoa, there. Be careful.</translation>
 <translation id="7593653750169415785">Automatically blocked because you declined notifications a few times</translation>
@@ -6564,6 +6570,7 @@
 <translation id="8191230140820435481">Manage your apps, extensions, and themes</translation>
 <translation id="8195027750202970175">Size on disk</translation>
 <translation id="8198323535106903877">We'll install those <ph name="NUMBER_OF_APPS" /> apps for you</translation>
+<translation id="8198456017687137612">Cast tab</translation>
 <translation id="8199300056570174101">Network (Service) and Device properties</translation>
 <translation id="8200772114523450471">Resume</translation>
 <translation id="8201717382574620700">Select <ph name="TOPIC_SOURCE" /> albums</translation>
@@ -7148,6 +7155,7 @@
 <translation id="8847523528195140327">Sign out when cover is closed</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">Hidden</translation>
+<translation id="8849219423513870962">Cancel removal of eSIM profile named <ph name="PROFILE_NAME" /></translation>
 <translation id="8850251000316748990">See more...</translation>
 <translation id="885246833287407341">API function arguments</translation>
 <translation id="8853586775156634952">This card will be saved to this device only</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index e664d0d3..c0fd587 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="ko">
 <translation id="1001307489511021749">앱, 설정 및 기타 맞춤설정이 내 Google 계정으로 로그인된 모든 Chrome OS 기기에서 동기화됩니다.</translation>
 <translation id="1003088604756913841">새 <ph name="APP" /> 창에서 링크 열기</translation>
+<translation id="100323615638474026">USB 기기(<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">사이트 액세스</translation>
 <translation id="1005274289863221750">마이크와 카메라 사용</translation>
 <translation id="1005333234656240382">ADB 디버깅을 사용 설정하시겠습니까?</translation>
@@ -573,6 +574,7 @@
 <translation id="1614511179807650956">할당된 모바일 데이터를 모두 사용한 것 같습니다. 추가 데이터를 구입하려면 <ph name="NAME" /> 활성화 포털을 방문하세요.</translation>
 <translation id="161460670679785907">휴대전화를 인식할 수 없습니다</translation>
 <translation id="1615402009686901181">기밀 콘텐츠가 보일 때 관리자 정책에서 화면 캡처를 사용 중지합니다.</translation>
+<translation id="1615755956145364867">사이트에서 보호된 콘텐츠 재생을 요청할 수 있음</translation>
 <translation id="1616206807336925449">이 확장 프로그램은 특별한 권한이 필요하지 않습니다.</translation>
 <translation id="1616298854599875024">확장 프로그램 '<ph name="IMPORT_NAME" />'은(는) 공유 모듈이 아니므로 가져올 수 없습니다</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{데이터가 조직 보안 정책을 준수하는지 확인하는 중입니다.}=1{파일이 조직 보안 정책을 준수하는지 확인하는 중입니다.}other{파일이 조직 보안 정책을 준수하는지 확인하는 중입니다.}}</translation>
@@ -767,6 +769,7 @@
 <translation id="1794051631868188691"><ph name="MERCHANT" /> 표시 안함</translation>
 <translation id="1794791083288629568">이 문제를 해결하는 데 도움이 되도록 의견 전송</translation>
 <translation id="1795214765651529549">기본 테마 사용</translation>
+<translation id="1796588414813960292">소리가 필요한 기능이 작동하지 않습니다</translation>
 <translation id="1799071797295057738">'<ph name="EXTENSION_NAME" />' 확장 프로그램 자동으로 사용 중지되었습니다.</translation>
 <translation id="1800973090344019061">"<ph name="APP_NAME" />" 확장 프로그램이 화면 내용을 공유하려고 합니다.</translation>
 <translation id="1802624026913571222">커버를 닫으면 절전 모드 진입</translation>
@@ -965,6 +968,7 @@
 <translation id="2007404777272201486">문제 신고...</translation>
 <translation id="2010501376126504057">호환 기기</translation>
 <translation id="2015232545623037616">PC와 Chromecast가 동일한 Wi-Fi 네트워크에 연결됨</translation>
+<translation id="2016473077102413275">이미지가 필요한 기능이 작동하지 않습니다</translation>
 <translation id="2016574333161572915">Google Meet 하드웨어 설정 준비가 완료되었습니다</translation>
 <translation id="2017334798163366053">성능 데이터 수집 사용 중지</translation>
 <translation id="2018352199541442911">죄송합니다. 연결하신 외부 저장장치는 현재 지원되지 않습니다.</translation>
@@ -1295,6 +1299,7 @@
 <translation id="2355604387869345912">인스턴트 테더링 켜기</translation>
 <translation id="2356070529366658676">확인</translation>
 <translation id="2357330829548294574"><ph name="USER_NAME" /> 삭제</translation>
+<translation id="2358561147588818967">사이트에서 자바스크립트를 사용할 수 있음</translation>
 <translation id="2359071692152028734">Linux 앱이 응답하지 않을 수 있습니다.</translation>
 <translation id="2359345697448000899">도구 메뉴에서 확장 프로그램을 클릭하여 확장 프로그램을 관리할 수 있습니다.</translation>
 <translation id="2359556993567737338">블루투스 기기 연결</translation>
@@ -1472,6 +1477,7 @@
 <translation id="2544853746127077729">인증서가 네트워크에 의해 거부됨</translation>
 <translation id="2546283357679194313">쿠키 및 사이트 데이터</translation>
 <translation id="2548347166720081527"><ph name="PERMISSION" /> 권한이 허용됨</translation>
+<translation id="2548545707296594436">eSIM 프로필 캐시 재설정</translation>
 <translation id="2549985041256363841">녹화 시작</translation>
 <translation id="2550212893339833758">교체된 메모리</translation>
 <translation id="2550596535588364872"><ph name="EXTENSION_NAME" />에서 <ph name="FILE_NAME" /> 파일을 열도록 허용하시겠습니까?</translation>
@@ -1665,6 +1671,7 @@
 <translation id="2765217105034171413">작게</translation>
 <translation id="2766006623206032690">붙여넣어 바로가기(&amp;S)</translation>
 <translation id="2766161002040448006">부모님에게 묻기</translation>
+<translation id="2767077837043621282">Chromebook을 업데이트할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
 <translation id="2767127727915954024">이 사이트의 탭을 모두 닫을 때까지 <ph name="ORIGIN" />에서 <ph name="FILENAME" /> 파일을 수정할 수 있게 됩니다.</translation>
 <translation id="2770465223704140727">목록에서 삭제</translation>
 <translation id="2770690685823456775">비밀번호를 다른 폴더로 내보냅니다.</translation>
@@ -1942,6 +1949,7 @@
 <translation id="3060379269883947824">텍스트 읽어주기 사용</translation>
 <translation id="3060952009917586498">기기 언어를 변경합니다. 현재 언어는 <ph name="LANGUAGE" />입니다.</translation>
 <translation id="3060987956645097882">휴대전화와 연결을 설정할 수 없습니다. 휴대전화가 근처에 있고, 잠금이 해제되어 있으며, 블루투스와 Wi-Fi가 켜져 있는지 확인하세요.</translation>
+<translation id="3064871050034234884">사이트에서 소리를 재생할 수 있음</translation>
 <translation id="3065041951436100775">탭 사용 중지 관련 피드백</translation>
 <translation id="3065522099314259755">키보드 반복 지연 시간</translation>
 <translation id="3067198179881736288">앱을 설치하시겠습니까?</translation>
@@ -2292,6 +2300,7 @@
 <translation id="3462413494201477527">계정 설정을 취소하시겠습니까?</translation>
 <translation id="3464145797867108663">직장 프로필 추가</translation>
 <translation id="346431825526753"><ph name="CUSTODIAN_EMAIL" />님이 관리하는 어린이용 계정입니다.</translation>
+<translation id="3465480292013046659">업데이트 다운로드 중 문제가 발생했습니다. 나중에 다시 시도해 주세요.</translation>
 <translation id="3468298837301810372">라벨</translation>
 <translation id="3468999815377931311">Android 휴대전화</translation>
 <translation id="3470442499439619530">이 사용자 삭제</translation>
@@ -2323,6 +2332,7 @@
 <translation id="3495496470825196617">충전 시 전력 유휴 상태로 설정</translation>
 <translation id="3495660573538963482">Google 어시스턴트 설정</translation>
 <translation id="3496213124478423963">축소</translation>
+<translation id="3497501929010263034"><ph name="VENDOR_NAME" />의 USB 기기(제품 <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">기념일 로고 공유</translation>
 <translation id="3498215018399854026">현재 부모님께 연락할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
 <translation id="3500417806337761827">공유를 마운트하는 중에 오류가 발생했습니다. 너무 많은 SMB 공유가 이미 마운트되었습니다.</translation>
@@ -2410,6 +2420,7 @@
 <translation id="3600792891314830896">소리를 재생하는 사이트 음소거</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" />, <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">새로운 기능이 출시되면 즉시 제공합니다.</translation>
+<translation id="3602179428782502464">관리자가 업데이트를 차단함</translation>
 <translation id="3602290021589620013">미리보기</translation>
 <translation id="3602870520245633055">인쇄 및 스캔</translation>
 <translation id="3603622770190368340">네트워크 인증서 받기</translation>
@@ -2419,6 +2430,7 @@
 <translation id="3610369246614755442">도크 팬 서비스 필요</translation>
 <translation id="361106536627977100">Flash 데이터</translation>
 <translation id="3611655097742243705">Play 스토어에 방문하여 더 많은 앱을 찾아보세요.</translation>
+<translation id="3611658447322220736">최근에 닫은 사이트에서 데이터 송수신을 완료할 수 있음</translation>
 <translation id="3612673635130633812">&lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt;에서 다운로드함</translation>
 <translation id="3613134908380545408"><ph name="FOLDER_NAME" /> 표시</translation>
 <translation id="3613422051106148727">새 탭에서 열기(&amp;O)</translation>
@@ -2451,6 +2463,7 @@
 <translation id="3639220004740062347">읽기 모드 종료</translation>
 <translation id="3640214691812501263"><ph name="USER_NAME" />님에 대하여 '<ph name="EXTENSION_NAME" />'을(를) 추가할까요?</translation>
 <translation id="3640613767643722554">어시스턴트가 내 음성을 인식하도록 학습시키기</translation>
+<translation id="3641456520301071208">사이트에서 위치 정보를 요청할 수 있음</translation>
 <translation id="3645372836428131288">지문의 다른 부분이 인식되도록 손가락을 살짝 움직이세요.</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{<ph name="DEVICE_NAME" />에서 <ph name="ATTACHMENTS" /> 수신}other{<ph name="DEVICE_NAME" />에서 <ph name="ATTACHMENTS" /> 수신}}</translation>
 <translation id="3648348069317717750"><ph name="USB_DEVICE_NAME" /> 발견됨</translation>
@@ -2493,6 +2506,7 @@
 <translation id="3688526734140524629">채널 변경</translation>
 <translation id="3688578402379768763">최신</translation>
 <translation id="3688794912214798596">언어 변경...</translation>
+<translation id="3690128548376345212"><ph name="NETWORK_COUNT" />개 중 <ph name="NETWORK_INDEX" />번째 네트워크, <ph name="NETWORK_NAME" />, 비활성화됨, <ph name="CONNECTION_STATUS" />, 신호 강도 <ph name="SIGNAL_STRENGTH" />%, 세부정보</translation>
 <translation id="3690369331356918524">데이터 유출로 인해 비밀번호가 노출된 경우 알립니다.</translation>
 <translation id="3691231116639905343">키보드 앱</translation>
 <translation id="3691267899302886494"><ph name="HOST" />에서 화면을 공유하려고 합니다</translation>
@@ -2574,6 +2588,7 @@
 <translation id="3772609330847318323"><ph name="ORIGIN" /> 비밀번호 업데이트</translation>
 <translation id="3775432569830822555">SSL 서버 인증서</translation>
 <translation id="3775705724665058594">기기로 전송</translation>
+<translation id="3776508619697147021">사이트에서 여러 파일의 자동 다운로드를 요청할 수 있음</translation>
 <translation id="3776796446459804932">이 확장 프로그램은 Chrome 웹 스토어 정책을 위반합니다.</translation>
 <translation id="3777483481409781352">모바일 기기를 활성화하지 못함</translation>
 <translation id="3777806571986431400">확장 프로그램을 사용하도록 설정됨</translation>
@@ -2875,6 +2890,7 @@
 <translation id="4078738236287221428">강한 규칙</translation>
 <translation id="4079140982534148664">향상된 맞춤법 검사 기능 사용</translation>
 <translation id="4081242589061676262">파일을 전송할 수 없음</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" />에서 휴대전화로 알림을 보냈습니다. 본인 인증을 하려면 알림의 단계를 따라주세요.</translation>
 <translation id="4084682180776658562">북마크</translation>
 <translation id="4084835346725913160"><ph name="TAB_NAME" /> 닫기</translation>
 <translation id="4085270836953633510">사이트에서 직렬 포트에 액세스하려고 할 때 확인</translation>
@@ -3034,6 +3050,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{표시}other{모두 표시}}</translation>
 <translation id="4289372044984810120">여기에서 계정을 관리하세요. <ph name="LINK_BEGIN" />자세히 알아보기<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">개요</translation>
+<translation id="4290791284969893584">페이지를 닫으면 시작한 작업이 완료되지 않을 수 있습니다</translation>
 <translation id="4295072614469448764">단말기에서 앱을 사용할 수 있습니다. 런처에 아이콘이 있을 수도 있습니다.</translation>
 <translation id="4295839147292213505">컴퓨터에서 문자 메시지를 보내고, 인터넷 연결을 공유하고, 대화 알림에 답장을 보내고, 휴대전화로 <ph name="DEVICE_TYPE" /> 기기의 잠금을 해제할 수 있습니다.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />자세히 알아보기<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">웹사이트, 앱, Chrome 확장 프로그램 및 Google Play에서 계정(<ph name="USER_EMAIL" />)을 사용하도록 확인하려면 다시 로그인하세요. 계정을 삭제할 수도 있습니다. <ph name="LINK_BEGIN" />자세히 알아보기<ph name="LINK_END" /></translation>
@@ -3229,6 +3246,7 @@
 <translation id="4514610446763173167">동영상 재생 또는 일시중지 전환</translation>
 <translation id="451515744433878153">제거</translation>
 <translation id="4515872537870654449">Dell에 문의하여 서비스를 받으세요. 팬이 작동하지 않으면 도크가 종료됩니다.</translation>
+<translation id="4519331665958994620">사이트에서 카메라 사용을 요청할 수 있음</translation>
 <translation id="4519935350946509010">연결 오류입니다.</translation>
 <translation id="4520385623207007473">사용 중인 쿠키</translation>
 <translation id="452039078290142656"><ph name="VENDOR_NAME" />의 알 수 없는 기기</translation>
@@ -3408,6 +3426,7 @@
 <translation id="4694604912444486114">원숭이</translation>
 <translation id="4697071790493980729">검색결과 없음</translation>
 <translation id="4697551882387947560">탐색 세션이 종료될 때</translation>
+<translation id="469838979880025581">사이트에서 마이크 사용을 요청할 수 있음</translation>
 <translation id="4699172675775169585">캐시된 이미지 및 파일</translation>
 <translation id="4699357559218762027">(자동 실행)</translation>
 <translation id="4701025263201366865">부모 로그인</translation>
@@ -3590,6 +3609,10 @@
 <translation id="4918086044614829423">수락</translation>
 <translation id="4921290200821452703">부모님을 위한 학교 계정 정보</translation>
 <translation id="4921348630401250116">TTS(텍스트 음성 변환)</translation>
+<translation id="4921809350408880559">과거의 Google Drive 이용 활동을 바탕으로 표시되는 최근 문서와 추천 문서입니다.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google Drive에서 수집하는 데이터와 수집 목적을 알아보려면 <ph name="BEGIN_LINK" />여기<ph name="END_LINK" />를 클릭하세요.</translation>
 <translation id="49226369361073053">{0,plural, =0{지금 기기 업데이트}=1{1초 내 기기 업데이트}other{#초 내 기기 업데이트}}</translation>
 <translation id="492299503953721473">Android 앱 삭제</translation>
 <translation id="492363500327720082"><ph name="APP_NAME" /> 제거 중…</translation>
@@ -4350,6 +4373,7 @@
 <translation id="5794700615121138172">Linux 공유 폴더</translation>
 <translation id="5794786537412027208">모든 Chrome 앱 종료</translation>
 <translation id="5797070761912323120">Google에서 내 방문 기록을 사용하여 Google 검색, 광고 및 다른 Google 서비스를 맞춤설정할 수 있습니다.</translation>
+<translation id="5798079537501238810">사이트에서 결제 핸들러를 설치할 수 있음</translation>
 <translation id="579907812742603813">보호된 콘텐츠</translation>
 <translation id="579915268381781820">보안 키가 삭제되었습니다.</translation>
 <translation id="5799478978078236781"><ph name="DEVICE_TYPE" /> 관련 도움말, 혜택 및 소식을 받아 보고 의견을 공유하세요.</translation>
@@ -4382,6 +4406,7 @@
 <translation id="5833726373896279253">이 설정은 소유자만 수정할 수 있습니다.</translation>
 <translation id="5834581999798853053">약 <ph name="TIME" />분 남음</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - 카메라 또는 마이크 녹음</translation>
+<translation id="583673505367439042">사이트에서 기기의 파일 및 폴더 수정을 요청할 수 있음</translation>
 <translation id="5840680448799937675">항상 오프라인으로 파일 공유</translation>
 <translation id="5841270259333717135">이더넷 구성</translation>
 <translation id="5842497610951477805">블루투스 사용</translation>
@@ -4431,6 +4456,7 @@
 <translation id="5889282057229379085">중간 인증기관(CA)의 최대 개수: <ph name="NUM_INTERMEDIATE_CA" />개</translation>
 <translation id="5891688036610113830">선호하는 Wi-Fi 네트워크</translation>
 <translation id="5895138241574237353">다시 시작</translation>
+<translation id="5896749729057314184"><ph name="NETWORK_COUNT" />개 중 <ph name="NETWORK_INDEX" />번째 네트워크, <ph name="NETWORK_NAME" />, 비활성화됨, 신호 강도 <ph name="SIGNAL_STRENGTH" />%, 세부정보</translation>
 <translation id="5900302528761731119">Google 프로필 사진</translation>
 <translation id="590036993063074298">미러링 품질 세부정보</translation>
 <translation id="5901069264981746702">지문 데이터는 안전하게 저장되며 절대 <ph name="DEVICE_TYPE" /> 외부로 유출되지 않습니다. <ph name="LINK_BEGIN" />자세히 알아보기<ph name="LINK_END" /></translation>
@@ -4675,6 +4701,7 @@
 <translation id="6155141482566063812">배경 탭에서 화면을 공유하는 중입니다.</translation>
 <translation id="6156323911414505561">북마크바 표시</translation>
 <translation id="6156863943908443225">스크립트 캐시</translation>
+<translation id="615930144153753547">사이트에서 이미지를 표시할 수 있음</translation>
 <translation id="6160625263637492097">인증에 사용할 인증서 제공</translation>
 <translation id="6163363155248589649">보통(&amp;N)</translation>
 <translation id="6163376401832887457">Kerberos 설정</translation>
@@ -4881,6 +4908,10 @@
 <translation id="6398715114293939307">Google Play 스토어 삭제</translation>
 <translation id="6398765197997659313">전체화면 닫기</translation>
 <translation id="6399774419735315745">스파이</translation>
+<translation id="6400510847800135340">과거의 Google 서비스 이용 활동을 바탕으로 표시된 항목입니다. <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />에서 데이터를 확인 및 삭제하고 설정을 변경할 수 있습니다.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google에서 수집하는 데이터와 수집 목적을 자세히 알아보려면 <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" />을 참고하세요.</translation>
 <translation id="6404511346730675251">북마크 수정</translation>
 <translation id="6406303162637086258">브라우저 다시 시작 시뮬레이션</translation>
 <translation id="6406506848690869874">동기화</translation>
@@ -4930,6 +4961,7 @@
 <translation id="6452251728599530347"><ph name="PERCENT" /> 완료</translation>
 <translation id="645286928527869380">레시피 아이디어</translation>
 <translation id="6452961788130242735">네트워크 문제 또는 잘못된 영역</translation>
+<translation id="6453921811609336127">다음 입력 방법으로 전환하려면 <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" />를 누르세요.</translation>
 <translation id="6455264371803474013">특정 사이트에서</translation>
 <translation id="6455894534188563617">새 폴더(&amp;N)</translation>
 <translation id="645705751491738698">자바스크립트 계속 차단</translation>
@@ -5055,6 +5087,7 @@
 <translation id="6590458744723262880">폴더 이름 바꾸기</translation>
 <translation id="6592267180249644460">WebRTC 로그 캡처 시간: <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">지문이 등록되었습니다.</translation>
+<translation id="6593881952206664229">저작권이 있는 미디어는 재생되지 않을 수 있습니다</translation>
 <translation id="6594011207075825276">직렬 기기를 찾는 중...</translation>
 <translation id="6595187330192059106"><ph name="HOST" />의 MIDI 기기 전체 제어 항상 차단</translation>
 <translation id="6596325263575161958">암호화 옵션</translation>
@@ -6012,6 +6045,7 @@
 <translation id="7661451191293163002">등록 인증서를 확인할 수 없습니다.</translation>
 <translation id="7662283695561029522">설정하려면 탭하세요.</translation>
 <translation id="7663719505383602579">수신기: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">단축키 사용 가능</translation>
 <translation id="7664620655576155379">지원되지 않는 블루투스 기기(<ph name="DEVICE_NAME" />)입니다.</translation>
 <translation id="7665082356120621510">용량 예약</translation>
 <translation id="7665369617277396874">계정 추가</translation>
@@ -6191,6 +6225,7 @@
 <translation id="7835178595033117206">북마크가 삭제됨</translation>
 <translation id="7836850009646241041">보안 키 다시 터치해 보기</translation>
 <translation id="7837776265184002579">홈페이지가 <ph name="URL" />(으)로 변경되었습니다.</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{<ph name="DEVICE_NAME" />에 <ph name="ATTACHMENTS" /> 전송됨}other{<ph name="DEVICE_NAME" />에 <ph name="ATTACHMENTS" /> 전송됨}}</translation>
 <translation id="7839051173341654115">미디어 보기/백업</translation>
 <translation id="7839192898639727867">인증서 대상 키 ID</translation>
 <translation id="7842692330619197998">새 계정을 만들려면 g.co/ChromeEnterpriseAccount를 방문하세요.</translation>
@@ -6888,6 +6923,7 @@
 <translation id="8633025649649592204">최근 활동</translation>
 <translation id="8635628933471165173">새로 고치는 중...</translation>
 <translation id="8636284842992792762">확장 프로그램 초기화 중...</translation>
+<translation id="8636500887554457830">사이트에서 팝업을 전송하거나 리디렉션을 사용할 수 없음</translation>
 <translation id="8637542770513281060">컴퓨터에 보안 모듈이 있습니다. 보안 모듈은 Chrome OS에서 여러 중요한 보안 기능을 구현하는 데 사용됩니다. 자세히 알아보려면 Chromebook 고객센터의 다음 페이지를 방문하세요. https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">시스템 업데이트 사용가능. 다운로드 준비 중…</translation>
 <translation id="863903787380594467">잘못된 PIN입니다. 기회가 <ph name="RETRIES" />번 남았습니다.</translation>
@@ -7105,6 +7141,7 @@
 <translation id="8842594465773264717">이 지문 삭제</translation>
 <translation id="8845001906332463065">도움말 보기</translation>
 <translation id="8846132060409673887">이 컴퓨터의 제조업체 및 모델을 읽습니다.</translation>
+<translation id="8846163936679269230">eSIM 프로필 재설정</translation>
 <translation id="8847523528195140327">커버를 닫으면 로그아웃</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">숨김</translation>
@@ -7160,6 +7197,7 @@
 <translation id="8898822736010347272">모든 웹 사용자에게 영향을 주는 새로운 위협을 발견하고 사용자를 보호하는 데 도움을 주기 위해 방문한 일부 페이지의 URL, 제한된 시스템 정보, 일부 페이지 콘텐츠를 Google로 전송합니다.</translation>
 <translation id="8899851313684471736">새 창에서 링크 열기(&amp;W)</translation>
 <translation id="8900413463156971200">셀룰러 사용</translation>
+<translation id="8901994452417867840">프로필이 추가되었습니다. 기기의 모든 사용자가 이 네트워크 연결을 사용할 수 있습니다.</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" />에서 오늘 데이터를 백업하고 이 <ph name="DEVICE_TYPE" /> 기기를 반납할 것을 요청합니다.}other{<ph name="MANAGER" />에서 기한 전에 데이터를 백업하고 이 <ph name="DEVICE_TYPE" /> 기기를 반납할 것을 요청합니다.}}</translation>
 <translation id="8902667442496790482">텍스트 읽어주기 설정 열기</translation>
 <translation id="8903263458134414071">로그인 계정 선택</translation>
@@ -7341,6 +7379,7 @@
 <translation id="9094982973264386462">제거</translation>
 <translation id="9095253524804455615">제거</translation>
 <translation id="909554839118732438">시크릿 창 닫기</translation>
+<translation id="9100416672768993722">마지막에 사용한 입력 방법으로 전환하려면 <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" />를 누르세요.</translation>
 <translation id="9100610230175265781">암호를 입력해야 합니다.</translation>
 <translation id="9100765901046053179">고급 설정</translation>
 <translation id="9101691533782776290">앱 실행</translation>
diff --git a/chrome/app/resources/generated_resources_lo.xtb b/chrome/app/resources/generated_resources_lo.xtb
index 39bd27c..4de8172 100644
--- a/chrome/app/resources/generated_resources_lo.xtb
+++ b/chrome/app/resources/generated_resources_lo.xtb
@@ -62,6 +62,7 @@
 <translation id="1066613507389053689">ຕ້ອງອັບເດດ Chrome OS</translation>
 <translation id="1067048845568873861">ສ້າງຂຶ້ນແລ້ວ</translation>
 <translation id="1067922213147265141">ການບໍລິການອື່ນຂອງ Google</translation>
+<translation id="1069355737714877171">ລຶບໂປຣໄຟລ໌ eSIM ຊື່ <ph name="PROFILE_NAME" /> ອອກແລ້ວ</translation>
 <translation id="1070377999570795893">ໂປຣແກຣມອື່ນຢູ່ໃນຄອມພິວເຕີຂອງທ່{ານໄດ້ເພີ່ມສ່ວນ​ຂະ​ຫຍາຍທີ່ອາດຈະປ່ຽນແປງວິທີການເຮັດວຽກຂອງ Chrome ແລ້ວ.
 
 <ph name="EXTENSION_NAME" /></translation>
@@ -357,6 +358,7 @@
 <translation id="138784436342154190">ກູ້ຄືນໜ້າເລີ່ມຕົ້ນຕາມຄ່າເລີ່ມຕົ້ນບໍ?</translation>
 <translation id="1388253969141979417">ໄດ້ຮັບອະນຸຍາດໃຫ້ໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ</translation>
 <translation id="1388728792929436380"><ph name="DEVICE_TYPE" /> ຈະຣີສະຕາດເມື່ອການອັບເດດສຳເລັດແລ້ວ.</translation>
+<translation id="138900021244932468">ບໍ່ສາມາດຄົ້ນພົບໂປຣໄຟລ໌ໃດເລີຍ. ເພື່ອຕັ້ງຄ່າເຄືອຂ່າຍໃໝ່, ກະລຸນາສະແກນລະຫັດ QR ໂດຍໃຊ້ກ້ອງຖ່າຍຮູບອຸປະກອນ ຫຼື ປ້ອນລະຫັດການເປີດນຳໃຊ້ທີ່ຜູ້ໃຫ້ບໍລິການຂອງທ່ານສະໜອງໃຫ້.</translation>
 <translation id="139013308650923562">ອະນຸຍາດໃຫ້ໃຊ້ຟອນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນຂອງທ່ານໄດ້</translation>
 <translation id="1390548061267426325">ເປີດເປັນແຖບທໍາມະດາ</translation>
 <translation id="1393283411312835250">ແສງແດດ ແລະ ເມກເຝື້ອ</translation>
@@ -992,6 +994,7 @@
 ທ່ານສາມາດຈັດການການຕັ້ງຄ່າບັນຊີນີ້ໄດ້ໂດຍການຕິດຕັ້ງແອັບ Family Link ໃນອຸປະກອນຂອງທ່ານ.  ພວກເຮົາໄດ້ສົ່ງຄຳແນະນຳໃຫ້ທ່ານໃນອີເມວ.</translation>
 <translation id="2040460856718599782">ອຸ້ຍ! ມີບາງອັນຜິດພາດ ເມື່ອພະຍາຍາມຮັບຮອງ. ກະລຸນາກວດເບິ່ງໃບຢັ້ງຢືນການລົງຊື່ເຂົ້າໃຊ້ໃຫ້ດີ ແລະລອງໃໝ່ອີກ.</translation>
 <translation id="2044014337866019681">ກະລຸນາກວດສອບໃຫ້ແນ່ໃຈວ່າທ່ານກຳລັງຢັ້ງຢືນ <ph name="ACCOUNT" /> ເພື່ອປົດລັອກເຊດຊັນ.</translation>
+<translation id="2044023416777079300">ບໍ່ໄດ້ລົງທະບຽນໂມເດັມ</translation>
 <translation id="204497730941176055">ຊື່​ແມ່​ແບບໃບຢັ້ງຢືນ Microsoft</translation>
 <translation id="2045117674524495717">ຕົວຊ່ວຍທາງລັດແປ້ນພິມ</translation>
 <translation id="2045969484888636535">ສືບຕໍ່ບລັອກຄຸກກີ້</translation>
@@ -4095,6 +4098,7 @@
 <translation id="5486261815000869482">ຢືນ​ຢັນ​ລະ​ຫັດ​ຜ່ານ​</translation>
 <translation id="5486275809415469523"><ph name="APP_NAME" /> ກໍາລັງແຊຣ໌ໜ້າຈໍຂອງທ່ານກັບ <ph name="TAB_NAME" />.</translation>
 <translation id="5486561344817861625">ຈໍາລອງການເລີ່ມປິດເປີດບຣາວ​ເຊີໃໝ່</translation>
+<translation id="5487460042548760727">ປ່ຽນຊື່ໂປຣໄຟລ໌ເປັນ <ph name="PROFILE_NAME" /></translation>
 <translation id="5487521232677179737">ລຶບລ້າງຂໍ້ມູນ</translation>
 <translation id="5488093641312826914">ສຳເນົາ '<ph name="COPIED_ITEM_NAME" />' ແລ້ວ</translation>
 <translation id="5488508217173274228">ຕົວເລືອກການຊິ້ງຂໍ້ມູນການເຂົ້າລະຫັດລັບ</translation>
@@ -4836,6 +4840,7 @@
 <translation id="6308937455967653460">ບັນທຶກລິ້ງເປັນ...</translation>
 <translation id="6309443618838462258">ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານບໍ່ອະນຸຍາດວິທີການປ້ອນຂໍ້ມູນນີ້</translation>
 <translation id="6309510305002439352">ປິດໄມໂຄຣໂຟນແລ້ວ</translation>
+<translation id="6310141306111263820">ບໍ່ສາມາດຕິດຕັ້ງໂປຣໄຟລ໌ eSIM ໄດ້. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການຂອງທ່ານເພື່ອຂໍຄວາມຊ່ວຍເຫຼືອ.</translation>
 <translation id="6311220991371174222">ບໍ່ສາມາດເລີ່ມ Chrome ໄດ້ເພາະວ່າມີບາງຢ່າງຜິດພາດໃນເວລາເປີດໂປຣໄຟລ໌ຂອງທ່ານ. ກະລຸນາລອງປິດເປີດ Chrome ຄືນໃໝ່.</translation>
 <translation id="6312403991423642364">ຄວາມຜິດພາດ​ຂອງເຄືອຂ່າຍທີ່ບໍ່ຮູ້ຈັກ</translation>
 <translation id="6312567056350025599">{NUM_DAYS,plural, =1{ດຳເນີນການກວດສອບຄວາມປອດໄພເມື່ອ 1 ມື້ກ່ອນ}other{ດຳເນີນການກວດສອບຄວາມປອດໄພເມື່ອ {NUM_DAYS} ມື້ກ່ອນ}}</translation>
@@ -5972,6 +5977,7 @@
 <translation id="7582582252461552277">ມັກ​ເຄືອ​ຂ່າຍ​ນີ້</translation>
 <translation id="7582844466922312471">ຂໍ້​ມູນ​ມື​ຖື</translation>
 <translation id="7583948862126372804">ຈຳນວນ</translation>
+<translation id="7586051298768394542">ບໍ່ສາມາດດາວໂຫຼດໄຟລ໌ສຽງເວົ້າໄດ້. ການປ້ອນຂໍ້ມູນດ້ວຍສຽງຈະສືບຕໍ່ເຮັດວຽກໂດຍການສົ່ງສຽງຂອງທ່ານໄປໃຫ້ Google.</translation>
 <translation id="7586498138629385861">Chrome ຈະສືບຕໍ່ແລ່ນຢູ່ໃນຂະນະທີ່ແອັບ Chrome ເປີດ.</translation>
 <translation id="7589461650300748890">ໂຮ້​, ນັ້ນ. ​ລະ​ມັດ​ລະ​ວັງ!</translation>
 <translation id="7593653750169415785">ບລັອກໄວ້ໂດຍອັດຕະໂນມັດແລ້ວ ເພາະວ່າທ່ານປະຕິເສດການແຈ້ງເຕືອນສອງສາມຄັ້ງແລ້ວ</translation>
@@ -6559,6 +6565,7 @@
 <translation id="8191230140820435481">ຈັດການແອັບ, ສ່ວນຂະຫຍາຍ, ແລະເທມຂອງທ່ານ</translation>
 <translation id="8195027750202970175">ຂະໜາດໃນດິສ</translation>
 <translation id="8198323535106903877">ພວກເຮົາຈະຕິດຕັ້ງແອັບ <ph name="NUMBER_OF_APPS" /> ເຫຼົ່ານີ້ໃຫ້ທ່ານ</translation>
+<translation id="8198456017687137612">ແຖບການສົ່ງສັນຍານ</translation>
 <translation id="8199300056570174101">ຄຸນລັກສະນະຂອງເຄືອຂ່າຍ (ການບໍລິການ) ແລະ ອຸປະກອນ</translation>
 <translation id="8200772114523450471">ເລີ່ມຕົ້ນປິດເປີດໃໝ່</translation>
 <translation id="8201717382574620700">ເລືອກອະລະບໍ້າ <ph name="TOPIC_SOURCE" /></translation>
@@ -7143,6 +7150,7 @@
 <translation id="8847523528195140327">ອອກຈາກລະບົບເມື່ອປິດຝາ</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">ເຊື່ອງໄວ້</translation>
+<translation id="8849219423513870962">ຍົກເລີກການລຶບໂປຣໄຟລ໌ eSIM ຊື່ <ph name="PROFILE_NAME" /> ອອກ</translation>
 <translation id="8850251000316748990">ເບິ່ງເພີ່ມເຕີມ...</translation>
 <translation id="885246833287407341">ອາກິວເມັນຂອງຟັງຊັນ API</translation>
 <translation id="8853586775156634952">ບັດນີ້ຈະຖືກບັນທຶກໄວ້ໃນອຸປະກອນນີ້ເທົ່ານັ້ນ</translation>
diff --git a/chrome/app/resources/generated_resources_mn.xtb b/chrome/app/resources/generated_resources_mn.xtb
index 331bcb77..deab575 100644
--- a/chrome/app/resources/generated_resources_mn.xtb
+++ b/chrome/app/resources/generated_resources_mn.xtb
@@ -3374,7 +3374,7 @@
 <translation id="4646675363240786305">Портууд</translation>
 <translation id="4647090755847581616">Цонхыг хаах</translation>
 <translation id="4647283074445570750">Алхам <ph name="TOTAL_STEPS" />-н <ph name="CURRENT_STEP" /></translation>
-<translation id="4647697156028544508">"<ph name="DEVICE_NAME" />": - ийн PIN кодыг оруулна уу.</translation>
+<translation id="4647697156028544508">"<ph name="DEVICE_NAME" />": - ийн ПИН кодыг оруулна уу.</translation>
 <translation id="4648491805942548247">Хангалтгүй зөвшөөрөл</translation>
 <translation id="4650591383426000695">Утсаа <ph name="DEVICE_TYPE" />-с салгах</translation>
 <translation id="4651484272688821107">Демо горимын эх сурвалжтай онлайн бүрэлдэхүүн хэсгийг ачаалж чадсангүй.</translation>
@@ -3735,7 +3735,7 @@
 <translation id="5075131525758602494">SIM-н ПИН-г оруулна уу</translation>
 <translation id="5075910247684008552">Аюулгүй сайт дээрх аюултай контентыг өгөгдмөл тохиргоогоор блоклосон байна</translation>
 <translation id="5078638979202084724">Бүх цонхнуудыг жагсааж хадгалах</translation>
-<translation id="5078796286268621944">PIN код буруу байна</translation>
+<translation id="5078796286268621944">ПИН код буруу байна</translation>
 <translation id="5079950360618752063">Санал болгосон нууц үг ашиглах</translation>
 <translation id="508059534790499809">Kerberos тасалбарыг дахин шинэчлэх</translation>
 <translation id="5084230410268011727">Сайтуудад хөдөлгөөн болон гэрэл мэдрэгч ашиглахыг нь зөвшөөрөх</translation>
@@ -4200,7 +4200,7 @@
 <translation id="5595485650161345191">Хаягийг засах</translation>
 <translation id="5596627076506792578">Бусад сонголт</translation>
 <translation id="5600706100022181951">Шинэчлэлтийг <ph name="UPDATE_SIZE_MB" /> МБ эсвэл мобайл датагаар татна. Та үргэлжлүүлэх үү?</translation>
-<translation id="5601503069213153581">PIN</translation>
+<translation id="5601503069213153581">ПИН</translation>
 <translation id="5601823921345337195">MIDI төхөөрөмжүүдэд холбогдохыг зөвшөөрөөгүй</translation>
 <translation id="5602765853043467355">Энэ төхөөрөмжөөс хавчуурга, түүх, нууц үг болон бусад зүйлийг устгах</translation>
 <translation id="5605623530403479164">Бусад хайлтын систем</translation>
@@ -4724,7 +4724,7 @@
 <translation id="6196640612572343990">Гуравдагч талын күүкиг блоклох</translation>
 <translation id="6196854373336333322">"<ph name="EXTENSION_NAME" />" өргөтгөл нь таны прокси тохиргоог удирдаж байгаа бөгөөд энэ нь таны онлайнаар хийсэн зүйлийг өөрчилж, гэмтээж, хуулбарлах боломжтой гэсэн үг юм. Энэ өөрчлөлт яагаад гарсныг та мэдэхгүй байгаа бол энэ таны хүссэн зүйл биш байна.</translation>
 <translation id="6198102561359457428">Үйлдлийн системээс гараад, дахин нэвтрэнэ үү...</translation>
-<translation id="6198252989419008588">PIN кодыг өөрчлөх</translation>
+<translation id="6198252989419008588">ПИН кодыг өөрчлөх</translation>
 <translation id="6202304368170870640">Ta төхөөрөмждөө нэвтрэх эсвэл түгжээг нь тайлахын тулд ПИН кодоо ашиглаж болно.</translation>
 <translation id="6206311232642889873">Зургийг хуулах</translation>
 <translation id="6207200176136643843">Томруулах өгөгдмөл түвшинд тохируулах</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index f96ccbc..295792e 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -62,6 +62,7 @@
 <translation id="1066613507389053689">Kemaskinian OS Chrome diperlukan</translation>
 <translation id="1067048845568873861">Dibuat</translation>
 <translation id="1067922213147265141">Perkhidmatan Google yang lain</translation>
+<translation id="1069355737714877171">Alih keluar profil eSIM yang bernama <ph name="PROFILE_NAME" /></translation>
 <translation id="1070377999570795893">Program lain pada komputer anda telah menambahkan sambungan yang boleh mengubah cara Chrome berfungsi.
 
 <ph name="EXTENSION_NAME" /></translation>
@@ -357,6 +358,7 @@
 <translation id="138784436342154190">Pulihkan halaman permulaan lalai?</translation>
 <translation id="1388253969141979417">Dibenarkan untuk menggunakan mikrofon anda</translation>
 <translation id="1388728792929436380"><ph name="DEVICE_TYPE" /> akan dimulakan semula apabila kemaskinian selesai.</translation>
+<translation id="138900021244932468">Tiada profil dijumpai. Untuk menyediakan rangkaian baharu, imbas kod QR menggunakan kamera peranti atau masukkan kod pengaktifan yang disediakan oleh pembawa anda.</translation>
 <translation id="139013308650923562">Dibenarkan untuk menggunakan fon yang dipasang pada peranti anda</translation>
 <translation id="1390548061267426325">Buka sebagai Tab Biasa</translation>
 <translation id="1393283411312835250">Matahari dan awan</translation>
@@ -995,6 +997,7 @@
 Anda boleh mengurus tetapan akaun ini dengan memasang apl Family Link pada peranti anda.  Kami telah menghantar arahan kepada anda dalam e-mel.</translation>
 <translation id="2040460856718599782">Op! Berlaku masalah semasa cuba mengesahkan anda. Sila semak bukti kelayakan log masuk anda sekali lagi dan cuba semula.</translation>
 <translation id="2044014337866019681">Sila pastikan anda mengesahkan <ph name="ACCOUNT" /> untuk membuka kunci sesi.</translation>
+<translation id="2044023416777079300">Modem tidak didaftarkan</translation>
 <translation id="204497730941176055">Nama Templat Sijil Microsoft</translation>
 <translation id="2045117674524495717">Pembantu Pintasan Papan Kekunci</translation>
 <translation id="2045969484888636535">Terus menyekat kuki</translation>
@@ -4098,6 +4101,7 @@
 <translation id="5486261815000869482">Sahkan kata laluan</translation>
 <translation id="5486275809415469523"><ph name="APP_NAME" /> mengongsi skrin anda dengan <ph name="TAB_NAME" />.</translation>
 <translation id="5486561344817861625">Rangsang Mula Semula Penyemak Imbas</translation>
+<translation id="5487460042548760727">Namakan semula profil kepada <ph name="PROFILE_NAME" /></translation>
 <translation id="5487521232677179737">Kosongkan data</translation>
 <translation id="5488093641312826914">'<ph name="COPIED_ITEM_NAME" />' disalin</translation>
 <translation id="5488508217173274228">Pilihan penyulitan penyegerakan</translation>
@@ -4839,6 +4843,7 @@
 <translation id="6308937455967653460">Simpan pau&amp;tan sebagai...</translation>
 <translation id="6309443618838462258">Pentadbir anda tidak membenarkan kaedah masukan ini</translation>
 <translation id="6309510305002439352">Mikrofon dimatikan</translation>
+<translation id="6310141306111263820">Tidak dapat memasang profil eSIM. Untuk mendapatkan bantuan, sila hubungi pembawa anda.</translation>
 <translation id="6311220991371174222">Tidak dapat memulakan Chrome kerana berlaku kesilapan semasa membuka profil anda. Cuba mulakan semula Chrome.</translation>
 <translation id="6312403991423642364">Ralat rangkaian tidak diketahui</translation>
 <translation id="6312567056350025599">{NUM_DAYS,plural, =1{Semakan keselamatan dijalankan 1 hari yang lalu}other{Semakan keselamatan dijalankan {NUM_DAYS} hari yang lalu}}</translation>
@@ -5975,6 +5980,7 @@
 <translation id="7582582252461552277">Lebih suka rangkaian ini</translation>
 <translation id="7582844466922312471">Data Mudah Alih</translation>
 <translation id="7583948862126372804">Kiraan</translation>
+<translation id="7586051298768394542">Tidak dapat memuat turun fail pertuturan. Pengimlakan akan terus berfungsi dengan menghantar suara anda kepada Google.</translation>
 <translation id="7586498138629385861">Chrome akan terus berjalan semasa Apl Chrome terbuka.</translation>
 <translation id="7589461650300748890">Wah, di sana. Berhati-hati.</translation>
 <translation id="7593653750169415785">Disekat secara automatik kerana anda telah menolak pemberitahuan beberapa kali</translation>
@@ -6564,6 +6570,7 @@
 <translation id="8191230140820435481">Uruskan apl, sambungan dan tema anda</translation>
 <translation id="8195027750202970175">Saiz pada cakera</translation>
 <translation id="8198323535106903877">Kami akan memasang <ph name="NUMBER_OF_APPS" /> apl itu untuk anda</translation>
+<translation id="8198456017687137612">Menghantar tab</translation>
 <translation id="8199300056570174101">Sifat Rangkaian (Perkhidmatan) dan Peranti</translation>
 <translation id="8200772114523450471">Sambung semula</translation>
 <translation id="8201717382574620700">Pilih album <ph name="TOPIC_SOURCE" /></translation>
@@ -7149,6 +7156,7 @@
 <translation id="8847523528195140327">Log keluar apabila penutup ditutup</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">Disembunyikan</translation>
+<translation id="8849219423513870962">Batalkan pengalihan keluar profil eSIM yang bernama <ph name="PROFILE_NAME" /></translation>
 <translation id="8850251000316748990">Lihat lagi...</translation>
 <translation id="885246833287407341">Argumen fungsi API</translation>
 <translation id="8853586775156634952">Kad ini akan disimpan ke peranti ini sahaja</translation>
diff --git a/chrome/app/resources/generated_resources_pa.xtb b/chrome/app/resources/generated_resources_pa.xtb
index 310b20bc..ea3d418b 100644
--- a/chrome/app/resources/generated_resources_pa.xtb
+++ b/chrome/app/resources/generated_resources_pa.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="pa">
 <translation id="1001307489511021749">ਤੁਹਾਡੇ Google ਖਾਤੇ ਨਾਲ ਸਾਈਨ-ਇਨ ਕੀਤੇ ਸਾਰੇ Chrome OS ਡੀਵਾਈਸਾਂ ਵਿੱਚ ਤੁਹਾਡੀਆਂ ਐਪਾਂ, ਸੈਟਿੰਗਾਂ ਅਤੇ ਹੋਰ ਵਿਉਂਤਬੱਧਕਰਨਾਂ ਦਾ ਸਮਕਾਲੀਕਰਨ ਕੀਤਾ ਜਾਵੇਗਾ।</translation>
 <translation id="1003088604756913841">ਨਵੀਂ <ph name="APP" /> ਵਿੰਡੋ ਵਿੱਚ ਲਿੰਕ ਖੋਲ੍ਹੋ</translation>
+<translation id="100323615638474026">USB ਡੀਵਾਈਸ (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">ਸਾਈਟ ਤੱਕ ਪਹੁੰਚ</translation>
 <translation id="1005274289863221750">ਆਪਣਾ ਮਾਈਕ੍ਰੋਫੋਨ ਅਤੇ ਕੈਮਰਾ ਵਰਤੋ</translation>
 <translation id="1005333234656240382">ਕੀ ADB ਡੀਬੱਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕਰਨਾ ਹੈ?</translation>
@@ -574,6 +575,7 @@
 <translation id="1614511179807650956">ਸ਼ਾਇਦ ਤੁਸੀਂ ਆਪਣਾ ਮੋਬਾਈਲ ਡਾਟਾ ਭੱਤਾ ਵਰਤ ਲਿਆ ਹੈ। ਹੋਰ ਡਾਟਾ ਖਰੀਦਣ ਲਈ <ph name="NAME" /> ਦੇ ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਵਾਲੇ ਪੋਰਟਲ 'ਤੇ ਜਾਓ</translation>
 <translation id="161460670679785907">ਤੁਹਾਡੇ ਫ਼ੋਨ ਦਾ ਪਤਾ ਨਹੀਂ ਲਗਾਇਆ ਜਾ ਸਕਿਆ</translation>
 <translation id="1615402009686901181">ਗੁਪਤ ਸਮੱਗਰੀ ਦੇ ਦਿਸਣਯੋਗ ਹੋਣ 'ਤੇ ਪ੍ਰਸ਼ਾਸਕ ਨੀਤੀ ਸਕ੍ਰੀਨ ਕੈਪਚਰ ਨੂੰ ਬੰਦ ਕਰ ਦਿੰਦੀ ਹੈ</translation>
+<translation id="1615755956145364867">ਸਾਈਟਾਂ ਸੁਰੱਖਿਅਤ ਸਮੱਗਰੀ ਚਲਾਉਣ ਲਈ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="1616206807336925449">ਇਸ ਐਕਸਟੈਂਸ਼ਨ ਲਈ ਕੋਈ ਖ਼ਾਸ ਇਜਾਜ਼ਤਾਂ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।</translation>
 <translation id="1616298854599875024">"<ph name="IMPORT_NAME" />" ਐਕਸਟੈਂਸ਼ਨ ਨੂੰ ਆਯਾਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ, ਕਿਉਂਕਿ ਇਹ ਇੱਕ ਸਾਂਝਾ ਕੀਤਾ ਗਿਆ ਮਾਡਿਊਲ ਨਹੀਂ ਹੈ</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{ਤੁਹਾਡੀ ਸੰਸਥਾ ਦੀ ਸੁਰੱਖਿਆ ਨੀਤੀਆਂ ਨਾਲ ਇਸ ਡਾਟੇ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...}=1{ਤੁਹਾਡੀ ਸੰਸਥਾ ਦੀ ਸੁਰੱਖਿਆ ਨੀਤੀਆਂ ਨਾਲ ਇਸ ਫ਼ਾਈਲ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...}other{ਤੁਹਾਡੀ ਸੰਸਥਾ ਦੀ ਸੁਰੱਖਿਆ ਨੀਤੀਆਂ ਨਾਲ ਇਹਨਾਂ ਫ਼ਾਈਲਾਂ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...}}</translation>
@@ -768,6 +770,7 @@
 <translation id="1794051631868188691"><ph name="MERCHANT" /> ਕਦੇ ਨਾ ਦਿਖਾਓ</translation>
 <translation id="1794791083288629568">ਇਸ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱਚ ਸਾਡੀ ਮਦਦ ਕਰਨ ਲਈ ਪ੍ਰਤੀਕਰਮ ਭੇਜੋ।</translation>
 <translation id="1795214765651529549">ਕਲਾਸਿਕ ਵਰਤੋ</translation>
+<translation id="1796588414813960292">ਜਿਨ੍ਹਾਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਧੁਨੀ ਦੀ ਲੋੜ ਹੈ ਉਹ ਕੰਮ ਨਹੀਂ ਕਰਨਗੀਆਂ</translation>
 <translation id="1799071797295057738">ਐਕਸਟੈਂਸ਼ਨ "<ph name="EXTENSION_NAME" />" ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਬੰਦ ਕੀਤੀ ਗਈ।</translation>
 <translation id="1800973090344019061">ਐਕਸਟੈਂਸ਼ਨ "<ph name="APP_NAME" />" ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਸਾਂਝਾ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ।</translation>
 <translation id="1802624026913571222">ਕਵਰ ਬੰਦ ਹੋਣ 'ਤੇ ਸਲੀਪ ਮੋਡ ਵਿੱਚ ਜਾਓ</translation>
@@ -966,6 +969,7 @@
 <translation id="2007404777272201486">ਇੱਕ ਸਮੱਸਿਆ ਦੀ ਰਿਪੋਰਟ ਕਰੋ...</translation>
 <translation id="2010501376126504057">ਅਨੁਰੂਪ ਡੀਵਾਈਸ</translation>
 <translation id="2015232545623037616">PC ਅਤੇ Chromecast ਇੱਕੋ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ 'ਤੇ ਹਨ</translation>
+<translation id="2016473077102413275">ਜਿਨ੍ਹਾਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਿੱਤਰਾਂ ਦੀ ਲੋੜ ਹੈ ਉਹ ਕੰਮ ਨਹੀਂ ਕਰਨਗੀਆਂ</translation>
 <translation id="2016574333161572915">ਤੁਹਾਡਾ Google Meet ਹਾਰਡਵੇਅਰ ਸੈੱਟਅੱਪ ਲਈ ਤਿਆਰ ਹੈ</translation>
 <translation id="2017334798163366053">ਕਾਰਗੁਜ਼ਾਰੀ ਡਾਟਾ ਸੰਗ੍ਰਹਿ ਨੂੰ ਬੰਦ ਕਰੋ</translation>
 <translation id="2018352199541442911">ਮਾਫ਼ ਕਰਨਾ, ਤੁਹਾਡਾ ਬਾਹਰੀ ਸਟੋਰੇਜ ਡੀਵਾਈਸ ਇਸ ਵੇਲੇ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।</translation>
@@ -1233,6 +1237,7 @@
 <translation id="2296099049346876573">{NUM_HOURS,plural, =1{Chrome ਨੂੰ ਤੁਹਾਡੇ ਕੰਪਿਊਟਰ 'ਤੇ ਕੋਈ ਹਾਨੀਕਾਰਕ ਸਾਫ਼ਟਵੇਅਰ ਨਹੀਂ ਲੱਭਿਆ • 1 ਘੰਟਾ ਪਹਿਲਾਂ ਜਾਂਚ ਕੀਤੀ ਗਈ}one{Chrome ਨੂੰ ਤੁਹਾਡੇ ਕੰਪਿਊਟਰ 'ਤੇ ਕੋਈ ਹਾਨੀਕਾਰਕ ਸਾਫ਼ਟਵੇਅਰ ਨਹੀਂ ਲੱਭਿਆ • {NUM_HOURS} ਘੰਟਾ ਪਹਿਲਾਂ ਜਾਂਚ ਕੀਤੀ ਗਈ}other{Chrome ਨੂੰ ਤੁਹਾਡੇ ਕੰਪਿਊਟਰ 'ਤੇ ਕੋਈ ਹਾਨੀਕਾਰਕ ਸਾਫ਼ਟਵੇਅਰ ਨਹੀਂ ਲੱਭਿਆ • {NUM_HOURS} ਘੰਟੇ ਪਹਿਲਾਂ ਜਾਂਚ ਕੀਤੀ ਗਈ}}</translation>
 <translation id="2296218178174497398">ਡੀਵਾਈਸ ਖੋਜ</translation>
 <translation id="2297705863329999812">ਪ੍ਰਿੰਟਰ ਖੋਜੋ</translation>
+<translation id="2297822946037605517">ਇਹ ਪੰਨਾ ਸਾਂਝਾ ਕਰੋ</translation>
 <translation id="2299734369537008228">ਸਲਾਈਡਰ: <ph name="MIN_LABEL" /> ਤੋਂ <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">ਡੀਬੱਗ ਵੱਲੋਂ ਇਕੱਤਰ ਕੀਤੀਆਂ ਸਾਰੀਆਂ ਲੌਗ ਫ਼ਾਈਲਾਂ ਨੂੰ ਵੱਖਰੇ ਪੁਰਾਲੇਖ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰੋ।</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -1295,6 +1300,7 @@
 <translation id="2355604387869345912">ਤਤਕਾਲ ਟੈਦਰਿੰਗ ਨੂੰ ਚਾਲੂ ਕਰੋ</translation>
 <translation id="2356070529366658676">ਪੁੱਛੋ</translation>
 <translation id="2357330829548294574"><ph name="USER_NAME" /> ਨੂੰ ਹਟਾਓ</translation>
+<translation id="2358561147588818967">ਸਾਈਟਾਂ JavaScript ਵਰਤ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="2359071692152028734">Linux ਐਪਾਂ ਪ੍ਰਤੀਕਿਰਿਆਹੀਣ ਹੋ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="2359345697448000899">ਟੂਲ ਮੀਨੂ ਵਿੱਚ ਐਕਸਟੈਂਸ਼ਨਾਂ 'ਤੇ ਕਲਿੱਕ ਕਰਕੇ ਆਪਣੇ ਐਕਸਟੈਂਸ਼ਨ ਪ੍ਰਬੰਧਿਤ ਕਰੋ।</translation>
 <translation id="2359556993567737338">ਬਲੂਟੁੱਥ ਡੀਵਾਈਸ ਕਨੈਕਟ ਕਰੋ</translation>
@@ -1471,6 +1477,7 @@
 <translation id="2544853746127077729">ਪ੍ਰਮਾਣੀਕਰਨ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਨੂੰ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਅਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="2546283357679194313">ਕੁਕੀਜ਼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ</translation>
 <translation id="2548347166720081527">ਮਨਜ਼ੂਰਸ਼ੁਦਾ <ph name="PERMISSION" /></translation>
+<translation id="2548545707296594436">ਈ-ਸਿਮ ਪ੍ਰੋਫਾਈਲ ਕੈਸ਼ੇ ਰੀਸੈੱਟ ਕਰੋ</translation>
 <translation id="2549985041256363841">ਰਿਕਾਰਡਿੰਗ ਸ਼ੁੁਰੂ ਕਰੋ</translation>
 <translation id="2550212893339833758">ਸਵੈਪ ਕੀਤੀ ਗਈ ਮੈਮਰੀ</translation>
 <translation id="2550596535588364872">ਕੀ <ph name="EXTENSION_NAME" /> ਨੂੰ <ph name="FILE_NAME" /> ਖੋਲ੍ਹਣ ਦੇਣੀ ਹੈ?</translation>
@@ -1664,6 +1671,7 @@
 <translation id="2765217105034171413">ਛੋਟਾ</translation>
 <translation id="2766006623206032690">ਪੇ&amp;ਸਟ ਕਰੋ ਅਤੇ ਜਾਓ</translation>
 <translation id="2766161002040448006">ਮਾਂ-ਪਿਓ ਨੂੰ ਪੁੱਛੋ</translation>
+<translation id="2767077837043621282">ਤੁਹਾਡੀ Chromebook ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="2767127727915954024"><ph name="ORIGIN" /> ਇਸ ਸਾਈਟ ਲਈ ਸਾਰੀਆਂ ਟੈਬਾਂ ਬੰਦ ਨਾ ਕੀਤੇ ਜਾਣ ਤੱਕ <ph name="FILENAME" /> ਦਾ ਸੰਪਾਦਨ ਕਰ ਸਕੇਗੀ</translation>
 <translation id="2770465223704140727">ਸੂਚੀ ਵਿੱਚੋਂ ਹਟਾਓ</translation>
 <translation id="2770690685823456775">ਆਪਣੇ ਪਾਸਵਰਡਾਂ ਨੂੰ ਕਿਸੇ ਹੋਰ ਫੋਲਡਰ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ</translation>
@@ -1940,6 +1948,7 @@
 <translation id="3060379269883947824">'ਚੁਣੋ ਅਤੇ ਸੁਣੋ' ਨੂੰ ਚਾਲੂ ਕਰੋ</translation>
 <translation id="3060952009917586498">ਡੀਵਾਈਸ ਦੀ ਭਾਸ਼ਾ ਬਦਲੋ। ਮੌਜੂਦਾ ਭਾਸ਼ਾ <ph name="LANGUAGE" /> ਹੈ।</translation>
 <translation id="3060987956645097882">ਅਸੀਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਨਾਲ ਕਨੈਕਸ਼ਨ ਸਥਾਪਤ ਨਹੀਂ ਕਰ ਸਕੇ। ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਨਜ਼ਦੀਕ ਹੈ, ਅਣਲਾਕ ਹੈ ਅਤੇ ਉਸਦਾ ਬਲੂਟੁੱਥ ਅਤੇ ਵਾਈ-ਫਾਈ ਚਾਲੂ ਹੈ।</translation>
+<translation id="3064871050034234884">ਸਾਈਟਾਂ ਧੁਨੀ ਵਜਾ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="3065041951436100775">ਨਸ਼ਟ ਕੀਤੀ ਟੈਬ ਫੀਡਬੈਕ</translation>
 <translation id="3065522099314259755">ਕੀ-ਬੋਰਡ ਦੁਹਰਾਓ ਵਿਲੰਬਤਾ</translation>
 <translation id="3067198179881736288">ਕੀ ਐਪ ਸਥਾਪਤ ਕਰਨੀ ਹੈ?</translation>
@@ -2290,6 +2299,7 @@
 <translation id="3462413494201477527">ਕੀ ਖਾਤਾ ਸੈੱਟਅੱਪ ਰੱਦ ਕਰਨਾ ਹੈ?</translation>
 <translation id="3464145797867108663">ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਸ਼ਾਮਲ ਕਰੋ</translation>
 <translation id="346431825526753">ਇਹ <ph name="CUSTODIAN_EMAIL" /> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਬੱਚਿਆਂ ਦਾ ਇੱਕ ਖਾਤਾ ਹੈ।</translation>
+<translation id="3465480292013046659">ਅੱਪਡੇਟ ਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆ ਗਈ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="3468298837301810372">ਲੇਬਲ</translation>
 <translation id="3468999815377931311">Android ਫ਼ੋਨ</translation>
 <translation id="3470442499439619530">ਇਹ ਵਰਤੋਂਕਾਰ ਹਟਾਓ</translation>
@@ -2321,6 +2331,7 @@
 <translation id="3495496470825196617">ਬੈਟਰੀ ਚਾਰਜ ਕਰਨ ਦੌਰਾਨ ਸਲੀਪ ਮੋਡ 'ਤੇ ਜਾਓ</translation>
 <translation id="3495660573538963482">Google ਸਹਾਇਕ ਸੈਟਿੰਗਾਂ</translation>
 <translation id="3496213124478423963">ਜ਼ੂਮ ਘਟਾਓ</translation>
+<translation id="3497501929010263034"><ph name="VENDOR_NAME" /> ਦਾ USB ਡੀਵਾਈਸ (ਉਤਪਾਦ <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">ਡੂਡਲ ਸਾਂਝਾ ਕਰੋ</translation>
 <translation id="3498215018399854026">ਇਸ ਇਸ ਵੇਲੇ ਤੁਹਾਡੇ ਮਾਤਾ ਜਾਂ ਪਿਤਾ ਨਾਲ ਸੰਪਰਕ ਨਹੀਂ ਕਰ ਸਕੇ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="3500417806337761827">ਸਾਂਝਾਕਰਨ ਮਾਊਂਟ ਕਰਨ ਵਿੱਚ ਗੜਬੜ ਹੋਈ। ਬਹੁਤ ਸਾਰੇ SMB ਸਾਂਝਾਕਰਨਾਂ ਨੂੰ ਪਹਿਲਾਂ ਹੀ ਮਾਊਂਟ ਕੀਤਾ ਜਾ ਚੁੱਕਿਆ ਹੈ।</translation>
@@ -2408,6 +2419,7 @@
 <translation id="3600792891314830896">ਧੁਨੀ ਵਜਾਉਣ ਵਾਲੀਆਂ ਸਾਈਟਾਂ ਨੂੰ ਮਿਊਟ ਕਰੋ</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">ਉਪਲਬਧ ਹੋਣ 'ਤੇ ਨਵੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਪੇਸ਼ਕਸ਼</translation>
+<translation id="3602179428782502464">ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਅੱਪਡੇਟ ਨੂੰ ਬਲਾਕ ਕਰ ਦਿੱਤਾ ਹੈ</translation>
 <translation id="3602290021589620013">ਪ੍ਰੀਵਿਊ</translation>
 <translation id="3602870520245633055">ਪ੍ਰਿੰਟ ਅਤੇ ਸਕੈਨ ਕਰੋ</translation>
 <translation id="3603622770190368340">ਨੈੱਟਵਰਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਪ੍ਰਾਪਤ ਕਰੋ</translation>
@@ -2417,6 +2429,7 @@
 <translation id="3610369246614755442">ਡੌਕ ਦੇ ਪੱਖੇ ਦੀ ਮੁਰੰਮਤ ਕਰਵਾਉਣ ਦੀ ਲੋੜ ਹੈ</translation>
 <translation id="361106536627977100">Flash ਡਾਟਾ</translation>
 <translation id="3611655097742243705">ਹੋਰ ਐਪਾਂ ਲੱਭਣ ਲਈ Play Store 'ਤੇ ਜਾਓ</translation>
+<translation id="3611658447322220736">ਹਾਲ ਹੀ ਵਿੱਚ ਬੰਦ ਕੀਤੀਆਂ ਸਾਈਟਾਂ ਡਾਟਾ ਭੇਜਣ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਮੁਕੰਮਲ ਕਰ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="3612673635130633812">&lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt; ਵੱਲੋਂ ਡਾਊਨਲੋਡ ਕੀਤਾ</translation>
 <translation id="3613134908380545408"><ph name="FOLDER_NAME" /> ਦਿਖਾਓ</translation>
 <translation id="3613422051106148727">&amp;ਨਵੀਂ ਟੈਬ ਵਿੱਚ ਖੋਲ੍ਹੋ</translation>
@@ -2449,6 +2462,7 @@
 <translation id="3639220004740062347">ਰੀਡਰ ਮੋਡ ਤੋਂ ਬਾਹਰ ਆਓ</translation>
 <translation id="3640214691812501263">ਕੀ <ph name="USER_NAME" /> ਲਈ "<ph name="EXTENSION_NAME" />" ਨੂੰ ਜੋੜਨਾ ਹੈ?</translation>
 <translation id="3640613767643722554">ਆਪਣੀ 'ਅਸਿਸਟੈਂਟ' ਨੂੰ ਤੁਹਾਡੀ ਅਵਾਜ਼ ਪਛਾਣਨਾ ਸਿਖਾਓ</translation>
+<translation id="3641456520301071208">ਸਾਈਟਾਂ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਬਾਰੇ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="3645372836428131288">ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੇ ਇੱਕ ਵੱਖਰੇ ਹਿੱਸੇ ਨੂੰ ਕੈਪਚਰ ਕਰਨ ਲਈ ਉਂਗਲ ਨੂੰ ਥੋੜ੍ਹਾ ਜਿਹਾ ਹਿਲਾਓ।</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{<ph name="DEVICE_NAME" /> ਤੋਂ <ph name="ATTACHMENTS" /> ਪ੍ਰਾਪਤ ਹੋਈ}one{<ph name="DEVICE_NAME" /> ਤੋਂ <ph name="ATTACHMENTS" /> ਪ੍ਰਾਪਤ ਹੋਈ}other{<ph name="DEVICE_NAME" /> ਤੋਂ <ph name="ATTACHMENTS" /> ਪ੍ਰਾਪਤ ਹੋਈਆਂ}}</translation>
 <translation id="3648348069317717750"><ph name="USB_DEVICE_NAME" /> ਖੋਜਿਆ ਗਿਆ</translation>
@@ -2491,6 +2505,7 @@
 <translation id="3688526734140524629">ਚੈਨਲ ਬਦਲੋ</translation>
 <translation id="3688578402379768763">ਅਪ-ਟੂ-ਡੇਟ</translation>
 <translation id="3688794912214798596">ਭਾਸ਼ਾਵਾਂ ਬਦਲੋ...</translation>
+<translation id="3690128548376345212"><ph name="NETWORK_COUNT" /> ਵਿੱਚੋਂ <ph name="NETWORK_INDEX" /> ਨੈੱਟਵਰਕ, <ph name="NETWORK_NAME" />, ਅਕਿਰਿਆਸ਼ੀਲ ਕੀਤਾ ਗਿਆ, <ph name="CONNECTION_STATUS" />, ਸਿਗਨਲ ਦੀ ਤੀਬਰਤਾ <ph name="SIGNAL_STRENGTH" />%, ਵੇਰਵੇ</translation>
 <translation id="3690369331356918524">ਡਾਟਾ ਉਲੰਘਣਾ ਵਿੱਚ ਪਾਸਵਰਡਾਂ ਦਾ ਖੁਲਾਸਾ ਹੋਣ 'ਤੇ ਤੁਹਾਨੂੰ ਚਿਤਾਵਨੀ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ</translation>
 <translation id="3691231116639905343">ਕੀ-ਬੋਰਡ ਐਪਾਂ</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> ਦੀ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦੀ ਇੱਛਾ ਹੈ</translation>
@@ -2572,6 +2587,7 @@
 <translation id="3772609330847318323"><ph name="ORIGIN" /> ਲਈ ਪਾਸਵਰਡ ਅੱਪਡੇਟ ਕਰੋ</translation>
 <translation id="3775432569830822555">SSL ਸਰਵਰ ਪ੍ਰਮਾਣ-ਪੱਤਰ</translation>
 <translation id="3775705724665058594">ਆਪਣੇ ਡੀਵਾਈਸਾਂ 'ਤੇ ਭੇਜੋ</translation>
+<translation id="3776508619697147021">ਸਾਈਟਾਂ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਕਈ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="3776796446459804932">ਇਹ ਸੈਟਿੰਗ 'Chrome ਵੈੱਬ ਸਟੋਰ' ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕਰਦੀ ਹੈ।</translation>
 <translation id="3777483481409781352">ਸੈਲਿਊਲਰ ਡੀਵਾਈਸ ਕਿਰਿਆਸ਼ੀਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</translation>
 <translation id="3777806571986431400">ਐਕਸਟੈਂਸ਼ਨ ਚਾਲੂ ਕਰੋ</translation>
@@ -2873,6 +2889,7 @@
 <translation id="4078738236287221428">ਆਕਰਮਣਸ਼ੀਲ</translation>
 <translation id="4079140982534148664">ਵਿਸਤ੍ਰਿਤ ਸ਼ਬਦ-ਜੋੜ ਜਾਂਚ ਵਰਤੋ</translation>
 <translation id="4081242589061676262">ਫ਼ਾਈਲ ਕਾਸਟ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> ਨੇ ਤੁਹਾਡੇ ਫ਼ੋਨ 'ਤੇ ਕੋਈ ਸੂਚਨਾ ਭੇਜੀ ਹੈ। ਆਪਣੀ ਪਛਾਣ ਦੀ ਤਸਦੀਕ ਕਰਨ ਲਈ, ਇਹਨਾਂ ਪੜਾਵਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ।</translation>
 <translation id="4084682180776658562">ਬੁੱਕਮਾਰਕ</translation>
 <translation id="4084835346725913160"><ph name="TAB_NAME" /> ਨੂੰ ਬੰਦ ਕਰੋ</translation>
 <translation id="4085270836953633510">ਕਿਸੇ ਸਾਈਟ ਵੱਲੋਂ ਸੀਰੀਅਲ ਪੋਰਟਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਵੇਲੇ ਪੁੱਛੋ</translation>
@@ -3034,6 +3051,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{ਦਿਖਾਓ}one{ਦਿਖਾਓ}other{ਸਾਰੇ ਦਿਖਾਓ}}</translation>
 <translation id="4289372044984810120">ਆਪਣੇ ਖਾਤਿਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਇੱਥੇ ਕਰੋ। <ph name="LINK_BEGIN" />ਹੋਰ ਜਾਣੋ<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">ਓਵਰਵਿਊ</translation>
+<translation id="4290791284969893584">ਕਿਸੇ ਪੰਨੇ ਨੂੰ ਬੰਦ ਕਰਨ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਡੇ ਵੱਲੋਂ ਸ਼ੁਰੂ ਕੀਤੇ ਕਾਰਜ ਸ਼ਾਇਦ ਮੁਕੰਮਲ ਨਾ ਹੋਣ</translation>
 <translation id="4295072614469448764">ਐਪ ਤੁਹਾਡੇ ਟਰਮੀਨਲ ਵਿੱਚ ਉਪਲਬਧ ਹੈ। ਤੁਹਾਡੇ ਲਾਂਚਰ ਵਿੱਚ ਇੱਕ ਪ੍ਰਤੀਕ ਵੀ ਹੋ ਸਕਦਾ ਹੈ।</translation>
 <translation id="4295839147292213505">ਤੁਸੀਂ ਆਪਣੇ ਕੰਪਿਊਟਰ ਤੋਂ ਲਿਖਤ ਸੁਨੇਹਾ ਭੇਜ ਸਕਦੇ ਹੋ, ਆਪਣਾ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਸਾਂਝਾ ਕਰ ਸਕਦੇ ਹੋ, ਗੱਲਬਾਤ ਸੂਚਨਾ ਦਾ ਜਵਾਬ ਦੇ ਸਕਦੇ ਹੋ ਅਤੇ ਆਪਣੇ ਫ਼ੋਨ ਨਾਲ ਆਪਣਾ <ph name="DEVICE_TYPE" /> ਅਣਲਾਕ ਕਰ ਸਕਦੇ ਹੋ।<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />ਹੋਰ ਜਾਣੋ<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">ਕਿਰਪਾ ਕਰਕੇ ਇਹ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਦੁਬਾਰਾ ਸਾਈਨ-ਇਨ ਕਰੋ ਕਿ ਤੁਹਾਡਾ ਖਾਤਾ <ph name="USER_EMAIL" /> Chrome ਅਤੇ Google Play ਵਿੱਚ ਵੈੱਬਸਾਈਟਾਂ, ਐਪਾਂ ਅਤੇ ਐਕਸਟੈਂਸ਼ਨਾਂ ਨਾਲ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ। ਤੁਸੀਂ ਇਹ ਖਾਤਾ ਹਟਾ ਵੀ ਸਕਦੇ ਹੋ। <ph name="LINK_BEGIN" />ਹੋਰ ਜਾਣੋ<ph name="LINK_END" /></translation>
@@ -3230,6 +3248,7 @@
 <translation id="4514610446763173167">ਵੀਡੀਓ ਨੂੰ ਚਲਾਉਣ ਜਾਂ ਰੋਕਣ ਲਈ ਟੌਗਲ ਕਰੋ</translation>
 <translation id="451515744433878153">ਹਟਾਓ</translation>
 <translation id="4515872537870654449">ਸੇਵਾ ਲਈ Dell ਨੂੰ ਸੰਪਰਕ ਕਰੋ। ਇਹ ਡੌਕ, ਪੱਖੇ ਦੇ ਕੰਮ ਨਾ ਕਰਨ 'ਤੇ ਬੰਦ ਹੋ ਜਾਵੇਗਾ।</translation>
+<translation id="4519331665958994620">ਸਾਈਟਾਂ ਤੁਹਾਡਾ ਕੈਮਰਾ ਵਰਤਣ ਲਈ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="4519935350946509010">ਕਨੈਕਸ਼ਨ ਵਿੱਚ ਗੜਬੜ।</translation>
 <translation id="4520385623207007473">ਵਰਤੀਆਂ ਜਾ ਰਹੀਆਂ ਕੁਕੀਜ਼</translation>
 <translation id="452039078290142656"><ph name="VENDOR_NAME" /> ਵੱਲੋਂ ਅਗਿਆਤ ਡਿਵਾਈਸਾਂ</translation>
@@ -3409,6 +3428,7 @@
 <translation id="4694604912444486114">ਬਾਂਦਰ</translation>
 <translation id="4697071790493980729">ਕੋਈ ਨਤੀਜਾ ਨਹੀਂ ਮਿਲਿਆ</translation>
 <translation id="4697551882387947560">ਜਦੋਂ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸੈਸ਼ਨ ਖ਼ਤਮ ਹੁੰਦਾ ਹੈ</translation>
+<translation id="469838979880025581">ਸਾਈਟਾਂ ਤੁਹਾਡਾ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਵਰਤਣ ਲਈ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="4699172675775169585">ਕੈਚ ਕੀਤੇ ਚਿੱਤਰ ਅਤੇ ਫਾਈਲਾਂ</translation>
 <translation id="4699357559218762027">(ਆਟੋ-ਲੌਂਚ ਕੀਤਾ)</translation>
 <translation id="4701025263201366865">ਮਾਂ-ਪਿਓ ਦਾ ਸਾਈਨ-ਇਨ</translation>
@@ -3591,6 +3611,10 @@
 <translation id="4918086044614829423">ਸਵੀਕਾਰ ਕਰੋ</translation>
 <translation id="4921290200821452703">ਮਾਂ-ਪਿਓ ਲਈ ਸਕੂਲੀ ਖਾਤੇ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ</translation>
 <translation id="4921348630401250116">ਲਿਖਤ-ਤੋਂ-ਬੋਲੀ</translation>
+<translation id="4921809350408880559">ਤੁਸੀਂ ਆਪਣੇ ਹਾਲੀਆ ਅਤੇ ਸੁਝਾਏ ਦਸਤਾਵੇਜ਼ Google Drive ਨੂੰ ਵਰਤ ਕੇ ਆਪਣੀ ਪਿਛਲੀ ਸਰਗਰਮੀ ਦੇ ਆਧਾਰ 'ਤੇ ਦੇਖ ਰਹੇ ਹੋ।
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google Drive ਵੱਲੋਂ ਇਕੱਤਰ ਕੀਤੇ ਜਾਂਦੇ ਡਾਟੇ ਅਤੇ ਉਸਦੇ ਕਾਰਨਾਂ ਬਾਰੇ <ph name="BEGIN_LINK" />ਇੱਥੇ<ph name="END_LINK" /> ਜਾਣੋ।</translation>
 <translation id="49226369361073053">{0,plural, =0{ਡੀਵਾਈਸ ਨੂੰ ਹੁਣੇ ਅੱਪਡੇਟ ਕਰੋ}=1{ਡੀਵਾਈਸ ਨੂੰ 1 ਸਕਿੰਟ ਦੇ ਅੰਦਰ ਅੱਪਡੇਟ ਕਰੋ}other{ਡੀਵਾਈਸ ਨੂੰ # ਸਕਿੰਟਾਂ ਦੇ ਅੰਦਰ ਅੱਪਡੇਟ ਕਰੋ}}</translation>
 <translation id="492299503953721473">Android ਐਪਾਂ ਹਟਾਓ</translation>
 <translation id="492363500327720082"><ph name="APP_NAME" /> ਨੂੰ ਅਣਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...</translation>
@@ -4351,6 +4375,7 @@
 <translation id="5794700615121138172">Linux ਸਾਂਝੇ ਕੀਤੇ ਫੋਲਡਰ</translation>
 <translation id="5794786537412027208">ਸਾਰੀਆਂ Chrome ਐਪਾਂ ਛੱਡੋ</translation>
 <translation id="5797070761912323120">Google ਖੋਜ, ਵਿਗਿਆਪਨਾਂ ਅਤੇ ਹੋਰਾਂ Google ਸੇਵਾਵਾਂ ਨੂੰ ਵਿਅਕਤੀਗਤ ਬਣਾਉਣ ਲਈ ਤੁਹਾਡੇ ਇਤਿਹਾਸ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦਾ ਹੈ</translation>
+<translation id="5798079537501238810">ਸਾਈਟਾਂ ਭੁਗਤਾਨ ਹੈਂਡਲਰਾਂ ਨੂੰ ਸਥਾਪਤ ਕਰ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="579907812742603813">ਸੁਰੱਖਿਅਤ ਸਮੱਗਰੀ</translation>
 <translation id="579915268381781820">ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਕੁੰਜੀ ਹਟਾ ਦਿੱਤੀ ਗਈ ਸੀ।</translation>
 <translation id="5799478978078236781"><ph name="DEVICE_TYPE" /> ਨੁਕਤੇ, ਪੇਸ਼ਕਸ਼ਾਂ ਅਤੇ ਅੱਪਡੇਟ ਪ੍ਰਾਪਤ ਕਰੋ ਅਤੇ ਵਿਚਾਰ ਸਾਂਝਾ ਕਰੋ।</translation>
@@ -4383,6 +4408,7 @@
 <translation id="5833726373896279253">ਇਹ ਸੈਟਿੰਗਾਂ ਕੇਵਲ ਮਾਲਕ ਵੱਲੋਂ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ।</translation>
 <translation id="5834581999798853053">ਲਗਭਗ <ph name="TIME" /> ਮਿੰਟ ਬਾਕੀ</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - ਕੈਮਰਾ ਜਾਂ ਮਾਈਕ੍ਰੋਫੋਨ ਰਿਕਾਰਡਿੰਗ</translation>
+<translation id="583673505367439042">ਸਾਈਟਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਵਿਚਲੀਆਂ ਫ਼ਾਈਲਾਂ ਅਤੇ ਫੋਲਡਰਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਪੁੱਛ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="5840680448799937675">ਫ਼ਾਈਲਾਂ ਨੂੰ ਹਮੇਸ਼ਾਂ ਆਫ਼ਲਾਈਨ ਹੀ ਸਾਂਝਾ ਕੀਤਾ ਜਾਵੇਗਾ</translation>
 <translation id="5841270259333717135">ਈਥਰਨੈੱਟ ਦਾ ਸੰਰੂਪਣ ਕਰੋ</translation>
 <translation id="5842497610951477805">ਬਲੂਟੁੱਥ ਚਾਲੂ</translation>
@@ -4432,6 +4458,7 @@
 <translation id="5889282057229379085">ਵਿਚਕਾਰਲੇ CA ਦੀ ਅਧਿਕਤਮ ਸੰਖਿਆ: <ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">ਤਰਜੀਹੀ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ</translation>
 <translation id="5895138241574237353">ਰੀਸਟਾਰਟ ਕਰੋ</translation>
+<translation id="5896749729057314184"><ph name="NETWORK_COUNT" /> ਵਿੱਚੋਂ <ph name="NETWORK_INDEX" /> ਨੈੱਟਵਰਕ, <ph name="NETWORK_NAME" />, ਅਕਿਰਿਆਸ਼ੀਲ ਕੀਤਾ ਗਿਆ, ਸਿਗਨਲ ਦੀ ਤੀਬਰਤਾ <ph name="SIGNAL_STRENGTH" />%, ਵੇਰਵੇ</translation>
 <translation id="5900302528761731119">Google ਪ੍ਰੋਫਾਈਲ ਫ਼ੋਟੋ</translation>
 <translation id="590036993063074298">ਪ੍ਰਤਿਬਿੰਬੀਕਰਨ ਕੁਆਲਿਟੀ ਦੇ ਵੇਰਵੇ</translation>
 <translation id="5901069264981746702">ਤੁਹਾਡਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਡਾਟਾ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਸਟੋਰ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਅਤੇ ਕਦੇ ਵੀ ਤੁਹਾਡੇ <ph name="DEVICE_TYPE" /> ਤੋਂ ਬਾਹਰ ਨਹੀਂ ਜਾਂਦਾ ਹੈ। <ph name="LINK_BEGIN" />ਹੋਰ ਜਾਣੋ<ph name="LINK_END" /></translation>
@@ -4676,6 +4703,7 @@
 <translation id="6155141482566063812">ਬੈਕਗ੍ਰਾਊਂਡ ਟੈਬ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਸਾਂਝਾ ਕਰ ਰਹੀ ਹੈ</translation>
 <translation id="6156323911414505561">ਬੁੱਕਮਾਰਕ ਬਾਰ  ਦਿਖਾਓ </translation>
 <translation id="6156863943908443225">ਸਕ੍ਰਿਪਟ ਕੈਸ਼ੇ</translation>
+<translation id="615930144153753547">ਸਾਈਟਾਂ ਚਿੱਤਰਾਂ ਨੂੰ ਦਿਖਾ ਸਕਦੀਆਂ ਹਨ</translation>
 <translation id="6160625263637492097">ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਸਰਟੀਫਿਕੇਟ ਮੁਹੱਈਆ ਕਰਵਾਓ</translation>
 <translation id="6163363155248589649">&amp;ਸਧਾਰਨ</translation>
 <translation id="6163376401832887457">Kerberos ਸੈਟਿੰਗਾਂ</translation>
@@ -4882,6 +4910,10 @@
 <translation id="6398715114293939307">Google Play ਸਟੋਰ ਹਟਾਓ</translation>
 <translation id="6398765197997659313">ਪੂਰੀ ਸਕ੍ਰੀਨ ਤੋਂ ਬਾਹਰ ਜਾਓ</translation>
 <translation id="6399774419735315745">ਜਸੂਸ</translation>
+<translation id="6400510847800135340">ਤੁਸੀਂ ਇਹ ਆਈਟਮ Google ਸੇਵਾਵਾਂ ਨੂੰ ਵਰਤ ਕੇ ਆਪਣੀ ਪਿਛਲੀ ਸਰਗਰਮੀ ਦੇ ਆਧਾਰ 'ਤੇ ਦੇਖ ਰਹੇ ਹੋ। ਤੁਸੀਂ <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 'ਤੇ ਆਪਣੇ ਡਾਟੇ ਨੂੰ ਦੇਖ ਸਕਦੇ ਹੋ, ਇਸਨੂੰ ਮਿਟਾ ਸਕਦੇ ਹੋ ਅਤੇ ਆਪਣੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" /> 'ਤੇ Google ਵੱਲੋਂ ਇਕੱਤਰ ਕੀਤੇ ਜਾਂਦੇ ਡਾਟੇ ਅਤੇ ਉਸਦੇ ਕਾਰਨਾਂ ਬਾਰੇ ਜਾਣੋ।</translation>
 <translation id="6404511346730675251">ਬੁੱਕਮਾਰਕ ਸੰਪਾਦਿਤ ਕਰੋ</translation>
 <translation id="6406303162637086258">ਬ੍ਰਾਊਜ਼ਰ ਰੀਸਟਾਰਟ ਦੀ ਨਕਲ ਕਰੋ</translation>
 <translation id="6406506848690869874">ਸਿੰਕ ਕਰੋ</translation>
@@ -4931,6 +4963,7 @@
 <translation id="6452251728599530347"><ph name="PERCENT" /> ਪੂਰਾ</translation>
 <translation id="645286928527869380">ਪਕਵਾਨ-ਵਿਧੀ ਸੰਬੰਧੀ ਸੁਝਾਅ</translation>
 <translation id="6452961788130242735">ਨੈੱਟਵਰਕ ਸਮੱਸਿਆ ਜਾਂ ਖਰਾਬ ਖੇਤਰ</translation>
+<translation id="6453921811609336127">ਅਗਲੀ ਇਨਪੁੱਟ ਵਿਧੀ 'ਤੇ ਜਾਣ ਲਈ, <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> ਦਬਾਓ</translation>
 <translation id="6455264371803474013">ਕੁਝ ਖਾਸ ਸਾਈਟਾਂ 'ਤੇ</translation>
 <translation id="6455894534188563617">&amp;ਨਵਾਂ ਫੋਲਡਰ</translation>
 <translation id="645705751491738698">JavaScript ਨੂੰ ਬਲੌਕ ਕਰਨਾ ਜਾਰੀ ਰੱਖੋ</translation>
@@ -5056,6 +5089,7 @@
 <translation id="6590458744723262880">ਫੋਲਡਰ ਦਾ ਨਾਮ ਬਦਲੋ</translation>
 <translation id="6592267180249644460">WebRTC ਲੌਗ ਕੈਪਚਰ ਕੀਤਾ <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">ਤੁਹਾਡਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਕੈਪਚਰ ਕੀਤਾ ਗਿਆ</translation>
+<translation id="6593881952206664229">ਕਾਪੀਰਾਈਟ ਵਾਲਾ ਮੀਡੀਆ ਸ਼ਾਇਦ ਨਾ ਚੱਲੇ</translation>
 <translation id="6594011207075825276">ਸੀਰੀਅਲ ਡੀਵਾਈਸ ਲੱਭੇ ਜਾ ਰਹੇ ਹਨ...</translation>
 <translation id="6595187330192059106"><ph name="HOST" /> ਨੂੰ ਹਮੇਸ਼ਾਂ MIDI ਡੀਵਾਈਸਾਂ ਦਾ ਪੂਰਾ ਕੰਟਰੋਲ ਲੈਣ ਤੋਂ ਬਲਾਕ ਕਰੋ।</translation>
 <translation id="6596325263575161958">ਐਨਕ੍ਰਿਪਸ਼ਨ ਚੋਣਾਂ</translation>
@@ -6013,6 +6047,7 @@
 <translation id="7661451191293163002">ਇੱਕ ਰਜਿਸਟਰ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।</translation>
 <translation id="7662283695561029522">ਸੰਰੂਪਣ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ</translation>
 <translation id="7663719505383602579">ਰਿਸੀਵਰ: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਹੈ</translation>
 <translation id="7664620655576155379">ਅਸਮਰਥਿਤ ਬਲੂਟੁੱਥ ਡਿਵਾਈਸ: "<ph name="DEVICE_NAME" />"।</translation>
 <translation id="7665082356120621510">ਆਕਾਰ ਰਾਖਵਾਂ ਕਰੋ</translation>
 <translation id="7665369617277396874">ਖਾਤਾ ਸ਼ਾਮਲ ਕਰੋ</translation>
@@ -6191,6 +6226,7 @@
 <translation id="7835178595033117206">ਬੁੱਕਮਾਰਕ ਹਟਾਇਆ ਗਿਆ</translation>
 <translation id="7836850009646241041">ਆਪਣੀ ਸੁਰੱਖਿਆ ਕੁੰਜੀ ਨੂੰ ਦੁਬਾਰਾ ਸਪਰਸ਼ ਕਰਕੇ ਦੇਖੋ</translation>
 <translation id="7837776265184002579">ਤੁਹਾਡਾ ਮੁੱਖ ਪੰਨਾ <ph name="URL" /> 'ਤੇ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਸੀ।</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{<ph name="ATTACHMENTS" /> ਨੂੰ <ph name="DEVICE_NAME" /> 'ਤੇ ਭੇਜਿਆ ਗਿਆ}one{<ph name="ATTACHMENTS" /> ਨੂੰ <ph name="DEVICE_NAME" /> 'ਤੇ ਭੇਜਿਆ ਗਿਆ}other{<ph name="ATTACHMENTS" /> ਨੂੰ <ph name="DEVICE_NAME" /> 'ਤੇ ਭੇਜਿਆ ਗਿਆ}}</translation>
 <translation id="7839051173341654115">ਮੀਡੀਆ ਦੇਖੋ/ਬੈਕਅੱਪ ਲਓ</translation>
 <translation id="7839192898639727867">ਪ੍ਰਮਾਣ-ਪੱਤਰ ਵਿਸ਼ਾ ਕੁੰਜੀ ID</translation>
 <translation id="7842692330619197998">ਜੇ ਤੁਹਾਨੂੰ ਨਵਾਂ ਖਾਤਾ ਬਣਾਉਣ ਦੀ ਲੋੜ ਹੈ ਤਾਂ g.co/ChromeEnterpriseAccount 'ਤੇ ਜਾਓ।</translation>
@@ -6886,6 +6922,7 @@
 <translation id="8633025649649592204">ਹਾਲੀਆ ਸਰਗਰਮੀ</translation>
 <translation id="8635628933471165173">ਰੀਲੋਡ ਹੋ ਰਹੀ ਹੈ...</translation>
 <translation id="8636284842992792762">ਐਕਸਟੈਂਸ਼ਨਾਂ ਨੂੰ ਸ਼ੁਰੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...</translation>
+<translation id="8636500887554457830">ਸਾਈਟਾਂ ਨੂੰ ਪੌਪ-ਅੱਪ ਭੇਜਣ ਜਾਂ ਰੀਡਾਇਰੈਕਟ ਵਰਤਣ ਦੀ ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ</translation>
 <translation id="8637542770513281060">ਤੁਹਾਡੇ ਕੰਪਿਊਟਰ ਵਿੱਚ ਇੱਕ ਸੁਰੱਖਿਅਤ ਮਾਡਿਊਲ ਹੈ, ਜੋ Chrome OS ਵਿੱਚ ਕਈ ਆਲੋਚਨਾਤਮਿਕ ਸੁਰੱਖਿਆ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਹੈ। ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ Chromebook ਦੇ ਮਦਦ ਕੇਂਦਰ 'ਤੇ ਜਾਓ: https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">ਸਿਸਟਮ ਅੱਪਡੇਟ ਉਪਲਬਧ। ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਤਿਆਰੀ ਕਰ ਰਿਹਾ ਹੈ…</translation>
 <translation id="863903787380594467">ਗਲਤ ਪਿੰਨ। ਤੁਹਾਡੇ ਕੋਲ <ph name="RETRIES" /> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</translation>
@@ -7104,6 +7141,7 @@
 <translation id="8842594465773264717">ਇਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨੂੰ ਮਿਟਾਓ</translation>
 <translation id="8845001906332463065">ਮਦਦ ਪ੍ਰਾਪਤ ਕਰੋ</translation>
 <translation id="8846132060409673887">ਇਸ ਕੰਪਿਊਟਰ ਦੇ ਨਿਰਮਾਤਾ ਅਤੇ ਮਾਡਲ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਪੜ੍ਹੋ</translation>
+<translation id="8846163936679269230">ਈ-ਸਿਮ ਪ੍ਰੋਫਾਈਲਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ</translation>
 <translation id="8847523528195140327">ਕਵਰ ਬੰਦ ਹੋਣ 'ਤੇ ਸਾਈਨ-ਆਊਟ ਕਰੋ</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">ਲੁਕੀ ਹੋਈ</translation>
@@ -7159,6 +7197,7 @@
 <translation id="8898822736010347272">ਵੈੱਬ 'ਤੇ ਨਵੇਂ ਖਤਰਿਆਂ ਨੂੰ ਲੱਭ ਕੇ ਹਰੇਕ ਦੀ ਸੁਰੱਖਿਆ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਵੱਲੋਂ ਦੇਖੇ ਗਏ ਕੁਝ ਪੰਨਿਆਂ ਦੇ URL, ਸੀਮਤ ਸਿਸਟਮ ਜਾਣਕਾਰੀ ਅਤੇ ਕੁਝ ਨਵੀਂ ਪੰਨਾ ਸਮੱਗਰੀ Google ਨੂੰ ਭੇਜੇ ਜਾਂਦੇ ਹਨ।</translation>
 <translation id="8899851313684471736">ਨਵੀਂ &amp;window ਵਿੱਚ ਲਿੰਕ ਖੋਲ੍ਹੋ</translation>
 <translation id="8900413463156971200">ਸੈਲਿਊਲਰ ਨੈੱਟਵਰਕ ਨੂੰ ਚਾਲੂ ਕਰੋ</translation>
+<translation id="8901994452417867840">ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਸਫਲਤਾਪੂਰਵਕ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ। ਇਹ ਕਨੈਕਸ਼ਨ ਇਸ ਡੀਵਾਈਸ ਦੇ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਉਪਲਬਧ ਰਹੇਗਾ।</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> ਲਈ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡਾਟੇ ਦਾ ਬੈਕਅੱਪ ਲੈਣ ਅਤੇ ਇਸ <ph name="DEVICE_TYPE" /> ਨੂੰ ਅੱਜ ਹੀ ਵਾਪਸ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।}one{<ph name="MANAGER" /> ਲਈ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡਾਟੇ ਦਾ ਬੈਕਅੱਪ ਲੈਣ ਅਤੇ ਸਮਾਂ-ਸੀਮਾ ਤੋਂ ਪਹਿਲਾਂ ਇਸ <ph name="DEVICE_TYPE" /> ਨੂੰ ਵਾਪਸ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।}other{<ph name="MANAGER" /> ਲਈ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡਾਟੇ ਦਾ ਬੈਕਅੱਪ ਲੈਣ ਅਤੇ ਸਮਾਂ-ਸੀਮਾ ਤੋਂ ਪਹਿਲਾਂ ਇਸ <ph name="DEVICE_TYPE" /> ਨੂੰ ਵਾਪਸ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।}}</translation>
 <translation id="8902667442496790482">'ਚੁਣੋ ਅਤੇ ਸੁਣੋ' ਸੈਟਿੰਗਾਂ ਦਾ ਪੰਨਾ ਖੋਲ੍ਹੋ</translation>
 <translation id="8903263458134414071">ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਕੋਈ ਖਾਤਾ ਚੁਣੋ</translation>
@@ -7340,6 +7379,7 @@
 <translation id="9094982973264386462">ਹਟਾਓ</translation>
 <translation id="9095253524804455615">ਹਟਾਓ</translation>
 <translation id="909554839118732438">ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋਆਂ ਬੰਦ ਕਰੋ</translation>
+<translation id="9100416672768993722">ਪਿਛਲੀ ਵਾਰ ਵਰਤੀ ਇਨਪੁੱਟ ਵਿਧੀ 'ਤੇ ਜਾਣ ਲਈ, <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> ਦਬਾਓ</translation>
 <translation id="9100610230175265781">ਪਾਸਫਰੇਜ਼ ਲੋੜੀਂਦਾ</translation>
 <translation id="9100765901046053179">ਉੱਨਤ ਸੈਟਿੰਗਾਂ</translation>
 <translation id="9101691533782776290">ਐਪ ਲਾਂਚ ਕਰੋ</translation>
diff --git a/chrome/app/resources/generated_resources_si.xtb b/chrome/app/resources/generated_resources_si.xtb
index 79e32a9..501a713 100644
--- a/chrome/app/resources/generated_resources_si.xtb
+++ b/chrome/app/resources/generated_resources_si.xtb
@@ -62,6 +62,7 @@
 <translation id="1066613507389053689">Chrome OS යාවත්කාලීනය අවශ්‍යයි</translation>
 <translation id="1067048845568873861">සාදන ලදි</translation>
 <translation id="1067922213147265141">වෙනත් Google සේවාවන්</translation>
+<translation id="1069355737714877171"><ph name="PROFILE_NAME" /> නම් වූ eSIM පැතිකඩ ඉවත් කරන්න</translation>
 <translation id="1070377999570795893">ඔබේ පරිගණකයේ ඇති වෙනත් ක්‍රමලේඛයක් දිගුවක් එක් කර ඇති අතර එයින් Chrome ක්‍රියා කරන ආකරය වෙනස් විය හැකිය.
 
 <ph name="EXTENSION_NAME" /></translation>
@@ -358,6 +359,7 @@
 <translation id="138784436342154190">පෙරනිමි ආරම්භක පිටුව ප්‍රතිසාධනය කරනවා ද?</translation>
 <translation id="1388253969141979417">ඔබගේ මයික්‍රෆෝනය භාවිත කිරීමට ඉඩ දේ</translation>
 <translation id="1388728792929436380">යාවත්කාලීන සම්පූර්ණ වූ විට <ph name="DEVICE_TYPE" /> යළි ආරම්භ වනු ඇත.</translation>
+<translation id="138900021244932468">පැතිකඩවල් සොයා නොගන්නා ලදි. නව ජාලයක් පිහිටුවීමට, උපාංග කැමරාව භාවිතයෙන් QR කේතය ස්කෑන් කරන්න හෝ ඔබගේ වාහකය විසින් සපයන ලද සක්‍රිය කිරීමේ කේතය ඇතුළු කරන්න</translation>
 <translation id="139013308650923562">ඔබගේ උපාංගයේ ස්ථාපනය කර ඇති ෆොන්ට භාවිත කිරීමට ඉඩ දේ</translation>
 <translation id="1390548061267426325">සාමාන්‍ය ටැබයක් ලෙස විවෘත කරන්න</translation>
 <translation id="1393283411312835250">හිරු හා වළාකුළු</translation>
@@ -984,6 +986,7 @@
 ඔබට ඔබේ උපාංගය මත Family Link යෙදුම ස්ථාපන කිරීමෙන්, මෙම ගිණුමේ සැකසීම් කළමනා කළ හැක.  අපි ඔබට ඉ-තැපෑලකින් උපදෙස් යැවුවෙමු.</translation>
 <translation id="2040460856718599782">අහෝ! ඔබට අවසරදීමේදී ගැටළුවක් ඇති විය. ඔබේ පිවිසුම් තොරතුරු දෙවරක් පිරික්සා නැවත උත්සහ කරන්න.</translation>
 <translation id="2044014337866019681">සැසිය අගුලු හැරීමට ඔබ <ph name="ACCOUNT" /> සත්‍යාපනය කරන බවට සහතික කර ගන්න.</translation>
+<translation id="2044023416777079300">මොඩමය ලියාපදිංචි කර නැත</translation>
 <translation id="204497730941176055">Microsoft සහතික ආකෘති නාමය</translation>
 <translation id="2045117674524495717">යතුරුපුවරු කෙටිමං උපකාරකය</translation>
 <translation id="2045969484888636535">කුකීස් අවහිර කිරීම දිගටම කරන්න</translation>
@@ -4086,6 +4089,7 @@
 <translation id="5486261815000869482">රහස්වචනය තහවුරු කරන්න</translation>
 <translation id="5486275809415469523"><ph name="APP_NAME" /> විසින් ඔබේ තිරය <ph name="TAB_NAME" /> සමග හුවමාරු කර ගනී.</translation>
 <translation id="5486561344817861625">බ්‍රවුසර යළි ආරම්භය ප්‍රති නිර්මාණය කරන්න</translation>
+<translation id="5487460042548760727">පැතිකඩ <ph name="PROFILE_NAME" /> ලෙස යළි නම් කරන ලදි</translation>
 <translation id="5487521232677179737">දත්ත හිස් කරන්නෙ</translation>
 <translation id="5488093641312826914">'<ph name="COPIED_ITEM_NAME" />' පිටපත් කරන ලදී</translation>
 <translation id="5488508217173274228">සංකේතන විකල්ප සමමුහුර්ත කරන්න</translation>
@@ -4828,6 +4832,7 @@
 <translation id="6308937455967653460">ලින්ක් ලෙස සුරකින්න...</translation>
 <translation id="6309443618838462258">ඔබගේ පරිපාලක මෙම ආදාන ක්‍රමය සඳහා ඉඩ නොදේ</translation>
 <translation id="6309510305002439352">මයික්‍රොෆෝනය අක්‍රියයි</translation>
+<translation id="6310141306111263820">eSIM පැතිකඩ ස්ථාපනය කළ නොහැකි විය. උදව් සඳහා, කරුණාකර ඔබගේ වාහකය අමතන්න.</translation>
 <translation id="6311220991371174222">ඔබේ පැතිකඩ විවෘත කරන විට යම් දෙයක් වැරදී ගිය නිසා Chrome ආරම්භ කළ නොහැකිය. Chrome නැවත ආරම්භ කිරීමට උත්සාහ කරන්න.</translation>
 <translation id="6312403991423642364">නොදන්නා ජාල දෝෂය</translation>
 <translation id="6312567056350025599">{NUM_DAYS,plural, =1{ආරක්‍ෂක පරීක්‍ෂාව 1 දිනකට පෙර ධාවන විය}one{ආරක්‍ෂක පරීක්‍ෂාව දින {NUM_DAYS} කට පෙර ධාවන විය}other{ආරක්‍ෂක පරීක්‍ෂාව දින {NUM_DAYS} කට පෙර ධාවන විය}}</translation>
@@ -5962,6 +5967,7 @@
 <translation id="7582582252461552277">මෙම ජාලය නිර්දේශිතයි</translation>
 <translation id="7582844466922312471">ජංගම දත්ත</translation>
 <translation id="7583948862126372804">ගණන</translation>
+<translation id="7586051298768394542">කථන ගොනු බාගැනීමට නොහැකිය. අනුලේඛනය ඔබගේ කටහඬ Google වෙත යැවීමෙන් දිගටම ක්‍රියා කරනු ඇත.</translation>
 <translation id="7586498138629385861">Chrome යෙදුම් විවෘත අතරතුර Chrome දිගටම ධාවනය වනු ඇත.</translation>
 <translation id="7589461650300748890">නවතිනු, ඔතැනම. පරිස්සම් වෙන්න.</translation>
 <translation id="7593653750169415785">ඔබ කිහිප වරක් දැනුම්දීම් ප්‍රතික්‍ෂේප කළ බැවින් ස්වයංක්‍රීයව අවහිර කළා</translation>
@@ -6549,6 +6555,7 @@
 <translation id="8191230140820435481">ඔබගේ යෙදුම්, දිගු සහ තේමා පාලනය කරන්න</translation>
 <translation id="8195027750202970175">තැටිය මත තරම</translation>
 <translation id="8198323535106903877">ඔබ වෙනුවෙන් එම <ph name="NUMBER_OF_APPS" /> යෙදුම් අපි ස්ථාපනය කරන් නම්</translation>
+<translation id="8198456017687137612">විකාශ ටැබය</translation>
 <translation id="8199300056570174101">ජාල (සේවාව) සහ උපාංග ගුණාංග</translation>
 <translation id="8200772114523450471">කරගෙන යන්න</translation>
 <translation id="8201717382574620700"><ph name="TOPIC_SOURCE" /> ඇල්බම තෝරන්න</translation>
@@ -7134,6 +7141,7 @@
 <translation id="8847523528195140327">ආවරණය වැසුණු විට වරන්න</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">සඟවා ඇත</translation>
+<translation id="8849219423513870962"><ph name="PROFILE_NAME" /> නම් වූ eSIM පැතිකඩ ඉවත් කිරීම අවලංගු කරන්න</translation>
 <translation id="8850251000316748990">තවත් බලන්න...</translation>
 <translation id="885246833287407341">API කාර්ය විස්තාර</translation>
 <translation id="8853586775156634952">මෙම කාඩ්පත මෙම උපාංගයට පමණක් සුරකිනු ලැබේ</translation>
diff --git a/chrome/app/resources/generated_resources_sq.xtb b/chrome/app/resources/generated_resources_sq.xtb
index 3825616..9c0c74e6 100644
--- a/chrome/app/resources/generated_resources_sq.xtb
+++ b/chrome/app/resources/generated_resources_sq.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="sq">
 <translation id="1001307489511021749">Aplikacionet, cilësimet dhe personalizimet e tua të tjera do të sinkronizohen nëpër të gjitha pajisjet me Chrome OS ku je identifikuar me "Llogarinë tënde të Google".</translation>
 <translation id="1003088604756913841">Hape lidhjen në një dritare të re të <ph name="APP" /></translation>
+<translation id="100323615638474026">Pajisja USB (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">Qasja në sajt</translation>
 <translation id="1005274289863221750">Përdor mikrofonin dhe kamerën</translation>
 <translation id="1005333234656240382">Të aktivizohet korrigjimi i ADB-së?</translation>
@@ -567,6 +568,7 @@
 <translation id="1614511179807650956">Mund ta kesh shfrytëzuar sasinë e lejuar të të dhënave celulare. Vizito portalin e aktivizimit të <ph name="NAME" /> për të blerë më shumë të dhëna.</translation>
 <translation id="161460670679785907">Telefoni yt nuk mund të zbulohet</translation>
 <translation id="1615402009686901181">Politika e administratorit çaktivizon regjistrimin e ekranit kur përmbajtja konfidenciale është e dukshme</translation>
+<translation id="1615755956145364867">Sajtet mund të kërkojnë të luajnë përmbajtje të mbrojtura</translation>
 <translation id="1616206807336925449">Kjo shtesë nuk kërkon leje të veçanta.</translation>
 <translation id="1616298854599875024">Importimi i shtesës "<ph name="IMPORT_NAME" />" është i pamundur, sepse nuk është një modul i ndarë.</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{Po kontrollon këto të dhëna me politikat e sigurisë së organizatës sate...}=1{Po kontrollon këtë skedar me politikat e sigurisë së organizatës sate...}other{Po kontrollon këta skedarë me politikat e sigurisë së organizatës sate...}}</translation>
@@ -753,6 +755,7 @@
 <translation id="1794051631868188691">Mos shfaq asnjëherë <ph name="MERCHANT" /></translation>
 <translation id="1794791083288629568">Dërgo komente për të na ndihmuar ta rregullojmë këtë problem.</translation>
 <translation id="1795214765651529549">Përdor temën klasike</translation>
+<translation id="1796588414813960292">Veçoritë që kanë nevojë për tingujt nuk do të funksionojnë</translation>
 <translation id="1799071797295057738">Shtesa "<ph name="EXTENSION_NAME" />" u çaktivizua automatikisht.</translation>
 <translation id="1800973090344019061">Shtesa "<ph name="APP_NAME" />" dëshiron të ndajë përmbajtjet e ekranit tënd.</translation>
 <translation id="1802624026913571222">Në gjumë kur mbyllet kapaku</translation>
@@ -950,6 +953,7 @@
 <translation id="2007404777272201486">Raporto një problem...</translation>
 <translation id="2010501376126504057">Pajisjet e pajtueshme</translation>
 <translation id="2015232545623037616">Kompjuteri dhe Chromecast-i në të njëjtin rrjet Wi-Fi</translation>
+<translation id="2016473077102413275">Veçoritë që kanë nevojë për imazhet nuk do të funksionojnë</translation>
 <translation id="2016574333161572915">Hardueri i Google Meet është gati për t'u konfiguruar</translation>
 <translation id="2017334798163366053">Çaktivizo mbledhjen e të dhënave të aktivitetit</translation>
 <translation id="2018352199541442911">Na vjen keq, por hapësira e jashtme ruajtëse në pajisjen tënde nuk mbështetet në këtë moment.</translation>
@@ -1215,6 +1219,7 @@
 <translation id="2296099049346876573">{NUM_HOURS,plural, =1{Chrome nuk gjeti softuerë të dëmshëm në kompjuterin tënd • Kontrolluar 1 orë më parë}other{Chrome nuk gjeti softuerë të dëmshëm në kompjuterin tënd • Kontrolluar {NUM_HOURS} orë më parë}}</translation>
 <translation id="2296218178174497398">Zbulimi i pajisjes</translation>
 <translation id="2297705863329999812">Kërko printerët</translation>
+<translation id="2297822946037605517">Ndaje këtë faqe</translation>
 <translation id="2299734369537008228">Rrëshqitësi: <ph name="MIN_LABEL" /> në <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">Përfshi të gjithë skedarët e evidencave të mbledhur nga debugd si një arkiv të veçantë.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -1277,6 +1282,7 @@
 <translation id="2355604387869345912">Aktivizo "Ndarjen e internetit në çast"</translation>
 <translation id="2356070529366658676">Pyet</translation>
 <translation id="2357330829548294574">Hiqe <ph name="USER_NAME" /></translation>
+<translation id="2358561147588818967">Sajtet mund të përdorin JavaScript</translation>
 <translation id="2359071692152028734">Aplikacionet e Linux mund të bëhen joreaguese.</translation>
 <translation id="2359345697448000899">Menaxho shtesat duke klikuar "Shtesat" në menynë e "Veglave".</translation>
 <translation id="2359556993567737338">Lidh pajisje me Bluetooth</translation>
@@ -1454,6 +1460,7 @@
 <translation id="2544853746127077729">Certifikata e vërtetimit u refuzua nga rrjeti</translation>
 <translation id="2546283357679194313">Kukit dhe të dhënat e faqes</translation>
 <translation id="2548347166720081527"><ph name="PERMISSION" /> është lejuar</translation>
+<translation id="2548545707296594436">Rivendos memorien specifike të profilit të eSIM</translation>
 <translation id="2549985041256363841">Nis regjistrimin</translation>
 <translation id="2550212893339833758">Memoria e shkëmbyer</translation>
 <translation id="2550596535588364872">T'i lejohet <ph name="EXTENSION_NAME" /> të hapë <ph name="FILE_NAME" />?</translation>
@@ -1646,6 +1653,7 @@
 <translation id="2765217105034171413">E vogël</translation>
 <translation id="2766006623206032690">Ngj&amp;it dhe vazhdo</translation>
 <translation id="2766161002040448006">Pyet një prind</translation>
+<translation id="2767077837043621282">Chromebook nuk mund të përditësohej. Provo përsëri më vonë.</translation>
 <translation id="2767127727915954024"><ph name="ORIGIN" /> do të mund ta modifikojë <ph name="FILENAME" /> deri sa t'i mbyllësh të gjitha skedat për këtë sajt</translation>
 <translation id="2770465223704140727">Hiqe nga lista</translation>
 <translation id="2770690685823456775">Eksporto fjalëkalimet e tua te një dosje tjetër</translation>
@@ -1923,6 +1931,7 @@
 <translation id="3060379269883947824">Aktivizo "Zgjidh që të thuhet"</translation>
 <translation id="3060952009917586498">Ndrysho gjuhën e pajisjes. Gjuha aktuale është <ph name="LANGUAGE" />.</translation>
 <translation id="3060987956645097882">Nuk ishim në gjendje të krijonim një lidhje me telefonin tënd. Sigurohu që telefoni yt të jetë pranë, i shkyçur dhe të ketë të aktivizuar Bluetooth-in dhe Wi-Fi.</translation>
+<translation id="3064871050034234884">Sajtet mund të luajnë tinguj</translation>
 <translation id="3065041951436100775">Komente për skedën e mbyllur.</translation>
 <translation id="3065522099314259755">Vonesa e përsëritjes së tastierës</translation>
 <translation id="3067198179881736288">Të instalohet aplikacioni?</translation>
@@ -2273,6 +2282,7 @@
 <translation id="3462413494201477527">Të anulohet konfigurimi i llogarisë?</translation>
 <translation id="3464145797867108663">Shto profilin e punës</translation>
 <translation id="346431825526753">Kjo është një llogari për fëmijë, e menaxhuar nga <ph name="CUSTODIAN_EMAIL" />.</translation>
+<translation id="3465480292013046659">Ndodhi një problem me shkarkimin e përditësimit. Provo përsëri më vonë.</translation>
 <translation id="3468298837301810372">Etiketa</translation>
 <translation id="3468999815377931311">Telefon me Android</translation>
 <translation id="3470442499439619530">Hiqe këtë përdorues</translation>
@@ -2304,6 +2314,7 @@
 <translation id="3495496470825196617">Energjia e gjendjes joaktive gjatë karikimit</translation>
 <translation id="3495660573538963482">Cilësimet e "Asistentit të Google"</translation>
 <translation id="3496213124478423963">Zvogëlo</translation>
+<translation id="3497501929010263034">Pajisja USB nga <ph name="VENDOR_NAME" /> (produkti <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">Ndaje vizatimin Doodle</translation>
 <translation id="3498215018399854026">Nuk mund të kontaktonim me prindin tënd për momentin. Provo përsëri.</translation>
 <translation id="3500417806337761827">Gabim në montimin e ndarjes. Janë montuar tashmë shumë ndarje SMB.</translation>
@@ -2391,6 +2402,7 @@
 <translation id="3600792891314830896">Hiq zërin për sajtet që luajnë tinguj</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">Të ofrojë funksione të reja kur të mundësohen</translation>
+<translation id="3602179428782502464">Ky përditësim është bllokuar nga administratori yt</translation>
 <translation id="3602290021589620013">Pamje paraprake</translation>
 <translation id="3602870520245633055">Printo dhe skano</translation>
 <translation id="3603622770190368340">Merr certifikatën e rrjetit</translation>
@@ -2400,6 +2412,7 @@
 <translation id="3610369246614755442">Ventilatori i stacionit ka nevojë për shërbim</translation>
 <translation id="361106536627977100">Të dhënat Flash</translation>
 <translation id="3611655097742243705">Vizito "Dyqanin e Play" për të gjetur më shumë aplikacione</translation>
+<translation id="3611658447322220736">Sajtet e mbyllura së fundi mund të përfundojnë dërgimin dhe marrjen e të dhënave</translation>
 <translation id="3612673635130633812">Shkarkoje nga &lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt;</translation>
 <translation id="3613134908380545408">Shfaq <ph name="FOLDER_NAME" /></translation>
 <translation id="3613422051106148727">&amp;Hape në një skedë të re</translation>
@@ -2432,6 +2445,7 @@
 <translation id="3639220004740062347">Dil nga modaliteti i lexuesit</translation>
 <translation id="3640214691812501263">Shto "<ph name="EXTENSION_NAME" />" për <ph name="USER_NAME" />?</translation>
 <translation id="3640613767643722554">Mësoje "Asistentin" të njohë zërin tënd</translation>
+<translation id="3641456520301071208">Sajtet mund të pyesin për vendndodhjen tënde</translation>
 <translation id="3645372836428131288">Lëvize pak për të kapur një pjesë tjetër të gjurmës së gishtit.</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{Marrja nga <ph name="DEVICE_NAME" /> me sukses: <ph name="ATTACHMENTS" />}other{Marrja nga <ph name="DEVICE_NAME" /> me sukses: <ph name="ATTACHMENTS" />}}</translation>
 <translation id="3648348069317717750">U zbulua <ph name="USB_DEVICE_NAME" /></translation>
@@ -2474,6 +2488,7 @@
 <translation id="3688526734140524629">Ndrysho kanalin</translation>
 <translation id="3688578402379768763">I përditësuar</translation>
 <translation id="3688794912214798596">Ndrysho gjuhët...</translation>
+<translation id="3690128548376345212">Rrjeti <ph name="NETWORK_INDEX" /> nga <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, i paaktivizuar, <ph name="CONNECTION_STATUS" />, fuqia e sinjalit <ph name="SIGNAL_STRENGTH" />%, detajet</translation>
 <translation id="3690369331356918524">Të paralajmëron nëse fjalëkalimet janë ekspozuar në një nxjerrje të paautorizuar të të dhënave</translation>
 <translation id="3691231116639905343">Aplikacionet e tastierës</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> kërkon të ndajë ekranin tënd</translation>
@@ -2555,6 +2570,7 @@
 <translation id="3772609330847318323">Përditëso fjalëkalimin për <ph name="ORIGIN" /></translation>
 <translation id="3775432569830822555">Certifikata e serverit SSL</translation>
 <translation id="3775705724665058594">Dërgo te pajisjet e tua</translation>
+<translation id="3776508619697147021">Sajtet mund të kërkojnë të shkarkojnë automatikisht shumë skedarë</translation>
 <translation id="3776796446459804932">Kjo shtesë shkel politikën e Dyqanit të uebit të Chrome.</translation>
 <translation id="3777483481409781352">Pajisja celulare nuk mund të aktivizohej</translation>
 <translation id="3777806571986431400">Shtesa u aktivizua</translation>
@@ -2856,6 +2872,7 @@
 <translation id="4078738236287221428">Agresiv</translation>
 <translation id="4079140982534148664">Përdor kontrolluesin drejtshkrimor të përmirësuar</translation>
 <translation id="4081242589061676262">Skedari nuk mund të transmetohet.</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> dërgoi një njoftim në telefonin tënd. Për të konfirmuar që je ti, ndiq hapat në telefon.</translation>
 <translation id="4084682180776658562">Faqeshënuesi</translation>
 <translation id="4084835346725913160">Mbyll <ph name="TAB_NAME" /></translation>
 <translation id="4085270836953633510">Pyet kur një sajt dëshiron të ketë qasje te portat seriale</translation>
@@ -3017,6 +3034,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{Shfaq}other{Shfaqi të gjitha}}</translation>
 <translation id="4289372044984810120">Menaxho llogaritë e tua këtu. <ph name="LINK_BEGIN" />Mëso më shumë<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">Përmbledhje</translation>
+<translation id="4290791284969893584">Pasi të mbyllësh një faqe, detyrat që ke nisur mund të mos përfundojnë</translation>
 <translation id="4295072614469448764">Aplikacioni ofrohet në terminalin tënd. Mund dhe të ketë një ikonë te "Nisësi" yt.</translation>
 <translation id="4295839147292213505">Mund të dërgosh mesazhe me tekst nga kompjuteri yt, të ndash lidhjen tënde të internetit, t'u përgjigjesh njoftimeve të bisedës dhe ta shkyçësh <ph name="DEVICE_TYPE" /> me telefonin tënd.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />Mëso më shumë<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">Identifikohu përsëri për të konfirmuar se llogaria jote <ph name="USER_EMAIL" /> mund të përdoret me sajtet e uebit, aplikacionet dhe shtesat në Chrome dhe në Google Play. Gjithashtu edhe mund ta heqësh këtë llogari. <ph name="LINK_BEGIN" />Mëso më shumë<ph name="LINK_END" /></translation>
@@ -3212,6 +3230,7 @@
 <translation id="4514610446763173167">Ndrysho videon për të luajtur ose vendosur në pauzë</translation>
 <translation id="451515744433878153">Hiqe</translation>
 <translation id="4515872537870654449">Kontakto me Dell për shërbim. Stacioni do të mbyllet nëse ventilatori nuk funksionon.</translation>
+<translation id="4519331665958994620">Sajtet mund të kërkojnë të përdorin kamerën tënde</translation>
 <translation id="4519935350946509010">Gabim në lidhje.</translation>
 <translation id="4520385623207007473">Kukit në përdorim</translation>
 <translation id="452039078290142656">pajisje të panjohura nga <ph name="VENDOR_NAME" /></translation>
@@ -3391,6 +3410,7 @@
 <translation id="4694604912444486114">Majmun</translation>
 <translation id="4697071790493980729">Nuk u gjet asnjë rezultat</translation>
 <translation id="4697551882387947560">Kur mbaron seanca e shfletimit</translation>
+<translation id="469838979880025581">Sajtet mund të kërkojnë të përdorin mikrofonin tënd</translation>
 <translation id="4699172675775169585">Imazhet dhe skedarët në memorien specifike</translation>
 <translation id="4699357559218762027">(nisur automatikisht)</translation>
 <translation id="4701025263201366865">Identifikimi i prindit</translation>
@@ -3573,6 +3593,10 @@
 <translation id="4918086044614829423">Prano</translation>
 <translation id="4921290200821452703">Informacione për llogarinë e shkollës për prindërit</translation>
 <translation id="4921348630401250116">Tekst-në-ligjërim</translation>
+<translation id="4921809350408880559">Dokumentet e tua të fundit dhe të sugjeruara po i shikon bazuar në aktivitetin tënd të mëparshëm duke përdorur "Diskun e Google".
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Mëso rreth të dhënave që mbledh "Disku i Google" dhe pse i mbledh ato <ph name="BEGIN_LINK" />këtu<ph name="END_LINK" />.</translation>
 <translation id="49226369361073053">{0,plural, =0{Përditëso pajisjen tani}=1{Përditëso pajisjen brenda 1 sekonde}other{Përditëso pajisjen brenda # sekondash}}</translation>
 <translation id="492299503953721473">Hiq aplikacionet Android</translation>
 <translation id="492363500327720082"><ph name="APP_NAME" /> po çinstalohet...</translation>
@@ -4333,6 +4357,7 @@
 <translation id="5794700615121138172">Skedarët e ndarë të Linux</translation>
 <translation id="5794786537412027208">Dil nga të gjitha aplikacionet e Chrome</translation>
 <translation id="5797070761912323120">Google mund ta përdorë historikun tënd për të personalizuar "Kërko me Google", reklamat dhe shërbime të tjera të Google</translation>
+<translation id="5798079537501238810">Sajtet mund të instalojnë përpunuesit e pagesave</translation>
 <translation id="579907812742603813">përmbajtja e mbrojtur</translation>
 <translation id="579915268381781820">Çelësi yt i sigurisë është hequr.</translation>
 <translation id="5799478978078236781">Merr këshilla, oferta dhe përditësime për <ph name="DEVICE_TYPE" /> dhe ndaj komentet e tua.</translation>
@@ -4365,6 +4390,7 @@
 <translation id="5833726373896279253">Këto cilësime mund të modifikohen vetëm nga zotëruesi:</translation>
 <translation id="5834581999798853053">Rreth <ph name="TIME" /> minuta të mbetura</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - kamera ose mikrofoni po regjistron</translation>
+<translation id="583673505367439042">Sajtet mund të kërkojnë të modifikojnë skedarët ose dosjet në pajisjen tënde</translation>
 <translation id="5840680448799937675">Skedarët do të ndahen gjithmonë jashtë linje</translation>
 <translation id="5841270259333717135">Konfiguro eternetin</translation>
 <translation id="5842497610951477805">Aktivizo Bluetooth-in</translation>
@@ -4414,6 +4440,7 @@
 <translation id="5889282057229379085">Numri maksimal i autoriteteve ndërmjetëse të certifikatave: <ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">Rrjetet e preferuara Wi-Fi</translation>
 <translation id="5895138241574237353">Rinis</translation>
+<translation id="5896749729057314184">Rrjeti <ph name="NETWORK_INDEX" /> nga <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, i paaktivizuar, fuqia e sinjalit <ph name="SIGNAL_STRENGTH" />%, detajet</translation>
 <translation id="5900302528761731119">Fotografia e profilit të Google</translation>
 <translation id="590036993063074298">Detajet e cilësisë së pasqyrimit</translation>
 <translation id="5901069264981746702">Të dhënat e gjurmëve të tua të gishtave ruhen në mënyrë të sigurt dhe asnjëherë nuk largohen nga pajisja jote <ph name="DEVICE_TYPE" />. <ph name="LINK_BEGIN" />Mëso më shumë<ph name="LINK_END" /></translation>
@@ -4658,6 +4685,7 @@
 <translation id="6155141482566063812">Skeda në sfond po ndan ekranin tënd</translation>
 <translation id="6156323911414505561">Shfaq shiritin e faqeshënuesve</translation>
 <translation id="6156863943908443225">Memoria specifike e skriptit</translation>
+<translation id="615930144153753547">Sajtet mund të shfaqin imazhet</translation>
 <translation id="6160625263637492097">Ofron certifikata për vërtetimin</translation>
 <translation id="6163363155248589649">&amp;Normale</translation>
 <translation id="6163376401832887457">Cilësimet e Kerberos</translation>
@@ -4864,6 +4892,10 @@
 <translation id="6398715114293939307">Hiq "Dyqanin e Google Play"</translation>
 <translation id="6398765197997659313">Dil nga ekrani i plotë</translation>
 <translation id="6399774419735315745">Spiune</translation>
+<translation id="6400510847800135340">Këtë artikull po e shikon bazuar në aktivitetin tënd të mëparshëm duke përdorur shërbimet e Google. Mund t'i shikosh të dhënat e tua, t'i fshish ato dhe të ndryshosh cilësimet në <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+       Mëso më shumë rreth të dhënave që mbledh Google dhe pse i mbledh ato në <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" />.</translation>
 <translation id="6404511346730675251">Redakto faqeshënuesin</translation>
 <translation id="6406303162637086258">Simulo rinisjen e shfletuesit</translation>
 <translation id="6406506848690869874">Sinkronizo</translation>
@@ -4913,6 +4945,7 @@
 <translation id="6452251728599530347"><ph name="PERCENT" /> i përfunduar</translation>
 <translation id="645286928527869380">Ide për receta</translation>
 <translation id="6452961788130242735">Problem rrjeti ose zonë e keqe verifikimi</translation>
+<translation id="6453921811609336127">Për të kaluar te metoda tjetër e hyrjes, shtyp <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Hapësirë<ph name="END_SPACE" /><ph name="END_SHORTCUT" /></translation>
 <translation id="6455264371803474013">Në sajte të caktuara</translation>
 <translation id="6455894534188563617">&amp;Dosje e re</translation>
 <translation id="645705751491738698">Vazhdo bllokimin e JavaScript</translation>
@@ -5038,6 +5071,7 @@
 <translation id="6590458744723262880">Riemërto dosjen</translation>
 <translation id="6592267180249644460">Evidenca e WebRTC regjistroi <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">Gjurma e gishtit tënd u regjistrua</translation>
+<translation id="6593881952206664229">Mediat me të drejtat e autorit mund të mos luhen</translation>
 <translation id="6594011207075825276">Po gjen pajisjet me portë seriale...</translation>
 <translation id="6595187330192059106">Bllokoje gjithmonë <ph name="HOST" /> që të mos ketë kontroll të plotë mbi pajisjet MIDI.</translation>
 <translation id="6596325263575161958">Opsionet e enkriptimit</translation>
@@ -5995,6 +6029,7 @@
 <translation id="7661451191293163002">Nuk mund të merrej një certifikatë regjistrimi.</translation>
 <translation id="7662283695561029522">Trokit për të konfiguruar</translation>
 <translation id="7663719505383602579">Marrësi: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">Shkurtorja e tastierës është e disponueshme</translation>
 <translation id="7664620655576155379">Pajisje me Bluetooth e pambështetur: "<ph name="DEVICE_NAME" />".</translation>
 <translation id="7665082356120621510">Rezervo madhësinë</translation>
 <translation id="7665369617277396874">Shto një llogari</translation>
@@ -6173,6 +6208,7 @@
 <translation id="7835178595033117206">Faqeshënuesi u hoq</translation>
 <translation id="7836850009646241041">Provo të prekësh çelësin tënd të sigurisë përsëri</translation>
 <translation id="7837776265184002579">Faqja bazë u ndryshua në <ph name="URL" />.</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{<ph name="ATTACHMENTS" /> u dërgua te <ph name="DEVICE_NAME" />}other{<ph name="ATTACHMENTS" /> u dërguan te <ph name="DEVICE_NAME" />}}</translation>
 <translation id="7839051173341654115">Shiko/rezervo median</translation>
 <translation id="7839192898639727867">ID-ja e çelësit të certifikatës së subjektit</translation>
 <translation id="7842692330619197998">Vizito g.co/ChromeEnterpriseAccount nëse të duhet të krijosh një llogari të re.</translation>
@@ -6869,6 +6905,7 @@
 <translation id="8633025649649592204">Aktiviteti i fundit</translation>
 <translation id="8635628933471165173">Po ringarkohet...</translation>
 <translation id="8636284842992792762">Po nis shtesat...</translation>
+<translation id="8636500887554457830">Mos lejo që sajtet të dërgojnë dritare kërcyese ose të përdorin ridrejtimet</translation>
 <translation id="8637542770513281060">Kompjuteri yt përmban një modul të sigurt që përdoret për të zbatuar shumë funksione vendimtare të sigurisë në sistemin operativ Chrome. Vizito "Qendrën e ndihmës të Chromebook" për të mësuar më shumë: https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">Ofrohet një përditësim i sistemit. Po bëhet gati për të shkarkuar...</translation>
 <translation id="863903787380594467">Kodi PIN është i pasaktë. Të kanë mbetur edhe <ph name="RETRIES" /> përpjekje.</translation>
@@ -7086,6 +7123,7 @@
 <translation id="8842594465773264717">Fshije këtë gjurmë gishti</translation>
 <translation id="8845001906332463065">Kërko ndihmë</translation>
 <translation id="8846132060409673887">Lexo informacionet për prodhuesin dhe modelin e këtij kompjuteri</translation>
+<translation id="8846163936679269230">Rivendos profilet e kartës eSIM</translation>
 <translation id="8847523528195140327">Dil nga llogaria kur mbyllet kapaku</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">E fshehur</translation>
@@ -7141,6 +7179,7 @@
 <translation id="8898822736010347272">Dërgon te Google URL-të e disa faqeve që viziton, informacione të kufizuara të sistemit, si dhe disa përmbajtje faqeje për të ndihmuar në zbulimin e kërcënimeve të reja dhe për t'i mbrojtur të gjithë në ueb.</translation>
 <translation id="8899851313684471736">Hape lidhjen në një &amp;dritare të re</translation>
 <translation id="8900413463156971200">Aktivizo "Rrjetin celular"</translation>
+<translation id="8901994452417867840">Profili është shtuar me sukses. Kjo lidhje do të ofrohet për të gjithë përdoruesit e kësaj pajisjeje.</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> kërkon që të rezervosh të dhënat e tua dhe ta kthesh këtë pajisje <ph name="DEVICE_TYPE" /> sot.}other{<ph name="MANAGER" /> kërkon që të rezervosh të dhënat e tua dhe ta kthesh këtë pajisje <ph name="DEVICE_TYPE" /> para afatit.}}</translation>
 <translation id="8902667442496790482">Hap cilësimet e "Zgjidh që të thuhet"</translation>
 <translation id="8903263458134414071">Zgjidh një llogari për t'u identifikuar</translation>
@@ -7322,6 +7361,7 @@
 <translation id="9094982973264386462">Hiqe</translation>
 <translation id="9095253524804455615">Hiqe</translation>
 <translation id="909554839118732438">Mbyll dritaret e fshehta</translation>
+<translation id="9100416672768993722">Për të kaluar te metoda e hyrjes e përdorur për herë të fundit, shtyp <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Hapësirë<ph name="END_SPACE" /><ph name="END_SHORTCUT" /></translation>
 <translation id="9100610230175265781">Kërkohet shprehja e kalimit</translation>
 <translation id="9100765901046053179">Cilësimet e përparuara</translation>
 <translation id="9101691533782776290">Nis aplikacionin</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index 72e502f2..1850a9a8 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="te">
 <translation id="1001307489511021749">మీ Google ఖాతాతో సైన్ ఇన్ చేసిన అన్ని Chrome OS పరికరాలలో మీ యాప్‌లు, సెట్టింగ్‌లు, ఇతర అనుకూలీకరణలు సింక్ చేయబడతాయి.</translation>
 <translation id="1003088604756913841">కొత్త <ph name="APP" /> విండోలో లింక్‍ను తెరువు</translation>
+<translation id="100323615638474026">USB పరికరం (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">సైట్ యాక్సెస్</translation>
 <translation id="1005274289863221750">మీ మైక్రోఫోన్ మరియు కెమెరాను ఉపయోగించండి</translation>
 <translation id="1005333234656240382">ADB డీబగ్గింగ్‌ను ఎనేబుల్ చేయాలా?</translation>
@@ -573,6 +574,7 @@
 <translation id="1614511179807650956">మీరు మీకు అనుమతించిన మొబైల్ డేటాను పూర్తిగా ఉపయోగించి ఉండవచ్చు. మరింత డేటాను కొనుగోలు చేయడానికి <ph name="NAME" /> యాక్టివేషన్ పోర్టల్‌ను సందర్శించండి</translation>
 <translation id="161460670679785907">మీ ఫోన్‌ను గుర్తించడం సాధ్యపడలేదు</translation>
 <translation id="1615402009686901181">గోప్యమైన కంటెంట్ కనిపించినప్పుడు, అడ్మినిస్ట్రేటర్ పాలసీ స్క్రీన్ క్యాప్చర్‌ను డిజేబుల్ చేస్తుంది</translation>
+<translation id="1615755956145364867">రక్షించబడిన కంటెంట్‌ను ప్లే చేయడం కోసం సైట్‌లు అడగవచ్చు</translation>
 <translation id="1616206807336925449">ఈ పొడిగింపుకు ప్రత్యేక అనుమతులు ఏవీ అవసరం లేదు.</translation>
 <translation id="1616298854599875024">ఇది షేర్ చేసిన మాడ్యూల్ కానందున ఎక్స్‌టెన్షన్ "<ph name="IMPORT_NAME" />"ను దిగుమతి చేయడం సాధ్యపడలేదు</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{మీ సంస్థకు చెందిన భద్రతా పాలసీలతో ఈ డేటాను తనిఖీ చేస్తోంది...}=1{మీ సంస్థకు చెందిన భద్రతా పాలసీలతో ఈ ఫైల్‌ను తనిఖీ చేస్తోంది...}other{మీ సంస్థకు చెందిన భద్రతా పాలసీలతో ఈ ఫైల్స్‌ను తనిఖీ చేస్తోంది...}}</translation>
@@ -766,6 +768,7 @@
 <translation id="1794051631868188691"><ph name="MERCHANT" />ను ఎప్పుడూ చూపవద్దు</translation>
 <translation id="1794791083288629568">ఈ సమస్యను పరిష్కరించడంలో మాకు సహాయం చేయడానికి అభిప్రాయాన్ని పంపుతుంది.</translation>
 <translation id="1795214765651529549">క్లాసిక్‌ను ఉపయోగించు</translation>
+<translation id="1796588414813960292">సౌండ్ అవసరం అయ్యే ఫీచర్‌లు పని చేయవు</translation>
 <translation id="1799071797295057738">"<ph name="EXTENSION_NAME" />" పొడిగింపు స్వయంచాలకంగా నిలిపివేయబడింది.</translation>
 <translation id="1800973090344019061">"<ph name="APP_NAME" />" ఎక్స్‌టెన్షన్ మీ స్క్రీన్ కంటెంట్‌లను షేర్ చేయాలనుకుంటుంది.</translation>
 <translation id="1802624026913571222">కవర్ మూసి ఉన్నప్పుడు స్లీప్ స్థితికి వెళ్లు</translation>
@@ -964,6 +967,7 @@
 <translation id="2007404777272201486">సమస్యను రిపోర్ట్ చేయండి...</translation>
 <translation id="2010501376126504057">అనుకూల పరికరాలు</translation>
 <translation id="2015232545623037616">PC, Chromecast ఒకే Wi-Fi నెట్‌వర్క్‌లో ఉన్నాయి</translation>
+<translation id="2016473077102413275">ఇమేజ్‌లు అవసరం అయ్యే ఫీచర్‌లు పని చేయవు</translation>
 <translation id="2016574333161572915">మీ Google Meet హార్డ్‌వేర్ సెటప్ చేయడానికి సిద్ధంగా ఉంది</translation>
 <translation id="2017334798163366053">పనితీరు డేటా సేకరణను నిలిపివేయి</translation>
 <translation id="2018352199541442911">క్షమించండి, ఈ సమయంలో మీ బాహ్య నిల్వ పరికరానికి మద్దతు లేదు.</translation>
@@ -1294,6 +1298,7 @@
 <translation id="2355604387869345912">తక్షణ టెథెరింగ్‌ను ఆన్ చేయడం</translation>
 <translation id="2356070529366658676">అడుగు</translation>
 <translation id="2357330829548294574"><ph name="USER_NAME" />ను తీసివేయి</translation>
+<translation id="2358561147588818967">సైట్‌లు JavaScriptను ఉపయోగించగలవు</translation>
 <translation id="2359071692152028734">Linux యాప్‌లు ప్రతిస్పందించకపోవచ్చు.</translation>
 <translation id="2359345697448000899">'సాధనాలు' మెనూలోని ఎక్స్‌టెన్షన్‌లను క్లిక్ చేయడం ద్వారా మీ ఎక్స్‌టెన్షన్‌లను నిర్వహించండి.</translation>
 <translation id="2359556993567737338">బ్లూటూత్ పరికరాన్ని కనెక్ట్ చేయండి</translation>
@@ -1471,6 +1476,7 @@
 <translation id="2544853746127077729">ప్రామాణీకరణ ప్రమాణపత్రం నెట్‌వర్క్ ద్వారా తిరస్కరించబడింది</translation>
 <translation id="2546283357679194313">కుక్కీలు మరియు సైట్ డేటా</translation>
 <translation id="2548347166720081527"><ph name="PERMISSION" />‌ను అనుమతించారు</translation>
+<translation id="2548545707296594436">eSIM ప్రొఫైల్ కాష్‌ను రీసెట్ చేయండి</translation>
 <translation id="2549985041256363841">రికార్డింగ్‌ను ప్రారంభించు</translation>
 <translation id="2550212893339833758">వినిమయం చేసిన మెమరీ</translation>
 <translation id="2550596535588364872"><ph name="EXTENSION_NAME" />ని <ph name="FILE_NAME" /> తెరవడానికి అనుమతించాలా?</translation>
@@ -1664,6 +1670,7 @@
 <translation id="2765217105034171413">చిన్నది</translation>
 <translation id="2766006623206032690">పే&amp;స్ట్ చేసి ముందుకు వెళ్ళండి</translation>
 <translation id="2766161002040448006">తల్లి/తండ్రిని అడగండి</translation>
+<translation id="2767077837043621282">మీ Chromebookను అప్‌డేట్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ట్రై చేయండి.</translation>
 <translation id="2767127727915954024">మీరు ఈ సైట్‌లో అన్ని ట్యాబ్‌లను మూసివేసే వరకు <ph name="ORIGIN" />, <ph name="FILENAME" />ను ఎడిట్ చేయగలదు</translation>
 <translation id="2770465223704140727">లిస్ట్ నుండి తొలగించు</translation>
 <translation id="2770690685823456775">మీ పాస్‌వర్డ్‌లను మరో ఫోల్డర్‌కు ఎగుమతి చేయండి</translation>
@@ -1941,6 +1948,7 @@
 <translation id="3060379269883947824">వినడానికి-ఎంచుకోండిని ప్రారంభించు</translation>
 <translation id="3060952009917586498">పరికర భాషను మార్చండి. ప్రస్తుత భాష <ph name="LANGUAGE" />.</translation>
 <translation id="3060987956645097882">మీ ఫోన్‌తో కనెక్షన్‌ను ఏర్పాటు చేయడం మాకు సాధ్యపడలేదు. మీ ఫోన్ సమీపంలోనే ఉండి, అలాగే బ్లూటూత్, Wi-Fi ఆన్ చేయబడి ఉందని నిర్ధారించుకోండి.</translation>
+<translation id="3064871050034234884">సైట్‌లు సౌండ్‌ను ప్లే చేయగలవు</translation>
 <translation id="3065041951436100775">ట్యాబ్ మూసివేత ప్ర‌తిస్పంద‌న‌.</translation>
 <translation id="3065522099314259755">కీబోర్డ్ పునరావృత ప్రతిస్పందన సమయం</translation>
 <translation id="3067198179881736288">యాప్‌ను ఇన్‌స్టాల్ చేయాలా?</translation>
@@ -2291,6 +2299,7 @@
 <translation id="3462413494201477527">ఖాతా సెటప్‌ను రద్దు చేయాలా?</translation>
 <translation id="3464145797867108663">వర్క్ ప్రొఫైల్‌ను జోడించండి</translation>
 <translation id="346431825526753">ఇది <ph name="CUSTODIAN_EMAIL" /> నిర్వహించే చిన్నపిల్లల ఖాతా.</translation>
+<translation id="3465480292013046659">అప్‌డేట్‌ను డౌన్‌లోడ్ చేయడంలో సమస్య ఏర్పడింది. దయచేసి మళ్లీ ట్రై చేయండి.</translation>
 <translation id="3468298837301810372">లేబుల్</translation>
 <translation id="3468999815377931311">Android ఫోన్</translation>
 <translation id="3470442499439619530">ఈ వినియోగదారును తీసివేయి</translation>
@@ -2322,6 +2331,7 @@
 <translation id="3495496470825196617">ఛార్జింగ్‌లో ఉన్నప్పుడు ఇన్‌యాక్టివ్ పవర్</translation>
 <translation id="3495660573538963482">Google సహాయకం సెట్టింగ్‌లు</translation>
 <translation id="3496213124478423963">దూరంగా జూమ్ చేయి</translation>
+<translation id="3497501929010263034"><ph name="VENDOR_NAME" /> నుండి USB పరికరం (ప్రోడక్ట్ <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">డూడుల్‌ని షేర్ చేయి</translation>
 <translation id="3498215018399854026">మేము ప్రస్తుతం మీ తల్లి/తండ్రిని సంప్రదించలేకపోయాము. దయచేసి మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="3500417806337761827">షేర్‌ను మౌంట్ చేయడంలో ఎర్రర్ ఏర్పడింది. చాలా SMB షేర్‌లు ఇప్పటికే మౌంట్ చేయబడ్డాయి.</translation>
@@ -2409,6 +2419,7 @@
 <translation id="3600792891314830896">ధ్వనిని ప్లే చేసే సైట్‌లను మ్యూట్ చేస్తుంది</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">కొత్త ఫీచర్‌లు అందుబాటులోకి వస్తే వాటిని అందించడం</translation>
+<translation id="3602179428782502464">ఈ అప్‌డేట్‌ను మీ అడ్మినిస్ట్రేటర్ బ్లాక్ చేశారు</translation>
 <translation id="3602290021589620013">ప్రివ్యూ</translation>
 <translation id="3602870520245633055">ప్రింట్ చేయండి, స్కాన్ చేయండి</translation>
 <translation id="3603622770190368340">నెట్‌వర్క్ ప్రమాణపత్రాన్ని పొందండి</translation>
@@ -2418,6 +2429,7 @@
 <translation id="3610369246614755442">డాక్ ఫ్యాన్‌కు సర్వీస్ అవసరం</translation>
 <translation id="361106536627977100">ఫ్లాష్ డేటా</translation>
 <translation id="3611655097742243705">మరిన్ని యాప్‌లను కనుగొనడానికి Play స్టోర్‌ను సందర్శించండి</translation>
+<translation id="3611658447322220736">ఇటీవల మూసివేసిన సైట్‌లు డేటాను పంపడాన్ని, అందుకోవడాన్ని పూర్తి చేయగలవు</translation>
 <translation id="3612673635130633812">&lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt; ద్వారా డౌన్‌లోడ్ చేయబడింది</translation>
 <translation id="3613134908380545408"><ph name="FOLDER_NAME" />ని చూపు</translation>
 <translation id="3613422051106148727">&amp;కొత్త‌ ట్యాబ్‌లో తెరువు</translation>
@@ -2450,6 +2462,7 @@
 <translation id="3639220004740062347">రీడర్ మోడ్ నుండి నిష్క్రమించండి</translation>
 <translation id="3640214691812501263"><ph name="USER_NAME" /> కోసం "<ph name="EXTENSION_NAME" />"ని జోడించాలా?</translation>
 <translation id="3640613767643722554">మీ వాయిస్‌ను గుర్తించేలా అసిస్టెంట్‌కు తగిన శిక్షణ ఇవ్వండి</translation>
+<translation id="3641456520301071208">సైట్‌లు మీ లొకేషన్‌ను అడగవచ్చు</translation>
 <translation id="3645372836428131288">వేలిముద్రలోని వేరే భాగాన్ని క్యాప్చర్ చేయడం కోసం కొద్దిగా కదిలించండి.</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{<ph name="DEVICE_NAME" /> నుండి <ph name="ATTACHMENTS" /> అందుకున్నారు}other{<ph name="DEVICE_NAME" /> నుండి <ph name="ATTACHMENTS" /> అందుకున్నారు}}</translation>
 <translation id="3648348069317717750"><ph name="USB_DEVICE_NAME" /> గుర్తించబడింది</translation>
@@ -2492,6 +2505,7 @@
 <translation id="3688526734140524629">ఛానెల్‌ను మార్చు</translation>
 <translation id="3688578402379768763">తాజాగా ఉంది</translation>
 <translation id="3688794912214798596">భాషలను మార్చండి...</translation>
+<translation id="3690128548376345212"><ph name="NETWORK_COUNT" />లోని నెట్‌వర్క్ <ph name="NETWORK_INDEX" />, <ph name="NETWORK_NAME" />, యాక్టివేట్ చేయబడలేదు, <ph name="CONNECTION_STATUS" />, సిగ్నల్ సామర్థ్యం <ph name="SIGNAL_STRENGTH" />%, వివరాలు</translation>
 <translation id="3690369331356918524">మీరు ఉపయోగించే పాస్‌వర్డ్‌లు, ఏదైనా డేటా ఉల్లంఘనలో బహిర్గతమైతే మిమ్మల్ని హెచ్చరిస్తుంది</translation>
 <translation id="3691231116639905343">కీబోర్డ్ యాప్‌లు</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> మీ స్క్రీన్‌ని షేర్ చేయాలనుకుంటోంది</translation>
@@ -2573,6 +2587,7 @@
 <translation id="3772609330847318323"><ph name="ORIGIN" /> కోసం పాస్‌వర్డ్‌ను అప్‌డేట్ చేయండి</translation>
 <translation id="3775432569830822555">SSL సర్వర్ సర్టిఫికెట్</translation>
 <translation id="3775705724665058594">మీ పరికరాలకు పంపండి</translation>
+<translation id="3776508619697147021">అనేక ఫైల్‌లను ఆటోమేటిక్‌గా డౌన్‌లోడ్ చేయడానికి సైట్‌లు అడగవచ్చు</translation>
 <translation id="3776796446459804932">ఈ ఎక్స్‌టెన్ష‌న్‌ Chrome వెబ్ స్టోర్ విధానాన్ని ఉల్లంఘిస్తోంది.</translation>
 <translation id="3777483481409781352">సెల్యులార్ పరికరాన్ని యాక్టివేట్ చేయలేకపోయింది</translation>
 <translation id="3777806571986431400">పొడిగింపు ప్రారంభించబడింది</translation>
@@ -2874,6 +2889,7 @@
 <translation id="4078738236287221428">తీవ్రం</translation>
 <translation id="4079140982534148664">మెరుగైన స్పెల్ చెక్‌ను ఉపయోగించు</translation>
 <translation id="4081242589061676262">ఫైల్‌ని ప్రసారం చేయడం సాధ్యపడలేదు.</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> మీ ఫోన్‌కు నోటిఫికేషన్‌ను పంపింది. అది మీరేనని నిర్ధారించడానికి, అక్కడ ఉన్న దశలను ఫాలో అవ్వండి.</translation>
 <translation id="4084682180776658562">బుక్‌మార్క్ చేయి</translation>
 <translation id="4084835346725913160"><ph name="TAB_NAME" />ని మూసివేయి</translation>
 <translation id="4085270836953633510">ఏదైనా ఒక సైట్, సీరియల్ పోర్ట్‌లను యాక్సెస్ చేయాలని భావించినప్పుడు అనుమతి అడగాలి</translation>
@@ -3035,6 +3051,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{చూపించు}other{అన్నీ చూపించు}}</translation>
 <translation id="4289372044984810120">మీ ఖాతాలను ఇక్కడ మేనేజ్ చేయండి. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">స్థూలదృష్టి</translation>
+<translation id="4290791284969893584">మీరు పేజీని మూసివేసిన తర్వాత, మీరు ప్రారంభించిన టాస్క్‌లు పూర్తి అవ్వకపోవచ్చు</translation>
 <translation id="4295072614469448764">మీ టెర్మినల్‌లో యాప్ అందుబాటులో ఉంది. మీ లాంచర్‌లో కూడా ఒక చిహ్నం ఉండవచ్చు.</translation>
 <translation id="4295839147292213505">మీరు మీ కంప్యూటర్ నుండి టెక్స్ట్‌ను పంపవచ్చు, మీ ఇంటర్నెట్ కనెక్షన్‌ను షేర్ చేసుకోవచ్చు, సంభాషణ నోటిఫికేషన్‌కు రిప్లయి ఇవ్వవచ్చు, అలాగే మీ ఫోన్‌తో మీ <ph name="DEVICE_TYPE" />ను అన్‌లాక్ చేయవచ్చు.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">మీ <ph name="USER_EMAIL" /> ఖాతాను వెబ్‌సైట్‌లు, యాప్‌లు, Chromeలోని ఎక్స్‌టెన్షన్‌లు, Google Playలతో ఉపయోగించగలుగుతారని నిర్ధారించుకోవడానికి మళ్లీ సైన్ ఇన్ చేయండి. అలాగే, ఈ ఖాతాను మీరు వద్దనుకుంటే తీసివేయవచ్చు. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
@@ -3231,6 +3248,7 @@
 <translation id="4514610446763173167">ప్లే లేదా పాజ్ చేయడానికి వీడియోని టోగుల్ చేయండి</translation>
 <translation id="451515744433878153">తీసివేయి</translation>
 <translation id="4515872537870654449">సేవ పొందడానికి డెల్‌ను సంప్రదించండి. ఫ్యాన్ పని చేయలేదంటే, ఈ డాక్ షట్ డౌన్ అవుతుంది.</translation>
+<translation id="4519331665958994620">మీ కెమెరాను ఉపయోగించడానికి సైట్‌లు అడగవచ్చు</translation>
 <translation id="4519935350946509010">కనెక్షన్ ఎర్రర్.</translation>
 <translation id="4520385623207007473">ఉపయోగంలో ఉన్న కుక్కీలు</translation>
 <translation id="452039078290142656"><ph name="VENDOR_NAME" /> అందించిన తెలియని పరికరాలు</translation>
@@ -3410,6 +3428,7 @@
 <translation id="4694604912444486114">కోతి</translation>
 <translation id="4697071790493980729">ఫలితాలు ఏవీ కనుగొనబడలేదు</translation>
 <translation id="4697551882387947560">బ్రౌజింగ్ సెషన్ ముగిసినప్పుడు</translation>
+<translation id="469838979880025581">మీ మైక్రోఫోన్‌ను ఉపయోగించడానికి సైట్‌లు అడగవచ్చు</translation>
 <translation id="4699172675775169585">కాష్ చేసిన చిత్రాలు మరియు ఫైల్‌లు</translation>
 <translation id="4699357559218762027">(స్వయంచాలకంగా ప్రారంభించబడింది)</translation>
 <translation id="4701025263201366865">తల్లి/తండ్రి సైన్ ఇన్</translation>
@@ -3592,6 +3611,10 @@
 <translation id="4918086044614829423">ఆమోదించు</translation>
 <translation id="4921290200821452703">తల్లితండ్రుల కోసం పాఠశాల ఖాతా సమాచారం</translation>
 <translation id="4921348630401250116">టెక్స్ట్-టు-స్పీచ్</translation>
+<translation id="4921809350408880559">Google Driveను ఉపయోగించిన మీ మునుపటి యాక్టివిటీ ఆధారంగా మీరు ఇటీవలి, అలాగే సూచించిన డాక్యుమెంట్‌లను చూస్తున్నారు.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google Drive ఏ డేటాను, ఎందుకు సేకరిస్తుంది అనే దాని గురించి <ph name="BEGIN_LINK" />ఇక్కడ<ph name="END_LINK" /> తెలుసుకోండి.</translation>
 <translation id="49226369361073053">{0,plural, =0{ఇప్పుడే పరికరాన్ని అప్‌డేట్ చేయండి}=1{1 సెకను లోపు పరికరాన్ని అప్‌డేట్ చేయండి}other{# సెకన్ల లోపు పరికరాన్ని అప్‌డేట్ చేయండి}}</translation>
 <translation id="492299503953721473">Android యాప్‌లను తీసివేయి</translation>
 <translation id="492363500327720082"><ph name="APP_NAME" />ను అన్ఇన్‌స్టాల్ చేస్తోంది...</translation>
@@ -4352,6 +4375,7 @@
 <translation id="5794700615121138172">Linux షేర్ చేసిన ఫోల్డర్‌లు</translation>
 <translation id="5794786537412027208">అన్ని Chrome యాప్‌ల నుండి నిష్క్రమించు</translation>
 <translation id="5797070761912323120">శోధన, ప్రకటనలు, ఇతర Google సేవలను వ్యక్తిగతీకరించడానికి Google మీ చరిత్రను ఉపయోగించే అవకాశం ఉంటుంది</translation>
+<translation id="5798079537501238810">సైట్‌లు పేమెంట్ హ్యాండ్లర్‌లను ఇన్‌స్టాల్ చేయగలవు</translation>
 <translation id="579907812742603813">రక్షించబడిన కంటెంట్</translation>
 <translation id="579915268381781820">మీ 'సెక్యూరిటీ కీ' తీసివేయబడింది.</translation>
 <translation id="5799478978078236781"><ph name="DEVICE_TYPE" /> చిట్కాలు, ఆఫర్‌లతో పాటు అప్‌డేట్‌లను పొందండి, ఫీడ్‌బ్యాక్‌ను షేర్ చేయండి.</translation>
@@ -4384,6 +4408,7 @@
 <translation id="5833726373896279253">ఈ సెట్టింగ్‌లు మీ యజమాని ద్వారా మాత్రమే సవరించబడతాయి:</translation>
 <translation id="5834581999798853053">సుమారు <ph name="TIME" /> నిమిషాలు మిగిలి ఉన్నాయి</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - కెమెరా లేదా మైక్రోఫోన్ రికార్డ్ చేస్తోంది</translation>
+<translation id="583673505367439042">మీ పరికరంలో ఫైల్‌లు, అలాగే ఫోల్డర్‌లను ఎడిట్ చేయడానికి సైట్‌లు అడగవచ్చు</translation>
 <translation id="5840680448799937675">ఫైల్‌లు ఎల్లప్పుడూ ఆఫ్‌లైన్‌లో షేర్ చేయబడతాయి</translation>
 <translation id="5841270259333717135">ఈథర్‌నెట్‌ను కాన్ఫిగర్ చేయండి</translation>
 <translation id="5842497610951477805">బ్లూటూత్‌ను ప్రారంభించు</translation>
@@ -4433,6 +4458,7 @@
 <translation id="5889282057229379085">ఇంటర్మీడియట్ CAల అత్యధిక సంఖ్య: <ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">ప్రాధాన్య Wi-Fi నెట్‌వర్క్‌లు</translation>
 <translation id="5895138241574237353">మళ్ళీ ప్రారంభించు</translation>
+<translation id="5896749729057314184"><ph name="NETWORK_COUNT" /> <ph name="NETWORK_NAME" />‌లోని నెట్‌వర్క్ <ph name="NETWORK_INDEX" /> యాక్టివేట్ చేయబడలేదు, సిగ్నల్ సామర్థ్యం <ph name="SIGNAL_STRENGTH" />%, వివరాలు</translation>
 <translation id="5900302528761731119">Google ప్రొఫైల్ ఫోటో</translation>
 <translation id="590036993063074298">మిర్రరింగ్ క్వాలిటీ వివరాలు</translation>
 <translation id="5901069264981746702">మీ వేలిముద్ర డేటా సురక్షితంగా స్టోర్ చేయబడుతుంది, ఎప్పటికీ మీ <ph name="DEVICE_TYPE" />లోనే ఉంటుంది. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
@@ -4677,6 +4703,7 @@
 <translation id="6155141482566063812">బ్యాక్‌గ్రౌండ్ ట్యాబ్ మీ స్క్రీన్‌ను షేర్ చేస్తోంది</translation>
 <translation id="6156323911414505561">బుక్‌మార్క్‌ల బార్‌ను చూపించు</translation>
 <translation id="6156863943908443225">స్క్రిప్ట్ కాష్</translation>
+<translation id="615930144153753547">సైట్‌లు ఇమేజ్‌లను చూపగలవు</translation>
 <translation id="6160625263637492097">ప్రామాణీకరణ కోసం ప్రమాణపత్రాలను అందించడానికి అనుమతి</translation>
 <translation id="6163363155248589649">&amp;సాధారణంగా</translation>
 <translation id="6163376401832887457">Kerberos సెట్టింగ్‌లు</translation>
@@ -4883,6 +4910,10 @@
 <translation id="6398715114293939307">Google Play స్టోర్‌ని తీసివేయండి</translation>
 <translation id="6398765197997659313">పూర్తి స్క్రీన్ నుండి నిష్క్రమించు</translation>
 <translation id="6399774419735315745">గూఢచారి</translation>
+<translation id="6400510847800135340">Google సర్వీస్‌లను ఉపయోగించిన మీ మునుపటి యాక్టివిటీ ఆధారంగా మీరు ఈ ఐటెమ్‌ను చూస్తున్నారు. <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />లో మీరు మీ డేటాను చూడవచ్చు, తొలగించవచ్చు, మీ సెట్టింగ్‌లను మార్చవచ్చు.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Google ఏ డేటాను, ఎందుకు సేకరిస్తుంది అనే దాని గురించి <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" />లో తెలుసుకోండి.</translation>
 <translation id="6404511346730675251">బుక్‌మార్క్‌ను సవరించు</translation>
 <translation id="6406303162637086258">బ్రౌజర్ పునఃప్రారంభాన్ని ప్రారంభించు</translation>
 <translation id="6406506848690869874">Sync</translation>
@@ -4932,6 +4963,7 @@
 <translation id="6452251728599530347"><ph name="PERCENT" /> పూర్తయింది</translation>
 <translation id="645286928527869380">వంటకం ఐడియాలు</translation>
 <translation id="6452961788130242735">నెట్‌వర్క్ సమస్య ఉంది లేదా నెట్‌వర్క్ పరిధిలో లేదు</translation>
+<translation id="6453921811609336127">తర్వాతి ఇన్‌పుట్ విధానానికి స్విచ్ చేయడానికి, <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> కీలను నొక్కండి</translation>
 <translation id="6455264371803474013">కొన్ని నిర్దిష్ట సైట్‌లలో మాత్రమే</translation>
 <translation id="6455894534188563617">&amp;కొత్త ఫోల్డర్</translation>
 <translation id="645705751491738698">JavaScriptను నిరోధించడాన్ని కొనసాగించు</translation>
@@ -5057,6 +5089,7 @@
 <translation id="6590458744723262880">ఫోల్డర్‌ పేరు మార్చండి</translation>
 <translation id="6592267180249644460">WebRTC లాగ్ క్యాప్చర్ చేయబడినది <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">మీ వేలిముద్ర క్యాప్చర్ చేయబడింది</translation>
+<translation id="6593881952206664229">కాపీరైట్‌తో కూడిన మీడియా ప్లే అవ్వకపోవచ్చు</translation>
 <translation id="6594011207075825276">సీరియల్ పరికరాలను కనుగొంటోంది...</translation>
 <translation id="6595187330192059106">MIDI డివైజ్‌లపై పూర్తి కంట్రోల్ లేకుండా <ph name="HOST" />ను ఎల్లప్పుడూ బ్లాక్ చేయండి.</translation>
 <translation id="6596325263575161958">ఎన్‌క్రిప్షన్ ఎంపికలు</translation>
@@ -6014,6 +6047,7 @@
 <translation id="7661451191293163002">నమోదు ప్రమాణపత్రాన్ని పొందడం సాధ్యపడలేదు.</translation>
 <translation id="7662283695561029522">కాన్ఫిగర్ చేయడానికి నొక్కండి</translation>
 <translation id="7663719505383602579">స్వీకర్త: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">కీబోర్డ్ షార్ట్‌కట్ అందుబాటులో ఉంది</translation>
 <translation id="7664620655576155379">మద్దతు లేని బ్లూటూత్ పరికరం: "<ph name="DEVICE_NAME" />".</translation>
 <translation id="7665082356120621510">పరిమాణాన్ని రిజర్వ్ చేయి</translation>
 <translation id="7665369617277396874">ఖాతాను జోడించండి</translation>
@@ -6192,6 +6226,7 @@
 <translation id="7835178595033117206">బుక్‌మార్క్ తీసివేయబడింది</translation>
 <translation id="7836850009646241041">మీ సెక్యూరిటీ కీని మళ్లీ తాకి చూడండి</translation>
 <translation id="7837776265184002579">మీ హోమ్‌పేజీ <ph name="URL" />కు మార్చబడింది.</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{<ph name="ATTACHMENTS" /> <ph name="DEVICE_NAME" />కు పంపడం జరిగింది}other{<ph name="ATTACHMENTS" /> <ph name="DEVICE_NAME" />కు పంపడం జరిగింది}}</translation>
 <translation id="7839051173341654115">మీడియాను వీక్షించండి/బ్యాకప్ చేయండి</translation>
 <translation id="7839192898639727867">సర్టిఫికెట్ విషయం కీ ID</translation>
 <translation id="7842692330619197998">మీరు కొత్త ఖాతాను సృష్టించాలనుకుంటే g.co/ChromeEnterpriseAccount లింక్‌ను సందర్శించండి.</translation>
@@ -6886,6 +6921,7 @@
 <translation id="8633025649649592204">ఇటీవలి యాక్టివిటీ</translation>
 <translation id="8635628933471165173">మళ్ళీ లోడ్ అవుతోంది...</translation>
 <translation id="8636284842992792762">ఎక్స్‌టెన్షన్‌లను ప్రారంభిస్తోంది...</translation>
+<translation id="8636500887554457830">పాప్-అప్‌లను పంపడానికి లేదా మళ్లింపులను ఉపయోగించడానికి సైట్‌లను అనుమతించకండి</translation>
 <translation id="8637542770513281060">మీ కంప్యూటర్‌లో ఒక సురక్షిత మాడ్యూల్ ఉంది, Chrome OSలో అనేక కీలకమైన భద్రతా ఫీచర్‌లను అమలు చేయడానికి ఇది ఉపయోగించబడుతుంది. Chromebook సహాయ కేంద్రంలో దీని గురించి మరింత తెలుసుకోండి, ఇక్కడికి వెళ్లండి: https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">సిస్టమ్ అప్‌డేట్‌ అందుబాటులో ఉంది. డౌన్‌లోడ్ చేయ‌డానికి సిద్ధం చేస్తోంది...</translation>
 <translation id="863903787380594467">పిన్ తప్పు. మీకు <ph name="RETRIES" /> ప్రయత్నాలు మిగిలి ఉన్నాయి.</translation>
@@ -7103,6 +7139,7 @@
 <translation id="8842594465773264717">ఈ వేలిముద్రను తొలగించు</translation>
 <translation id="8845001906332463065">సహాయం పొందండి</translation>
 <translation id="8846132060409673887">ఈ కంప్యూటర్ తయారీదారు పేరు మరియు మోడల్‌కి సంబంధించిన సమాచారాన్ని చదవగలుగుతుంది</translation>
+<translation id="8846163936679269230">eSIM ప్రొఫైల్‌లను రీసెట్ చేయండి</translation>
 <translation id="8847523528195140327">కవర్ మూసి ఉన్నప్పుడు సైన్ అవుట్ స్థితికి వెళ్లు</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">దాచబడింది</translation>
@@ -7158,6 +7195,7 @@
 <translation id="8898822736010347272">కొత్త థ్రెట్స్‌ను గుర్తించడంలో, వెబ్‌లోని అందరు యూజర్‌లను రక్షించడంలో సహాయపడేందుకు మీరు సందర్శించే కొన్ని పేజీల URLలను, కొంత సిస్టమ్ సమాచారాన్ని, కొంత పేజీ కంటెంట్‌ను Googleకు పంపుతుంది.</translation>
 <translation id="8899851313684471736">కొత్త &amp;విండోలో లింక్‌ను తెరువు</translation>
 <translation id="8900413463156971200">సెల్యులార్‌ను ఎనేబుల్ చేయడం</translation>
+<translation id="8901994452417867840">ప్రొఫైల్‌ను విజయవంతంగా జోడించడం జరిగింది. ఈ కనెక్షన్ ఈ పరికరంలోని యూజర్‌లు అందరికీ అందుబాటులో ఉంటుంది.</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> కోసం మీ డేటాను బ్యాకప్ చేసి, ఈరోజే ఈ <ph name="DEVICE_TYPE" />ని రిటర్న్ చేయాల్సి ఉంటుంది.}other{<ph name="MANAGER" /> కోసం మీరు మీ డేటాను గడువు తేదీలోపు బ్యాకప్ చేసి, ఈ <ph name="DEVICE_TYPE" />ని రిటర్న్ చేయాల్సి ఉంటుంది.}}</translation>
 <translation id="8902667442496790482">వినడానికి-ఎంచుకోండి ఎంపికలను తెరువు</translation>
 <translation id="8903263458134414071">సైన్ ఇన్ చేయాల్సిన ఖాతాను ఎంచుకోండి</translation>
@@ -7339,6 +7377,7 @@
 <translation id="9094982973264386462">తీసివేయి</translation>
 <translation id="9095253524804455615">తీసివేయి</translation>
 <translation id="909554839118732438">అజ్ఞాత విండోలన్నింటినీ మూసివేయండి</translation>
+<translation id="9100416672768993722">చివరిగా ఉపయోగించిన ఇన్‌పుట్ విధానానికి స్విచ్ చేయడానికి, <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> కీలను నొక్కండి</translation>
 <translation id="9100610230175265781">రహస్య పదబంధం అవసరం</translation>
 <translation id="9100765901046053179">అధునాతన సెట్టింగ్‌లు</translation>
 <translation id="9101691533782776290">యాప్‌ను ప్రారంభించు</translation>
diff --git a/chrome/app/resources/generated_resources_ur.xtb b/chrome/app/resources/generated_resources_ur.xtb
index 822b05f..20bdd60 100644
--- a/chrome/app/resources/generated_resources_ur.xtb
+++ b/chrome/app/resources/generated_resources_ur.xtb
@@ -5074,7 +5074,7 @@
 <translation id="6590458744723262880">فولڈر کا نام تبدیل کریں</translation>
 <translation id="6592267180249644460">‏WebRTC لاگ کیپچر کرنے کا وقت <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">آپ کا فنگر پرنٹ کیپچر ہو گیا تھا</translation>
-<translation id="6593881952206664229">ممکن ہے کہ کاپی رائٹ کے ساتھ والا میڈیا نہ چل سکے</translation>
+<translation id="6593881952206664229">ممکن ہے کہ کاپی رائٹ والا میڈیا نہ چل سکے</translation>
 <translation id="6594011207075825276">سیریل آلات تلاش کئے جا رہے ہیں...</translation>
 <translation id="6595187330192059106">‏MIDI آلات کا مکمل کنٹرول حاصل کرنے سے <ph name="HOST" /> کو ہمیشہ مسدود کریں۔</translation>
 <translation id="6596325263575161958">مرموزکاری کے اختیارات</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index 942e808..a00a218 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="vi">
 <translation id="1001307489511021749">Các ứng dụng, tùy chọn cài đặt và những mục tùy chỉnh khác của bạn sẽ được đồng bộ hóa trên mọi thiết bị Chrome OS mà bạn đăng nhập bằng Tài khoản Google của mình.</translation>
 <translation id="1003088604756913841">Mở đường liên kết trong cửa sổ mới của <ph name="APP" /></translation>
+<translation id="100323615638474026">Thiết bị USB (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">Quyền truy cập vào trang web</translation>
 <translation id="1005274289863221750">Sử dụng micrô và máy ảnh của bạn</translation>
 <translation id="1005333234656240382">Bật tùy chọn gỡ lỗi ADB?</translation>
@@ -573,6 +574,7 @@
 <translation id="1614511179807650956">Bạn có thể đã dùng hết dữ liệu di động cho phép. Hãy truy cập vào cổng kích hoạt <ph name="NAME" /> để mua thêm dữ liệu</translation>
 <translation id="161460670679785907">Không phát hiện được điện thoại của bạn</translation>
 <translation id="1615402009686901181">Theo chính sách của quản trị viên, tính năng chụp ảnh màn hình bị tắt khi có nội dung bí mật</translation>
+<translation id="1615755956145364867">Các trang web có thể yêu cầu phát nội dung được bảo vệ</translation>
 <translation id="1616206807336925449">Tiện ích này không yêu cầu quyền đặc biệt.</translation>
 <translation id="1616298854599875024">Không thể nhập tiện ích "<ph name="IMPORT_NAME" />" do tiện ích này không phải là mô-đun được chia sẻ</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{Đang kiểm tra để xem dữ liệu này có tuân theo các chính sách bảo mật của tổ chức bạn hay không...}=1{Đang kiểm tra để xem tệp này có tuân theo các chính sách bảo mật của tổ chức bạn hay không...}other{Đang kiểm tra để xem những tệp này có tuân theo các chính sách bảo mật của tổ chức bạn hay không...}}</translation>
@@ -767,6 +769,7 @@
 <translation id="1794051631868188691">Không bao giờ hiển thị <ph name="MERCHANT" /></translation>
 <translation id="1794791083288629568">Gửi phản hồi để giúp chúng tôi khắc phục sự cố này.</translation>
 <translation id="1795214765651529549">Sử dụng chủ đề Cổ điển</translation>
+<translation id="1796588414813960292">Các tính năng cần dùng âm thanh sẽ không hoạt động</translation>
 <translation id="1799071797295057738">Tiện ích "<ph name="EXTENSION_NAME" />" đã tự động bị tắt.</translation>
 <translation id="1800973090344019061">Tiện ích "<ph name="APP_NAME" />" muốn chia sẻ các nội dung trên màn hình của bạn.</translation>
 <translation id="1802624026913571222">Chuyển sang chế độ ngủ khi đóng nắp màn hình</translation>
@@ -965,6 +968,7 @@
 <translation id="2007404777272201486">Báo cáo sự cố...</translation>
 <translation id="2010501376126504057">Thiết bị tương thích</translation>
 <translation id="2015232545623037616">PC dùng cùng mạng Wi-Fi với Chromecast</translation>
+<translation id="2016473077102413275">Các tính năng cần dùng hình ảnh sẽ không hoạt động</translation>
 <translation id="2016574333161572915">Bạn hiện có thể thiết lập thiết bị Google Meet</translation>
 <translation id="2017334798163366053">Tắt tính năng thu thập dữ liệu hoạt động</translation>
 <translation id="2018352199541442911">Rất tiếc, thiết bị lưu trữ bên ngoài của bạn không được hỗ trợ vào thời điểm này.</translation>
@@ -1295,6 +1299,7 @@
 <translation id="2355604387869345912">Bật tính năng Chia sẻ Internet tức thì</translation>
 <translation id="2356070529366658676">Yêu cầu</translation>
 <translation id="2357330829548294574">Xóa <ph name="USER_NAME" /></translation>
+<translation id="2358561147588818967">Các trang web có thể dùng JavaScript</translation>
 <translation id="2359071692152028734">Các ứng dụng Linux có thể sẽ không phản hồi.</translation>
 <translation id="2359345697448000899">Quản lý tiện ích của bạn bằng cách nhấp vào Tiện ích trong menu Công cụ.</translation>
 <translation id="2359556993567737338">Kết nối thiết bị Bluetooth</translation>
@@ -1472,6 +1477,7 @@
 <translation id="2544853746127077729">Chứng chỉ xác thực bị mạng từ chối</translation>
 <translation id="2546283357679194313">Cookie và dữ liệu trang web</translation>
 <translation id="2548347166720081527">Đã cho phép <ph name="PERMISSION" /></translation>
+<translation id="2548545707296594436">Đặt lại bộ nhớ đệm của hồ sơ eSIM</translation>
 <translation id="2549985041256363841">Bắt đầu ghi</translation>
 <translation id="2550212893339833758">Đã hoán đổi bộ nhớ</translation>
 <translation id="2550596535588364872">Bạn muốn cho phép <ph name="EXTENSION_NAME" /> mở <ph name="FILE_NAME" />?</translation>
@@ -1665,6 +1671,7 @@
 <translation id="2765217105034171413">Nhỏ</translation>
 <translation id="2766006623206032690">Dán và tru&amp;y cập</translation>
 <translation id="2766161002040448006">Xin phép cha mẹ</translation>
+<translation id="2767077837043621282">Không thể cập nhật chiếc Chromebook của bạn. Vui lòng thử lại sau.</translation>
 <translation id="2767127727915954024"><ph name="ORIGIN" /> sẽ có thể chỉnh sửa <ph name="FILENAME" /> cho đến khi bạn đóng tất cả các thẻ cho trang web này</translation>
 <translation id="2770465223704140727">Xóa khỏi danh sách</translation>
 <translation id="2770690685823456775">Xuất mật khẩu của bạn sang thư mục khác</translation>
@@ -1942,6 +1949,7 @@
 <translation id="3060379269883947824">Bật chọn để nói</translation>
 <translation id="3060952009917586498">Thay đổi ngôn ngữ của thiết bị. Ngôn ngữ hiện tại là <ph name="LANGUAGE" />.</translation>
 <translation id="3060987956645097882">Chúng tôi không thể thiết lập đường kết nối với điện thoại của bạn. Hãy đảm bảo điện thoại của bạn đang ở gần, mở khóa, đồng thời đã bật Bluetooth và Wi-Fi.</translation>
+<translation id="3064871050034234884">Các trang web có thể phát âm thanh</translation>
 <translation id="3065041951436100775">Phản hồi thẻ bị lỗi.</translation>
 <translation id="3065522099314259755">Độ trễ lặp lại trên bàn phím</translation>
 <translation id="3067198179881736288">Cài đặt ứng dụng?</translation>
@@ -2292,6 +2300,7 @@
 <translation id="3462413494201477527">Hủy thiết lập tài khoản?</translation>
 <translation id="3464145797867108663">Thêm hồ sơ công việc</translation>
 <translation id="346431825526753">Đây là tài khoản cho trẻ em do <ph name="CUSTODIAN_EMAIL" /> quản lý.</translation>
+<translation id="3465480292013046659">Đã xảy ra sự cố khi tải bản cập nhật này xuống. Vui lòng thử lại sau.</translation>
 <translation id="3468298837301810372">Nhãn</translation>
 <translation id="3468999815377931311">Điện thoại Android</translation>
 <translation id="3470442499439619530">Xóa người dùng này</translation>
@@ -2323,6 +2332,7 @@
 <translation id="3495496470825196617">Chế độ rảnh khi sạc pin</translation>
 <translation id="3495660573538963482">Cài đặt Trợ lý Google</translation>
 <translation id="3496213124478423963">Thu Nhỏ</translation>
+<translation id="3497501929010263034">Thiết bị USB của <ph name="VENDOR_NAME" /> (sản phẩm <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">Chia sẻ Doodle</translation>
 <translation id="3498215018399854026">Chúng tôi không thể liên lạc với cha mẹ của bạn vào thời điểm này. Vui lòng thử lại.</translation>
 <translation id="3500417806337761827">Lỗi kết nối mục chia sẻ. Đã có quá nhiều mục chia sẻ của doanh nghiệp vừa và nhỏ (SMB) được liên kết.</translation>
@@ -2410,6 +2420,7 @@
 <translation id="3600792891314830896">Tắt tiếng trên các trang web phát âm thanh</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">Cung cấp các tính năng mới khi có sẵn</translation>
+<translation id="3602179428782502464">Quản trị viên của bạn đã chặn bản cập nhật này</translation>
 <translation id="3602290021589620013">Xem trước</translation>
 <translation id="3602870520245633055">In và quét</translation>
 <translation id="3603622770190368340">Nhận chứng chỉ mạng</translation>
@@ -2419,6 +2430,7 @@
 <translation id="3610369246614755442">Quạt của đế sạc cần được bảo dưỡng</translation>
 <translation id="361106536627977100">Dữ liệu Flash</translation>
 <translation id="3611655097742243705">Hãy truy cập vào Cửa hàng Play để tìm thêm các ứng dụng khác</translation>
+<translation id="3611658447322220736">Các trang web đã đóng gần đây có thể hoàn tất thao tác gửi và nhận dữ liệu</translation>
 <translation id="3612673635130633812">Đã tải xuống bởi &lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt;</translation>
 <translation id="3613134908380545408">Hiển thị <ph name="FOLDER_NAME" /></translation>
 <translation id="3613422051106148727">&amp;Mở trong thẻ mới</translation>
@@ -2451,6 +2463,7 @@
 <translation id="3639220004740062347">Thoát khỏi Chế độ đọc</translation>
 <translation id="3640214691812501263">Thêm "<ph name="EXTENSION_NAME" />" cho <ph name="USER_NAME" />?</translation>
 <translation id="3640613767643722554">Hướng dẫn Trợ lý nhận dạng giọng nói của bạn</translation>
+<translation id="3641456520301071208">Các trang web có thể yêu cầu thông tin vị trí của bạn</translation>
 <translation id="3645372836428131288">Nhẹ nhàng di chuyển ngón tay để hệ thống quét các phần của vân tay.</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{Đã nhận <ph name="ATTACHMENTS" /> từ thiết bị <ph name="DEVICE_NAME" />}other{Đã nhận <ph name="ATTACHMENTS" /> từ thiết bị <ph name="DEVICE_NAME" />}}</translation>
 <translation id="3648348069317717750">Đã phát hiện thấy <ph name="USB_DEVICE_NAME" /></translation>
@@ -2493,6 +2506,7 @@
 <translation id="3688526734140524629">Thay đổi kênh</translation>
 <translation id="3688578402379768763">Cập nhật</translation>
 <translation id="3688794912214798596">Thay đổi ngôn ngữ...</translation>
+<translation id="3690128548376345212">Mạng <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, Chưa kích hoạt, <ph name="CONNECTION_STATUS" />, Cường độ tín hiệu: <ph name="SIGNAL_STRENGTH" />%, Thông tin chi tiết</translation>
 <translation id="3690369331356918524">Cảnh báo bạn nếu mật khẩu bị lộ trong một sự cố rò rỉ dữ liệu</translation>
 <translation id="3691231116639905343">Ứng dụng bàn phím</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> muốn chia sẻ màn hình của bạn</translation>
@@ -2574,6 +2588,7 @@
 <translation id="3772609330847318323">Cập nhật mật khẩu cho <ph name="ORIGIN" /></translation>
 <translation id="3775432569830822555">Chứng chỉ Máy chủ SSL</translation>
 <translation id="3775705724665058594">Gửi đến các thiết bị của bạn</translation>
+<translation id="3776508619697147021">Các trang web có thể yêu cầu tự động tải nhiều tệp xuống</translation>
 <translation id="3776796446459804932">Tiện ích này vi phạm chính sách của Cửa hàng Chrome trực tuyến.</translation>
 <translation id="3777483481409781352">Không kích hoạt được thiết bị di động</translation>
 <translation id="3777806571986431400">Đã bật tiện ích</translation>
@@ -2875,6 +2890,7 @@
 <translation id="4078738236287221428">Linh hoạt</translation>
 <translation id="4079140982534148664">Sử dụng tính năng kiểm tra lỗi chính tả nâng cao</translation>
 <translation id="4081242589061676262">Không thể truyền tệp.</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> đã gửi một thông báo đến điện thoại của bạn. Để xác nhận danh tính của bạn, hãy làm theo các bước trên chiếc điện thoại đó.</translation>
 <translation id="4084682180776658562">Dấu trang</translation>
 <translation id="4084835346725913160">Đóng <ph name="TAB_NAME" /></translation>
 <translation id="4085270836953633510">Hỏi khi có trang web muốn truy cập vào cổng nối tiếp</translation>
@@ -3036,6 +3052,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{Hiển thị}other{Hiển thị tất cả}}</translation>
 <translation id="4289372044984810120">Quản lý các tài khoản của bạn tại đây. <ph name="LINK_BEGIN" />Tìm hiểu thêm<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">Tổng quan</translation>
+<translation id="4290791284969893584">Sau khi đóng một trang, các thao tác bạn đã bắt đầu có thể không hoàn tất</translation>
 <translation id="4295072614469448764">Ứng dụng này hiện đã có trong thiết bị của bạn. Ngoài ra, có thể có một biểu tượng trong Trình chạy.</translation>
 <translation id="4295839147292213505">Bạn có thể nhắn tin từ máy tính, chia sẻ kết nối Internet, trả lời thông báo về cuộc trò chuyện và mở khóa <ph name="DEVICE_TYPE" /> bằng điện thoại.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />Tìm hiểu thêm<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">Vui lòng đăng nhập lại để xác nhận rằng tài khoản <ph name="USER_EMAIL" /> của bạn có thể dùng với các trang web, ứng dụng và tiện ích trong Chrome cũng như Google Play. Bạn cũng có thể xóa tài khoản này. <ph name="LINK_BEGIN" />Tìm hiểu thêm<ph name="LINK_END" /></translation>
@@ -3232,6 +3249,7 @@
 <translation id="4514610446763173167">Bật/tắt video để phát hoặc tạm dừng</translation>
 <translation id="451515744433878153">Xóa</translation>
 <translation id="4515872537870654449">Hãy liên hệ với Dell để được bảo dưỡng. Đế sạc sẽ tắt nếu quạt không hoạt động.</translation>
+<translation id="4519331665958994620">Các trang web có thể yêu cầu sử dụng máy ảnh của bạn</translation>
 <translation id="4519935350946509010">Lỗi kết nối.</translation>
 <translation id="4520385623207007473">Các cookie đang được sử dụng</translation>
 <translation id="452039078290142656">thiết bị không xác định từ <ph name="VENDOR_NAME" /></translation>
@@ -3411,6 +3429,7 @@
 <translation id="4694604912444486114">Khỉ</translation>
 <translation id="4697071790493980729">Không tìm thấy kết quả nào</translation>
 <translation id="4697551882387947560">Khi phiên duyệt kết thúc</translation>
+<translation id="469838979880025581">Các trang web có thể yêu cầu sử dụng micrô của bạn</translation>
 <translation id="4699172675775169585">Tệp và hình ảnh được lưu trong bộ nhớ đệm</translation>
 <translation id="4699357559218762027">(tự động chạy)</translation>
 <translation id="4701025263201366865">Hoạt động đăng nhập của cha mẹ</translation>
@@ -3593,6 +3612,10 @@
 <translation id="4918086044614829423">Chấp nhận</translation>
 <translation id="4921290200821452703">Thông tin về tài khoản trường học dành cho cha mẹ</translation>
 <translation id="4921348630401250116">Chuyển văn bản sang lời nói</translation>
+<translation id="4921809350408880559">Các tài liệu gần đây và tài liệu đề xuất của bạn xuất hiện dựa trên hoạt động mà bạn thực hiện trước đây thông qua Google Drive.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Để tìm hiểu về dữ liệu mà Google Drive thu thập và lý do thu thập, vui lòng truy cập vào <ph name="BEGIN_LINK" />đây<ph name="END_LINK" />.</translation>
 <translation id="49226369361073053">{0,plural, =0{Cập nhật thiết bị ngay}=1{Cập nhật thiết bị trong vòng 1 giây}other{Cập nhật thiết bị trong vòng # giây}}</translation>
 <translation id="492299503953721473">Xóa ứng dụng Android</translation>
 <translation id="492363500327720082">Đang gỡ cài đặt <ph name="APP_NAME" />...</translation>
@@ -4353,6 +4376,7 @@
 <translation id="5794700615121138172">Thư mục do Linux chia sẻ</translation>
 <translation id="5794786537412027208">Thoát khỏi tất cả các ứng dụng Chrome</translation>
 <translation id="5797070761912323120">Google có thể sử dụng lịch sử của bạn để điều chỉnh tính năng Tìm kiếm, quảng cáo và các dịch vụ khác của Google cho phù hợp với bạn</translation>
+<translation id="5798079537501238810">Các trang web có thể cài đặt trình xử lý thanh toán</translation>
 <translation id="579907812742603813">nội dung được bảo vệ</translation>
 <translation id="579915268381781820">Khóa bảo mật của bạn đã bị rút ra.</translation>
 <translation id="5799478978078236781">Nhận các mẹo, ưu đãi và thông tin cập nhật về <ph name="DEVICE_TYPE" />, cũng như chia sẻ ý kiến phản hồi.</translation>
@@ -4385,6 +4409,7 @@
 <translation id="5833726373896279253">Chỉ chủ sở hữu mới có thể sửa đổi các chế độ cài đặt này:</translation>
 <translation id="5834581999798853053">Còn khoảng <ph name="TIME" /> phút</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - Đang ghi âm hoặc quay phim</translation>
+<translation id="583673505367439042">Các trang web có thể yêu cầu chỉnh sửa tệp và thư mục trên thiết bị của bạn</translation>
 <translation id="5840680448799937675">Tệp sẽ luôn được chia sẻ mà không dùng Internet</translation>
 <translation id="5841270259333717135">Định cấu hình Ethernet</translation>
 <translation id="5842497610951477805">Bật Bluetooth</translation>
@@ -4434,6 +4459,7 @@
 <translation id="5889282057229379085">Số CA gián tiếp tối đa: <ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">Các mạng Wi-Fi ưu tiên</translation>
 <translation id="5895138241574237353">Khởi động lại</translation>
+<translation id="5896749729057314184">Mạng <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, Chưa kích hoạt, Cường độ tín hiệu: <ph name="SIGNAL_STRENGTH" />%, Thông tin chi tiết</translation>
 <translation id="5900302528761731119">Ảnh hồ sơ trên Google</translation>
 <translation id="590036993063074298">Thông tin chi tiết về chất lượng phản chiếu</translation>
 <translation id="5901069264981746702">Dữ liệu vân tay được lưu trữ an toàn và chỉ có trên <ph name="DEVICE_TYPE" /> của bạn. <ph name="LINK_BEGIN" />Tìm hiểu thêm<ph name="LINK_END" /></translation>
@@ -4678,6 +4704,7 @@
 <translation id="6155141482566063812">Thẻ nền đang chia sẻ màn hình</translation>
 <translation id="6156323911414505561">Hiển thị thanh dấu trang</translation>
 <translation id="6156863943908443225">Bộ nhớ đệm tập lệnh</translation>
+<translation id="615930144153753547">Các trang web có thể hiện hình ảnh</translation>
 <translation id="6160625263637492097">Cung cấp chứng chỉ để xác thực</translation>
 <translation id="6163363155248589649">Thườ&amp;ng</translation>
 <translation id="6163376401832887457">Cài đặt tài khoản Kerberos</translation>
@@ -4884,6 +4911,10 @@
 <translation id="6398715114293939307">Xóa Cửa hàng Google Play</translation>
 <translation id="6398765197997659313">Thoát khỏi chế độ toàn màn hình</translation>
 <translation id="6399774419735315745">Điệp viên</translation>
+<translation id="6400510847800135340">Mục này xuất hiện dựa trên hoạt động mà bạn thực hiện trước đây trên các dịch vụ của Google. Bạn có thể xem hoặc xóa dữ liệu này và thay đổi chế độ cài đặt tại <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        Để tìm hiểu về dữ liệu mà Google thu thập và lý do thu thập, vui lòng truy cập vào <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" />.</translation>
 <translation id="6404511346730675251">Chỉnh sửa dấu trang</translation>
 <translation id="6406303162637086258">Mô phỏng khởi động lại trình duyệt</translation>
 <translation id="6406506848690869874">Đồng bộ hóa</translation>
@@ -4933,6 +4964,7 @@
 <translation id="6452251728599530347">Đã hoàn tất <ph name="PERCENT" /></translation>
 <translation id="645286928527869380">Ý tưởng nấu ăn</translation>
 <translation id="6452961788130242735">Vấn đề về mạng hoặc vùng không hợp lệ</translation>
+<translation id="6453921811609336127">Để chuyển sang phương thức nhập tiếp theo, hãy nhấn tổ hợp phím <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Phím cách<ph name="END_SPACE" /><ph name="END_SHORTCUT" /></translation>
 <translation id="6455264371803474013">Trên các trang web cụ thể</translation>
 <translation id="6455894534188563617">&amp;Thư mục mới</translation>
 <translation id="645705751491738698">Tiếp tục chặn JavaScript</translation>
@@ -5058,6 +5090,7 @@
 <translation id="6590458744723262880">Đổi tên thư mục</translation>
 <translation id="6592267180249644460">Đã ghi nhật ký WebRTC vào <ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">Hệ thống đã ghi lại vân tay của bạn</translation>
+<translation id="6593881952206664229">Nội dung nghe nhìn có bản quyền có thể không phát được</translation>
 <translation id="6594011207075825276">Đang tìm thiết bị nối tiếp...</translation>
 <translation id="6595187330192059106">Luôn chặn không cho <ph name="HOST" /> toàn quyền kiểm soát các thiết bị MIDI.</translation>
 <translation id="6596325263575161958">Tùy chọn mã hóa</translation>
@@ -6015,6 +6048,7 @@
 <translation id="7661451191293163002">Không thể lấy chứng chỉ đăng ký.</translation>
 <translation id="7662283695561029522">Nhấn để định cấu hình</translation>
 <translation id="7663719505383602579">Bộ thu: <ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">Phím tắt bạn có thể dùng</translation>
 <translation id="7664620655576155379">Thiết bị Bluetooth không được hỗ trợ: "<ph name="DEVICE_NAME" />".</translation>
 <translation id="7665082356120621510">Dự trữ ổ đĩa</translation>
 <translation id="7665369617277396874">Thêm tài khoản</translation>
@@ -6194,6 +6228,7 @@
 <translation id="7835178595033117206">Đã xóa dấu trang</translation>
 <translation id="7836850009646241041">Thử chạm lại vào khóa bảo mật</translation>
 <translation id="7837776265184002579">Trang chủ của bạn đã được thay đổi thành <ph name="URL" />.</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{Đã gửi <ph name="ATTACHMENTS" /> đến <ph name="DEVICE_NAME" />}other{Đã gửi <ph name="ATTACHMENTS" /> đến <ph name="DEVICE_NAME" />}}</translation>
 <translation id="7839051173341654115">Xem/Sao lưu phương tiện</translation>
 <translation id="7839192898639727867">ID Khoá Đối tượng của Chứng chỉ</translation>
 <translation id="7842692330619197998">Hãy truy cập vào g.co/ChromeEnterpriseAccount nếu bạn cần tạo một tài khoản mới.</translation>
@@ -6891,6 +6926,7 @@
 <translation id="8633025649649592204">Hoạt động gần đây</translation>
 <translation id="8635628933471165173">Đang tải lại...</translation>
 <translation id="8636284842992792762">Đang khởi chạy các tiện ích...</translation>
+<translation id="8636500887554457830">Không cho phép các trang web gửi cửa sổ bật lên hoặc dùng lệnh chuyển hướng</translation>
 <translation id="8637542770513281060">Máy tính của bạn chứa một mô-đun an toàn dùng để triển khai nhiều tính năng bảo mật quan trọng trong Chrome OS. Hãy truy cập Trung tâm trợ giúp Chromebook để tìm hiểu thêm: https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">Có sẵn bản cập nhật hệ thống. Đang chuẩn bị tải xuống…</translation>
 <translation id="863903787380594467">Mã PIN không chính xác. Bạn còn <ph name="RETRIES" /> lần nhập.</translation>
@@ -7108,6 +7144,7 @@
 <translation id="8842594465773264717">Xóa vân tay này</translation>
 <translation id="8845001906332463065">Nhận trợ giúp</translation>
 <translation id="8846132060409673887">Đọc thông tin về nhà sản xuất và kiểu máy của máy tính này</translation>
+<translation id="8846163936679269230">Đặt lại hồ sơ eSIM</translation>
 <translation id="8847523528195140327">Đăng xuất khi đóng nắp màn hình</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">Đã ẩn</translation>
@@ -7163,6 +7200,7 @@
 <translation id="8898822736010347272">Gửi URL của một số trang bạn truy cập, thông tin về hệ thống (có giới hạn) và một số nội dung trang cho Google, nhằm phát hiện các mối đe dọa mới và bảo vệ mọi người khi dùng web.</translation>
 <translation id="8899851313684471736">Mở đường liên kết bằng cửa sổ &amp;mới</translation>
 <translation id="8900413463156971200">Bật mạng di động</translation>
+<translation id="8901994452417867840">Đã thêm thành công hồ sơ. Tất cả những người dùng thiết bị này đều có thể sử dụng đường kết nối này.</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> yêu cầu bạn sao lưu dữ liệu và trả lại thiết bị <ph name="DEVICE_TYPE" /> này ngay hôm nay.}other{<ph name="MANAGER" /> yêu cầu bạn sao lưu dữ liệu và trả lại thiết bị <ph name="DEVICE_TYPE" /> này trước thời hạn.}}</translation>
 <translation id="8902667442496790482">Mở mục cài đặt tính năng chọn để nói</translation>
 <translation id="8903263458134414071">Chọn một tài khoản để đăng nhập</translation>
@@ -7344,6 +7382,7 @@
 <translation id="9094982973264386462">Xóa</translation>
 <translation id="9095253524804455615">Xóa</translation>
 <translation id="909554839118732438">Đóng cửa sổ ẩn danh</translation>
+<translation id="9100416672768993722">Để chuyển sang phương thức nhập mà bạn dùng gần đây nhất, hãy nhấn tổ hợp phím <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Phím cách<ph name="END_SPACE" /><ph name="END_SHORTCUT" /></translation>
 <translation id="9100610230175265781">Yêu cầu cụm mật khẩu</translation>
 <translation id="9100765901046053179">Cài đặt nâng cao</translation>
 <translation id="9101691533782776290">Chạy ứng dụng</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 892d1d7..5fb8cc9 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="zh-TW">
 <translation id="1001307489511021749">當你使用 Google 帳戶登入後,所有 Chrome 作業系統裝置上的應用程式、設定和其他自訂項目都會保持同步。</translation>
 <translation id="1003088604756913841">在新的「<ph name="APP" />」視窗中開啟連結</translation>
+<translation id="100323615638474026">USB 裝置 (<ph name="VENDOR_ID" />:<ph name="PRODUCT_ID" />)</translation>
 <translation id="1004218526896219317">網站存取權</translation>
 <translation id="1005274289863221750">使用你的麥克風和相機</translation>
 <translation id="1005333234656240382">是否要啟用 ADB 偵錯?</translation>
@@ -570,6 +571,7 @@
 <translation id="1614511179807650956">你的行動數據配額可能已經用完。造訪 <ph name="NAME" /> 啟用入口網站即可購買更多數據量。</translation>
 <translation id="161460670679785907">偵測不到你的手機</translation>
 <translation id="1615402009686901181">當畫面上出現機密內容,系統管理員政策就會停用螢幕畫面擷取功能</translation>
+<translation id="1615755956145364867">網站可以要求播放受版權保護的內容</translation>
 <translation id="1616206807336925449">這個擴充功能不需要特殊權限。</translation>
 <translation id="1616298854599875024">「<ph name="IMPORT_NAME" />」擴充功能不是共用模組,因此無法匯入</translation>
 <translation id="1617765145568323981">{NUM_FILES,plural, =0{正在檢查這項資料是否符合貴機構的安全性政策...}=1{正在檢查這個檔案是否符合貴機構的安全性政策...}other{正在檢查這些檔案是否符合貴機構的安全性政策...}}</translation>
@@ -756,6 +758,7 @@
 <translation id="1794051631868188691">永不顯示「<ph name="MERCHANT" />」</translation>
 <translation id="1794791083288629568">提供意見,協助我們修正這個問題。</translation>
 <translation id="1795214765651529549">使用傳統版</translation>
+<translation id="1796588414813960292">需要使用音訊的功能將無法運作</translation>
 <translation id="1799071797295057738">系統已自動停用「<ph name="EXTENSION_NAME" />」擴充功能。</translation>
 <translation id="1800973090344019061">「<ph name="APP_NAME" />」擴充功能要求分享你的螢幕內容。</translation>
 <translation id="1802624026913571222">蓋上機蓋時進入休眠狀態</translation>
@@ -953,6 +956,7 @@
 <translation id="2007404777272201486">回報問題...</translation>
 <translation id="2010501376126504057">相容裝置</translation>
 <translation id="2015232545623037616">電腦和 Chromecast 使用相同的 Wi-Fi 網路</translation>
+<translation id="2016473077102413275">需要使用圖片的功能將無法運作</translation>
 <translation id="2016574333161572915">現在可以開始設定你的 Google Meet 設備了</translation>
 <translation id="2017334798163366053">停用效能資料收集</translation>
 <translation id="2018352199541442911">很抱歉,系統目前不支援你的外部儲存裝置。</translation>
@@ -1280,6 +1284,7 @@
 <translation id="2355604387869345912">開啟即時網路共用功能</translation>
 <translation id="2356070529366658676">詢問</translation>
 <translation id="2357330829548294574">移除「<ph name="USER_NAME" />」</translation>
+<translation id="2358561147588818967">網站可以使用 JavaScript</translation>
 <translation id="2359071692152028734">Linux 應用程式可能會沒有回應。</translation>
 <translation id="2359345697448000899">如要管理擴充功能,只要按一下 [工具] 選單裡的 [擴充功能] 即可。</translation>
 <translation id="2359556993567737338">連線至藍牙裝置</translation>
@@ -1456,6 +1461,7 @@
 <translation id="2544853746127077729">網路已拒絕驗證憑證</translation>
 <translation id="2546283357679194313">Cookie 和網站資料</translation>
 <translation id="2548347166720081527">已允許使用<ph name="PERMISSION" /></translation>
+<translation id="2548545707296594436">重設 eSIM 卡設定檔快取</translation>
 <translation id="2549985041256363841">開始錄影</translation>
 <translation id="2550212893339833758">交換的記憶體</translation>
 <translation id="2550596535588364872">要允許「<ph name="EXTENSION_NAME" />」開啟「<ph name="FILE_NAME" />」嗎?</translation>
@@ -1649,6 +1655,7 @@
 <translation id="2765217105034171413">小</translation>
 <translation id="2766006623206032690">貼上及前往(&amp;S)</translation>
 <translation id="2766161002040448006">詢問家長</translation>
+<translation id="2767077837043621282">無法更新 Chromebook。請稍後再試。</translation>
 <translation id="2767127727915954024">在你關閉這個網站的所有分頁前,<ph name="ORIGIN" /> 都可以編輯「<ph name="FILENAME" />」</translation>
 <translation id="2770465223704140727">從清單中移除</translation>
 <translation id="2770690685823456775">將你的密碼匯出至其他資料夾</translation>
@@ -1926,6 +1933,7 @@
 <translation id="3060379269883947824">啟用隨選朗讀功能</translation>
 <translation id="3060952009917586498">變更裝置語言。目前語言為<ph name="LANGUAGE" />。</translation>
 <translation id="3060987956645097882">無法與你的手機建立連線。請確認你的手機在附近,且已解鎖及開啟藍牙和 Wi-Fi。</translation>
+<translation id="3064871050034234884">網站可以播放音效</translation>
 <translation id="3065041951436100775">分頁毀損意見回饋。</translation>
 <translation id="3065522099314259755">鍵盤重複延遲</translation>
 <translation id="3067198179881736288">要安裝應用程式嗎?</translation>
@@ -2276,6 +2284,7 @@
 <translation id="3462413494201477527">取消設定帳戶?</translation>
 <translation id="3464145797867108663">新增工作資料夾</translation>
 <translation id="346431825526753">這是由 <ph name="CUSTODIAN_EMAIL" /> 所管理的兒童專用帳戶。</translation>
+<translation id="3465480292013046659">下載更新時發生問題。請稍後再試。</translation>
 <translation id="3468298837301810372">標籤</translation>
 <translation id="3468999815377931311">Android 手機</translation>
 <translation id="3470442499439619530">移除這個使用者</translation>
@@ -2307,6 +2316,7 @@
 <translation id="3495496470825196617">充電時閒置電源</translation>
 <translation id="3495660573538963482">Google 助理設定</translation>
 <translation id="3496213124478423963">縮小</translation>
+<translation id="3497501929010263034">來自 <ph name="VENDOR_NAME" /> 的 USB 裝置 (產品 ID:<ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">分享 Doodle</translation>
 <translation id="3498215018399854026">我們暫時無法與您的家長聯絡,請再試一次。</translation>
 <translation id="3500417806337761827">掛接檔案共用區時發生錯誤。已掛接過多 SMB 檔案共用區。</translation>
@@ -2394,6 +2404,7 @@
 <translation id="3600792891314830896">將播放音訊的網站設為靜音</translation>
 <translation id="3601151620448429694"><ph name="NETWORK_NAME" /> · <ph name="CARRIER_NAME" /></translation>
 <translation id="360180734785106144">在新功能推出時立即提供你使用</translation>
+<translation id="3602179428782502464">系統管理員已禁止這個更新作業</translation>
 <translation id="3602290021589620013">預覽</translation>
 <translation id="3602870520245633055">列印及掃描</translation>
 <translation id="3603622770190368340">取得網路憑證</translation>
@@ -2403,6 +2414,7 @@
 <translation id="3610369246614755442">座架風扇需要維修</translation>
 <translation id="361106536627977100">Flash 資料</translation>
 <translation id="3611655097742243705">請前往 Play 商店尋找更多應用程式</translation>
+<translation id="3611658447322220736">最近關閉的網站可以完成資料收發作業</translation>
 <translation id="3612673635130633812">「&lt;a href="<ph name="URL" />"&gt;<ph name="EXTENSION" />&lt;/a&gt;」下載了這個檔案</translation>
 <translation id="3613134908380545408">顯示「<ph name="FOLDER_NAME" />」</translation>
 <translation id="3613422051106148727">在新分頁中開啟(&amp;O)</translation>
@@ -2435,6 +2447,7 @@
 <translation id="3639220004740062347">結束閱讀器模式</translation>
 <translation id="3640214691812501263">為<ph name="USER_NAME" />新增「<ph name="EXTENSION_NAME" />」?</translation>
 <translation id="3640613767643722554">訓練 Google 助理辨識你的聲音</translation>
+<translation id="3641456520301071208">網站可以要求取得你的位置資訊</translation>
 <translation id="3645372836428131288">請稍微移動手指,讓系統擷取完整指紋</translation>
 <translation id="3647998456578545569">{COUNT,plural, =1{已收到來自「<ph name="DEVICE_NAME" />」的 <ph name="ATTACHMENTS" />}other{已收到來自「<ph name="DEVICE_NAME" />」的 <ph name="ATTACHMENTS" />}}</translation>
 <translation id="3648348069317717750">偵測到 <ph name="USB_DEVICE_NAME" /></translation>
@@ -2477,6 +2490,7 @@
 <translation id="3688526734140524629">變更版本</translation>
 <translation id="3688578402379768763">最新狀態</translation>
 <translation id="3688794912214798596">變更語言...</translation>
+<translation id="3690128548376345212"><ph name="NETWORK_COUNT" /> 個網路中的第 <ph name="NETWORK_INDEX" /> 個,<ph name="NETWORK_NAME" />,未啟用,<ph name="CONNECTION_STATUS" />,訊號強度 <ph name="SIGNAL_STRENGTH" />%,詳細資料</translation>
 <translation id="3690369331356918524">可在發生資料侵害事件導致密碼外洩時顯示警告訊息</translation>
 <translation id="3691231116639905343">鍵盤應用程式</translation>
 <translation id="3691267899302886494"><ph name="HOST" /> 要求分享螢幕畫面</translation>
@@ -2558,6 +2572,7 @@
 <translation id="3772609330847318323">更新 <ph name="ORIGIN" /> 的密碼</translation>
 <translation id="3775432569830822555">SSL 伺服器憑證</translation>
 <translation id="3775705724665058594">傳送至你的裝置</translation>
+<translation id="3776508619697147021">網站可以要求自動下載多個檔案</translation>
 <translation id="3776796446459804932">這個擴充功能違反了 Chrome 線上應用程式商店政策。</translation>
 <translation id="3777483481409781352">無法啟用行動裝置</translation>
 <translation id="3777806571986431400">擴充功能已啟用</translation>
@@ -2858,6 +2873,7 @@
 <translation id="4078738236287221428">積極</translation>
 <translation id="4079140982534148664">使用進階拼字檢查功能</translation>
 <translation id="4081242589061676262">無法投放檔案。</translation>
+<translation id="408223403876103285"><ph name="WEBSITE" /> 已傳送通知到你的手機。如要確認自己的身分,請按照手機上的步驟操作。</translation>
 <translation id="4084682180776658562">書籤</translation>
 <translation id="4084835346725913160">關閉 <ph name="TAB_NAME" /></translation>
 <translation id="4085270836953633510">當網站要存取序列埠時,必須先詢問你</translation>
@@ -3019,6 +3035,7 @@
 <translation id="4287502603002637393">{MUTED_NOTIFICATIONS_COUNT,plural, =1{顯示}other{全部顯示}}</translation>
 <translation id="4289372044984810120">請在這裡管理帳戶。<ph name="LINK_BEGIN" />瞭解詳情<ph name="LINK_END" /></translation>
 <translation id="4289540628985791613">總覽</translation>
+<translation id="4290791284969893584">關閉網頁後,你已啟動的工作可能無法完成</translation>
 <translation id="4295072614469448764">應用程式已出現在你的終端機上,且可能在啟動器中顯示圖示。</translation>
 <translation id="4295839147292213505">你可以從電腦傳送訊息、分享網際網路連線、回覆對話通知,以及使用手機解鎖 <ph name="DEVICE_TYPE" />。<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />瞭解詳情<ph name="LINK_END" /></translation>
 <translation id="4295979599050707005">請再次登入,並確認你的帳戶 (<ph name="USER_EMAIL" />) 可用於 Chrome 和 Google Play 的網站、應用程式與擴充功能。你也可以移除這個帳戶。<ph name="LINK_BEGIN" />瞭解詳情<ph name="LINK_END" /></translation>
@@ -3214,6 +3231,7 @@
 <translation id="4514610446763173167">在播放和暫停影片之間切換</translation>
 <translation id="451515744433878153">移除</translation>
 <translation id="4515872537870654449">請聯絡 Dell 以取得支援服務。風扇故障時,座架將會停止運作。</translation>
+<translation id="4519331665958994620">網站可以要求使用你的攝影機</translation>
 <translation id="4519935350946509010">連線錯誤。</translation>
 <translation id="4520385623207007473">使用中的 Cookie</translation>
 <translation id="452039078290142656">由 <ph name="VENDOR_NAME" /> 製造的不明裝置</translation>
@@ -3393,6 +3411,7 @@
 <translation id="4694604912444486114">猴子</translation>
 <translation id="4697071790493980729">找不到相符的搜尋結果</translation>
 <translation id="4697551882387947560">瀏覽工作階段結束時</translation>
+<translation id="469838979880025581">網站可以要求使用你的麥克風</translation>
 <translation id="4699172675775169585">快取圖片和檔案</translation>
 <translation id="4699357559218762027">(自動啟動)</translation>
 <translation id="4701025263201366865">家長登入</translation>
@@ -3575,6 +3594,10 @@
 <translation id="4918086044614829423">接受</translation>
 <translation id="4921290200821452703">給家長的學校帳戶資訊</translation>
 <translation id="4921348630401250116">文字轉語音</translation>
+<translation id="4921809350408880559">這是根據你使用 Google 雲端硬碟的活動記錄而顯示的最近和建議文件。
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        如要瞭解 Google 雲端硬碟會收集哪些資料,以及收集這些資料的原因,請前往<ph name="BEGIN_LINK" />這裡<ph name="END_LINK" />。</translation>
 <translation id="49226369361073053">{0,plural, =0{請立即更新裝置}=1{請在 1 秒內更新裝置}other{請在 # 秒內更新裝置}}</translation>
 <translation id="492299503953721473">移除 Android 應用程式</translation>
 <translation id="492363500327720082">正在解除安裝「<ph name="APP_NAME" />」...</translation>
@@ -4335,6 +4358,7 @@
 <translation id="5794700615121138172">Linux 共用資料夾</translation>
 <translation id="5794786537412027208">結束所有 Chrome 應用程式</translation>
 <translation id="5797070761912323120">Google 可能會使用你的歷史記錄,為你提供個人化的搜尋服務、廣告內容和其他各項 Google 服務</translation>
+<translation id="5798079537501238810">網站可以安裝付款處理常式</translation>
 <translation id="579907812742603813">受保護內容</translation>
 <translation id="579915268381781820">你的安全金鑰已移除。</translation>
 <translation id="5799478978078236781">現在可以取得 <ph name="DEVICE_TYPE" /> 的實用提示、優惠資訊與最新消息,並提供意見回饋。</translation>
@@ -4367,6 +4391,7 @@
 <translation id="5833726373896279253">你必須是擁有者,才能修改這些設定:</translation>
 <translation id="5834581999798853053">剩下 <ph name="TIME" /> 分鐘</translation>
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - 攝影機或麥克風錄影/錄音中</translation>
+<translation id="583673505367439042">網站可以要求編輯裝置上的檔案和資料夾</translation>
 <translation id="5840680448799937675">一律在離線時分享檔案</translation>
 <translation id="5841270259333717135">設定乙太網路</translation>
 <translation id="5842497610951477805">啟用藍牙</translation>
@@ -4416,6 +4441,7 @@
 <translation id="5889282057229379085">中繼 CA 數目上限:<ph name="NUM_INTERMEDIATE_CA" /></translation>
 <translation id="5891688036610113830">偏好的 Wi-Fi 網路</translation>
 <translation id="5895138241574237353">重新啟動</translation>
+<translation id="5896749729057314184"><ph name="NETWORK_COUNT" /> 個網路中的第 <ph name="NETWORK_INDEX" /> 個,<ph name="NETWORK_NAME" />,未啟用,訊號強度 <ph name="SIGNAL_STRENGTH" />%,詳細資料</translation>
 <translation id="5900302528761731119">Google 個人資料相片</translation>
 <translation id="590036993063074298">鏡像品質詳細資訊</translation>
 <translation id="5901069264981746702">你的指紋資料會安全地儲存在 <ph name="DEVICE_TYPE" /> 上,絕不會外洩。<ph name="LINK_BEGIN" />瞭解詳情<ph name="LINK_END" /></translation>
@@ -4660,6 +4686,7 @@
 <translation id="6155141482566063812">背景分頁正在分享你的螢幕畫面</translation>
 <translation id="6156323911414505561">顯示書籤列</translation>
 <translation id="6156863943908443225">指令碼快取</translation>
+<translation id="615930144153753547">網站可以顯示圖片</translation>
 <translation id="6160625263637492097">提供驗證所需的憑證</translation>
 <translation id="6163363155248589649">一般(&amp;N)</translation>
 <translation id="6163376401832887457">Kerberos 設定</translation>
@@ -4866,6 +4893,10 @@
 <translation id="6398715114293939307">移除 Google Play 商店</translation>
 <translation id="6398765197997659313">退出全螢幕模式</translation>
 <translation id="6399774419735315745">女間諜</translation>
+<translation id="6400510847800135340">這是根據你使用 Google 服務的活動記錄而顯示的項目。你可以前往 <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 查看或刪除自己的資料,也可以變更設定。
+        <ph name="BREAK" />
+        <ph name="BREAK" />
+        如要瞭解 Google 會收集哪些資料,以及收集這些資料的原因,請前往 <ph name="BEGIN_LINK" />policies.google.com<ph name="END_LINK" />。</translation>
 <translation id="6404511346730675251">編輯書籤</translation>
 <translation id="6406303162637086258">模擬瀏覽器重新啟動</translation>
 <translation id="6406506848690869874">同步</translation>
@@ -4915,6 +4946,7 @@
 <translation id="6452251728599530347">已完成 <ph name="PERCENT" /></translation>
 <translation id="645286928527869380">食譜建議</translation>
 <translation id="6452961788130242735">網路發生問題或領域無效</translation>
+<translation id="6453921811609336127">如要切換至下一個輸入法,請按下 <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR1" /><ph name="BEGIN_SHIFT" />Shift<ph name="END_SHIFT" /><ph name="SEPARATOR2" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> 鍵</translation>
 <translation id="6455264371803474013">在特定網站上</translation>
 <translation id="6455894534188563617">新增資料夾(&amp;N)</translation>
 <translation id="645705751491738698">繼續封鎖 JavaScript</translation>
@@ -5040,6 +5072,7 @@
 <translation id="6590458744723262880">重新命名資料夾</translation>
 <translation id="6592267180249644460">WebRTC 記錄擷取時間:<ph name="WEBRTC_LOG_CAPTURE_TIME" /></translation>
 <translation id="6592808042417736307">已擷取你的指紋</translation>
+<translation id="6593881952206664229">系統可能不會播放受版權保護的媒體</translation>
 <translation id="6594011207075825276">正在尋找序列裝置…</translation>
 <translation id="6595187330192059106">一律禁止 <ph name="HOST" /> 取得 MIDI 裝置的完整控制權限。</translation>
 <translation id="6596325263575161958">加密選項</translation>
@@ -5997,6 +6030,7 @@
 <translation id="7661451191293163002">無法取得註冊憑證。</translation>
 <translation id="7662283695561029522">輕觸即可進行設定</translation>
 <translation id="7663719505383602579">接收端:<ph name="ARC_PROCESS_NAME" /></translation>
+<translation id="7663774460282684730">可以使用鍵盤快速鍵</translation>
 <translation id="7664620655576155379">不支援的藍牙裝置:「<ph name="DEVICE_NAME" />」。</translation>
 <translation id="7665082356120621510">預留大小</translation>
 <translation id="7665369617277396874">新增帳戶</translation>
@@ -6176,6 +6210,7 @@
 <translation id="7835178595033117206">已移除書籤</translation>
 <translation id="7836850009646241041">請再次輕觸你的安全金鑰</translation>
 <translation id="7837776265184002579">你的首頁已變更為 <ph name="URL" />。</translation>
+<translation id="7838971600045234625">{COUNT,plural, =1{已傳送 <ph name="ATTACHMENTS" />給 <ph name="DEVICE_NAME" />}other{已傳送 <ph name="ATTACHMENTS" />給 <ph name="DEVICE_NAME" />}}</translation>
 <translation id="7839051173341654115">查看/備份媒體</translation>
 <translation id="7839192898639727867">憑證主體金鑰識別碼</translation>
 <translation id="7842692330619197998">如需建立新帳戶,請前往 g.co/ChromeEnterpriseAccount。</translation>
@@ -6872,6 +6907,7 @@
 <translation id="8633025649649592204">近期活動</translation>
 <translation id="8635628933471165173">正在重新載入…</translation>
 <translation id="8636284842992792762">正在初始化擴充功能...</translation>
+<translation id="8636500887554457830">禁止網站傳送彈出式視窗或使用重新導向</translation>
 <translation id="8637542770513281060">你的電腦含有安全模組,用於實作 Chrome 作業系統中許多重要的安全性功能。如需瞭解詳情,請造訪 Chromebook 說明中心:https://support.google.com/chromebook/?p=sm</translation>
 <translation id="8637688295594795546">可安裝系統更新,正在準備下載…</translation>
 <translation id="863903787380594467">PIN 碼不正確,你還有 <ph name="RETRIES" /> 次重試機會。</translation>
@@ -7089,6 +7125,7 @@
 <translation id="8842594465773264717">刪除這個指紋</translation>
 <translation id="8845001906332463065">尋求協助</translation>
 <translation id="8846132060409673887">閱讀這部電腦的製造商和型號資訊</translation>
+<translation id="8846163936679269230">重設 eSIM 卡設定檔</translation>
 <translation id="8847523528195140327">蓋上機蓋時登出帳戶</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8849001918648564819">隱藏</translation>
@@ -7144,6 +7181,7 @@
 <translation id="8898822736010347272">將部分已造訪網頁的網址、特定的系統資訊和部分網頁內容傳送至 Google,以協助發現新威脅並保障所有網路使用者的安全。</translation>
 <translation id="8899851313684471736">在新視窗中開啟連結(&amp;W)</translation>
 <translation id="8900413463156971200">啟用行動數據</translation>
+<translation id="8901994452417867840">設定檔新增成功。這部裝置的所有使用者都可以連上這個網路。</translation>
 <translation id="8902059453911237649">{NUM_DAYS,plural, =1{<ph name="MANAGER" /> 要求你備份自己的資料,並且在今天內返還這部 <ph name="DEVICE_TYPE" />。}other{<ph name="MANAGER" /> 要求你備份自己的資料,並且在期限內返還這部 <ph name="DEVICE_TYPE" />。}}</translation>
 <translation id="8902667442496790482">開啟隨選朗讀設定</translation>
 <translation id="8903263458134414071">請選取要登入的帳戶</translation>
@@ -7325,6 +7363,7 @@
 <translation id="9094982973264386462">移除</translation>
 <translation id="9095253524804455615">移除</translation>
 <translation id="909554839118732438">關閉無痕模式</translation>
+<translation id="9100416672768993722">如要切換到上次使用的輸入法,請按下 <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> 鍵</translation>
 <translation id="9100610230175265781">請提供通關密語</translation>
 <translation id="9100765901046053179">進階設定</translation>
 <translation id="9101691533782776290">啟動應用程式</translation>
diff --git a/chrome/app/resources/google_chrome_strings_bn.xtb b/chrome/app/resources/google_chrome_strings_bn.xtb
index 7156ea7..f91469f 100644
--- a/chrome/app/resources/google_chrome_strings_bn.xtb
+++ b/chrome/app/resources/google_chrome_strings_bn.xtb
@@ -11,6 +11,7 @@
 <translation id="1125124144982679672">Chrome কে ব্যবহার করছেন?</translation>
 <translation id="1142745911746664600">Chrome আপডেট করা যাচ্ছে না</translation>
 <translation id="1154147086299354128">&amp;Chrome এ খুলুন</translation>
+<translation id="1278833599417554002">&amp;Chrome আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="1293325835983155583"><ph name="MANAGER" />-এ এই ডিভাইস ব্যবহার করার আগে আপনাকে নিম্নলিখিত পরিষেবার শর্তাবলী পড়ে নিতে হবে এবং তাতে সম্মতি দিতে হবে। এইসব শর্ত Google Chrome OS-এর শর্তাবলীকে সম্প্রসারণ, পরিবর্তন বা সীমাবদ্ধ করে না।</translation>
 <translation id="1302523850133262269">Chrome যখন সাম্প্রতিক সিস্টেম আপডেটগুলিকে ইনস্টল করে তখন দয়া করে অপেক্ষা করুন৷</translation>
 <translation id="137466361146087520">Google Chrome বিটা</translation>
@@ -48,6 +49,7 @@
 <translation id="2063848847527508675">আপডেটটি প্রয়োগ করতে Chrome OS আবার চালু করা প্রয়োজন।</translation>
 <translation id="2094919256425865063">তা স্বত্তেও Chrome বন্ধ করবেন?</translation>
 <translation id="2120620239521071941">এটি এই ডিভাইস থেকে <ph name="ITEMS_COUNT" />টি আইটেম মুছে দেবে। আপনার ডেটা পরে পুনরুদ্ধার করার জন্য, Chrome-এ <ph name="USER_EMAIL" /> হিসেবে সাইন-ইন করুন।</translation>
+<translation id="2121284319307530122">&amp;Chrome আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="2123055963409958220"><ph name="BEGIN_LINK" />বর্তমান সেটিংস<ph name="END_LINK" />-এর রিপোর্ট করে Chrome-কে আরও ভাল করে তুলতে সাহায্য করুন</translation>
 <translation id="2151406531797534936">এখনই Chrome রিস্টার্ট করুন</translation>
 <translation id="2246246234298806438">বিলট-ইন PDF viewer অনুপস্থিত থাকার সময়ে Google Chrome প্রিন্ট প্রিভিউ দেখাতে পারে না৷</translation>
@@ -239,6 +241,7 @@
 <translation id="7629695634924605473">আপনার পাসওয়ার্ড কখনও চুরি হলে তা Chrome আপনাকে জানিয়ে দেবে</translation>
 <translation id="7641148173327520642"><ph name="TARGET_URL_HOSTNAME" /> অ্যাক্সেস করতে <ph name="ALTERNATIVE_BROWSER_NAME" /> ব্যবহার করার জন্য আপনার সিস্টেম অ্যাডমিনিস্ট্রেটর Google Chrome কনফিগার করেছে।</translation>
 <translation id="7651907282515937834">Chrome এন্টারপ্রাইজ লোগো</translation>
+<translation id="7665553140559834626">&amp;Chrome OS আপডেট করতে আবার লঞ্চ করুন</translation>
 <translation id="7747138024166251722">ইনস্টলারটি অস্থায়ী ডাইরেক্টরি তৈরি করতে পারে নি৷ অনুগ্রহ করে খালি ডিস্ক স্পেশ এবং সফটওয়্যারটি ইনস্টল করার অনুমতি যাচাই করে নিন৷</translation>
 <translation id="7761834446675418963">Chrome খোলার জন্য আপনার নামের উপরে ক্লিক করুন এবং ব্রাউজ করা শুরু করুন৷</translation>
 <translation id="7777080907402804672">যদি ছবিতে প্রয়োজনীয় বিবরণ দেওয়া না থাকে, তাহলে Chrome আপনাকে একটি বিবরণ দেওয়ার চেষ্টা করবে। বিবরণ তৈরির জন্য, Google-এ ছবি পাঠানো হয়। সেটিংসে গিয়ে আপনি যেকোনও সময়ে এটি বন্ধ করতে পারেন।</translation>
diff --git a/chrome/app/resources/google_chrome_strings_ko.xtb b/chrome/app/resources/google_chrome_strings_ko.xtb
index ae81fda9..1587828 100644
--- a/chrome/app/resources/google_chrome_strings_ko.xtb
+++ b/chrome/app/resources/google_chrome_strings_ko.xtb
@@ -13,6 +13,7 @@
 <translation id="1125124144982679672">Chrome 사용자 선택</translation>
 <translation id="1142745911746664600">Chrome을 업데이트할 수 없음</translation>
 <translation id="1154147086299354128">Chrome에서 열기(&amp;O)</translation>
+<translation id="1278833599417554002">다시 실행하여 Chrome 업데이트</translation>
 <translation id="1293325835983155583">기기를 사용하기 전에 <ph name="MANAGER" />에서 다음 서비스 약관을 읽고 이에 동의해야 합니다. 이 약관은 Chrome OS 약관을 확대, 수정 또는 제한하지 않습니다.</translation>
 <translation id="1302523850133262269">Chrome에서 최신 시스템 업데이트를 설치하는 동안 잠시 기다려 주세요.</translation>
 <translation id="137466361146087520">Chrome 베타</translation>
@@ -50,6 +51,7 @@
 <translation id="2063848847527508675">업데이트를 적용하려면 Chrome OS를 다시 시작해야 합니다.</translation>
 <translation id="2094919256425865063">Chrome을 종료하시겠습니까?</translation>
 <translation id="2120620239521071941">항목 <ph name="ITEMS_COUNT" />개가 기기에서 삭제됩니다. 나중에 데이터를 가져오려면 Chrome에 <ph name="USER_EMAIL" />(으)로 로그인하세요.</translation>
+<translation id="2121284319307530122">다시 실행하여 Chrome 업데이트</translation>
 <translation id="2123055963409958220"><ph name="BEGIN_LINK" />현재 설정<ph name="END_LINK" />을 보고하여 Chrome 개선에 참여</translation>
 <translation id="2151406531797534936">지금 Chrome을 다시 시작하세요</translation>
 <translation id="2246246234298806438">기본 제공되는 PDF 뷰어가 없는 경우 Chrome에서 인쇄 미리보기를 표시할 수 없습니다.</translation>
@@ -243,6 +245,7 @@
 <translation id="7629695634924605473">비밀번호가 유출되면 Chrome에서 알려줍니다.</translation>
 <translation id="7641148173327520642">시스템 관리자가 <ph name="TARGET_URL_HOSTNAME" /> 액세스를 위해 <ph name="ALTERNATIVE_BROWSER_NAME" />을(를) 열도록 Chrome을 구성했습니다.</translation>
 <translation id="7651907282515937834">Chrome Enterprise 로고</translation>
+<translation id="7665553140559834626">다시 실행하여 Chrome OS 업데이트</translation>
 <translation id="7747138024166251722">설치 프로그램이 임시 디렉터리를 만들지 못했습니다. 디스크 공간 및 설치 권한을 확인해 보세요.</translation>
 <translation id="7761834446675418963">Chrome을 열고 탐색을 시작하려면 내 이름을 클릭하세요.</translation>
 <translation id="7777080907402804672">이미지에 유용한 설명이 없으면 Chrome에서 자동으로 설명을 제공하려고 시도합니다. 설명을 생성하기 위해 이미지가 Google로 전송됩니다. 이 기능은 언제든지 설정에서 사용 중지할 수 있습니다.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_pa.xtb b/chrome/app/resources/google_chrome_strings_pa.xtb
index 8957d58..934042b 100644
--- a/chrome/app/resources/google_chrome_strings_pa.xtb
+++ b/chrome/app/resources/google_chrome_strings_pa.xtb
@@ -13,6 +13,7 @@
 <translation id="1125124144982679672">Chrome ਕੌਣ ਵਰਤ ਰਿਹਾ ਹੈ?</translation>
 <translation id="1142745911746664600">Chrome ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ</translation>
 <translation id="1154147086299354128">&amp;Chrome ਵਿੱਚ ਖੋਲ੍ਹੋ</translation>
+<translation id="1278833599417554002">&amp;Chrome ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="1293325835983155583"><ph name="MANAGER" /> ਦੀ ਸ਼ਰਤ ਹੈ ਕਿ ਤੁਸੀਂ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਵਰਤਣ ਤੋਂ ਪਹਿਲਾਂ ਹੇਠਾਂ ਦਿੱਤੇ ਸੇਵਾ ਦੇ ਨਿਯਮ ਪੜ੍ਹ ਕੇ ਸਵੀਕਾਰ ਕਰੋ। ਇਹ ਨਿਯਮ Google Chrome OS ਦੇ ਨਿਯਮਾਂ ਦਾ ਵਿਸਤਾਰ ਨਹੀਂ ਕਰਦੇ, ਇਹਨਾਂ ਵਿੱਚ ਕੋਈ ਸੋਧ ਨਹੀਂ ਕਰਦੇ ਜਾਂ ਇਹਨਾਂ ਨੂੰ ਸੀਮਤ ਨਹੀਂ ਕਰਦੇ ਹਨ।</translation>
 <translation id="1302523850133262269">ਕਿਰਪਾ ਕਰਕੇ Chrome ਵੱਲੋਂ ਨਵੀਨਤਮ ਸਿਸਟਮ ਅੱਪਡੇਟਾਂ ਨੂੰ ਸਥਾਪਤ ਕੀਤੇ ਜਾਣ ਤੱਕ ਉਡੀਕ ਕਰੋ।</translation>
 <translation id="137466361146087520">Google Chrome ਬੀਟਾ</translation>
@@ -50,6 +51,7 @@
 <translation id="2063848847527508675">ਅੱਪਡੇਟ ਲਾਗੂ ਕਰਨ ਲਈ Chrome OS ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕੀਤੇ ਜਾਣ ਦੀ ਲੋੜ ਹੈ।</translation>
 <translation id="2094919256425865063">ਕੀ ਫਿਰ ਵੀ Chrome ਨੂੰ ਛੱਡਣਾ ਹੈ?</translation>
 <translation id="2120620239521071941">ਇਸ ਨਾਲ ਇਸ ਡੀਵਾਈਸ ਤੋਂ <ph name="ITEMS_COUNT" /> ਆਈਟਮਾਂ ਮਿਟਾ ਦਿੱਤੀਆਂ ਜਾਣਗੀਆਂ। ਬਾਅਦ ਵਿੱਚ ਆਪਣੇ ਡਾਟੇ ਨੂੰ ਮੁੜ-ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, Chrome 'ਤੇ <ph name="USER_EMAIL" /> ਵਜੋਂ ਸਾਈਨ-ਇਨ ਕਰੋ।</translation>
+<translation id="2121284319307530122">&amp;Chrome ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="2123055963409958220"><ph name="BEGIN_LINK" />ਵਰਤਮਾਨ ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਦੀ ਰਿਪੋਰਟ ਕਰਕੇ Chrome ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰੋ</translation>
 <translation id="2151406531797534936">ਕਿਰਪਾ ਕਰਕੇ ਹੁਣੇ Chrome ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ</translation>
 <translation id="2246246234298806438">ਬਿਲਟ-ਇਨ PDF ਵਿਊਅਰ ਮੌਜੂਦ ਨਾ ਹੋਣ 'ਤੇ Google Chrome ਪ੍ਰਿੰਟ ਦੀ ਪੂਰਵ-ਝਲਕ ਨਹੀਂ ਦਿਖਾ ਸਕਦਾ।</translation>
@@ -243,6 +245,7 @@
 <translation id="7629695634924605473">Chrome ਤੁਹਾਨੂੰ ਇਹ ਗੱਲ ਦੱਸਦਾ ਹੈ ਕਿ ਤੁਹਾਡੇ ਪਾਸਵਰਡਾਂ ਨਾਲ ਪਹਿਲਾਂ ਕਦੇ ਛੇੜਛਾੜ ਹੋਈ ਹੈ ਜਾਂ ਨਹੀਂ</translation>
 <translation id="7641148173327520642">ਤੁਹਾਡੇ ਸਿਸਟਮ ਪ੍ਰਸ਼ਾਸਕ ਨੇ <ph name="TARGET_URL_HOSTNAME" /> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਵਾਸਤੇ <ph name="ALTERNATIVE_BROWSER_NAME" /> ਖੋਲ੍ਹਣ ਲਈ Google Chrome ਦਾ ਸੰਰੂਪਣ ਕੀਤਾ ਹੈ।</translation>
 <translation id="7651907282515937834">Chrome Enterprise ਲੋਗੋ</translation>
+<translation id="7665553140559834626">&amp;Chrome OS ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਮੁੜ-ਲਾਂਚ ਕਰੋ</translation>
 <translation id="7747138024166251722">ਸਥਾਪਨਾਕਾਰ ਇੱਕ ਅਸਥਾਈ ਡਾਇਰੈਕਟਰੀ ਨਹੀਂ ਬਣਾ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਸਾਫ਼ਟਵੇਅਰ ਨੂੰ ਸਥਾਪਤ ਕਰਨ ਲਈ ਖਾਲੀ ਡਿਸਕ ਸਪੇਸ ਅਤੇ ਇਜਾਜ਼ਤ ਦੀ ਜਾਂਚ ਕਰੋ।</translation>
 <translation id="7761834446675418963">Chrome ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਆਪਣੇ ਨਾਮ 'ਤੇ ਕਲਿੱਕ ਕਰੋ ਅਤੇ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸ਼ੁਰੂ ਕਰੋ।</translation>
 <translation id="7777080907402804672">ਜੇ ਕਿਸੇ ਚਿੱਤਰ ਦਾ ਲਾਭਕਾਰੀ ਵਰਣਨ ਨਹੀਂ ਹੈ, ਤਾਂ Chrome ਤੁਹਾਡੇ ਲਈ ਇੱਕ ਵਰਣਨ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਵਰਣਨ ਬਣਾਉਣ ਲਈ, ਚਿੱਤਰ Google ਨੂੰ ਭੇਜੇ ਜਾਂਦੇ ਹਨ। ਤੁਸੀਂ ਕਿਸੇ ਵੇਲੇ ਵੀ ਇਸਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬੰਦ ਕਰ ਸਕਦੇ ਹੋ।</translation>
diff --git a/chrome/app/resources/google_chrome_strings_sq.xtb b/chrome/app/resources/google_chrome_strings_sq.xtb
index 1eb7cff2..c0e9a3ab 100644
--- a/chrome/app/resources/google_chrome_strings_sq.xtb
+++ b/chrome/app/resources/google_chrome_strings_sq.xtb
@@ -13,6 +13,7 @@
 <translation id="1125124144982679672">Kush po e përdor Chrome?</translation>
 <translation id="1142745911746664600">Chrome nuk mund të përditësohet</translation>
 <translation id="1154147086299354128">&amp;Hape në Chrome</translation>
+<translation id="1278833599417554002">Nise përsëri për të përditësuar &amp;Chrome</translation>
 <translation id="1293325835983155583"><ph name="MANAGER" /> kërkon që të lexosh dhe të pranosh Kushtet e shërbimit më poshtë para se ta përdorësh këtë pajisje. Këto kushte nuk i zgjerojnë, modifikojnë apo kufizojnë kushtet e sistemit operativ të Google Chrome.</translation>
 <translation id="1302523850133262269">Prit ndërsa Chrome instalon përditësimet më të fundit të sistemit.</translation>
 <translation id="137466361146087520">Google Chrome Beta</translation>
@@ -49,6 +50,7 @@
 <translation id="2063848847527508675">Chrome OS ka nevojë të riniset për të zbatuar përditësimin.</translation>
 <translation id="2094919256425865063">Dëshiron ta mbyllësh Chrome gjithsesi?</translation>
 <translation id="2120620239521071941">Kjo do të fshijë <ph name="ITEMS_COUNT" /> artikuj nga kjo pajisje. Për t'i marrë më vonë të dhënat, identifikohu te Chrome si <ph name="USER_EMAIL" />.</translation>
+<translation id="2121284319307530122">Nise përsëri për të përditësuar &amp;Chrome</translation>
 <translation id="2123055963409958220">Ndihmo në përmirësimin e Chrome duke raportuar <ph name="BEGIN_LINK" />cilësimet aktuale<ph name="END_LINK" /></translation>
 <translation id="2151406531797534936">Rinise Chrome tani</translation>
 <translation id="2246246234298806438">Google Chrome nuk mund ta tregojë afishimin paraprak të printimit kur mungon shikuesi i integruar për PDF-të.</translation>
@@ -242,6 +244,7 @@
 <translation id="7629695634924605473">Chrome të informon nëse fjalëkalimet e tua komprometohen ndonjëherë</translation>
 <translation id="7641148173327520642">Administratori i sistemit ka konfiguruar Google Chrome që të hapë <ph name="ALTERNATIVE_BROWSER_NAME" /> për t'u qasur te <ph name="TARGET_URL_HOSTNAME" />.</translation>
 <translation id="7651907282515937834">Logoja e Chrome Enterprise</translation>
+<translation id="7665553140559834626">Nise përsëri për të përditësuar &amp;Chrome OS</translation>
 <translation id="7747138024166251722">Instaluesi nuk mund të krijonte një direktori të përkohshme. Kontrollo për hapësirë të lirë në disk dhe për lejen për të instaluar softuerin.</translation>
 <translation id="7761834446675418963">Kliko tek emri yt për të hapur Chrome dhe fillo shfletimin.</translation>
 <translation id="7777080907402804672">Nëse një imazh nuk ka një përshkrim të dobishëm, Chrome do të përpiqet të të japë një përshkrim. Për të krijuar përshkrime, imazhet dërgohen te Google. Këtë mund ta çaktivizosh te cilësimet në çdo moment.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_te.xtb b/chrome/app/resources/google_chrome_strings_te.xtb
index f3de9a5..8aedc5ae 100644
--- a/chrome/app/resources/google_chrome_strings_te.xtb
+++ b/chrome/app/resources/google_chrome_strings_te.xtb
@@ -11,6 +11,7 @@
 <translation id="1125124144982679672">Chromeను ఎవరు ఉపయోగిస్తున్నారు?</translation>
 <translation id="1142745911746664600">Chromeను అప్‌డేట్ చేయడం సాధ్యం కాదు</translation>
 <translation id="1154147086299354128">&amp;Chromeలో తెరువు</translation>
+<translation id="1278833599417554002">&amp;Chromeను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="1293325835983155583"><ph name="MANAGER" /> కోసం ఈ పరికరాన్ని ఉపయోగించడానికి ముందు కింది సర్వీస్ నియమాలను మీరు చదివి, అంగీకరించాలి. ఈ నియమాలు Google Chrome OS నియమాలను విస్తరింపజేయవు, సవరించవు లేదా పరిమితం చేయవు.</translation>
 <translation id="1302523850133262269">దయచేసి Chrome తాజా సిస్టమ్ నవీకరణలను ఇన్‌స్టాల్ చేస్తున్నప్పుడు వేచి ఉండండి.</translation>
 <translation id="137466361146087520">Google Chrome బీటా</translation>
@@ -46,6 +47,7 @@
 <translation id="2063848847527508675">అప్‌డేట్‌ను వర్తింపజేయడానికి Chrome OSను పునఃప్రారంభించాలి.</translation>
 <translation id="2094919256425865063">ఏదేమైనా Chromeని మూసివేయాలా?</translation>
 <translation id="2120620239521071941">ఇది ఈ పరికరం నుండి <ph name="ITEMS_COUNT" /> అంశాలను తొలగిస్తుంది. మీ డేటాను తర్వాత తిరిగి పొందడానికి, Chromeకు <ph name="USER_EMAIL" /> లాగా సైన్ ఇన్ చేయండి.</translation>
+<translation id="2121284319307530122">&amp;Chromeను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="2123055963409958220">Chromeను మెరుగుపరచడంలో సహాయపడటానికి <ph name="BEGIN_LINK" />ప్రస్తుత సెట్టింగ్‌లను<ph name="END_LINK" /> రిపోర్ట్ చేయండి</translation>
 <translation id="2151406531797534936">దయచేసి Chromeను ఇప్పుడే మళ్ళీ ప్రారంభించండి</translation>
 <translation id="2246246234298806438">అంతర్గత PDF వ్యూవర్ లేనప్పుడు Google Chrome ముద్రణ ప్రివ్యూను చూపించదు.</translation>
@@ -235,6 +237,7 @@
 <translation id="7629695634924605473">మీ పాస్‌వర్డ్‌లు ఎప్పుడైనా హ్యాక్ అయితే, Chrome మీకు తెలియచేస్తుంది</translation>
 <translation id="7641148173327520642"><ph name="TARGET_URL_HOSTNAME" />ను యాక్సెస్ చేయడం కోసం <ph name="ALTERNATIVE_BROWSER_NAME" />ను తెరిచే విధంగా Google Chromeను మీ సిస్టమ్ నిర్వాహకుడు కాన్ఫిగర్ చేసారు.</translation>
 <translation id="7651907282515937834">Chrome ఎంటర్‌ప్రైజ్ లోగో</translation>
+<translation id="7665553140559834626">&amp;Chrome OSను అప్‌డేట్ చేయడానికి రీ-లాంచ్ చేయండి</translation>
 <translation id="7747138024166251722">ఇన్‌స్టాలర్ ఒక తాత్కాలిక డైరక్టరీని సృష్టించలేకపోయింది. సాఫ్ట్‌వేర్‌ను ఇన్‌స్టాల్ చేయడానికి దయచేసి ఖాళీ డిస్క్ స్థలం, అనుమతిని తనిఖీ చేయండి.</translation>
 <translation id="7761834446675418963">Chromeను తెరిచి, బ్రౌజింగ్‌ను ప్రారంభించడానికి మీ పేరును క్లిక్ చేయండి.</translation>
 <translation id="7777080907402804672">చిత్రంలో ఉపయోగకరమైన వివరణ లేకుంటే, మీ కోసం ఒక వివరణను అందించడానికి Chrome ప్రయత్నిస్తుంది. వివరణలను సృష్టించడానికి, చిత్రాలు Googleకు పంపబడతాయి. మీరు దీన్ని ఎప్పుడైనా సెట్టింగ్‌లలో ఆఫ్ చేయవచ్చు.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_vi.xtb b/chrome/app/resources/google_chrome_strings_vi.xtb
index dedef27..1a85258 100644
--- a/chrome/app/resources/google_chrome_strings_vi.xtb
+++ b/chrome/app/resources/google_chrome_strings_vi.xtb
@@ -11,6 +11,7 @@
 <translation id="1125124144982679672">Ai đang sử dụng Chrome?</translation>
 <translation id="1142745911746664600">Không thể cập nhật Chrome</translation>
 <translation id="1154147086299354128">&amp;Mở trong Chrome</translation>
+<translation id="1278833599417554002">Chạy lại để cập nhật &amp;Chrome</translation>
 <translation id="1293325835983155583"><ph name="MANAGER" /> yêu cầu bạn phải đọc và chấp nhận Điều khoản dịch vụ sau đây trước khi sử dụng thiết bị này. Những điều khoản này không mở rộng, sửa đổi hoặc giới hạn Điều khoản của Google Chrome OS.</translation>
 <translation id="1302523850133262269">Vui lòng đợi khi Chrome cài đặt các bản cập nhật hệ thống mới nhất.</translation>
 <translation id="137466361146087520">Google Chrome Beta</translation>
@@ -48,6 +49,7 @@
 <translation id="2063848847527508675">Chrome OS cần được khởi động lại để áp dụng bản cập nhật.</translation>
 <translation id="2094919256425865063">Bạn vẫn muốn thoát khỏi Chrome?</translation>
 <translation id="2120620239521071941">Thao tác này sẽ xóa <ph name="ITEMS_COUNT" /> mục khỏi thiết bị này. Để truy xuất dữ liệu của bạn sau, hãy đăng nhập vào Chrome dưới dạng <ph name="USER_EMAIL" />.</translation>
+<translation id="2121284319307530122">Chạy lại để cập nhật &amp;Chrome</translation>
 <translation id="2123055963409958220">Giúp cải thiện Chrome bằng cách báo cáo <ph name="BEGIN_LINK" />cài đặt hiện tại<ph name="END_LINK" /></translation>
 <translation id="2151406531797534936">Vui lòng khởi động lại Chrome ngay bây giờ</translation>
 <translation id="2246246234298806438">Google Chrome không thể hiển thị xem trước bản in khi thiếu trình xem PDF được cài sẵn.</translation>
@@ -239,6 +241,7 @@
 <translation id="7629695634924605473">Chrome cho bạn biết mật khẩu của bạn có bị đánh cắp hay không</translation>
 <translation id="7641148173327520642">Quản trị viên hệ thống đã định cấu hình Google Chrome để mở <ph name="ALTERNATIVE_BROWSER_NAME" /> khi truy cập vào <ph name="TARGET_URL_HOSTNAME" />.</translation>
 <translation id="7651907282515937834">Biểu trưng Chrome Enterprise</translation>
+<translation id="7665553140559834626">Chạy lại để cập nhật &amp;Chrome OS</translation>
 <translation id="7747138024166251722">Trình cài đặt không thể tạo thư mục tạm thời. Vui lòng kiểm tra dung lượng ổ đĩa còn trống và quyền cài đặt phần mềm.</translation>
 <translation id="7761834446675418963">Nhấp vào tên của bạn để mở Chrome và bắt đầu duyệt web.</translation>
 <translation id="7777080907402804672">Chrome sẽ cố gắng mô tả cho bạn những hình ảnh không có nội dung mô tả hữu ích. Để tạo nội dung mô tả, các hình ảnh sẽ được gửi đến Google. Bạn có thể tắt dịch vụ này trong phần cài đặt bất kỳ lúc nào.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_zh-TW.xtb b/chrome/app/resources/google_chrome_strings_zh-TW.xtb
index 832228e..74423ab 100644
--- a/chrome/app/resources/google_chrome_strings_zh-TW.xtb
+++ b/chrome/app/resources/google_chrome_strings_zh-TW.xtb
@@ -11,6 +11,7 @@
 <translation id="1125124144982679672">誰在使用 Chrome?</translation>
 <translation id="1142745911746664600">無法更新 Chrome</translation>
 <translation id="1154147086299354128">在 Chrome 中開啟(&amp;O)</translation>
+<translation id="1278833599417554002">重新啟動以更新 &amp;Chrome</translation>
 <translation id="1293325835983155583">根據 <ph name="MANAGER" /> 的規定,您必須先詳閱並接受下列《服務條款》,才能使用這部裝置。這些條款不會擴充、修改或限制《Google Chrome 作業系統條款》。</translation>
 <translation id="1302523850133262269">請稍候,Chrome 正在安裝最新的系統更新。</translation>
 <translation id="137466361146087520">Google Chrome 測試版</translation>
@@ -45,6 +46,7 @@
 <translation id="2063848847527508675">Chrome 作業系統必須重新啟動,才能套用更新。</translation>
 <translation id="2094919256425865063">確定要關閉 Chrome 嗎?</translation>
 <translation id="2120620239521071941">登出後,系統會將 <ph name="ITEMS_COUNT" /> 個項目從這個裝置上刪除。日後如要重新取得你的資料,請以 <ph name="USER_EMAIL" /> 身分登入 Chrome。</translation>
+<translation id="2121284319307530122">重新啟動以更新 &amp;Chrome</translation>
 <translation id="2123055963409958220">只要回報<ph name="BEGIN_LINK" />目前的設定<ph name="END_LINK" />,就能助我們一臂之力,讓 Chrome 更臻完美</translation>
 <translation id="2151406531797534936">請立即重新啟動 Chrome</translation>
 <translation id="2246246234298806438">缺乏內建的 PDF 檢視器時,Google Chrome 無法顯示列印預覽。</translation>
@@ -236,6 +238,7 @@
 <translation id="7629695634924605473">Chrome 會通知你密碼是否曾遭外洩</translation>
 <translation id="7641148173327520642">你的系統管理員已設定由 Google Chrome 開啟 <ph name="ALTERNATIVE_BROWSER_NAME" /> 以存取 <ph name="TARGET_URL_HOSTNAME" />。</translation>
 <translation id="7651907282515937834">Chrome Enterprise 標誌</translation>
+<translation id="7665553140559834626">重新啟動以更新 &amp;Chrome 作業系統</translation>
 <translation id="7747138024166251722">安裝程式無法建立暫時目錄,請檢查可用磁碟空間與權限,以順利安裝軟體。</translation>
 <translation id="7761834446675418963">按一下你的名稱即可開啟 Chrome 並開始瀏覽。</translation>
 <translation id="7777080907402804672">如果圖片缺少有用的說明,Chrome 會嘗試為你提供說明。系統會將圖片傳送給 Google,以便產生說明。你隨時可以在設定中關閉這項功能。</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 580dd0e..490d97c3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -96,6 +96,7 @@
     "ENABLE_CHROMIUM_UPDATER=$enable_chromium_updater",
     "ENABLE_APP_SESSION_SERVICE=$enable_app_session_service",
     "USE_THIN_LTO=$use_thin_lto",
+    "ENABLE_PAK_FILE_INTEGRITY_CHECKS=$enable_pak_file_integrity_checks",
   ]
   if (is_win) {
     flags += [ "ENABLE_SEGMENT_HEAP=$enable_segment_heap" ]
@@ -1525,8 +1526,6 @@
     "sessions/restore_on_startup_policy_handler.h",
     "sessions/session_common_utils.cc",
     "sessions/session_common_utils.h",
-    "sessions/session_data_deleter.cc",
-    "sessions/session_data_deleter.h",
     "sessions/session_tab_helper_factory.cc",
     "sessions/session_tab_helper_factory.h",
     "sessions/tab_restore_service_factory.cc",
@@ -3895,6 +3894,8 @@
       "resource_coordinator/tab_metrics_logger.h",
       "resource_coordinator/usage_clock.cc",
       "resource_coordinator/usage_clock.h",
+      "resources_integrity.cc",
+      "resources_integrity.h",
       "safe_browsing/generated_safe_browsing_pref.cc",
       "safe_browsing/generated_safe_browsing_pref.h",
       "search/background/ntp_background_data.cc",
@@ -4261,6 +4262,10 @@
       ]
     }
 
+    if (enable_pak_file_integrity_checks) {
+      deps += [ "//chrome:packed_resources_integrity" ]
+    }
+
     if (is_posix || is_fuchsia) {
       sources += [
         "chrome_browser_main_posix.cc",
@@ -4335,6 +4340,8 @@
       "apps/app_service/webapk/webapk_install_task.h",
       "apps/app_service/webapk/webapk_manager.cc",
       "apps/app_service/webapk/webapk_manager.h",
+      "apps/app_service/webapk/webapk_prefs.cc",
+      "apps/app_service/webapk/webapk_prefs.h",
       "apps/icon_standardizer.cc",
       "apps/icon_standardizer.h",
       "browser_process_platform_part_chromeos.cc",
@@ -6237,6 +6244,8 @@
 
   if (enable_session_service) {
     sources += [
+      "sessions/session_data_deleter.cc",
+      "sessions/session_data_deleter.h",
       "sessions/session_data_service.cc",
       "sessions/session_data_service.h",
       "sessions/session_data_service_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 66df7184..66483d86 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3419,6 +3419,13 @@
      flag_descriptions::kBypassAppBannerEngagementChecksDescription, kOsAll,
      SINGLE_VALUE_TYPE(webapps::switches::kBypassAppBannerEngagementChecks)},
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+    {"allow-default-web-app-migration-for-chrome-os-managed-users",
+     flag_descriptions::kAllowDefaultWebAppMigrationForChromeOsManagedUsersName,
+     flag_descriptions::
+         kAllowDefaultWebAppMigrationForChromeOsManagedUsersDescription,
+     kOsCrOS,
+     FEATURE_VALUE_TYPE(
+         web_app::kAllowDefaultWebAppMigrationForChromeOsManagedUsers)},
     {"enable-default-chat-web-app", flag_descriptions::kDefaultChatWebAppName,
      flag_descriptions::kDefaultChatWebAppDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(web_app::kDefaultChatWebApp)},
@@ -3784,6 +3791,9 @@
     {"offlining-recent-pages", flag_descriptions::kOffliningRecentPagesName,
      flag_descriptions::kOffliningRecentPagesDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(offline_pages::kOffliningRecentPagesFeature)},
+    {"offline-pages-ct", flag_descriptions::kOfflinePagesCtName,
+     flag_descriptions::kOfflinePagesCtDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(offline_pages::kOfflinePagesCTFeature)},
     {"offline-pages-ct-v2", flag_descriptions::kOfflinePagesCtV2Name,
      flag_descriptions::kOfflinePagesCtV2Description, kOsAndroid,
      FEATURE_VALUE_TYPE(offline_pages::kOfflinePagesCTV2Feature)},
diff --git a/chrome/browser/android/autofill_assistant/starter_android.cc b/chrome/browser/android/autofill_assistant/starter_android.cc
index eb782c5..426c691 100644
--- a/chrome/browser/android/autofill_assistant/starter_android.cc
+++ b/chrome/browser/android/autofill_assistant/starter_android.cc
@@ -7,6 +7,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/time/default_tick_clock.h"
 #include "chrome/android/features/autofill_assistant/jni_headers/AssistantDependenciesImpl_jni.h"
 #include "chrome/android/features/autofill_assistant/jni_headers/AutofillAssistantServiceInjector_jni.h"
 #include "chrome/android/features/autofill_assistant/jni_headers_public/Starter_jni.h"
@@ -51,7 +52,8 @@
 
   starter_ = std::make_unique<Starter>(
       web_contents_, this, ukm::UkmRecorder::Get(),
-      RuntimeManagerImpl::GetForWebContents(web_contents_)->GetWeakPtr());
+      RuntimeManagerImpl::GetForWebContents(web_contents_)->GetWeakPtr(),
+      base::DefaultTickClock::GetInstance());
 }
 
 void StarterAndroid::Detach(JNIEnv* env, const JavaParamRef<jobject>& jcaller) {
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
index 53837a1..ade81732 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
+++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
@@ -48,9 +48,9 @@
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       decider_(OomInterventionDecider::GetForBrowserContext(
-          web_contents->GetBrowserContext())),
-      scoped_observer_(this) {
-  scoped_observer_.Add(crash_reporter::CrashMetricsReporter::GetInstance());
+          web_contents->GetBrowserContext())) {
+  scoped_observation_.Observe(
+      crash_reporter::CrashMetricsReporter::GetInstance());
 }
 
 OomInterventionTabHelper::~OomInterventionTabHelper() = default;
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
index dc22483c..631e4c6 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
+++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
@@ -8,7 +8,7 @@
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/android/oom_intervention/near_oom_monitor.h"
@@ -121,9 +121,9 @@
   base::TimeTicks last_navigation_timestamp_;
   base::TimeTicks start_monitor_timestamp_;
 
-  ScopedObserver<crash_reporter::CrashMetricsReporter,
-                 crash_reporter::CrashMetricsReporter::Observer>
-      scoped_observer_;
+  base::ScopedObservation<crash_reporter::CrashMetricsReporter,
+                          crash_reporter::CrashMetricsReporter::Observer>
+      scoped_observation_{this};
 
   base::WeakPtrFactory<OomInterventionTabHelper> weak_ptr_factory_{this};
   WEB_CONTENTS_USER_DATA_KEY_DECL();
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index 3b7adff..8d70c43 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -277,13 +277,6 @@
   return domain;
 }
 
-void SigninManagerAndroid::
-    LogOutAllAccountsForMobileIdentityConsistencyRollback(JNIEnv* env) {
-  identity_manager_->GetAccountsCookieMutator()->LogOutAllAccounts(
-      gaia::GaiaSource::kAccountReconcilorMirror,
-      base::DoNothing::Once<const GoogleServiceAuthError&>());
-}
-
 void SigninManagerAndroid::WipeProfileData(
     JNIEnv* env,
     const JavaParamRef<jobject>& j_callback) {
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index 9ac6015..45119b1 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -74,10 +74,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& j_callback);
 
-  // Logs out all Google accounts on the web as a part of the rollback flow.
-  // TODO(https://crbug.com/1065029): Remove this along with the feature flag.
-  void LogOutAllAccountsForMobileIdentityConsistencyRollback(JNIEnv* env);
-
  private:
   friend class SigninManagerAndroidTest;
   FRIEND_TEST_ALL_PREFIXES(SigninManagerAndroidTest,
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 417816a..da9d1bfb9 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -1521,8 +1521,8 @@
   if (!profile)
     return nullptr;
 
-  // Guest sessions must always be OffTheRecord. Use that when opening windows.
-  if (profile->IsGuestSession())
+  // When opening a Guest session or if incognito is forced.
+  if (ProfileManager::IsOffTheRecordModeForced(profile))
     return profile->GetPrimaryOTRProfile(/*create_if_needed=*/true);
 
   return profile;
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index dbcec3a..bb7bf7c 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -30,6 +30,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_init_params.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
@@ -917,6 +918,37 @@
   EXPECT_EQ(profile1_submenu, [ac bookmarkMenuBridge]->BookmarkMenu());
 }
 
+// Tests opening a new window from a browser command while incognito is forced.
+// Regression test for https://crbug.com/1206726
+IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
+                       ForcedIncognito_NewWindow) {
+  EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
+  // Close the current non-incognito browser.
+  Profile* profile = browser()->profile();
+  chrome::CloseAllBrowsers();
+  ui_test_utils::WaitForBrowserToClose();
+  EXPECT_TRUE(BrowserList::GetInstance()->empty());
+  // Force incognito mode.
+  IncognitoModePrefs::SetAvailability(profile->GetPrefs(),
+                                      IncognitoModePrefs::FORCED);
+  // Simulate click on "New window".
+  ui_test_utils::BrowserChangeObserver browser_added_observer(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+  NSMenu* menu = [ac applicationDockMenu:NSApp];
+  ASSERT_TRUE(menu);
+  NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
+  ASSERT_TRUE(item);
+  [ac commandDispatch:item];
+  // Check that a new incognito browser is opened.
+  Browser* new_browser = browser_added_observer.Wait();
+  EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
+  EXPECT_TRUE(new_browser->profile()->IsPrimaryOTRProfile());
+  EXPECT_EQ(profile, new_browser->profile()->GetOriginalProfile());
+}
+
 }  // namespace
 
 //--------------------------AppControllerHandoffBrowserTest---------------------
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_queue.cc b/chrome/browser/apps/app_service/webapk/webapk_install_queue.cc
index 897c7dd..0defa70b 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_install_queue.cc
+++ b/chrome/browser/apps/app_service/webapk/webapk_install_queue.cc
@@ -73,4 +73,15 @@
   connection_ready_ = false;
 }
 
+std::unique_ptr<WebApkInstallTask> WebApkInstallQueue::PopTaskForTest() {
+  DCHECK(!current_install_);
+  std::unique_ptr<WebApkInstallTask> task;
+  if (!pending_installs_.empty()) {
+    task = std::move(pending_installs_.front());
+    pending_installs_.pop_front();
+  }
+
+  return task;
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_queue.h b/chrome/browser/apps/app_service/webapk/webapk_install_queue.h
index c2057294..682cde8 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_install_queue.h
+++ b/chrome/browser/apps/app_service/webapk/webapk_install_queue.h
@@ -34,6 +34,8 @@
   void OnConnectionReady() override;
   void OnConnectionClosed() override;
 
+  std::unique_ptr<WebApkInstallTask> PopTaskForTest();
+
  private:
   void PostMaybeStartNext();
   void MaybeStartNext();
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_task.cc b/chrome/browser/apps/app_service/webapk/webapk_install_task.cc
index 8e7af4b..070706c3 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_install_task.cc
+++ b/chrome/browser/apps/app_service/webapk/webapk_install_task.cc
@@ -16,6 +16,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_restrictions.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
@@ -311,7 +312,13 @@
     ResultCallback callback,
     arc::mojom::WebApkInstallResult result) {
   VLOG(1) << "WebAPK installation finished with result " << result;
-  std::move(callback).Run(result == arc::mojom::WebApkInstallResult::kSuccess);
+
+  bool success = result == arc::mojom::WebApkInstallResult::kSuccess;
+  if (success) {
+    webapk_prefs::AddWebApk(profile_, app_id_, package_name);
+  }
+
+  std::move(callback).Run(success);
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_task.h b/chrome/browser/apps/app_service/webapk/webapk_install_task.h
index d822283..6b4d1a64 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_install_task.h
+++ b/chrome/browser/apps/app_service/webapk/webapk_install_task.h
@@ -42,6 +42,8 @@
 
   void Start(ResultCallback callback);
 
+  const std::string& app_id() { return app_id_; }
+
  private:
   void OnLoadedIcon(std::unique_ptr<webapk::WebApk> webapk,
                     ResultCallback callback,
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc b/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc
index be2a99d7..7f6c39c 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc
+++ b/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/test/bind.h"
 #include "chrome/browser/apps/app_service/app_service_test.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
@@ -198,6 +199,13 @@
   ASSERT_EQ(fake_webapk_instance()->handled_packages().size(), 1);
   ASSERT_EQ(fake_webapk_instance()->handled_packages()[0],
             "org.chromium.webapk.some_package");
+
+  base::flat_set<std::string> installed_webapks =
+      apps::webapk_prefs::GetWebApkAppIds(profile());
+  ASSERT_EQ(installed_webapks.size(), 1);
+  ASSERT_TRUE(installed_webapks.contains(app_id));
+  ASSERT_EQ(*apps::webapk_prefs::GetWebApkPackageName(profile(), app_id),
+            "org.chromium.webapk.some_package");
 }
 
 TEST_F(WebApkInstallTaskTest, ShareTarget) {
@@ -246,6 +254,7 @@
   auto app_id = web_app::test::InstallWebApp(profile(), std::move(app_info));
 
   ASSERT_FALSE(InstallWebApk(app_id));
+  ASSERT_EQ(apps::webapk_prefs::GetWebApkAppIds(profile()).size(), 0);
 }
 
 TEST_F(WebApkInstallTaskTest, FailedServerCall) {
@@ -257,6 +266,7 @@
   ASSERT_FALSE(InstallWebApk(app_id));
 
   ASSERT_EQ(fake_webapk_instance()->handled_packages().size(), 0);
+  ASSERT_EQ(apps::webapk_prefs::GetWebApkAppIds(profile()).size(), 0);
 }
 
 TEST_F(WebApkInstallTaskTest, FailedArcInstall) {
@@ -271,4 +281,5 @@
   ASSERT_FALSE(InstallWebApk(app_id));
   ASSERT_EQ(fake_webapk_instance()->handled_packages()[0],
             "org.chromium.webapk.some_package");
+  ASSERT_EQ(apps::webapk_prefs::GetWebApkAppIds(profile()).size(), 0);
 }
diff --git a/chrome/browser/apps/app_service/webapk/webapk_manager.cc b/chrome/browser/apps/app_service/webapk/webapk_manager.cc
index af4d0331..5c14e8ea 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_manager.cc
+++ b/chrome/browser/apps/app_service/webapk/webapk_manager.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/webapk/webapk_install_queue.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_prefs.h"
 #include "chrome/browser/ash/apps/apk_web_app_service.h"
-#include "chrome/browser/ash/apps/apk_web_app_service_factory.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
@@ -23,9 +23,10 @@
 WebApkManager::WebApkManager(Profile* profile)
     : profile_(profile),
       web_app_registrar_(
-          web_app::WebAppProviderBase::GetProviderBase(profile)->registrar()) {
+          web_app::WebAppProviderBase::GetProviderBase(profile)->registrar()),
+      initialized_(false) {
   proxy_ = apps::AppServiceProxyFactory::GetForProfile(profile);
-  apk_service_ = ash::ApkWebAppServiceFactory::GetForProfile(profile_);
+  apk_service_ = ash::ApkWebAppService::Get(profile_);
   DCHECK(apk_service_);
   install_queue_ = std::make_unique<WebApkInstallQueue>(profile);
 
@@ -35,17 +36,33 @@
 WebApkManager::~WebApkManager() = default;
 
 void WebApkManager::OnAppUpdate(const AppUpdate& update) {
-  // TODO(crbug.com/1198433): Observe new installations and updates.
+  // TODO(crbug.com/119433): Install WebAPKs for existing apps which become
+  // eligible, and update existing WebAPKs when app metadata changes.
+  if (!initialized_) {
+    return;
+  }
+
+  // Install new WebAPKs when an eligible app is installed. Note that it
+  // generally shouldn't be possible to have an existing WebAPK installed while
+  // StateIsNull, but we include the check for completeness' sake.
+  if (update.StateIsNull() && IsAppEligibleForWebApk(update) &&
+      !apps::webapk_prefs::GetWebApkPackageName(profile_, update.AppId())) {
+    QueueInstall(update);
+    return;
+  }
 }
 
 void WebApkManager::OnAppTypeInitialized(apps::mojom::AppType type) {
   if (type == apps::mojom::AppType::kWeb) {
-    proxy_->AppRegistryCache().ForEachApp(
-        [this](const apps::AppUpdate& update) {
-          if (IsAppEligibleForWebApk(update)) {
-            QueueInstall(update);
-          }
-        });
+    initialized_ = true;
+
+    // Install any WebAPK which should be installed but currently isn't.
+    proxy_->AppRegistryCache().ForEachApp([&](const apps::AppUpdate& update) {
+      if (IsAppEligibleForWebApk(update) &&
+          !apps::webapk_prefs::GetWebApkPackageName(profile_, update.AppId())) {
+        QueueInstall(update);
+      }
+    });
   }
 }
 
@@ -54,6 +71,10 @@
   Observe(nullptr);
 }
 
+apps::WebApkInstallQueue* WebApkManager::GetInstallQueueForTest() {
+  return install_queue_.get();
+}
+
 bool WebApkManager::IsAppEligibleForWebApk(const apps::AppUpdate& app) {
   if (app.AppType() != apps::mojom::AppType::kWeb) {
     return false;
diff --git a/chrome/browser/apps/app_service/webapk/webapk_manager.h b/chrome/browser/apps/app_service/webapk/webapk_manager.h
index 2b1b19b..0b0c003 100644
--- a/chrome/browser/apps/app_service/webapk/webapk_manager.h
+++ b/chrome/browser/apps/app_service/webapk/webapk_manager.h
@@ -34,15 +34,19 @@
   void OnAppRegistryCacheWillBeDestroyed(
       apps::AppRegistryCache* cache) override;
 
+  apps::WebApkInstallQueue* GetInstallQueueForTest();
+
  private:
   bool IsAppEligibleForWebApk(const apps::AppUpdate& app);
-  void QueueInstall(const AppUpdate& update);
+  void QueueInstall(const apps::AppUpdate& update);
 
   Profile* profile_;
   apps::AppServiceProxyBase* proxy_;
   ash::ApkWebAppService* apk_service_;
   web_app::AppRegistrar& web_app_registrar_;
 
+  bool initialized_;
+
   std::unique_ptr<apps::WebApkInstallQueue> install_queue_;
 };
 
diff --git a/chrome/browser/apps/app_service/webapk/webapk_manager_unittest.cc b/chrome/browser/apps/app_service/webapk/webapk_manager_unittest.cc
new file mode 100644
index 0000000..7f40d3f
--- /dev/null
+++ b/chrome/browser/apps/app_service/webapk/webapk_manager_unittest.cc
@@ -0,0 +1,157 @@
+// 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/apps/app_service/webapk/webapk_manager.h"
+
+#include <memory>
+
+#include "base/strings/strcat.h"
+#include "chrome/browser/apps/app_service/app_service_test.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_install_queue.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_install_task.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
+#include "chrome/browser/web_applications/test/test_web_app_provider.h"
+#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kTestAppUrl[] = "https://www.example.com/";
+constexpr char kTestAppActionUrl[] = "https://www.example.com/share";
+constexpr char kTestManifestUrl[] = "https://www.example.com/manifest.json";
+constexpr char kTestShareTextParam[] = "share_text";
+const std::u16string kTestAppTitle = u"Test App";
+
+std::unique_ptr<WebApplicationInfo> BuildDefaultWebAppInfo() {
+  auto app_info = std::make_unique<WebApplicationInfo>();
+  app_info->start_url = GURL(kTestAppUrl);
+  app_info->scope = GURL(kTestAppUrl);
+  app_info->title = kTestAppTitle;
+  app_info->manifest_url = GURL(kTestManifestUrl);
+
+  apps::ShareTarget target;
+  target.action = GURL(kTestAppActionUrl);
+  target.method = apps::ShareTarget::Method::kPost;
+  target.enctype = apps::ShareTarget::Enctype::kMultipartFormData;
+  target.params.text = kTestShareTextParam;
+  app_info->share_target = target;
+
+  return app_info;
+}
+
+}  // namespace
+
+class WebApkManagerTest : public testing::Test {
+ public:
+  WebApkManagerTest() = default;
+
+  void SetUp() override {
+    testing::Test::SetUp();
+
+    extensions::TestExtensionSystem* extension_system(
+        static_cast<extensions::TestExtensionSystem*>(
+            extensions::ExtensionSystem::Get(&profile_)));
+    extension_service_ = extension_system->CreateExtensionService(
+        base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
+    extension_service_->Init();
+
+    arc_test_.SetUp(&profile_);
+
+    auto* const provider = web_app::TestWebAppProvider::Get(profile());
+    provider->SetRunSubsystemStartupTasks(true);
+    provider->Start();
+  }
+
+  void StartWebApkManager() {
+    app_service_test_.SetUp(&profile_);
+    app_service_test_.FlushMojoCalls();
+    webapk_manager_ = std::make_unique<apps::WebApkManager>(profile());
+  }
+
+  void AssertNoPendingInstalls() {
+    ASSERT_FALSE(webapk_manager()->GetInstallQueueForTest()->PopTaskForTest());
+  }
+
+  TestingProfile* profile() { return &profile_; }
+  apps::AppServiceTest* app_service_test() { return &app_service_test_; }
+  apps::WebApkManager* webapk_manager() { return webapk_manager_.get(); }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+  ArcAppTest arc_test_;
+  apps::AppServiceTest app_service_test_;
+  extensions::ExtensionService* extension_service_ = nullptr;
+
+  std::unique_ptr<apps::WebApkManager> webapk_manager_;
+};
+
+TEST_F(WebApkManagerTest, InstallsWebApkOnStartup) {
+  auto app_id =
+      web_app::test::InstallWebApp(profile(), BuildDefaultWebAppInfo());
+
+  StartWebApkManager();
+
+  auto install_task =
+      webapk_manager()->GetInstallQueueForTest()->PopTaskForTest();
+  ASSERT_TRUE(install_task);
+  ASSERT_EQ(install_task->app_id(), app_id);
+  AssertNoPendingInstalls();
+}
+
+TEST_F(WebApkManagerTest, InstallWebApkAfterStartup) {
+  StartWebApkManager();
+  AssertNoPendingInstalls();
+
+  auto app_id =
+      web_app::test::InstallWebApp(profile(), BuildDefaultWebAppInfo());
+  app_service_test()->FlushMojoCalls();
+
+  auto install_task =
+      webapk_manager()->GetInstallQueueForTest()->PopTaskForTest();
+  ASSERT_TRUE(install_task);
+  ASSERT_EQ(install_task->app_id(), app_id);
+  AssertNoPendingInstalls();
+}
+
+// Does not install web apps without a Share Target definition.
+TEST_F(WebApkManagerTest, NoShareTarget) {
+  auto app_info = std::make_unique<WebApplicationInfo>();
+  app_info->start_url = GURL(kTestAppUrl);
+  app_info->title = kTestAppTitle;
+  auto app_id = web_app::test::InstallWebApp(profile(), std::move(app_info));
+
+  StartWebApkManager();
+
+  AssertNoPendingInstalls();
+}
+
+// When two eligible apps are available during startup, but one of them already
+// has a WebAPK installed, only install a new WebAPK for the other app.
+TEST_F(WebApkManagerTest, IgnoresAlreadyInstalledWebApkOnStartup) {
+  auto app_info_1 = BuildDefaultWebAppInfo();
+  auto app_info_2 = BuildDefaultWebAppInfo();
+  // Change the start_url so that the two apps have different IDs.
+  app_info_2->start_url = GURL(base::StrCat({kTestAppUrl, "/app_2"}));
+
+  auto app_id_1 =
+      web_app::test::InstallWebApp(profile(), std::move(app_info_1));
+  auto app_id_2 =
+      web_app::test::InstallWebApp(profile(), std::move(app_info_2));
+  apps::webapk_prefs::AddWebApk(profile(), app_id_1,
+                                "org.chromium.webapk.some_package");
+
+  StartWebApkManager();
+
+  auto install_task =
+      webapk_manager()->GetInstallQueueForTest()->PopTaskForTest();
+  ASSERT_TRUE(install_task);
+  ASSERT_EQ(install_task->app_id(), app_id_2);
+  AssertNoPendingInstalls();
+}
diff --git a/chrome/browser/apps/app_service/webapk/webapk_prefs.cc b/chrome/browser/apps/app_service/webapk/webapk_prefs.cc
new file mode 100644
index 0000000..ad602e4
--- /dev/null
+++ b/chrome/browser/apps/app_service/webapk/webapk_prefs.cc
@@ -0,0 +1,80 @@
+// 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/apps/app_service/webapk/webapk_prefs.h"
+
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/scoped_user_pref_update.h"
+
+namespace {
+
+// The pref dict is:
+// {
+//  ...
+//  "generated_webapks" : {
+//    <app_id_1> : {
+//      "package_name" : <webapk_package_name_1>
+//    },
+//    <app_id_2> : {
+//      "package_name" : <webapk_package_name_2>,
+//    },
+//    ...
+//  },
+//  ...
+// }
+constexpr char kGeneratedWebApksPref[] = "generated_webapks";
+constexpr char kPackageNameKey[] = "package_name";
+
+}  // namespace
+
+namespace apps {
+namespace webapk_prefs {
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterDictionaryPref(kGeneratedWebApksPref);
+}
+
+void AddWebApk(Profile* profile,
+               const std::string& app_id,
+               const std::string& package_name) {
+  DictionaryPrefUpdate generated_webapks(profile->GetPrefs(),
+                                         kGeneratedWebApksPref);
+
+  generated_webapks->SetPath({app_id, kPackageNameKey},
+                             base::Value(package_name));
+}
+
+base::Optional<std::string> GetWebApkPackageName(Profile* profile,
+                                                 const std::string& app_id) {
+  const base::Value* app_dict = profile->GetPrefs()
+                                    ->GetDictionary(kGeneratedWebApksPref)
+                                    ->FindDictKey(app_id);
+  if (!app_dict) {
+    return base::nullopt;
+  }
+
+  const std::string* package_name = app_dict->FindStringKey(kPackageNameKey);
+  if (!package_name) {
+    return base::nullopt;
+  }
+
+  return *package_name;
+}
+
+base::flat_set<std::string> GetWebApkAppIds(Profile* profile) {
+  base::flat_set<std::string> ids;
+  const base::Value* generated_webapks =
+      profile->GetPrefs()->GetDictionary(kGeneratedWebApksPref);
+
+  for (auto kv : generated_webapks->DictItems()) {
+    ids.insert(kv.first);
+  }
+
+  return ids;
+}
+
+}  // namespace webapk_prefs
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/webapk/webapk_prefs.h b/chrome/browser/apps/app_service/webapk/webapk_prefs.h
new file mode 100644
index 0000000..7904d77
--- /dev/null
+++ b/chrome/browser/apps/app_service/webapk/webapk_prefs.h
@@ -0,0 +1,34 @@
+// 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_APPS_APP_SERVICE_WEBAPK_WEBAPK_PREFS_H_
+#define CHROME_BROWSER_APPS_APP_SERVICE_WEBAPK_WEBAPK_PREFS_H_
+
+#include <string>
+
+#include "base/containers/flat_set.h"
+#include "base/optional.h"
+
+class PrefRegistrySimple;
+class Profile;
+
+namespace apps {
+namespace webapk_prefs {
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+void AddWebApk(Profile* profile,
+               const std::string& app_id,
+               const std::string& package_name);
+
+base::Optional<std::string> GetWebApkPackageName(Profile* profile,
+                                                 const std::string& app_id);
+
+// Returns the app IDs of all WebAPKs installed in the profile.
+base::flat_set<std::string> GetWebApkAppIds(Profile* profile);
+
+}  // namespace webapk_prefs
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_SERVICE_WEBAPK_WEBAPK_PREFS_H_
diff --git a/chrome/browser/ash/apps/apk_web_app_service_factory.cc b/chrome/browser/ash/apps/apk_web_app_service_factory.cc
index e8e68526..75810795 100644
--- a/chrome/browser/ash/apps/apk_web_app_service_factory.cc
+++ b/chrome/browser/ash/apps/apk_web_app_service_factory.cc
@@ -40,10 +40,6 @@
 
 ApkWebAppServiceFactory::~ApkWebAppServiceFactory() {}
 
-bool ApkWebAppServiceFactory::ServiceIsNULLWhileTesting() const {
-  return true;
-}
-
 KeyedService* ApkWebAppServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
diff --git a/chrome/browser/ash/apps/apk_web_app_service_factory.h b/chrome/browser/ash/apps/apk_web_app_service_factory.h
index c90e15e..43e44e2e 100644
--- a/chrome/browser/ash/apps/apk_web_app_service_factory.h
+++ b/chrome/browser/ash/apps/apk_web_app_service_factory.h
@@ -36,9 +36,6 @@
   ApkWebAppServiceFactory();
   ~ApkWebAppServiceFactory() override;
 
-  // KeyedServiceBaseFactory:
-  bool ServiceIsNULLWhileTesting() const override;
-
   // BrowserContextKeyedServiceFactory:
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
diff --git a/chrome/browser/ash/login/webview_login_browsertest.cc b/chrome/browser/ash/login/webview_login_browsertest.cc
index 5c3a88f0..1b51d8d 100644
--- a/chrome/browser/ash/login/webview_login_browsertest.cc
+++ b/chrome/browser/ash/login/webview_login_browsertest.cc
@@ -291,7 +291,7 @@
     command_line->AppendSwitch(switches::kOobeSkipPostLogin);
     OobeBaseTest::SetUpCommandLine(command_line);
   }
-  base::HistogramTester histogram_tester;
+  base::HistogramTester histogram_tester_;
 
  protected:
   void ExpectIdentifierPage() {
@@ -341,6 +341,17 @@
     return web_view_found;
   }
 
+  void DisableImplicitServices() {
+    SigninFrameJS().ExecuteAsync(
+        "gaia.chromeOSLogin.sendImplicitServices = false");
+  }
+
+  void WaitForServicesSet() {
+    test::OobeJS()
+        .CreateWaiter("$('gaia-signin').authenticator_.services_")
+        ->Wait();
+  }
+
  protected:
   chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
@@ -350,8 +361,70 @@
   DISALLOW_COPY_AND_ASSIGN(WebviewLoginTest);
 };
 
+/* is kGaiaCloseViewMessage enabled */
+/* Does Gaia send the 'closeView' message */
+using CloseViewParam = std::tuple<bool, bool>;
+
+class WebviewCloseViewLoginTest
+    : public WebviewLoginTest,
+      public ::testing::WithParamInterface<CloseViewParam> {
+ public:
+  WebviewCloseViewLoginTest() {
+    scoped_feature_list_.Reset();
+    if (IsFeatureEnabled(GetParam())) {
+      scoped_feature_list_.InitAndEnableFeature(
+          ash::features::kGaiaCloseViewMessage);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          ash::features::kGaiaCloseViewMessage);
+    }
+  }
+
+  static std::string GetName(
+      const testing::TestParamInfo<CloseViewParam>& param) {
+    std::string result;
+    result +=
+        IsFeatureEnabled(param.param) ? "ClientEnabled" : "ClientDisabled";
+    result += "_";
+    result +=
+        GaiaSendsCloseView(param.param) ? "ServerEnabled" : "ServerDisabled";
+    return result;
+  }
+
+ protected:
+  static bool IsFeatureEnabled(const CloseViewParam& param) {
+    return std::get<0>(param);
+  }
+  static bool GaiaSendsCloseView(const CloseViewParam& param) {
+    return std::get<1>(param);
+  }
+
+  void SendCloseViewOrEmulateTimeout() {
+    if (GaiaSendsCloseView(GetParam())) {
+      SigninFrameJS().ExecuteAsync("gaia.chromeOSLogin.sendCloseView()");
+      return;
+    }
+
+    if (!IsFeatureEnabled(GetParam()))
+      return;
+
+    EmulateGaiaDoneTimeout();
+  }
+
+  void EmulateGaiaDoneTimeout() {
+    // Wait for user info timer to be set.
+    test::OobeJS()
+        .CreateWaiter("$('gaia-signin').authenticator_.gaiaDoneTimer_")
+        ->Wait();
+
+    // Emulate timeout fire.
+    test::OobeJS().ExecuteAsync(
+        "$('gaia-signin').authenticator_.onGaiaDoneTimeout_()");
+  }
+};
+
 // Basic signin with username and password.
-IN_PROC_BROWSER_TEST_F(WebviewLoginTest, NativeTest) {
+IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, NativeTest) {
   WaitForGaiaPageLoadAndPropertyUpdate();
   ExpectIdentifierPage();
   SigninFrameJS().TypeIntoPath(FakeGaiaMixin::kFakeUserEmail,
@@ -397,11 +470,27 @@
                                FakeGaiaMixin::kPasswordPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
+  if (IsFeatureEnabled(GetParam()))
+    WaitForServicesSet();
+
+  SendCloseViewOrEmulateTimeout();
+
   test::WaitForPrimaryUserSessionStart();
+
+  histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.UserInfo",
+                                       true, 1);
+  if (!IsFeatureEnabled(GetParam())) {
+    histogram_tester_.ExpectTotalCount("ChromeOS.Gaia.Message.Gaia.CloseView",
+                                       0);
+    return;
+  }
+
+  histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.CloseView",
+                                       GaiaSendsCloseView(GetParam()), 1);
 }
 
 // Basic signin with username and password.
-IN_PROC_BROWSER_TEST_F(WebviewLoginTest, Basic) {
+IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, Basic) {
   WaitForGaiaPageLoadAndPropertyUpdate();
 
   ExpectIdentifierPage();
@@ -420,6 +509,11 @@
                                FakeGaiaMixin::kPasswordPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
+  if (IsFeatureEnabled(GetParam()))
+    WaitForServicesSet();
+
+  SendCloseViewOrEmulateTimeout();
+
   // The login view should be destroyed after the browser window opens.
   ui_test_utils::WaitForBrowserToOpen();
   EXPECT_FALSE(LoginDisplayHost::default_host()->GetWebUILoginView());
@@ -431,11 +525,11 @@
 
   EXPECT_FALSE(LoginDisplayHost::default_host());
 
-  histogram_tester.ExpectUniqueSample("ChromeOS.SAML.APILogin", 0, 1);
-  histogram_tester.ExpectTotalCount("OOBE.GaiaLoginTime", 1);
+  histogram_tester_.ExpectUniqueSample("ChromeOS.SAML.APILogin", 0, 1);
+  histogram_tester_.ExpectTotalCount("OOBE.GaiaLoginTime", 1);
 }
 
-IN_PROC_BROWSER_TEST_F(WebviewLoginTest, BackButton) {
+IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, BackButton) {
   WaitForGaiaPageLoadAndPropertyUpdate();
 
   // Start with identifer page.
@@ -467,6 +561,11 @@
                                FakeGaiaMixin::kPasswordPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
+  if (IsFeatureEnabled(GetParam()))
+    WaitForServicesSet();
+
+  SendCloseViewOrEmulateTimeout();
+
   test::WaitForPrimaryUserSessionStart();
 }
 
@@ -644,7 +743,7 @@
             reauth_user_.account_id.GetUserEmail());
   EXPECT_EQ(fake_gaia_.fake_gaia()->is_supervised(), "1");
   EXPECT_EQ(fake_gaia_.fake_gaia()->is_device_owner(), "1");
-  histogram_tester.ExpectTotalCount("OOBE.GaiaLoginTime", 0);
+  histogram_tester_.ExpectTotalCount("OOBE.GaiaLoginTime", 0);
 }
 
 IN_PROC_BROWSER_TEST_F(WebviewLoginTest, StoragePartitionHandling) {
@@ -1546,6 +1645,7 @@
 IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentBeforeAuthFinished) {
   WaitForGaiaPageLoadAndPropertyUpdate();
   ExpectIdentifierPage();
+  DisableImplicitServices();
   SigninFrameJS().TypeIntoPath(child_account_id_.GetUserEmail(),
                                FakeGaiaMixin::kEmailPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
@@ -1555,12 +1655,10 @@
                                FakeGaiaMixin::kPasswordPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
-  // Wait for services to be set.
-  test::OobeJS()
-      .CreateWaiter("$('gaia-signin').authenticator_.services_")
-      ->Wait();
+  WaitForServicesSet();
+
   // Timer should not be set.
-  test::OobeJS().ExpectFalse("$('gaia-signin').authenticator_.userInfoTimer_");
+  test::OobeJS().ExpectFalse("$('gaia-signin').authenticator_.gaiaDoneTimer_");
 
   test::WaitForPrimaryUserSessionStart();
 
@@ -1574,6 +1672,7 @@
 IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentAfterTimerSet) {
   WaitForGaiaPageLoadAndPropertyUpdate();
   ExpectIdentifierPage();
+  DisableImplicitServices();
   SigninFrameJS().TypeIntoPath(child_account_id_.GetUserEmail(),
                                FakeGaiaMixin::kEmailPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
@@ -1583,7 +1682,7 @@
 
   // Wait for user info timer to be set.
   test::OobeJS()
-      .CreateWaiter("$('gaia-signin').authenticator_.userInfoTimer_")
+      .CreateWaiter("$('gaia-signin').authenticator_.gaiaDoneTimer_")
       ->Wait();
 
   // Send user info after that.
@@ -1597,9 +1696,10 @@
 }
 
 // Verifies flow when user info message is never sent.
-IN_PROC_BROWSER_TEST_F(WebviewLoginTest, UserInfoNeverSent) {
+IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, UserInfoNeverSent) {
   WaitForGaiaPageLoadAndPropertyUpdate();
   ExpectIdentifierPage();
+  DisableImplicitServices();
   SigninFrameJS().TypeIntoPath(FakeGaiaMixin::kFakeUserEmail,
                                FakeGaiaMixin::kEmailPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
@@ -1607,17 +1707,16 @@
                                FakeGaiaMixin::kPasswordPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
-  // Wait for user info timer to be set.
-  test::OobeJS()
-      .CreateWaiter("$('gaia-signin').authenticator_.userInfoTimer_")
-      ->Wait();
+  if (GaiaSendsCloseView(GetParam()))
+    SigninFrameJS().ExecuteAsync("gaia.chromeOSLogin.sendCloseView()");
 
-  // Emulate timeout fire.
-  test::OobeJS().ExecuteAsync(
-      "$('gaia-signin').authenticator_.onUserInfoTimeout_()");
+  EmulateGaiaDoneTimeout();
 
   test::WaitForPrimaryUserSessionStart();
 
+  histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.UserInfo",
+                                       false, 1);
+
   const user_manager::UserManager* const user_manager =
       user_manager::UserManager::Get();
   EXPECT_FALSE(user_manager->GetActiveUser()->IsChild());
@@ -1632,7 +1731,6 @@
                                FakeGaiaMixin::kEmailPath);
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
-  base::HistogramTester histogram_tester;
   // This should generate first "Started" event.
   SigninFrameJS().ExecuteAsync(
       "gaia.chromeOSLogin.attemptLogin('email@email.com', 'password')");
@@ -1643,8 +1741,13 @@
   test::OobeJS().ClickOnPath(kPrimaryButton);
 
   test::WaitForPrimaryUserSessionStart();
-  histogram_tester.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 0, 2);
-  histogram_tester.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 1, 1);
+  histogram_tester_.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 0, 2);
+  histogram_tester_.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 1, 1);
 }
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         WebviewCloseViewLoginTest,
+                         testing::Combine(testing::Bool(), testing::Bool()),
+                         &WebviewCloseViewLoginTest::GetName);
+
 }  // namespace chromeos
diff --git a/chrome/browser/ash/system/kernel_feature_manager.cc b/chrome/browser/ash/system/kernel_feature_manager.cc
new file mode 100644
index 0000000..baf4fc88
--- /dev/null
+++ b/chrome/browser/ash/system/kernel_feature_manager.cc
@@ -0,0 +1,101 @@
+// 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/ash/system/kernel_feature_manager.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_split.h"
+#include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
+#include "third_party/cros_system_api/dbus/debugd/dbus-constants.h"
+
+namespace chromeos {
+
+KernelFeatureManager::KernelFeatureManager(
+    DebugDaemonClient* debug_daemon_client)
+    : debug_daemon_client_(debug_daemon_client) {
+  debug_daemon_client_->WaitForServiceToBeAvailable(
+      base::BindOnce(&KernelFeatureManager::OnDebugDaemonReady,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+KernelFeatureManager::~KernelFeatureManager() = default;
+
+void KernelFeatureManager::OnDebugDaemonReady(bool service_is_ready) {
+  if (!service_is_ready) {
+    LOG(ERROR) << "debugd service not ready";
+    return;
+  }
+
+  // Initialize the system.
+  debug_daemon_ready_ = true;
+  GetKernelFeatureList();
+}
+
+void KernelFeatureManager::GetKernelFeatureList() {
+  debug_daemon_client_->GetKernelFeatureList(
+      base::BindOnce(&KernelFeatureManager::OnKernelFeatureList,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void KernelFeatureManager::OnKernelFeatureList(bool result,
+                                               const std::string& out) {
+  if (result) {
+    // Split the CSV into a feature list
+    kernel_feature_list_ = base::SplitString(out, ",", base::TRIM_WHITESPACE,
+                                             base::SPLIT_WANT_NONEMPTY);
+    if (!kernel_feature_list_.empty()) {
+      // Find out which of these features requested in Finch
+      EnableKernelFeatures();
+      return;
+    }
+  }
+  LOG(ERROR) << "Failed to get or parse kernel feature list from debugd.";
+}
+
+void KernelFeatureManager::EnableKernelFeatures() {
+  base::FeatureList* feature_list_instance = base::FeatureList::GetInstance();
+  DCHECK(feature_list_instance);
+
+  for (const auto& name : kernel_feature_list_) {
+    VLOG(1) << "Enabling kernel feature via debugd: " << name << std::endl;
+
+    // Was this feature requested in the field trial and also enabled?
+    // Note: We don't support dynamic disabling of kernel features right now.
+    // So any requests to disable a feature are ignored. Disabled is the
+    // default.
+    if (!feature_list_instance->GetEnabledFieldTrialByFeatureName(name)) {
+      continue;
+    }
+
+    debug_daemon_client_->KernelFeatureEnable(
+        name, base::BindOnce(&KernelFeatureManager::OnKernelFeatureEnable,
+                             weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void KernelFeatureManager::OnKernelFeatureEnable(bool result,
+                                                 const std::string& out) {
+  DCHECK(!result ||
+         base::FeatureList::GetInstance()->GetAssociatedFieldTrialByFeatureName(
+             out));
+
+  if (result) {
+    base::FeatureList::GetInstance()
+        ->GetAssociatedFieldTrialByFeatureName(out)
+        ->group();
+    VLOG(1) << "Kernel feature " << out << "activated successfully!";
+    return;
+  }
+  VLOG(1) << "Kernel feature has not been activated: " << out;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ash/system/kernel_feature_manager.h b/chrome/browser/ash/system/kernel_feature_manager.h
new file mode 100644
index 0000000..03b9611
--- /dev/null
+++ b/chrome/browser/ash/system/kernel_feature_manager.h
@@ -0,0 +1,60 @@
+// 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_CHROMEOS_KERNEL_FEATURES_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_KERNEL_FEATURES_MANAGER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+
+namespace chromeos {
+
+class DebugDaemonClient;
+
+// It is desirable to test kernel patches on a population to measure benefits
+// or problems with application of a kernel patch. For experimentation,
+// a patch or tuning can be applied to all kernels, and finch will enable it on
+// subset of the user population. An experiment has an ‘enablement method’.
+// This method can involve writing to sysfs, procfs entry, or executing
+// other commands, via debugd. This class manages the enabling of these
+// kernel experiments, when Chrome starts, via ChromeOS's debugd. The behavior
+// of the running kernel is changed live without requiring a restart.
+class KernelFeatureManager {
+ public:
+  explicit KernelFeatureManager(DebugDaemonClient* debug_daemon_client);
+  KernelFeatureManager(const KernelFeatureManager&) = delete;
+  KernelFeatureManager& operator=(const KernelFeatureManager&) = delete;
+  ~KernelFeatureManager();
+
+ private:
+  void OnDebugDaemonReady(bool service_is_ready);
+
+  // Get a list of kernel features that debugd can enable. The list of features
+  // are passed to the callback in |out| as a comma separate value string, or
+  // an error string containing the reason for failure. |result| contains true
+  // or false depending on if the request succeeds or fails.
+  void GetKernelFeatureList();
+  void OnKernelFeatureList(bool result, const std::string& out);
+
+  // Enable all kernel features that were requested to be enabled in field trial
+  // experiments. A callback is called for each feature that is enabled, with
+  // |result| containing true or false depending on if the request succeeds or
+  // fails. |out| contains an error string on failure and name of the feature on
+  // success.
+  void EnableKernelFeatures();
+  void OnKernelFeatureEnable(bool result, const std::string& out);
+
+  DebugDaemonClient* const debug_daemon_client_;
+  bool debug_daemon_ready_ = false;
+  std::vector<std::string> kernel_feature_list_;
+
+  base::WeakPtrFactory<KernelFeatureManager> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_KERNEL_FEATURES_MANAGER_H_
diff --git a/chrome/browser/ash/system/kernel_feature_manager_unittest.cc b/chrome/browser/ash/system/kernel_feature_manager_unittest.cc
new file mode 100644
index 0000000..466ee99
--- /dev/null
+++ b/chrome/browser/ash/system/kernel_feature_manager_unittest.cc
@@ -0,0 +1,113 @@
+// 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/ash/system/kernel_feature_manager.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_field_trial_list_resetter.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestFakeDebugDaemonClient : public chromeos::FakeDebugDaemonClient {
+ public:
+  void GetKernelFeatureList(KernelFeatureListCallback callback) override {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), true,
+                                  "TrialExample1,TrialExample2,TrialExample3"));
+  }
+
+  void KernelFeatureEnable(const std::string& name,
+                           KernelFeatureListCallback callback) override {
+    bool result = false;
+    std::string out;
+
+    // Hardcode the behavior of different trials.
+    if (name == "TrialExample1") {
+      result = true;
+      out = "TrialExample1";
+    } else if (name == "TrialExample2") {
+      out = "Device does not support";
+    } else if (name == "TrialExample3") {
+      out = "Disable is the default, not doing anything";
+    } else {
+      out = "Unknown feature requested to be enabled";
+    }
+
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), result, out));
+  }
+};
+
+class KernelFeatureManagerTest : public testing::Test {
+ public:
+  KernelFeatureManagerTest() {
+    // Provide an empty FeatureList to each test by default.
+    scoped_feature_list_.InitWithFeatureList(
+        std::make_unique<base::FeatureList>());
+  }
+  KernelFeatureManagerTest(const KernelFeatureManagerTest&) = delete;
+  KernelFeatureManagerTest& operator=(const KernelFeatureManagerTest&) = delete;
+  ~KernelFeatureManagerTest() override = default;
+
+  TestFakeDebugDaemonClient debug_daemon_client_;
+  base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(KernelFeatureManagerTest, EnableIfDeviceSupports) {
+  base::test::ScopedFieldTrialListResetter resetter;
+  base::FieldTrialList field_trial_list(nullptr);
+  auto feature_list = std::make_unique<base::FeatureList>();
+
+  // Feature that the device supports and we enable.
+  base::FieldTrial* trial1 =
+      base::FieldTrialList::CreateFieldTrial("TrialExample1", "A");
+
+  // Feature that the device lists but does not support and we want to enable.
+  base::FieldTrial* trial2 =
+      base::FieldTrialList::CreateFieldTrial("TrialExample2", "B");
+
+  // Feature that the device supports and we try to disable (note that disable
+  // is the default so this really should not do anything. We test that
+  // the code is not buggy enough to accidentally enable it.
+  base::FieldTrial* trial3 =
+      base::FieldTrialList::CreateFieldTrial("TrialExample3", "C");
+
+  // Feature that the device does not list or support and we want to enable.
+  base::FieldTrial* trial4 =
+      base::FieldTrialList::CreateFieldTrial("TrialExample4", "D");
+
+  feature_list->RegisterFieldTrialOverride(
+      "TrialExample1", base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial1);
+  feature_list->RegisterFieldTrialOverride(
+      "TrialExample2", base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial2);
+  feature_list->RegisterFieldTrialOverride(
+      "TrialExample3", base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial3);
+  feature_list->RegisterFieldTrialOverride(
+      "TrialExample4", base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial4);
+
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+  // Initially, no trial should be active.
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial1->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial2->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial3->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial4->trial_name()));
+
+  chromeos::KernelFeatureManager manager(&debug_daemon_client_);
+  debug_daemon_client_.SetServiceIsAvailable(true);
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(base::FieldTrialList::IsTrialActive(trial1->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial2->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial3->trial_name()));
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive(trial4->trial_name()));
+}
+
+}  // namespace
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
index c736634..f4b0d1d 100644
--- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -294,8 +294,8 @@
             MediaAppUiBrowserTest::EvalJsInAppFrame(app, kCheckInkLoaded));
 }
 
-// Tests that clicking on the 'Info' button in the app bar opens the information
-// panel.
+// Tests that clicking on the 'Info' button in the app bar toggles the
+// information panel.
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, InformationPanel) {
   WaitForTestSystemAppInstall();
   auto params = LaunchParamsForApp(web_app::SystemAppType::MEDIA);
@@ -321,9 +321,30 @@
   // icon-button ids are calculated from a hash of the button labels. Id is used
   // because the UI toolkit has loose guarantees about where the actual label
   // appears in the shadow DOM.
-  clickAppBarButton(app, "#icon-button-2283726");
+  const std::string kInfoButtonSelector = "#icon-button-2283726";
+  clickAppBarButton(app, kInfoButtonSelector);
   EXPECT_EQ(true,
             MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen));
+
+  // Expect info panel to be closed after clicking info button again.
+  // After closing we must wait for the DOM update because the panel doesn't
+  // disappear from the DOM until the close animation is complete.
+  clickAppBarButton(app, kInfoButtonSelector);
+  constexpr char kWaitForImageHandlerUpdate[] = R"(
+    (async () => {
+      const imageHandler = await getNode('backlight-image-handler');
+      await new Promise(resolve => {
+        const observer = new MutationObserver(() => {
+          resolve();
+          observer.disconnect();
+        });
+        observer.observe(imageHandler.shadowRoot, {childList: true});
+      });
+    })();
+  )";
+  MediaAppUiBrowserTest::EvalJsInAppFrame(app, kWaitForImageHandlerUpdate);
+  EXPECT_EQ(false,
+            MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen));
 }
 #endif  // BUILDFLAG(ENABLE_CROS_MEDIA_APP)
 
diff --git a/chrome/browser/autocomplete/shortcuts_extensions_manager.cc b/chrome/browser/autocomplete/shortcuts_extensions_manager.cc
index 5f6cf3a..c053f53d 100644
--- a/chrome/browser/autocomplete/shortcuts_extensions_manager.cc
+++ b/chrome/browser/autocomplete/shortcuts_extensions_manager.cc
@@ -12,7 +12,7 @@
 ShortcutsExtensionsManager::ShortcutsExtensionsManager(Profile* profile)
     : profile_(profile) {
   DCHECK(profile_);
-  registry_observer_.Add(extensions::ExtensionRegistry::Get(profile_));
+  registry_observation_.Observe(extensions::ExtensionRegistry::Get(profile_));
 }
 
 ShortcutsExtensionsManager::~ShortcutsExtensionsManager() {}
@@ -33,5 +33,5 @@
 
 void ShortcutsExtensionsManager::OnShutdown(
     extensions::ExtensionRegistry* registry) {
-  registry_observer_.RemoveAll();
+  registry_observation_.Reset();
 }
diff --git a/chrome/browser/autocomplete/shortcuts_extensions_manager.h b/chrome/browser/autocomplete/shortcuts_extensions_manager.h
index 8f876d6..33b3bbb 100644
--- a/chrome/browser/autocomplete/shortcuts_extensions_manager.h
+++ b/chrome/browser/autocomplete/shortcuts_extensions_manager.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_AUTOCOMPLETE_SHORTCUTS_EXTENSIONS_MANAGER_H_
 
 #include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/supports_user_data.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
@@ -29,9 +29,9 @@
   void OnShutdown(extensions::ExtensionRegistry* registry) override;
 
  private:
-  ScopedObserver<extensions::ExtensionRegistry,
-                 extensions::ExtensionRegistryObserver>
-      registry_observer_{this};
+  base::ScopedObservation<extensions::ExtensionRegistry,
+                          extensions::ExtensionRegistryObserver>
+      registry_observation_{this};
   Profile* profile_;
 
   DISALLOW_COPY_AND_ASSIGN(ShortcutsExtensionsManager);
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index f6516726..ad858f8 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ash/system/automatic_reboot_manager.h"
 #include "chrome/browser/ash/system/device_disabling_manager.h"
 #include "chrome/browser/ash/system/device_disabling_manager_default_delegate.h"
+#include "chrome/browser/ash/system/kernel_feature_manager.h"
 #include "chrome/browser/ash/system/system_clock.h"
 #include "chrome/browser/ash/system/timezone_resolver_manager.h"
 #include "chrome/browser/ash/system/timezone_util.h"
@@ -263,6 +264,16 @@
   scheduler_configuration_manager_.reset();
 }
 
+void BrowserProcessPlatformPart::InitializeKernelFeatureManager() {
+  DCHECK(!kernel_feature_manager_);
+  kernel_feature_manager_ = std::make_unique<chromeos::KernelFeatureManager>(
+      chromeos::DBusThreadManager::Get()->GetDebugDaemonClient());
+}
+
+void BrowserProcessPlatformPart::ShutdownKernelFeatureManager() {
+  kernel_feature_manager_.reset();
+}
+
 void BrowserProcessPlatformPart::InitializePrimaryProfileServices(
     Profile* primary_profile) {
   DCHECK(primary_profile);
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h
index 7f7fd16..3e057d1b 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.h
+++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -37,6 +37,7 @@
 
 namespace chromeos {
 class InSessionPasswordChangeManager;
+class KernelFeatureManager;
 class SchedulerConfigurationManager;
 class TimeZoneResolver;
 }  // namespace chromeos
@@ -70,6 +71,9 @@
   void InitializeSchedulerConfigurationManager();
   void ShutdownSchedulerConfigurationManager();
 
+  void InitializeKernelFeatureManager();
+  void ShutdownKernelFeatureManager();
+
   // Initializes all services that need the primary profile. Gets called as soon
   // as the primary profile is available, which implies that the primary user
   // has logged in. The services are shut down automatically when the primary
@@ -105,6 +109,10 @@
     return scheduler_configuration_manager_.get();
   }
 
+  chromeos::KernelFeatureManager* kernel_feature_manager() {
+    return kernel_feature_manager_.get();
+  }
+
   ash::system::DeviceDisablingManager* device_disabling_manager() {
     return device_disabling_manager_.get();
   }
@@ -197,6 +205,7 @@
 
   std::unique_ptr<chromeos::SchedulerConfigurationManager>
       scheduler_configuration_manager_;
+  std::unique_ptr<chromeos::KernelFeatureManager> kernel_feature_manager_;
 
   BrowserRestoreObserver browser_restore_observer;
 
diff --git a/chrome/browser/buildflags.gni b/chrome/browser/buildflags.gni
index ff2e8f1..8c19e70 100644
--- a/chrome/browser/buildflags.gni
+++ b/chrome/browser/buildflags.gni
@@ -4,6 +4,7 @@
 
 import("//build/config/chrome_build.gni")
 import("//build/config/chromeos/ui_mode.gni")
+import("//build/toolchain/gcc_toolchain.gni")
 import("//chromecast/chromecast.gni")
 
 declare_args() {
@@ -21,3 +22,10 @@
   enable_app_session_service =
       !(is_chromeos_lacros || is_chromecast || is_android)
 }
+
+# If true, the resource .pak files will be hashed and the digest will be
+# embedded in the binary and checked at run-time. This is incompatible with
+# enable_resource_allowlist_generation on Windows because it creates a circular
+# dependency with chrome_dll.
+enable_pak_file_integrity_checks =
+    !(enable_resource_allowlist_generation && is_win) && !is_android
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 592ddfe6..7e02216 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -55,6 +55,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/buildflags.h"
 #include "chrome/browser/chrome_browser_field_trials.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "chrome/browser/component_updater/registration.h"
@@ -316,6 +317,10 @@
 #include "components/spellcheck/common/spellcheck_features.h"
 #endif  // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
 
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+#include "chrome/browser/resources_integrity.h"
+#endif
+
 namespace {
 
 #if !defined(OS_ANDROID)
@@ -1102,6 +1107,10 @@
   g_browser_process->GetTabManager()->Start();
 #endif
 
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+  CheckPakFileIntegrity();
+#endif
+
   // The RulesetService will make the filtering rules available to renderers
   // immediately after its construction, provided that the rules are already
   // available at no cost in an indexed format. This enables activating
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index bd46e60d..90b963cf 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1822,6 +1822,8 @@
     "../ash/system/input_device_settings.cc",
     "../ash/system/input_device_settings.h",
     "../ash/system/input_device_settings_impl_ozone.cc",
+    "../ash/system/kernel_feature_manager.cc",
+    "../ash/system/kernel_feature_manager.h",
     "../ash/system/pointer_device_observer.cc",
     "../ash/system/pointer_device_observer.h",
     "../ash/system/procfs_util.cc",
@@ -3873,6 +3875,7 @@
     "../ash/sync/turn_sync_on_helper_unittest.cc",
     "../ash/system/automatic_reboot_manager_unittest.cc",
     "../ash/system/device_disabling_manager_unittest.cc",
+    "../ash/system/kernel_feature_manager_unittest.cc",
     "../ash/system/procfs_util_unittest.cc",
     "../ash/system/user_removal_manager_unittest.cc",
     "../ash/system_logs/crosapi_system_log_source_unittest.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 55ac618..00b6d60 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -74,6 +74,7 @@
 #include "chrome/browser/ash/settings/shutdown_policy_forwarder.h"
 #include "chrome/browser/ash/system/breakpad_consent_watcher.h"
 #include "chrome/browser/ash/system/input_device_settings.h"
+#include "chrome/browser/ash/system/kernel_feature_manager.h"
 #include "chrome/browser/ash/system/user_removal_manager.h"
 #include "chrome/browser/ash/usb/cros_usb_detector.h"
 #include "chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
@@ -649,6 +650,8 @@
   arc_service_launcher_ = std::make_unique<arc::ArcServiceLauncher>(
       g_browser_process->platform_part()->scheduler_configuration_manager());
 
+  g_browser_process->platform_part()->InitializeKernelFeatureManager();
+
   session_termination_manager_ =
       std::make_unique<chromeos::SessionTerminationManager>();
 
@@ -1333,6 +1336,8 @@
   web_kiosk_app_manager_.reset();
   chrome_keyboard_controller_client_.reset();
 
+  g_browser_process->platform_part()->ShutdownKernelFeatureManager();
+
   // All ARC related modules should have been shut down by this point, so
   // destroy ARC.
   // Specifically, this should be done after Profile destruction run in
diff --git a/chrome/browser/content_settings/generated_cookie_prefs.cc b/chrome/browser/content_settings/generated_cookie_prefs.cc
index ca85a5d7..3730bdafd 100644
--- a/chrome/browser/content_settings/generated_cookie_prefs.cc
+++ b/chrome/browser/content_settings/generated_cookie_prefs.cc
@@ -84,7 +84,7 @@
     : profile_(profile), pref_name_(pref_name) {
   host_content_settings_map_ =
       HostContentSettingsMapFactory::GetForProfile(profile_);
-  content_settings_observer_.Add(host_content_settings_map_);
+  content_settings_observation_.Observe(host_content_settings_map_);
 
   user_prefs_registrar_.Init(profile->GetPrefs());
   user_prefs_registrar_.Add(
diff --git a/chrome/browser/content_settings/generated_cookie_prefs.h b/chrome/browser/content_settings/generated_cookie_prefs.h
index f0e8331..0af90c2 100644
--- a/chrome/browser/content_settings/generated_cookie_prefs.h
+++ b/chrome/browser/content_settings/generated_cookie_prefs.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CONTENT_SETTINGS_GENERATED_COOKIE_PREFS_H_
 #define CHROME_BROWSER_CONTENT_SETTINGS_GENERATED_COOKIE_PREFS_H_
 
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
@@ -46,8 +46,8 @@
   Profile* const profile_;
   HostContentSettingsMap* host_content_settings_map_;
   const std::string pref_name_;
-  ScopedObserver<HostContentSettingsMap, content_settings::Observer>
-      content_settings_observer_{this};
+  base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+      content_settings_observation_{this};
   PrefChangeRegistrar user_prefs_registrar_;
 };
 
diff --git a/chrome/browser/content_settings/generated_notification_pref.cc b/chrome/browser/content_settings/generated_notification_pref.cc
index 63c690b..f59c102 100644
--- a/chrome/browser/content_settings/generated_notification_pref.cc
+++ b/chrome/browser/content_settings/generated_notification_pref.cc
@@ -43,7 +43,7 @@
 
   host_content_settings_map_ =
       HostContentSettingsMapFactory::GetForProfile(profile_);
-  content_setting_observer_.Add(host_content_settings_map_);
+  content_setting_observation_.Observe(host_content_settings_map_);
 }
 
 GeneratedNotificationPref::~GeneratedNotificationPref() = default;
diff --git a/chrome/browser/content_settings/generated_notification_pref.h b/chrome/browser/content_settings/generated_notification_pref.h
index dff8bb8d..bb39b0d6 100644
--- a/chrome/browser/content_settings/generated_notification_pref.h
+++ b/chrome/browser/content_settings/generated_notification_pref.h
@@ -7,7 +7,7 @@
 
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -55,8 +55,8 @@
 
   Profile* const profile_;
   HostContentSettingsMap* host_content_settings_map_;
-  ScopedObserver<HostContentSettingsMap, content_settings::Observer>
-      content_setting_observer_{this};
+  base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+      content_setting_observation_{this};
   PrefChangeRegistrar user_prefs_registrar_;
 };
 
diff --git a/chrome/browser/content_settings/mock_settings_observer.cc b/chrome/browser/content_settings/mock_settings_observer.cc
index 199d24e..d2a3bf7b 100644
--- a/chrome/browser/content_settings/mock_settings_observer.cc
+++ b/chrome/browser/content_settings/mock_settings_observer.cc
@@ -10,7 +10,7 @@
 
 MockSettingsObserver::MockSettingsObserver(HostContentSettingsMap* map)
     : map_(map) {
-  observer_.Add(map_);
+  observation_.Observe(map_);
 }
 
 MockSettingsObserver::~MockSettingsObserver() {}
diff --git a/chrome/browser/content_settings/mock_settings_observer.h b/chrome/browser/content_settings/mock_settings_observer.h
index 68b82c85..f034443 100644
--- a/chrome/browser/content_settings/mock_settings_observer.h
+++ b/chrome/browser/content_settings/mock_settings_observer.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CONTENT_SETTINGS_MOCK_SETTINGS_OBSERVER_H_
 
 #include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_types.h"
@@ -35,8 +35,8 @@
   // The map that this Observer is watching.
   HostContentSettingsMap* map_;
 
-  ScopedObserver<HostContentSettingsMap, content_settings::Observer> observer_{
-      this};
+  base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+      observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MockSettingsObserver);
 };
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.cc b/chrome/browser/content_settings/sound_content_setting_observer.cc
index 6a089fe..6955ee7 100644
--- a/chrome/browser/content_settings/sound_content_setting_observer.cc
+++ b/chrome/browser/content_settings/sound_content_setting_observer.cc
@@ -32,7 +32,7 @@
       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
   host_content_settings_map_ =
       HostContentSettingsMapFactory::GetForProfile(profile);
-  observer_.Add(host_content_settings_map_);
+  observation_.Observe(host_content_settings_map_);
 
 #if !defined(OS_ANDROID)
   // Listen to changes of the block autoplay pref.
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.h b/chrome/browser/content_settings/sound_content_setting_observer.h
index 1f8c405..92b5d76d 100644
--- a/chrome/browser/content_settings/sound_content_setting_observer.h
+++ b/chrome/browser/content_settings/sound_content_setting_observer.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
 #define CHROME_BROWSER_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
 
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "build/build_config.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -70,8 +70,8 @@
 
   HostContentSettingsMap* host_content_settings_map_;
 
-  ScopedObserver<HostContentSettingsMap, content_settings::Observer> observer_{
-      this};
+  base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+      observation_{this};
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
diff --git a/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java b/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java
index 57715b1..e144029 100644
--- a/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java
+++ b/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java
@@ -17,7 +17,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Extracts search results by parsing in the renderer.
@@ -61,7 +63,11 @@
         List<PageGroup> groups = new ArrayList<PageGroup>();
         for (int i = 0; i < groupLabel.length; i++) {
             List<PageItem> results = new ArrayList<PageItem>();
+            Set<GURL> groupUrls = new HashSet<>();
             for (int j = 0; j < groupSize[i]; j++) {
+                // Uniquify urls within the group.
+                if (!groupUrls.add(urls[groupOffset + j])) continue;
+
                 results.add(new PageItem(urls[groupOffset + j], titles[groupOffset + j]));
             }
             groupOffset += groupSize[i];
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
index 05a39cee..f4070970 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
@@ -32,7 +32,8 @@
       profile->GetPrefs()->GetList(prefs::kAttestationExtensionAllowlist);
   DCHECK_NE(list, nullptr);
   base::Value value(extension->id());
-  return std::find(list->begin(), list->end(), value) != list->end();
+  return std::find(list->GetList().begin(), list->GetList().end(), value) !=
+         list->GetList().end();
 }
 
 }  // namespace platform_keys
diff --git a/chrome/browser/extensions/api/font_settings/font_settings_api.cc b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
index 59c213d..1c444caa 100644
--- a/chrome/browser/extensions/api/font_settings/font_settings_api.cc
+++ b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
@@ -183,7 +183,7 @@
 
   base::ListValue args;
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->Set(key, pref->GetValue()->CreateDeepCopy());
+  dict->Set(key, base::Value::ToUniquePtrValue(pref->GetValue()->Clone()));
   args.Append(std::move(dict));
 
   extensions::preference_helpers::DispatchEventToExtensions(
@@ -299,9 +299,9 @@
 ExtensionFunction::ResponseValue
 FontSettingsGetFontListFunction::CopyFontsToResult(base::ListValue* fonts) {
   std::unique_ptr<base::ListValue> result(new base::ListValue());
-  for (auto it = fonts->begin(); it != fonts->end(); ++it) {
-    base::ListValue* font_list_value;
-    if (!it->GetAsList(&font_list_value)) {
+  for (const auto& entry : fonts->GetList()) {
+    const base::ListValue* font_list_value;
+    if (!entry.GetAsList(&font_list_value)) {
       NOTREACHED();
       return Error("");
     }
@@ -354,7 +354,8 @@
           profile, extension_id(), GetPrefName(), kIncognito);
 
   std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
-  result->Set(GetKey(), pref->GetValue()->CreateDeepCopy());
+  result->Set(GetKey(),
+              base::Value::ToUniquePtrValue(pref->GetValue()->Clone()));
   result->SetString(kLevelOfControlKey, level_of_control);
   return RespondNow(
       OneArgument(base::Value::FromUniquePtrValue(std::move(result))));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a7f29367..5266b57aa 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -79,6 +79,14 @@
     "expiry_milestone": 93
   },
   {
+    "name": "allow-default-web-app-migration-for-chrome-os-managed-users",
+    "owners": [
+      "alancutter@chromium.org",
+      "chromeos-web-apps-platform-syd@google.com"
+    ],
+    "expiry_milestone": 96
+  },
+  {
     "name": "allow-disable-mouse-acceleration",
     "owners": [ "zentaro" ],
     "expiry_milestone": 82
@@ -3816,6 +3824,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "offline-pages-ct",
+    "owners": [ "sclittle", "srsudar", "offline-dev" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "offline-pages-ct-suppress-completed-notification",
     "owners": [ "sclittle", "srsudar", "offline-dev" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index cc4551e..73a2a46 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3136,6 +3136,9 @@
 const char kOfflineIndicatorV2Description[] =
     "Show a persistent offline indicator when offline.";
 
+const char kOfflinePagesCtName[] = "Enable Offline Pages CT features.";
+const char kOfflinePagesCtDescription[] = "Enable Offline Pages CT features.";
+
 const char kOfflinePagesCtV2Name[] = "Enable Offline Pages CT V2 features.";
 const char kOfflinePagesCtV2Description[] =
     "V2 features include attributing pages to the app that initiated the "
@@ -4926,6 +4929,14 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+const char kAllowDefaultWebAppMigrationForChromeOsManagedUsersName[] =
+    "Allow default web app migration for Chrome OS managed users";
+const char kAllowDefaultWebAppMigrationForChromeOsManagedUsersDescription[] =
+    "The web app migration flags "
+    "(chrome://flags/#enable-migrate-default-chrome-app-to-web-apps-gsuite and "
+    "chrome://flags/#enable-migrate-default-chrome-app-to-web-apps-non-gsuite) "
+    "are ignored for managed Chrome OS users unless this feature is enabled.";
+
 const char kDefaultChatWebAppName[] = "Default Chat web app";
 const char kDefaultChatWebAppDescription[] =
     "Enables the Chat web app to be installed by default.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 0912524..7c23b35 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1823,6 +1823,9 @@
 extern const char kOfflineIndicatorV2Name[];
 extern const char kOfflineIndicatorV2Description[];
 
+extern const char kOfflinePagesCtName[];
+extern const char kOfflinePagesCtDescription[];
+
 extern const char kOfflinePagesCtV2Name[];
 extern const char kOfflinePagesCtV2Description[];
 
@@ -2872,6 +2875,10 @@
 #endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+extern const char kAllowDefaultWebAppMigrationForChromeOsManagedUsersName[];
+extern const char
+    kAllowDefaultWebAppMigrationForChromeOsManagedUsersDescription[];
+
 extern const char kDefaultChatWebAppName[];
 extern const char kDefaultChatWebAppDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 3cf84e1e..0f41f117 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -278,6 +278,7 @@
     &language::kTranslateIntent,
     &messages::kMessagesForAndroidInfrastructure,
     &offline_pages::kOfflineIndicatorFeature,
+    &offline_pages::kOfflinePagesCTFeature,    // See crbug.com/620421.
     &offline_pages::kOfflinePagesCTV2Feature,  // See crbug.com/734753.
     &offline_pages::kOfflinePagesDescriptiveFailStatusFeature,
     &offline_pages::kOfflinePagesDescriptivePendingStatusFeature,
diff --git a/chrome/browser/infobars/infobar_observer.cc b/chrome/browser/infobars/infobar_observer.cc
index ebd8ef1..9b0efaf1 100644
--- a/chrome/browser/infobars/infobar_observer.cc
+++ b/chrome/browser/infobars/infobar_observer.cc
@@ -5,10 +5,10 @@
 #include "chrome/browser/infobars/infobar_observer.h"
 
 InfoBarObserver::InfoBarObserver(infobars::InfoBarManager* manager, Type type)
-    : type_(type), infobar_observer_(this) {
+    : type_(type) {
   // There may be no |manager| if the browser window is currently closing.
   if (manager)
-    infobar_observer_.Add(manager);
+    infobar_observation_.Observe(manager);
 }
 
 InfoBarObserver::~InfoBarObserver() {}
@@ -16,7 +16,7 @@
 void InfoBarObserver::Wait() {
   // When there is no manager being observed, there is nothing to wait on, so
   // return immediately.
-  if (infobar_observer_.IsObservingSources())
+  if (infobar_observation_.IsObserving())
     run_loop_.Run();
 }
 
@@ -35,7 +35,8 @@
 void InfoBarObserver::OnManagerShuttingDown(infobars::InfoBarManager* manager) {
   if (run_loop_.running())
     run_loop_.Quit();
-  infobar_observer_.Remove(manager);
+  DCHECK(infobar_observation_.IsObservingSource(manager));
+  infobar_observation_.Reset();
 }
 
 void InfoBarObserver::OnNotified(Type type) {
diff --git a/chrome/browser/infobars/infobar_observer.h b/chrome/browser/infobars/infobar_observer.h
index 09a7760..6e662e7 100644
--- a/chrome/browser/infobars/infobar_observer.h
+++ b/chrome/browser/infobars/infobar_observer.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "components/infobars/core/infobar_manager.h"
 
 // A test-only class to wait for infobar events.
@@ -41,8 +41,9 @@
 
   base::RunLoop run_loop_;
   const Type type_;
-  ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer>
-      infobar_observer_;
+  base::ScopedObservation<infobars::InfoBarManager,
+                          infobars::InfoBarManager::Observer>
+      infobar_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
 };
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index da67f505..f12891c 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -63,6 +63,11 @@
 #include "base/win/win_util.h"
 #endif
 
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+#include "chrome/browser/sessions/session_data_service.h"
+#include "chrome/browser/sessions/session_data_service_factory.h"
+#endif
+
 namespace chrome {
 
 namespace {
@@ -137,8 +142,16 @@
 
 void AttemptRestartInternal(IgnoreUnloadHandlers ignore_unload_handlers) {
   // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead?
-  for (auto* browser : *BrowserList::GetInstance())
+  // TODO(crbug.com/1205798): Unset SaveSessionState if the restart fails.
+  for (auto* browser : *BrowserList::GetInstance()) {
     content::BrowserContext::SaveSessionState(browser->profile());
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+    auto* session_data_service =
+        SessionDataServiceFactory::GetForProfile(browser->profile());
+    if (session_data_service)
+      session_data_service->SetForceKeepSessionState();
+#endif
+  }
 
   PrefService* pref_service = g_browser_process->local_state();
   pref_service->SetBoolean(prefs::kWasRestarted, true);
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.cc b/chrome/browser/policy/messaging_layer/public/report_client.cc
index ae36742..27abc85 100644
--- a/chrome/browser/policy/messaging_layer/public/report_client.cc
+++ b/chrome/browser/policy/messaging_layer/public/report_client.cc
@@ -333,8 +333,9 @@
           {base::TaskPriority::BEST_EFFORT, base::MayBlock()})) {
   // Storage location in the local file system (if local storage is enabled).
   base::FilePath user_data_dir;
-  DCHECK(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
-      << "Could not retrieve base path";
+  const auto res =
+      base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  DCHECK(res) << "Could not retrieve base path";
   reporting_path_ = user_data_dir.Append(kReportingDirectory);
 }
 
diff --git a/chrome/browser/policy/test/url_blacklist_policy_browsertest.cc b/chrome/browser/policy/test/url_blacklist_policy_browsertest.cc
index 29a7164..26fa2ad 100644
--- a/chrome/browser/policy/test/url_blacklist_policy_browsertest.cc
+++ b/chrome/browser/policy/test/url_blacklist_policy_browsertest.cc
@@ -344,7 +344,7 @@
 
   PrefService* prefs = browser()->profile()->GetPrefs();
   const base::ListValue* list_url = prefs->GetList(policy_prefs::kUrlBlocklist);
-  EXPECT_EQ(list_url->Find(base::Value("file://*")), list_url->end());
+  EXPECT_EQ(list_url->Find(base::Value("file://*")), list_url->GetList().end());
 
   base::ListValue disabledscheme;
   disabledscheme.AppendString("file");
@@ -354,7 +354,7 @@
   FlushBlacklistPolicy();
 
   list_url = prefs->GetList(policy_prefs::kUrlBlocklist);
-  EXPECT_NE(list_url->Find(base::Value("file://*")), list_url->end());
+  EXPECT_NE(list_url->Find(base::Value("file://*")), list_url->GetList().end());
 
   // Whitelist one folder and blacklist an another just inside.
   base::ListValue whitelist;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index fba43b9d..41162df 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -258,6 +258,7 @@
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_prefs.h"
 #include "chrome/browser/apps/app_service/app_platform_metrics_service.h"
+#include "chrome/browser/apps/app_service/webapk/webapk_prefs.h"
 #include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_cryptohome_remover.h"
@@ -417,6 +418,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_SESSION_SERVICE)
+#include "chrome/browser/sessions/session_data_service.h"
 #include "chrome/browser/sessions/session_service_log.h"
 #endif
 namespace {
@@ -1000,6 +1002,7 @@
 
 #if BUILDFLAG(ENABLE_SESSION_SERVICE)
   RegisterSessionServiceLogProfilePrefs(registry);
+  SessionDataService::RegisterProfilePrefs(registry);
 #endif
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -1100,6 +1103,7 @@
   app_list::AppListSyncableService::RegisterProfilePrefs(registry);
   app_list::ArcAppReinstallSearchProvider::RegisterProfilePrefs(registry);
   apps::AppPlatformMetricsService::RegisterProfilePrefs(registry);
+  apps::webapk_prefs::RegisterProfilePrefs(registry);
   arc::prefs::RegisterProfilePrefs(registry);
   ArcAppListPrefs::RegisterProfilePrefs(registry);
   certificate_manager::CertificatesHandler::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc
index 2f7e276..ab7d788 100644
--- a/chrome/browser/profiles/avatar_menu.cc
+++ b/chrome/browser/profiles/avatar_menu.cc
@@ -56,7 +56,7 @@
   // Register this as an observer of the SupervisedUserService to be notified
   // of changes to the custodian info.
   if (browser_) {
-    supervised_user_observer_.Add(
+    supervised_user_observation_.Observe(
         SupervisedUserServiceFactory::GetForProfile(browser_->profile()));
   }
 #endif
diff --git a/chrome/browser/profiles/avatar_menu.h b/chrome/browser/profiles/avatar_menu.h
index 9a14085..399a696 100644
--- a/chrome/browser/profiles/avatar_menu.h
+++ b/chrome/browser/profiles/avatar_menu.h
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/common/buildflags.h"
@@ -188,8 +188,8 @@
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   // Observes changes to a supervised user's custodian info.
-  ScopedObserver<SupervisedUserService, SupervisedUserServiceObserver>
-      supervised_user_observer_{this};
+  base::ScopedObservation<SupervisedUserService, SupervisedUserServiceObserver>
+      supervised_user_observation_{this};
 #endif
 
   // The storage that provides the profile attributes.
diff --git a/chrome/browser/profiles/profile_activity_metrics_recorder.cc b/chrome/browser/profiles/profile_activity_metrics_recorder.cc
index 4cb3145..00cbd4ab 100644
--- a/chrome/browser/profiles/profile_activity_metrics_recorder.cc
+++ b/chrome/browser/profiles/profile_activity_metrics_recorder.cc
@@ -149,8 +149,8 @@
 
     running_session_profile_ = active_profile;
     running_session_start_ = base::TimeTicks::Now();
-    profile_observer_.RemoveAll();
-    profile_observer_.Add(running_session_profile_);
+    profile_observation_.Reset();
+    profile_observation_.Observe(running_session_profile_);
 
     // Record state at startup (when |last_session_end_| is 0) and whenever the
     // user starts browsing after a longer time of inactivity. Do it
@@ -186,7 +186,8 @@
   // profiles.
   RecordProfileSessionDuration(running_session_profile_,
                                session_end - running_session_start_);
-  profile_observer_.Remove(running_session_profile_);
+  DCHECK(profile_observation_.IsObservingSource(running_session_profile_));
+  profile_observation_.Reset();
   running_session_profile_ = nullptr;
   last_session_end_ = base::TimeTicks::Now();
 }
@@ -201,7 +202,8 @@
   // TODO(crbug.com/1096145): explore having
   // DesktopSessionDurationTracker call OnSessionEnded() when the
   // profile is destroyed. Remove this workaround if this is done.
-  profile_observer_.Remove(running_session_profile_);
+  DCHECK(profile_observation_.IsObservingSource(running_session_profile_));
+  profile_observation_.Reset();
   running_session_profile_ = nullptr;
   last_active_profile_ = nullptr;
   last_session_end_ = base::TimeTicks::Now();
diff --git a/chrome/browser/profiles/profile_activity_metrics_recorder.h b/chrome/browser/profiles/profile_activity_metrics_recorder.h
index cbcbc0f..949f6d18 100644
--- a/chrome/browser/profiles/profile_activity_metrics_recorder.h
+++ b/chrome/browser/profiles/profile_activity_metrics_recorder.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/metrics/user_metrics.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
 #include "chrome/browser/profiles/profile.h"
@@ -61,7 +61,7 @@
 
   base::ActionCallback action_callback_;
 
-  ScopedObserver<Profile, ProfileObserver> profile_observer_{this};
+  base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
 };
 
 #endif  // CHROME_BROWSER_PROFILES_PROFILE_ACTIVITY_METRICS_RECORDER_H_
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index f275add..0273a40 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/scoped_multi_source_observation.h"
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
@@ -163,7 +164,7 @@
   ProfileDestructionWatcher() = default;
   ~ProfileDestructionWatcher() override = default;
 
-  void Watch(Profile* profile) { observed_profiles_.Add(profile); }
+  void Watch(Profile* profile) { observed_profiles_.AddObservation(profile); }
 
   bool destroyed() const { return destroyed_; }
 
@@ -175,12 +176,13 @@
     DCHECK(!destroyed_) << "Double profile destruction";
     destroyed_ = true;
     run_loop_.Quit();
-    observed_profiles_.Remove(profile);
+    observed_profiles_.RemoveObservation(profile);
   }
 
   bool destroyed_ = false;
   base::RunLoop run_loop_;
-  ScopedObserver<Profile, ProfileObserver> observed_profiles_{this};
+  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
+      observed_profiles_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ProfileDestructionWatcher);
 };
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index 19727f6..744a4c8 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -43,11 +43,9 @@
 }  // namespace
 
 ProfileDownloader::ProfileDownloader(ProfileDownloaderDelegate* delegate)
-    : delegate_(delegate),
-      identity_manager_(delegate_->GetIdentityManager()),
-      identity_manager_observer_(this) {
+    : delegate_(delegate), identity_manager_(delegate_->GetIdentityManager()) {
   DCHECK(delegate_);
-  identity_manager_observer_.Add(identity_manager_);
+  identity_manager_observation_.Observe(identity_manager_);
 }
 
 void ProfileDownloader::Start() {
@@ -142,7 +140,7 @@
 
 ProfileDownloader::~ProfileDownloader() {
   oauth2_access_token_fetcher_.reset();
-  identity_manager_observer_.Remove(identity_manager_);
+  DCHECK(identity_manager_observation_.IsObservingSource(identity_manager_));
 }
 
 void ProfileDownloader::FetchImageData() {
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 8c52d01..decb637 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/gtest_prod_util.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/image_decoder/image_decoder.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -123,8 +123,9 @@
   SkBitmap profile_picture_;
   PictureStatus picture_status_ = PICTURE_FAILED;
   signin::IdentityManager* identity_manager_;
-  ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
-      identity_manager_observer_;
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      identity_manager_observation_{this};
   bool waiting_for_account_info_ = false;
 };
 
diff --git a/chrome/browser/profiles/profile_keep_alive_types.cc b/chrome/browser/profiles/profile_keep_alive_types.cc
index 2263b03..bc6a765d 100644
--- a/chrome/browser/profiles/profile_keep_alive_types.cc
+++ b/chrome/browser/profiles/profile_keep_alive_types.cc
@@ -41,6 +41,8 @@
       return out << "kDevToolsWindow";
     case ProfileKeepAliveOrigin::kWebAppPermissionDialogWindow:
       return out << "kWebAppPermissionDialogWindow";
+    case ProfileKeepAliveOrigin::kSessionDataDeleter:
+      return out << "kSessionDataDeleter";
   }
   NOTREACHED();
   return out << static_cast<int>(origin);
diff --git a/chrome/browser/profiles/profile_keep_alive_types.h b/chrome/browser/profiles/profile_keep_alive_types.h
index 3ad9d7f..250071d 100644
--- a/chrome/browser/profiles/profile_keep_alive_types.h
+++ b/chrome/browser/profiles/profile_keep_alive_types.h
@@ -74,7 +74,10 @@
   // A web app permission dialog window is open.
   kWebAppPermissionDialogWindow = 15,
 
-  kMaxValue = kWebAppPermissionDialogWindow,
+  // Data for Clear on Exit is being deleted.
+  kSessionDataDeleter = 16,
+
+  kMaxValue = kSessionDataDeleter,
 };
 
 std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
index 8920c217..5e71c1f 100644
--- a/chrome/browser/profiles/renderer_updater.cc
+++ b/chrome/browser/profiles/renderer_updater.cc
@@ -56,10 +56,9 @@
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 }  // namespace
 
-RendererUpdater::RendererUpdater(Profile* profile)
-    : profile_(profile), identity_manager_observer_(this) {
+RendererUpdater::RendererUpdater(Profile* profile) : profile_(profile) {
   identity_manager_ = IdentityManagerFactory::GetForProfile(profile);
-  identity_manager_observer_.Add(identity_manager_);
+  identity_manager_observation_.Observe(identity_manager_);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   oauth2_login_manager_ =
       chromeos::OAuth2LoginManagerFactory::GetForProfile(profile_);
@@ -100,7 +99,7 @@
   oauth2_login_manager_->RemoveObserver(this);
   oauth2_login_manager_ = nullptr;
 #endif
-  identity_manager_observer_.RemoveAll();
+  identity_manager_observation_.Reset();
   identity_manager_ = nullptr;
 }
 
diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
index 2643b6f1..f4aab406 100644
--- a/chrome/browser/profiles/renderer_updater.h
+++ b/chrome/browser/profiles/renderer_updater.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/common/renderer_configuration.mojom-forward.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -86,8 +86,9 @@
   IntegerPrefMember force_youtube_restrict_;
   StringPrefMember allowed_domains_for_apps_;
 
-  ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
-      identity_manager_observer_;
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      identity_manager_observation_{this};
   signin::IdentityManager* identity_manager_;
 };
 
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index bd125ef..c613ade 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -271,7 +271,7 @@
 
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
-  refresh_observer_.Add(&refresher_);
+  refresh_observation_.Observe(&refresher_);
 }
 
 PushMessagingServiceImpl::~PushMessagingServiceImpl() = default;
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h
index 858deed..186b3a3 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.h
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -18,7 +18,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h"
 #include "chrome/browser/push_messaging/push_messaging_notification_manager.h"
@@ -423,8 +423,9 @@
 
   PushMessagingRefresher refresher_;
 
-  ScopedObserver<PushMessagingRefresher, PushMessagingRefresher::Observer>
-      refresh_observer_{this};
+  base::ScopedObservation<PushMessagingRefresher,
+                          PushMessagingRefresher::Observer>
+      refresh_observation_{this};
   // A multiset containing one entry for each in-flight push message delivery,
   // keyed by the receiver's app id.
   std::multiset<std::string> in_flight_message_deliveries_;
diff --git a/chrome/browser/resources/bluetooth_internals/BUILD.gn b/chrome/browser/resources/bluetooth_internals/BUILD.gn
index 26a9f6d..8c7254e7 100644
--- a/chrome/browser/resources/bluetooth_internals/BUILD.gn
+++ b/chrome/browser/resources/bluetooth_internals/BUILD.gn
@@ -255,6 +255,7 @@
     "device_collection.js",
     "device_details_page.js",
     "device_table.js",
+    "device_utils.js",
     "devices_page.js",
     "expandable_list.js",
     "bluetooth_internals.html",
diff --git a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
index 290fb38..cdd0e33 100644
--- a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
+++ b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
@@ -65,6 +65,7 @@
         <th data-field="address">Address</th>
         <th data-field="rssi.value">Latest RSSI</th>
         <th data-field="services.length">Services</th>
+        <th data-field="manufacturerDataMap">Manufacturer Data</th>
         <th data-field="isGattConnected">GATT Connection State</th>
         <th></th>
       </tr>
diff --git a/chrome/browser/resources/bluetooth_internals/device_details_page.js b/chrome/browser/resources/bluetooth_internals/device_details_page.js
index 6f84faf..66d2a68 100644
--- a/chrome/browser/resources/bluetooth_internals/device_details_page.js
+++ b/chrome/browser/resources/bluetooth_internals/device_details_page.js
@@ -12,6 +12,7 @@
 
 import {connectToDevice} from './device_broker.js';
 import {ConnectionStatus} from './device_collection.js';
+import {formatManufacturerDataMap} from './device_utils.js';
 import {ObjectFieldSet} from './object_fieldset.js';
 import {Page} from './page.js';
 import {ServiceList} from './service_list.js';
@@ -27,6 +28,7 @@
   isGattConnected: 'GATT Connected',
   'rssi.value': 'Latest RSSI',
   'services.length': 'Services',
+  manufacturerDataMap: 'Manufacturer Data',
 };
 
 /**
@@ -166,12 +168,16 @@
       serviceCount = services.length;
     }
 
+    const manufacturerDataMapText =
+        formatManufacturerDataMap(this.deviceInfo.manufacturerDataMap);
+
     const deviceViewObj = {
       name: this.deviceInfo.nameForDisplay,
       address: this.deviceInfo.address,
       isGattConnected: connectedText,
       'rssi.value': rssiValue,
       'services.length': serviceCount,
+      manufacturerDataMap: manufacturerDataMapText,
     };
 
     this.deviceFieldSet_.setObject(deviceViewObj);
diff --git a/chrome/browser/resources/bluetooth_internals/device_table.js b/chrome/browser/resources/bluetooth_internals/device_table.js
index ad11e92da..327d804 100644
--- a/chrome/browser/resources/bluetooth_internals/device_table.js
+++ b/chrome/browser/resources/bluetooth_internals/device_table.js
@@ -10,14 +10,16 @@
 import {$} from 'chrome://resources/js/util.m.js';
 
 import {DeviceCollection} from './device_collection.js';
+import {formatManufacturerDataMap} from './device_utils.js';
 
 const COLUMNS = {
   NAME: 0,
   ADDRESS: 1,
   RSSI: 2,
-  SERVICES: 3,
-  CONNECTION_STATE: 4,
-  LINKS: 5,
+  MANUFACTURER_DATA: 3,
+  SERVICES: 4,
+  CONNECTION_STATE: 5,
+  LINKS: 6,
 };
 
 /**
@@ -230,6 +232,8 @@
 
       if (propName == 'isGattConnected') {
         obj = obj ? 'Connected' : 'Not Connected';
+      } else if (propName == 'manufacturerDataMap') {
+        obj = formatManufacturerDataMap(obj);
       }
 
       const cell = row.cells[i];
diff --git a/chrome/browser/resources/bluetooth_internals/device_utils.js b/chrome/browser/resources/bluetooth_internals/device_utils.js
new file mode 100644
index 0000000..c64b4ee3
--- /dev/null
+++ b/chrome/browser/resources/bluetooth_internals/device_utils.js
@@ -0,0 +1,19 @@
+// 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.
+
+/**
+ * Format in a user readable way device manufacturer data map. Keys are
+ * Bluetooth company identifiers (unsigned short), values are bytes.
+ * @param {Map<string, array<number>>} manufacturerDataMap
+ * @return {string}
+ */
+export function formatManufacturerDataMap(manufacturerDataMap) {
+  return Object.entries(manufacturerDataMap)
+      .map(([key, value]) => {
+        const companyIdentifier = parseInt(key).toString(16).padStart(4, '0');
+        const data = value.map(v => v.toString(16).padStart(2, '0')).join('');
+        return `0x${companyIdentifier} 0x${data}`;
+      })
+      .join(' | ');
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_bn.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_bn.xtb
index db0860f..5c822d2 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_bn.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_bn.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">ইউআরএল-এর লিঙ্ক: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">টেক্সটের কার্সার একটি অক্ষরের পিছনে নিয়ে যান</translation>
 <translation id="2220529011494928058">কোনো সমস্যার অভিযোগ করুন</translation>
+<translation id="2243633977138166243">নেভিগেট করতে বাঁ বা ডানদিকের তীরচিহ্ন ও বেছে নিতে এন্টার টিপুন</translation>
 <translation id="224426591676115802"><ph name="LANGUAGE" /> ভাষার জন্য কোনও ভয়েস উপলভ্য নেই</translation>
 <translation id="2247700577781885251">লার্ন মোড থামানো হচ্ছে</translation>
 <translation id="225732394367814946">কথনের হার বাড়ান</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
index 8448d91..6bcedd2 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">링크 URL: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">한 글자 뒤로 이동</translation>
 <translation id="2220529011494928058">문제 신고</translation>
+<translation id="2243633977138166243">왼쪽 또는 오른쪽 화살표를 눌러서 이동, Enter 키를 눌러서 활성화</translation>
 <translation id="224426591676115802"><ph name="LANGUAGE" />에 사용 가능한 음성 없음</translation>
 <translation id="2247700577781885251">학습 모드 중지 중</translation>
 <translation id="225732394367814946">말하기 속도 증가</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_pa.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_pa.xtb
index d5c3270..951295d 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_pa.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_pa.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">ਲਿੰਕ ਦਾ URL: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">ਇੱਕ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਪਿੱਛੇ ਵੱਲ ਲਿਜਾਓ</translation>
 <translation id="2220529011494928058">ਇੱਕ ਸਮੱਸਿਆ ਦੀ ਰਿਪੋਰਟ ਕਰੋ</translation>
+<translation id="2243633977138166243">ਨੈਵੀਗੇਟ ਕਰਨ ਲਈ ਖੱਬਾ ਜਾਂ ਸੱਜਾ ਤੀਰ ਦਬਾਓ; ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
 <translation id="224426591676115802">ਇਸ ਭਾਸ਼ਾ ਲਈ ਕੋਈ ਅਵਾਜ਼ ਉਪਲਬਧ ਨਹੀਂ ਹੈ: <ph name="LANGUAGE" /></translation>
 <translation id="2247700577781885251">'ਸਿੱਖਣ ਸੰਬੰਧੀ ਮੋਡ' ਬੰਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ</translation>
 <translation id="225732394367814946">ਸਪੀਚ ਦਾ ਰੇਟ ਵਧਾਓ</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_sq.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_sq.xtb
index 30955f35..5e5ef3b 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_sq.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_sq.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">URL-ja e lidhjes: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">Lëviz prapa një karakter</translation>
 <translation id="2220529011494928058">Raporto një problem</translation>
+<translation id="2243633977138166243">Shtyp shigjetën majtas ose djathtas për të naviguar; shtyp "Enter" për ta aktivizuar</translation>
 <translation id="224426591676115802">Nuk ofrohet asnjë zë për gjuhën: <ph name="LANGUAGE" /></translation>
 <translation id="2247700577781885251">Po ndalon "Modalitetin e të mësuarit"</translation>
 <translation id="225732394367814946">Rrit shpejtësinë e ligjërimit</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_te.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_te.xtb
index 91a407d..e298ec0 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_te.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_te.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">లింక్ URL: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">ఒక అక్షరం వెనుకకు జరుపు</translation>
 <translation id="2220529011494928058">సమస్యను రిపోర్ట్ చేయండి</translation>
+<translation id="2243633977138166243">నావిగేట్ చేయడానికి ఎడమ లేదా కుడి వైపు బాణాన్ని నొక్కండి; యాక్టివేట్ చేయడానికి ఎంటర్‌ను నొక్కండి</translation>
 <translation id="224426591676115802">ఈ భాషలో వాయిస్ ఏదీ అందుబాటులో లేదు: <ph name="LANGUAGE" /></translation>
 <translation id="2247700577781885251">తెలుసుకునే మోడ్ ఆపివేయబడుతోంది</translation>
 <translation id="225732394367814946">ప్రసంగ రేటు పెంచండి</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_vi.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_vi.xtb
index fab5467..37fc238 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_vi.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_vi.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">URL của đường liên kết: <ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">Lùi lại một ký tự</translation>
 <translation id="2220529011494928058">Báo cáo sự cố</translation>
+<translation id="2243633977138166243">Nhấn mũi tên trái hoặc phải để di chuyển; nhấn phím Enter để kích hoạt</translation>
 <translation id="224426591676115802">Không có giọng nói cho ngôn ngữ: <ph name="LANGUAGE" /></translation>
 <translation id="2247700577781885251">Đang dừng Chế độ học</translation>
 <translation id="225732394367814946">Tăng tốc độ nói</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
index da883ac2..27c7a1fac 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
@@ -180,6 +180,7 @@
 <translation id="2216790501338699346">連結網址:<ph name="LINK_URL" /></translation>
 <translation id="2220205454259065436">移到上一個字元</translation>
 <translation id="2220529011494928058">回報問題</translation>
+<translation id="2243633977138166243">按下向左或向右鍵即可瀏覽;按下 Enter 鍵即可啟用</translation>
 <translation id="224426591676115802">下列語言沒有可用的語音服務:<ph name="LANGUAGE" /></translation>
 <translation id="2247700577781885251">正在停止學習模式</translation>
 <translation id="225732394367814946">加快說話速度</translation>
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 1e6aac39..886541a 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -93,6 +93,7 @@
    *   isSupervisedUser: boolean,
    *   isDeviceOwner: boolean,
    *   ssoProfile: string,
+   *   enableCloseView: boolean,
    * }}
    */
   /* #export */ let AuthParams;
@@ -109,6 +110,12 @@
   const SAML_REDIRECTION_PATH = 'samlredirect';
   const BLANK_PAGE_URL = 'about:blank';
 
+  // Metric names for messages we get from Gaia.
+  const GAIA_MESSAGE_SAML_USER_INFO = 'ChromeOS.Gaia.Message.Saml.UserInfo';
+  const GAIA_MESSAGE_GAIA_USER_INFO = 'ChromeOS.Gaia.Message.Gaia.UserInfo';
+  const GAIA_MESSAGE_SAML_CLOSE_VIEW = 'ChromeOS.Gaia.Message.Saml.CloseView';
+  const GAIA_MESSAGE_GAIA_CLOSE_VIEW = 'ChromeOS.Gaia.Message.Gaia.CloseView';
+
   /**
    * The source URL parameter for the constrained signin flow.
    */
@@ -206,12 +213,15 @@
     'isSupervisedUser',  // True if the user is supervised user.
     'isDeviceOwner',     // True if the user is device owner.
     'doSamlRedirect',    // True if the authentication is done via external IdP.
+    'enableCloseView',   // True if authenticator should wait for the closeView
+                         // message from Gaia.
   ];
 
-  // Timeout in ms to wait for the user info message. The message is used to
-  // extract user services and to define whether or not the account is a child
-  // one.
-  const USER_INFO_WAIT_TIMEOUT_MS = 5 * 1000;
+  // Timeout in ms to wait for the message from Gaia indicating end of the flow.
+  // Could be userInfo (The message is used to extract user services and to
+  // define whether or not the account is a child one) or closeView (specific
+  // message to indicate the end of the flow).
+  const GAIA_DONE_WAIT_TIMEOUT_MS = 5 * 1000;
 
   /**
    * Extract domain name from an URL.
@@ -267,6 +277,12 @@
     },
     'userInfo'(msg) {
       this.services_ = msg.services;
+      if (!this.authCompletedFired_) {
+        const metric = this.authFlow == AuthFlow.SAML ?
+            GAIA_MESSAGE_SAML_USER_INFO :
+            GAIA_MESSAGE_GAIA_USER_INFO;
+        chrome.send('metricsHandler:recordBooleanHistogram', [metric, true]);
+      }
       if (this.email_ && this.gaiaId_ && this.sessionIndex_) {
         this.maybeCompleteAuth_();
       }
@@ -321,6 +337,27 @@
         return;
       }
       this.syncTrustedVaultKeys_ = msg.value;
+    },
+    'closeView'(msg) {
+      if (!this.enableCloseView_) {
+        return;
+      }
+
+      if (!this.services_) {
+        console.error('Authenticator: UserInfo should come before closeView');
+      }
+
+      if (!this.authCompletedFired_) {
+        const metric = this.authFlow == AuthFlow.SAML ?
+            GAIA_MESSAGE_SAML_CLOSE_VIEW :
+            GAIA_MESSAGE_GAIA_CLOSE_VIEW;
+        chrome.send('metricsHandler:recordBooleanHistogram', [metric, true]);
+      }
+
+      this.closeViewReceived_ = true;
+      if (this.email_ && this.gaiaId_ && this.sessionIndex_) {
+        this.maybeCompleteAuth_();
+      }
     }
   };
 
@@ -377,6 +414,7 @@
           webview;
       assert(this.webview_);
       this.enableGaiaActionButtons_ = false;
+      this.enableCloseView_ = false;
       this.webviewEventManager_ = WebviewEventManager.create();
 
       this.clientId_ = null;
@@ -399,7 +437,7 @@
       this.needPassword = true;
       this.enableSyncTrustedVaultKeys_ = false;
       this.services_ = null;
-      this.userInfoTimer_ = null;
+      this.gaiaDoneTimer_ = null;
       /**
        * Caches the result of |getIsSamlUserPasswordlessCallback| invocation for
        * the current user. Null if no result is obtained yet.
@@ -412,6 +450,7 @@
       this.samlAclUrl_ = null;
       /** @private {?SyncTrustedVaultKeys} */
       this.syncTrustedVaultKeys_ = null;
+      this.closeViewReceived_ = false;
 
       window.addEventListener(
           'message', this.onMessageFromWebview_.bind(this), false);
@@ -449,9 +488,10 @@
       this.samlHandler_.reset();
       this.videoEnabled = false;
       this.services_ = null;
-      this.userInfoTimer_ = null;
+      this.gaiaDoneTimer_ = null;
       this.isSamlUserPasswordless_ = null;
       this.syncTrustedVaultKeys_ = null;
+      this.closeViewReceived_ = false;
     }
 
     /**
@@ -617,6 +657,7 @@
       this.dontResizeNonEmbeddedPages = data.dontResizeNonEmbeddedPages;
       this.enableGaiaActionButtons_ = data.enableGaiaActionButtons;
       this.enableSyncTrustedVaultKeys_ = !!data.enableSyncTrustedVaultKeys;
+      this.enableCloseView_ = !!data.enableCloseView;
 
       this.initialFrameUrl_ = this.constructInitialFrameUrl_(data);
       this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_;
@@ -1013,23 +1054,26 @@
       }
 
       // Could be set either by `userInfo` message or by the
-      // `onUserInfoTimeout_`.
+      // `onGaiaDoneTimeout_`.
       const userInfoAvailable = !!this.services_;
 
-      if (userInfoAvailable && this.userInfoTimer_) {
-        window.clearTimeout(this.userInfoTimer_);
-        this.userInfoTimer_ = null;
+      const gaiaDone = userInfoAvailable &&
+          (!this.enableCloseView_ || this.closeViewReceived_);
+
+      if (gaiaDone && this.gaiaDoneTimer_) {
+        window.clearTimeout(this.gaiaDoneTimer_);
+        this.gaiaDoneTimer_ = null;
       }
 
-      if (this.userInfoTimer_) {
-        // Early out if `userInfoTimer_` is running.
+      if (this.gaiaDoneTimer_) {
+        // Early out if `gaiaDoneTimer_` is running.
         return;
       }
 
-      if (!userInfoAvailable) {
-        // Start `userInfoTimer_` if user info is not available.
-        this.userInfoTimer_ = window.setTimeout(
-            this.onUserInfoTimeout_.bind(this), USER_INFO_WAIT_TIMEOUT_MS);
+      if (!gaiaDone) {
+        // Start `gaiaDoneTimer_` if user info is not available.
+        this.gaiaDoneTimer_ = window.setTimeout(
+            this.onGaiaDoneTimeout_.bind(this), GAIA_DONE_WAIT_TIMEOUT_MS);
         return;
       }
 
@@ -1387,11 +1431,27 @@
      * Callback for the user info message waiting timeout.
      * @private
      */
-    onUserInfoTimeout_() {
-      console.warn('User info timeout: Forcing empty services.');
-      assert(!this.services_);
-      this.services_ = [];
-      this.userInfoTimer_ = null;
+    onGaiaDoneTimeout_() {
+      if (!this.services_) {
+        console.error('Gaia done timeout: Forcing empty services.');
+        this.services_ = [];
+        const metric = this.authFlow == AuthFlow.SAML ?
+            GAIA_MESSAGE_SAML_USER_INFO :
+            GAIA_MESSAGE_GAIA_USER_INFO;
+        chrome.send('metricsHandler:recordBooleanHistogram', [metric, false]);
+      }
+
+      if (this.enableCloseView_ && !this.closeViewReceived_) {
+        console.error('Gaia done timeout: closeView was not called.');
+        this.closeViewReceived_ = true;
+
+        const metric = this.authFlow == AuthFlow.SAML ?
+            GAIA_MESSAGE_SAML_CLOSE_VIEW :
+            GAIA_MESSAGE_GAIA_CLOSE_VIEW;
+        chrome.send('metricsHandler:recordBooleanHistogram', [metric, false]);
+      }
+
+      this.gaiaDoneTimer_ = null;
       this.maybeCompleteAuth_();
     }
   }
diff --git a/chrome/browser/resources_integrity.cc b/chrome/browser/resources_integrity.cc
new file mode 100644
index 0000000..cbedea4
--- /dev/null
+++ b/chrome/browser/resources_integrity.cc
@@ -0,0 +1,92 @@
+// 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/resources_integrity.h"
+
+#include <array>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/path_service.h"
+#include "base/process/process_metrics.h"
+#include "base/ranges/algorithm.h"
+#include "base/task/thread_pool.h"
+#include "chrome/common/chrome_paths.h"
+#include "crypto/secure_hash.h"
+
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+#include "chrome/app/packed_resources_integrity.h"
+#endif
+
+namespace {
+
+bool CheckResourceIntegrityInternal(
+    const base::FilePath& path,
+    const base::span<const uint8_t, crypto::kSHA256Length> expected_signature) {
+  // Open the file for reading; allowing other consumers to also open it for
+  // reading and deleting. Do not allow others to write to it.
+  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
+                            base::File::FLAG_EXCLUSIVE_WRITE |
+                            base::File::FLAG_SHARE_DELETE);
+  if (!file.IsValid())
+    return false;
+
+  auto hash = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
+  std::vector<char> buffer(base::GetPageSize());
+
+  int bytes_read = 0;
+  do {
+    bytes_read = file.ReadAtCurrentPos(buffer.data(), buffer.size());
+    if (bytes_read == -1)
+      return false;
+    hash->Update(buffer.data(), bytes_read);
+  } while (bytes_read > 0);
+
+  std::array<uint8_t, crypto::kSHA256Length> digest;
+  hash->Finish(digest.data(), digest.size());
+
+  return base::ranges::equal(digest, expected_signature);
+}
+
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+void ReportPakIntegrity(const std::string& histogram_name, bool hash_matches) {
+  base::UmaHistogramBoolean(histogram_name, hash_matches);
+}
+#endif
+
+}  // namespace
+
+void CheckResourceIntegrity(
+    const base::FilePath& path,
+    const base::span<const uint8_t, crypto::kSHA256Length> expected_signature,
+    base::OnceCallback<void(bool)> callback) {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::BindOnce(&CheckResourceIntegrityInternal, path, expected_signature),
+      std::move(callback));
+}
+
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+void CheckPakFileIntegrity() {
+  base::FilePath resources_pack_path;
+  base::PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
+
+  CheckResourceIntegrity(resources_pack_path, kSha256_resources_pak,
+                         base::BindOnce(&ReportPakIntegrity,
+                                        "SafeBrowsing.PakIntegrity.Resources"));
+  CheckResourceIntegrity(
+      resources_pack_path.DirName().AppendASCII("chrome_100_percent.pak"),
+      kSha256_chrome_100_percent_pak,
+      base::BindOnce(&ReportPakIntegrity,
+                     "SafeBrowsing.PakIntegrity.Chrome100"));
+  CheckResourceIntegrity(
+      resources_pack_path.DirName().AppendASCII("chrome_200_percent.pak"),
+      kSha256_chrome_200_percent_pak,
+      base::BindOnce(&ReportPakIntegrity,
+                     "SafeBrowsing.PakIntegrity.Chrome200"));
+}
+#endif
diff --git a/chrome/browser/resources_integrity.h b/chrome/browser/resources_integrity.h
new file mode 100644
index 0000000..12e0a97
--- /dev/null
+++ b/chrome/browser/resources_integrity.h
@@ -0,0 +1,29 @@
+// 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_RESOURCES_INTEGRITY_H_
+#define CHROME_BROWSER_RESOURCES_INTEGRITY_H_
+
+#include "base/callback.h"
+#include "base/containers/span.h"
+#include "base/files/file_path.h"
+#include "chrome/browser/buildflags.h"
+#include "crypto/sha2.h"
+
+// Computes a SHA-256 hash of the contents of file at |path| and compares it
+// to the specified |expected_signature|. If no errors occur and the signatures
+// match, runs |callback| with |true|; otherwise runs it with |false|.
+void CheckResourceIntegrity(
+    const base::FilePath& path,
+    const base::span<const uint8_t, crypto::kSHA256Length> expected_signature,
+    base::OnceCallback<void(bool)> callback);
+
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+// Checks the main Chrome .pak files for corruption by calling
+// CheckResourceIntegrity(), using hashes generated from the
+// GN target //chrome:packed_resources_integrity.
+void CheckPakFileIntegrity();
+#endif
+
+#endif  // CHROME_BROWSER_RESOURCES_INTEGRITY_H_
diff --git a/chrome/browser/resources_integrity_unittest.cc b/chrome/browser/resources_integrity_unittest.cc
new file mode 100644
index 0000000..3cdf1949
--- /dev/null
+++ b/chrome/browser/resources_integrity_unittest.cc
@@ -0,0 +1,76 @@
+// 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/resources_integrity.h"
+
+#include "base/bind.h"
+#include "base/path_service.h"
+#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "chrome/browser/buildflags.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CheckResourceIntegrityTest : public testing::Test {
+ protected:
+  base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(CheckResourceIntegrityTest, Match) {
+  base::FilePath test_data_path;
+  ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_path));
+
+  std::array<uint8_t, crypto::kSHA256Length> expected = {
+      0x1b, 0x3a, 0x5c, 0x9f, 0x92, 0x74, 0x48, 0xcc, 0x89, 0x1a, 0xe8,
+      0x3e, 0xcb, 0xfa, 0xc6, 0x6e, 0xb8, 0x73, 0x03, 0xf2, 0xb2, 0x25,
+      0xee, 0xf3, 0xba, 0x7f, 0xb6, 0x94, 0x85, 0x61, 0xe2, 0xe8};
+
+  base::RunLoop loop;
+  CheckResourceIntegrity(test_data_path.AppendASCII("circle.svg"), expected,
+                         base::BindLambdaForTesting([&](bool matches) {
+                           EXPECT_TRUE(matches);
+                           loop.Quit();
+                         }));
+  loop.Run();
+}
+
+TEST_F(CheckResourceIntegrityTest, Mismatch) {
+  base::FilePath test_data_path;
+  ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_path));
+
+  std::vector<uint8_t> unexpected(crypto::kSHA256Length, 'a');
+  base::RunLoop loop;
+  CheckResourceIntegrity(test_data_path.AppendASCII("circle.svg"),
+                         base::make_span<32>(unexpected),
+                         base::BindLambdaForTesting([&](bool matches) {
+                           EXPECT_FALSE(matches);
+                           loop.Quit();
+                         }));
+  loop.Run();
+}
+
+TEST_F(CheckResourceIntegrityTest, NonExistentFile) {
+  std::vector<uint8_t> unexpected(crypto::kSHA256Length, 'a');
+  base::RunLoop loop;
+  CheckResourceIntegrity(
+      base::FilePath(FILE_PATH_LITERAL("this file does not exist.moo")),
+      base::make_span<crypto::kSHA256Length>(unexpected),
+      base::BindLambdaForTesting([&](bool matches) {
+        EXPECT_FALSE(matches);
+        loop.Quit();
+      }));
+  loop.Quit();
+}
+
+#if BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
+TEST_F(CheckResourceIntegrityTest, ChromePaks) {
+  base::HistogramTester tester;
+  CheckPakFileIntegrity();
+  task_environment_.RunUntilIdle();
+  tester.ExpectBucketCount("SafeBrowsing.PakIntegrity.Resources", 1, 1);
+  tester.ExpectBucketCount("SafeBrowsing.PakIntegrity.Chrome100", 1, 1);
+  tester.ExpectBucketCount("SafeBrowsing.PakIntegrity.Chrome200", 1, 1);
+}
+#endif  // BUILDFLAG(ENABLE_PAK_FILE_INTEGRITY_CHECKS)
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
index 58927ed..98aa854 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
@@ -72,7 +72,7 @@
       NOTREACHED();
       continue;
     }
-    if (keys_and_digests->empty())
+    if (keys_and_digests->DictEmpty())
       continue;
     int incident_type = 0;
     if (!base::StringToInt(iter.key(), &incident_type)) {
diff --git a/chrome/browser/safe_browsing/incident_reporting/state_store.cc b/chrome/browser/safe_browsing/incident_reporting/state_store.cc
index 91369be6..a37217e 100644
--- a/chrome/browser/safe_browsing/incident_reporting/state_store.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/state_store.cc
@@ -88,7 +88,7 @@
 
 void StateStore::Transaction::ClearAll() {
   // Clear the preference if it exists and contains any values.
-  if (store_->incidents_sent_ && !store_->incidents_sent_->empty())
+  if (store_->incidents_sent_ && !store_->incidents_sent_->DictEmpty())
     GetPrefDict()->Clear();
 }
 
@@ -131,7 +131,7 @@
   std::unique_ptr<base::DictionaryValue> value_dict(
       platform_state_store::Load(profile_));
   if (value_dict) {
-    if (value_dict->empty())
+    if (value_dict->DictEmpty())
       transaction.ClearAll();
     else if (!incidents_sent_ || *incidents_sent_ != *value_dict)
       transaction.ReplacePrefDict(std::move(value_dict));
diff --git a/chrome/browser/search_engines/chrome_template_url_service_client.cc b/chrome/browser/search_engines/chrome_template_url_service_client.cc
index 43446662..06b5974 100644
--- a/chrome/browser/search_engines/chrome_template_url_service_client.cc
+++ b/chrome/browser/search_engines/chrome_template_url_service_client.cc
@@ -14,7 +14,7 @@
   // backend can handle automatically adding the search terms as the user
   // navigates.
   if (history_service_)
-    history_service_observer_.Add(history_service_);
+    history_service_observation_.Observe(history_service_);
 }
 
 ChromeTemplateURLServiceClient::~ChromeTemplateURLServiceClient() {
@@ -28,7 +28,7 @@
   // Remove self from |history_service_| observers in the shutdown phase of the
   // two-phases since KeyedService are not supposed to use a dependend service
   // after the Shutdown call.
-  history_service_observer_.RemoveAll();
+  history_service_observation_.Reset();
 }
 
 void ChromeTemplateURLServiceClient::SetOwner(TemplateURLService* owner) {
diff --git a/chrome/browser/search_engines/chrome_template_url_service_client.h b/chrome/browser/search_engines/chrome_template_url_service_client.h
index 89d5257..f454fdfe 100644
--- a/chrome/browser/search_engines/chrome_template_url_service_client.h
+++ b/chrome/browser/search_engines/chrome_template_url_service_client.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_SEARCH_ENGINES_CHROME_TEMPLATE_URL_SERVICE_CLIENT_H_
 
 #include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/search_engines/template_url_service_client.h"
@@ -38,8 +38,9 @@
 
  private:
   TemplateURLService* owner_;
-  ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
-      history_service_observer_{this};
+  base::ScopedObservation<history::HistoryService,
+                          history::HistoryServiceObserver>
+      history_service_observation_{this};
   history::HistoryService* history_service_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeTemplateURLServiceClient);
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index ec48f9d..9b83830 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -13,13 +13,18 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_keep_alive_types.h"
+#include "chrome/browser/profiles/scoped_profile_keep_alive.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
@@ -40,18 +45,25 @@
          !policy->IsStorageProtected(origin.GetURL());
 }
 
-class SessionDataDeleter
-    : public base::RefCountedThreadSafe<SessionDataDeleter> {
+class SessionDataDeleterInternal
+    : public base::RefCountedThreadSafe<SessionDataDeleterInternal> {
  public:
-  SessionDataDeleter(storage::SpecialStoragePolicy* storage_policy,
-                     bool delete_only_by_session_only_policy);
+  SessionDataDeleterInternal(Profile* profile,
+                             bool delete_only_by_session_only_policy,
+                             base::OnceClosure callback);
 
   void Run(content::StoragePartition* storage_partition,
            HostContentSettingsMap* host_content_settings_map);
 
  private:
-  friend class base::RefCountedThreadSafe<SessionDataDeleter>;
-  ~SessionDataDeleter();
+  friend class base::RefCountedThreadSafe<SessionDataDeleterInternal>;
+  ~SessionDataDeleterInternal();
+
+  // These functions are used to hold a reference to this object until the
+  // cookie and storage deletions are done. This way the keep alives ensure that
+  // the profile does not shut down during the deletion.
+  void OnCookieDeletionDone(bool success) {}
+  void OnStorageDeletionDone() {}
 
   // Takes the result of a CookieManager::GetAllCookies() method, and
   // initiates deletion of all cookies that are session only by the
@@ -59,21 +71,31 @@
   void DeleteSessionOnlyOriginCookies(
       const std::vector<net::CanonicalCookie>& cookies);
 
+  std::unique_ptr<ScopedKeepAlive> keep_alive_;
+  std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
+  base::OnceClosure callback_;
   mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
   const bool delete_only_by_session_only_policy_;
 
-  DISALLOW_COPY_AND_ASSIGN(SessionDataDeleter);
+  DISALLOW_COPY_AND_ASSIGN(SessionDataDeleterInternal);
 };
 
-SessionDataDeleter::SessionDataDeleter(
-    storage::SpecialStoragePolicy* storage_policy,
-    bool delete_only_by_session_only_policy)
-    : storage_policy_(storage_policy),
-      delete_only_by_session_only_policy_(delete_only_by_session_only_policy) {
-}
+SessionDataDeleterInternal::SessionDataDeleterInternal(
+    Profile* profile,
+    bool delete_only_by_session_only_policy,
+    base::OnceClosure callback)
+    : keep_alive_(std::make_unique<ScopedKeepAlive>(
+          KeepAliveOrigin::SESSION_DATA_DELETER,
+          KeepAliveRestartOption::ENABLED)),
+      profile_keep_alive_(std::make_unique<ScopedProfileKeepAlive>(
+          profile,
+          ProfileKeepAliveOrigin::kSessionDataDeleter)),
+      callback_(std::move(callback)),
+      storage_policy_(profile->GetSpecialStoragePolicy()),
+      delete_only_by_session_only_policy_(delete_only_by_session_only_policy) {}
 
-void SessionDataDeleter::Run(
+void SessionDataDeleterInternal::Run(
     content::StoragePartition* storage_partition,
     HostContentSettingsMap* host_content_settings_map) {
   if (storage_policy_.get() && storage_policy_->HasSessionOnlyOrigins()) {
@@ -81,12 +103,14 @@
     const uint32_t removal_mask =
         content::StoragePartition::REMOVE_DATA_MASK_ALL &
         ~content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
+    // Clear storage and keep this object alive until deletion is done.
     storage_partition->ClearData(
         removal_mask, content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
         base::BindRepeating(&OriginMatcher),
         /*cookie_deletion_filter=*/nullptr,
         /*perform_storage_cleanup=*/false, base::Time(), base::Time::Max(),
-        base::DoNothing());
+        base::BindOnce(&SessionDataDeleterInternal::OnStorageDeletionDone,
+                       this));
   }
 
   storage_partition->GetNetworkContext()->GetCookieManager(
@@ -99,8 +123,9 @@
         network::mojom::CookieDeletionSessionControl::SESSION_COOKIES;
     cookie_manager_->DeleteCookies(
         std::move(filter),
-        // Fire and forget
-        network::mojom::CookieManager::DeleteCookiesCallback());
+        // Fire and forget. Session cookies will be cleaned up on start as well.
+        // (SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup)
+        base::DoNothing());
 
     // If the permissions policy feature is enabled, delete the client hint
     // preferences
@@ -114,20 +139,14 @@
     return;
 
   cookie_manager_->GetAllCookies(base::BindOnce(
-      &SessionDataDeleter::DeleteSessionOnlyOriginCookies, this));
+      &SessionDataDeleterInternal::DeleteSessionOnlyOriginCookies, this));
   // Note that from this point on |*this| is kept alive by scoped_refptr<>
   // references automatically taken by |Bind()|, so when the last callback
   // created by Bind() is released (after execution of that function), the
-  // object will be deleted.  This may result in any callbacks passed to
-  // |*cookie_manager_.get()| methods not being executed because of the
-  // destruction of the mojo::Remote<CookieManager>, but the model of the
-  // SessionDataDeleter is "fire-and-forget" and all such callbacks are
-  // empty, so that is ok.  Mojo guarantees that all messages pushed onto a
-  // pipe will be executed by the server side of the pipe even if the client
-  // side of the pipe is closed, so all deletion requested will still occur.
+  // object will be deleted.
 }
 
-void SessionDataDeleter::DeleteSessionOnlyOriginCookies(
+void SessionDataDeleterInternal::DeleteSessionOnlyOriginCookies(
     const std::vector<net::CanonicalCookie>& cookies) {
   auto delete_cookie_predicate =
       storage_policy_->CreateDeleteCookieOnExitPredicate();
@@ -137,34 +156,38 @@
     if (!delete_cookie_predicate.Run(cookie.Domain(), cookie.IsSecure())) {
       continue;
     }
-    // Fire and forget.
-    cookie_manager_->DeleteCanonicalCookie(cookie, base::DoNothing());
+    // Keep this object alive until all deletions are done.
+    cookie_manager_->DeleteCanonicalCookie(
+        cookie, base::BindOnce(
+                    &SessionDataDeleterInternal::OnCookieDeletionDone, this));
   }
 }
 
-SessionDataDeleter::~SessionDataDeleter() {}
+SessionDataDeleterInternal::~SessionDataDeleterInternal() {
+  if (callback_)
+    std::move(callback_).Run();
+}
 
 }  // namespace
 
-void DeleteSessionOnlyData(Profile* profile) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (browser_shutdown::IsTryingToQuit())
-    return;
+SessionDataDeleter::SessionDataDeleter(Profile* profile) : profile_(profile) {}
 
-  // TODO: Remove Athena special casing once the AthenaSessionRestore is in
-  // place.
-#if defined(OS_ANDROID)
-  SessionStartupPref::Type startup_pref_type =
-      SessionStartupPref::GetDefaultStartupType();
-#else
+SessionDataDeleter::~SessionDataDeleter() = default;
+
+void SessionDataDeleter::DeleteSessionOnlyData(base::OnceClosure callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // As this function is creating KeepAlives, it should not be
+  // called during shutdown.
+  DCHECK(!browser_shutdown::IsTryingToQuit());
+
   SessionStartupPref::Type startup_pref_type =
       StartupBrowserCreator::GetSessionStartupPref(
-          *base::CommandLine::ForCurrentProcess(), profile).type;
-#endif
+          *base::CommandLine::ForCurrentProcess(), profile_)
+          .type;
 
-  scoped_refptr<SessionDataDeleter> deleter(
-      new SessionDataDeleter(profile->GetSpecialStoragePolicy(),
-                             startup_pref_type == SessionStartupPref::LAST));
-  deleter->Run(profile->GetDefaultStoragePartition(),
-               HostContentSettingsMapFactory::GetForProfile(profile));
+  auto deleter = base::MakeRefCounted<SessionDataDeleterInternal>(
+      profile_, startup_pref_type == SessionStartupPref::LAST,
+      std::move(callback));
+  deleter->Run(profile_->GetDefaultStoragePartition(),
+               HostContentSettingsMapFactory::GetForProfile(profile_));
 }
diff --git a/chrome/browser/sessions/session_data_deleter.h b/chrome/browser/sessions/session_data_deleter.h
index 710cd7e..91283d27 100644
--- a/chrome/browser/sessions/session_data_deleter.h
+++ b/chrome/browser/sessions/session_data_deleter.h
@@ -5,11 +5,31 @@
 #ifndef CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
 #define CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
 
+#include "base/callback_forward.h"
+
 class Profile;
 
-// Clears cookies and local storage for origins that are session-only and clears
-// session cookies unless the startup preference is to continue the previous
-// session.
-void DeleteSessionOnlyData(Profile* profile);
+// Clears cookies and local storage for origins that are defined as session-only
+// through settings, extensions or enterprise policy and clears session cookies
+// (cookies without expiration date) unless the startup preference is set to
+// continue the previous session.
+// |callback| is called when session-only origin cookies and storage deletions
+// are finished. It does not wait for deletion of regular session cookies since
+// these cookies are cleaned up on startup as well.
+class SessionDataDeleter {
+ public:
+  explicit SessionDataDeleter(Profile* profile);
+  SessionDataDeleter(const SessionDataDeleter&) = delete;
+  SessionDataDeleter& operator=(const SessionDataDeleter&) = delete;
+  virtual ~SessionDataDeleter();
+
+  // Starts deletion of session data. Keeps the Profile and browser process
+  // alive until deletion is finished. Must not be called when the browser is
+  // already shutting down (browser_shutdown::IsTryingToQuit()).
+  virtual void DeleteSessionOnlyData(base::OnceClosure callback);
+
+ private:
+  Profile* profile_;
+};
 
 #endif  // CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
diff --git a/chrome/browser/sessions/session_data_service.cc b/chrome/browser/sessions/session_data_service.cc
index 010da88..da9f45ab0 100644
--- a/chrome/browser/sessions/session_data_service.cc
+++ b/chrome/browser/sessions/session_data_service.cc
@@ -5,15 +5,48 @@
 #include "chrome/browser/sessions/session_data_service.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/time/time.h"
 #include "chrome/browser/defaults.h"
+#include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_data_deleter.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "storage/browser/quota/special_storage_policy.h"
 
-SessionDataService::SessionDataService(Profile* profile) : profile_(profile) {
+namespace {
+// Pref name for Status preference.
+extern const char kSessionDataStatusPref[] = "sessions.session_data_status";
+}  // namespace
+
+// static
+void SessionDataService::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterIntegerPref(kSessionDataStatusPref,
+                                static_cast<int>(Status::kUninitialized));
+}
+
+SessionDataService::SessionDataService(
+    Profile* profile,
+    std::unique_ptr<SessionDataDeleter> deleter)
+    : profile_(profile), deleter_(std::move(deleter)) {
   DCHECK(profile_);
   DCHECK(!profile_->IsOffTheRecord());
+  DCHECK(deleter_);
+
+  Status last_status = static_cast<Status>(
+      profile_->GetPrefs()->GetInteger(kSessionDataStatusPref));
+
+  int int_status = static_cast<int>(last_status);
+  if (int_status < 0 || int_status > static_cast<int>(Status::kMaxValue))
+    last_status = Status::kUninitialized;
+
+  SetStatusPref(Status::kInitialized);
+  RecordHistogramForLastSession(last_status);
+
   for (Browser* browser : *BrowserList::GetInstance())
     OnBrowserAdded(browser);
 
@@ -24,12 +57,30 @@
   BrowserList::RemoveObserver(this);
 }
 
+void SessionDataService::RecordHistogramForLastSession(Status last_status) {
+  if (last_status == Status::kUninitialized)
+    return;
+
+  auto* policy = profile_->GetSpecialStoragePolicy();
+  if (!policy || !policy->HasSessionOnlyOrigins())
+    return;
+
+  base::UmaHistogramEnumeration("Session.SessionData.StatusFromLastSession",
+                                last_status);
+}
+
+void SessionDataService::SetStatusPref(Status status) {
+  profile_->GetPrefs()->SetInteger(kSessionDataStatusPref,
+                                   static_cast<int>(status));
+}
+
 void SessionDataService::OnBrowserAdded(Browser* browser) {
   if (browser->profile() != profile_)
     return;
 
   // A window was opened. Ensure that we run another cleanup the next time
   // all windows are closed.
+  SetStatusPref(Status::kInitialized);
   cleanup_started_ = false;
 }
 
@@ -37,11 +88,6 @@
   if (browser->profile() != profile_)
     return;
 
-  // Don't try anything if we're testing.  The browser_process is not fully
-  // created and DeleteSession will crash if we actually attempt it.
-  if (profile_->AsTestingProfile())
-    return;
-
   // Clear session data if the last window for a profile has been closed and
   // closing the last window would normally close Chrome.
   if (browser_defaults::kBrowserAliveWithNoWindows)
@@ -59,6 +105,31 @@
   if (cleanup_started_)
     return;
 
+  if (force_keep_session_state_)
+    return;
+
+  if (browser_shutdown::IsTryingToQuit()) {
+    SetStatusPref(Status::kNoDeletionDueToShutdown);
+    return;
+  }
+
   cleanup_started_ = true;
-  DeleteSessionOnlyData(profile_);
+  SetStatusPref(Status::kDeletionStarted);
+
+  // Using base::Unretained is safe as DeleteSessionOnlyData() uses a
+  // ScopedProfileKeepAlive.
+  deleter_->DeleteSessionOnlyData(
+      base::BindOnce(&SessionDataService::OnCleanupFinished,
+                     base::Unretained(this), base::TimeTicks::Now()));
+}
+
+void SessionDataService::OnCleanupFinished(base::TimeTicks time_started) {
+  SetStatusPref(Status::kDeletionFinished);
+  base::UmaHistogramMediumTimes("Session.SessionData.CleanupTime",
+                                base::TimeTicks::Now() - time_started);
+}
+
+void SessionDataService::SetForceKeepSessionState() {
+  SetStatusPref(Status::kNoDeletionDueToForceKeepSessionData);
+  force_keep_session_state_ = true;
 }
diff --git a/chrome/browser/sessions/session_data_service.h b/chrome/browser/sessions/session_data_service.h
index b5cf356..af31789 100644
--- a/chrome/browser/sessions/session_data_service.h
+++ b/chrome/browser/sessions/session_data_service.h
@@ -5,30 +5,66 @@
 #ifndef CHROME_BROWSER_SESSIONS_SESSION_DATA_SERVICE_H_
 #define CHROME_BROWSER_SESSIONS_SESSION_DATA_SERVICE_H_
 
+#include <memory>
+
+#include "base/time/time.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class Profile;
+class SessionDataDeleter;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
 
 // SessionDataService is responsible for deleting SessionOnly cookies and
 // site data when the browser or all windows of a profile are closed.
 class SessionDataService : public BrowserListObserver, public KeyedService {
  public:
-  explicit SessionDataService(Profile* profile);
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class Status {
+    kUninitialized = 0,
+    kInitialized = 1,
+    kDeletionStarted = 2,
+    kDeletionFinished = 3,
+    kNoDeletionDueToForceKeepSessionData = 4,
+    kNoDeletionDueToShutdown = 5,
+    kMaxValue = kNoDeletionDueToShutdown,
+  };
+
+  explicit SessionDataService(Profile* profile,
+                              std::unique_ptr<SessionDataDeleter> deleter);
   SessionDataService(const SessionDataService&) = delete;
   SessionDataService& operator=(const SessionDataService&) = delete;
   ~SessionDataService() override;
 
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
   // Starts a deletion of session only cookies and storage unless the deletion
   // is already running or the browser is already shutting down.
   void StartCleanup();
+  // Instructs this class not to delete session state on shutdown.
+  void SetForceKeepSessionState();
 
  private:
   // BrowserListObserver:
   void OnBrowserAdded(Browser* browser) override;
   void OnBrowserRemoved(Browser* browser) override;
 
+  // Records the Status of the last session if there is any session-only origin.
+  void RecordHistogramForLastSession(Status last_status);
+
+  void SetStatusPref(Status status);
+  void OnCleanupFinished(base::TimeTicks time_started);
+
   Profile* profile_;
+  std::unique_ptr<SessionDataDeleter> deleter_;
+  // A flag that is set to skip session data deletion on restarts.
+  bool force_keep_session_state_ = false;
+  // A flag to indicate that a deletion was started and further requests for
+  // cleanup should be ignored.
   bool cleanup_started_ = false;
 };
 
diff --git a/chrome/browser/sessions/session_data_service_factory.cc b/chrome/browser/sessions/session_data_service_factory.cc
index 8a0acdb..bb6286e 100644
--- a/chrome/browser/sessions/session_data_service_factory.cc
+++ b/chrome/browser/sessions/session_data_service_factory.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/sessions/session_data_service_factory.h"
 
+#include <memory>
+
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_data_deleter.h"
 #include "chrome/browser/sessions/session_data_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 
@@ -26,8 +29,10 @@
 SessionDataServiceFactory::~SessionDataServiceFactory() = default;
 
 KeyedService* SessionDataServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
-  return new SessionDataService(static_cast<Profile*>(profile));
+    content::BrowserContext* browser_context) const {
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  auto deleter = std::make_unique<SessionDataDeleter>(profile);
+  return new SessionDataService(profile, std::move(deleter));
 }
 
 bool SessionDataServiceFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/sessions/session_data_service_unittest.cc b/chrome/browser/sessions/session_data_service_unittest.cc
new file mode 100644
index 0000000..80f8fe4
--- /dev/null
+++ b/chrome/browser/sessions/session_data_service_unittest.cc
@@ -0,0 +1,138 @@
+// 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/sessions/session_data_service.h"
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/lifetime/browser_shutdown.h"
+#include "chrome/browser/sessions/session_data_deleter.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+using testing::StrictMock;
+
+namespace {
+// A test version of SessionDataDeleter that doesn't actually do any deletion.
+class TestSessionDataDeleter : public SessionDataDeleter {
+ public:
+  TestSessionDataDeleter() : SessionDataDeleter(nullptr) {}
+  MOCK_METHOD1(DeleteSessionOnlyData, void(base::OnceClosure));
+};
+}  // namespace
+
+class SessionDataServiceTest : public BrowserWithTestWindowTest {
+ public:
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+    RecreateService();
+  }
+
+  void TearDown() override {
+    session_data_service_.reset();
+    browser_shutdown::SetTryingToQuit(false);
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+  void RecreateService() {
+    auto deleter = std::make_unique<StrictMock<TestSessionDataDeleter>>();
+    session_data_deleter_ = deleter.get();
+    session_data_service_ =
+        std::make_unique<SessionDataService>(profile(), std::move(deleter));
+  }
+
+  SessionDataService* service() { return session_data_service_.get(); }
+  TestSessionDataDeleter* deleter() { return session_data_deleter_; }
+
+ private:
+  TestSessionDataDeleter* session_data_deleter_;
+  std::unique_ptr<SessionDataService> session_data_service_;
+};
+
+TEST_F(SessionDataServiceTest, StartCleanup) {
+  EXPECT_CALL(*deleter(), DeleteSessionOnlyData(_));
+  service()->StartCleanup();
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(SessionDataServiceTest, CleanupOnWindowClosed) {
+  const BrowserList* browser_list = BrowserList::GetInstance();
+  EXPECT_EQ(1U, browser_list->size());
+
+  auto new_window = CreateBrowserWindow();
+  auto new_browser =
+      CreateBrowser(profile(), Browser::TYPE_NORMAL, false, new_window.get());
+  EXPECT_EQ(2U, browser_list->size());
+
+  new_browser.reset();
+  EXPECT_EQ(1U, browser_list->size());
+  Mock::VerifyAndClearExpectations(service());
+
+  if (!browser_defaults::kBrowserAliveWithNoWindows)
+    EXPECT_CALL(*deleter(), DeleteSessionOnlyData(_));
+  set_browser(nullptr);
+  EXPECT_EQ(0U, browser_list->size());
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(SessionDataServiceTest, CleanupOnWindowClosedWithOtherProfileOpen) {
+  const BrowserList* browser_list = BrowserList::GetInstance();
+  EXPECT_EQ(1U, browser_list->size());
+
+  auto* new_profile = profile_manager()->CreateTestingProfile("second_profile");
+  auto new_window = CreateBrowserWindow();
+  auto new_browser =
+      CreateBrowser(new_profile, Browser::TYPE_NORMAL, false, new_window.get());
+  EXPECT_EQ(2U, browser_list->size());
+
+  if (!browser_defaults::kBrowserAliveWithNoWindows)
+    EXPECT_CALL(*deleter(), DeleteSessionOnlyData(_));
+  set_browser(nullptr);
+  EXPECT_EQ(1U, browser_list->size());
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(SessionDataServiceTest, RepeatCleanupAfterNewWindowOpened) {
+  // Close browser and expect cleanup.
+  EXPECT_CALL(*deleter(), DeleteSessionOnlyData(_));
+  set_browser(nullptr);
+  Mock::VerifyAndClearExpectations(service());
+
+  // Additional requests for cleanup will be ignored.
+  service()->StartCleanup();
+  Mock::VerifyAndClearExpectations(service());
+
+  // Unless a new browser is opened.
+  auto new_window = CreateBrowserWindow();
+  auto new_browser =
+      CreateBrowser(profile(), Browser::TYPE_NORMAL, false, new_window.get());
+  Mock::VerifyAndClearExpectations(service());
+
+  // And another cleanup is started.
+  EXPECT_CALL(*deleter(), DeleteSessionOnlyData(_));
+  service()->StartCleanup();
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(SessionDataServiceTest, SkipOnShutdown) {
+  browser_shutdown::SetTryingToQuit(true);
+  service()->StartCleanup();
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(SessionDataServiceTest, SkipOnForceSessionState) {
+  service()->SetForceKeepSessionState();
+  service()->StartCleanup();
+  Mock::VerifyAndClearExpectations(service());
+}
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
index 9b23e7c4..491faa7f 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.ApplicationTestUtils;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.base.test.util.UserActionTester;
 import org.chromium.chrome.R;
@@ -135,6 +136,7 @@
     @Test
     @MediumTest
     @Features.EnableFeatures({ChromeFeatureList.CHROME_SHARE_SCREENSHOT})
+    @FlakyTest(message = "crbug.com/1207314")
     public void getPropertyModels_screenshotEnabled() {
         setUpChromeProvidedSharingOptionsProviderTest(
                 /*printingEnabled=*/false, /*sharedDetailsMetrics=*/null);
@@ -156,6 +158,7 @@
     @Test
     @MediumTest
     @Features.DisableFeatures({ChromeFeatureList.CHROME_SHARE_SCREENSHOT})
+    @FlakyTest(message = "crbug.com/1207314")
     public void getPropertyModels_printingEnabled_includesPrinting() {
         setUpChromeProvidedSharingOptionsProviderTest(
                 /*printingEnabled=*/true, /*sharedDetailsMetrics=*/null);
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index e9b3b201..a4ecbde 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -1164,6 +1164,8 @@
   EXPECT_TRUE(deleted_profiles);
   EXPECT_EQ(1U, deleted_profiles->GetList().size());
 
+  content::RunAllTasksUntilIdle();
+
   // Verify that there is an active profile.
   Profile* initial_profile = browser()->profile();
   EXPECT_EQ(1U, g_browser_process->profile_manager()->GetNumberOfProfiles());
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc
index 77749779..a7bb679 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -300,7 +300,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, on_account_info_update_timeout_.callback(),
         base::TimeDelta::FromSeconds(5));
-    account_info_update_observer_.Add(identity_manager_);
+    account_info_update_observation_.Observe(identity_manager_);
   }
 }
 
@@ -330,7 +330,7 @@
 
 void DiceWebSigninInterceptor::Reset() {
   Observe(/*web_contents=*/nullptr);
-  account_info_update_observer_.RemoveAll();
+  account_info_update_observation_.Reset();
   on_account_info_update_timeout_.Cancel();
   is_interception_in_progress_ = false;
   account_id_ = CoreAccountId();
@@ -409,7 +409,7 @@
   if (!info.IsValid())
     return;
 
-  account_info_update_observer_.RemoveAll();
+  account_info_update_observation_.Reset();
   on_account_info_update_timeout_.Cancel();
   base::UmaHistogramTimes(
       "Signin.Intercept.AccountInfoFetchDuration",
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h
index 97d19149..6d3e997 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.h
+++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -12,7 +12,7 @@
 #include "base/feature_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -315,8 +315,9 @@
   // Members below are related to the interception in progress.
   bool is_interception_in_progress_ = false;
   CoreAccountId account_id_;
-  ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
-      account_info_update_observer_{this};
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      account_info_update_observation_{this};
   // Timeout for the fetch of the extended account info. The signin interception
   // is cancelled if the account info cannot be fetched quickly.
   base::CancelableOnceCallback<void()> on_account_info_update_timeout_;
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
index d4adc43..8e14fef 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -9,7 +9,6 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.cc b/chrome/browser/signin/signin_profile_attributes_updater.cc
index 51d3624..0aa601b5 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater.cc
@@ -28,8 +28,8 @@
   DCHECK(identity_manager_);
   DCHECK(signin_error_controller_);
   DCHECK(profile_attributes_storage_);
-  identity_manager_observer_.Add(identity_manager_);
-  signin_error_controller_observer_.Add(signin_error_controller);
+  identity_manager_observation_.Observe(identity_manager_);
+  signin_error_controller_observation_.Observe(signin_error_controller);
 
   UpdateProfileAttributes();
   // TODO(crbug.com/908457): Call OnErrorChanged() here, to catch any change
@@ -40,8 +40,8 @@
 SigninProfileAttributesUpdater::~SigninProfileAttributesUpdater() = default;
 
 void SigninProfileAttributesUpdater::Shutdown() {
-  identity_manager_observer_.RemoveAll();
-  signin_error_controller_observer_.RemoveAll();
+  identity_manager_observation_.Reset();
+  signin_error_controller_observation_.Reset();
 }
 
 void SigninProfileAttributesUpdater::UpdateProfileAttributes() {
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.h b/chrome/browser/signin/signin_profile_attributes_updater.h
index 7fd01f1b..fe477db 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.h
+++ b/chrome/browser/signin/signin_profile_attributes_updater.h
@@ -7,7 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_error_controller.h"
@@ -50,10 +50,12 @@
   ProfileAttributesStorage* profile_attributes_storage_;
   const base::FilePath profile_path_;
   PrefService* prefs_;
-  ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
-      identity_manager_observer_{this};
-  ScopedObserver<SigninErrorController, SigninErrorController::Observer>
-      signin_error_controller_observer_{this};
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      identity_manager_observation_{this};
+  base::ScopedObservation<SigninErrorController,
+                          SigninErrorController::Observer>
+      signin_error_controller_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SigninProfileAttributesUpdater);
 };
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index 21ae516..fbbc8ab6 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -129,8 +129,7 @@
             base::Unretained(this))),
         test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_)),
-        infobar_observer_(this) {}
+                &test_url_loader_factory_)) {}
 
 #if !defined(USE_AURA) && !defined(OS_MAC)
   // Ensure that we are testing under the bubble UI.
@@ -360,10 +359,6 @@
     removed_infobars_.insert(infobar->delegate());
   }
 
-  void OnManagerShuttingDown(infobars::InfoBarManager* manager) override {
-    infobar_observer_.Remove(manager);
-  }
-
   MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
 
  protected:
@@ -390,11 +385,12 @@
         ->translate_driver()
         ->set_translate_max_reload_attempts(0);
 
-    infobar_observer_.Add(infobar_manager());
+    infobar_observation_.Observe(infobar_manager());
   }
 
   void TearDown() override {
-    infobar_observer_.Remove(infobar_manager());
+    DCHECK(infobar_observation_.IsObservingSource(infobar_manager()));
+    infobar_observation_.Reset();
 
     ChromeRenderViewHostTestHarness::TearDown();
     TranslateService::ShutdownForTesting();
@@ -459,8 +455,9 @@
   std::unique_ptr<MockTranslateBubbleFactory> bubble_factory_;
   FakeTranslateAgent fake_agent_;
 
-  ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer>
-      infobar_observer_;
+  base::ScopedObservation<infobars::InfoBarManager,
+                          infobars::InfoBarManager::Observer>
+      infobar_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TranslateManagerRenderViewHostTest);
 };
diff --git a/chrome/browser/translate/translate_model_service_browsertest.cc b/chrome/browser/translate/translate_model_service_browsertest.cc
index 69e7f22e..3dd552c 100644
--- a/chrome/browser/translate/translate_model_service_browsertest.cc
+++ b/chrome/browser/translate/translate_model_service_browsertest.cc
@@ -328,7 +328,7 @@
 }
 
 // Disabled on macOS+ASAN due to high failure rate: crbug.com/1199854.
-#if defined(OS_MAC) && defined(ADDRESS_SANITIZER)
+#if (defined(OS_MAC) && defined(ADDRESS_SANITIZER)) || defined(OS_WIN)
 #define MAYBE_LanguageDetectionWithBackgroundTab \
   DISABLED_LanguageDetectionWithBackgroundTab
 #else
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb
index 0be97ddb..055a144 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb
@@ -533,6 +533,7 @@
 <translation id="4583164079174244168">{MINUTES,plural, =1{# minute ago}other{# minutes ago}}</translation>
 <translation id="4587589328781138893">Sites</translation>
 <translation id="4594952190837476234">This offline page is from <ph name="CREATION_TIME" /> and may differ from the online version.</translation>
+<translation id="4615382002648696011">Following, unread stories ready</translation>
 <translation id="4616150815774728855">Open <ph name="WEBAPK_NAME" /></translation>
 <translation id="4619564267100705184">Verify that it's you</translation>
 <translation id="4634124774493850572">Use password</translation>
@@ -1180,6 +1181,7 @@
 <translation id="8659579665266920523">How to search with Chrome</translation>
 <translation id="8662811608048051533">Signs you out of most sites.</translation>
 <translation id="8664979001105139458">File name already exists</translation>
+<translation id="8676789164135894283">Sign-in verifications</translation>
 <translation id="8683039184091909753">image</translation>
 <translation id="8687353297350450808">{N_BARS,plural, =1{Signal strength level: # bar}other{Signal strength level: # bars}}</translation>
 <translation id="869891660844655955">Expiry date</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
index 47c89483..0ff460d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
@@ -533,6 +533,7 @@
 <translation id="4583164079174244168">{MINUTES,plural, =1{# ນາທີກ່ອນນີ້}other{# ນາທີກ່ອນນີ້}}</translation>
 <translation id="4587589328781138893">ເວັບໄຊ</translation>
 <translation id="4594952190837476234">ໜ້າອອບລາຍນີ້ມາຈາກ <ph name="CREATION_TIME" /> ແລະ ອາດຈະແຕກຕ່າງຈາກເວີຊັນອອນລາຍ.</translation>
+<translation id="4615382002648696011">ກຳລັງຕິດຕາມ, ຂ່າວທີ່ຍັງບໍ່ໄດ້ອ່ານພ້ອມແລ້ວ</translation>
 <translation id="4616150815774728855">ເປີດ <ph name="WEBAPK_NAME" /></translation>
 <translation id="4619564267100705184">ຢັ້ງຢືນວ່າແມ່ນທ່ານແທ້</translation>
 <translation id="4634124774493850572">ໃຊ້ລະຫັດຜ່ານ</translation>
@@ -1180,6 +1181,7 @@
 <translation id="8659579665266920523">ວິທີຊອກຫາດ້ວຍ Chrome</translation>
 <translation id="8662811608048051533">ເອົາທ່ານອອກຈາກລະບົບເວັບໄຊສ່ວນໃຫຍ່.</translation>
 <translation id="8664979001105139458">ມີຊື່ໄຟລ໌ນີ້ຢູ່ແລ້ວ</translation>
+<translation id="8676789164135894283">ການຢັ້ງຢືນການເຂົ້າສູ່ລະບົບ</translation>
 <translation id="8683039184091909753">ຮູບ</translation>
 <translation id="8687353297350450808">{N_BARS,plural, =1{ລະດັບຄວາມແຮງສັນຍານ: # ຂີດ}other{ລະດັບຄວາມແຮງສັນຍານ: # ຂີດ}}</translation>
 <translation id="869891660844655955">ວັນ​ຫມົດ​ອາ​ຍຸ</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ms.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ms.xtb
index 63b37c4..efe90edc 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ms.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ms.xtb
@@ -533,6 +533,7 @@
 <translation id="4583164079174244168">{MINUTES,plural, =1{# minit yang lalu}other{# minit yang lalu}}</translation>
 <translation id="4587589328781138893">Tapak</translation>
 <translation id="4594952190837476234">Halaman luar talian ini dari <ph name="CREATION_TIME" /> dan mungkin berbeza daripada versi dalam talian.</translation>
+<translation id="4615382002648696011">Mengikuti, cerita belum dibaca sudah sedia</translation>
 <translation id="4616150815774728855">Buka <ph name="WEBAPK_NAME" /></translation>
 <translation id="4619564267100705184">Sahkan orang itu ialah anda</translation>
 <translation id="4634124774493850572">Gunakan kata laluan</translation>
@@ -1180,6 +1181,7 @@
 <translation id="8659579665266920523">Cara mencari menggunakan Chrome</translation>
 <translation id="8662811608048051533">Mengelog anda keluar daripada kebanyakan tapak.</translation>
 <translation id="8664979001105139458">Nama fail sudah wujud</translation>
+<translation id="8676789164135894283">Pengesahan log masuk</translation>
 <translation id="8683039184091909753">imej</translation>
 <translation id="8687353297350450808">{N_BARS,plural, =1{Tahap Kekuatan Isyarat: # bar}other{Tahap Kekuatan Isyarat: # bar}}</translation>
 <translation id="869891660844655955">Tarikh tamat tempoh</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
index f40dec2b..daf1196 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
@@ -533,6 +533,7 @@
 <translation id="4583164079174244168">{MINUTES,plural, =1{මිනිත්තු #කට පෙර}one{මිනිත්තු #කට පෙර}other{මිනිත්තු #කට පෙර}}</translation>
 <translation id="4587589328781138893">අඩවි</translation>
 <translation id="4594952190837476234">මෙම නොබැඳි පිටුව <ph name="CREATION_TIME" /> වෙතින් වන අතර සබැඳි අනුවාදයෙන් වෙනස් විය හැකිය.</translation>
+<translation id="4615382002648696011">අනුගමනය කරමින්, නොකියවූ කතන්දර සූදානම්ය</translation>
 <translation id="4616150815774728855"><ph name="WEBAPK_NAME" /> විවෘත කරන්න</translation>
 <translation id="4619564267100705184">ඒ ඔබ බව සත්‍යාපනය කරන්න</translation>
 <translation id="4634124774493850572">මුරපදය භාවිත කරන්න</translation>
@@ -1180,6 +1181,7 @@
 <translation id="8659579665266920523">Chrome සමගින් සොයන ආකාරය</translation>
 <translation id="8662811608048051533">ඔබව බොහෝ අඩවිවලින් වරනු ඇත.</translation>
 <translation id="8664979001105139458">ගොනු නාමය දැනටමත් පවතී</translation>
+<translation id="8676789164135894283">පිරීම් සත්‍යාපනය කිරීම්</translation>
 <translation id="8683039184091909753">රූපය</translation>
 <translation id="8687353297350450808">{N_BARS,plural, =1{සංඥා ප්‍රබලතා මට්ටම: කණු #}one{සංඥා ප්‍රබලතා මට්ටම: කණු #}other{සංඥා ප්‍රබලතා මට්ටම: කණු #}}</translation>
 <translation id="869891660844655955">කල් ඉකුත් වීමේ දිනය:</translation>
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 3c4a045f..eaa12d8371 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -621,10 +621,6 @@
   widget_ = CreateTestWidget();
   widget_->Show();
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::input_method::InitializeForTesting(
-      new chromeos::input_method::MockInputMethodManagerImpl);
-#endif
   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
       profile_.get(),
       base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor));
@@ -647,9 +643,6 @@
   util_.reset();
   profile_.reset();
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::input_method::Shutdown();
-#endif
   ChromeViewsTestBase::TearDown();
 }
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc
index 0199f1c..d1818651 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -154,8 +154,9 @@
 void ProfilePicker::Show(EntryPoint entry_point,
                          const GURL& on_select_profile_target_url) {
   if (!g_profile_picker_view)
-    g_profile_picker_view = new ProfilePickerView(on_select_profile_target_url);
-
+    g_profile_picker_view = new ProfilePickerView();
+  g_profile_picker_view->set_on_select_profile_target_url(
+      on_select_profile_target_url);
   g_profile_picker_view->Display(entry_point);
 }
 
@@ -449,11 +450,10 @@
 void ProfilePickerView::RemoveObserver(
     web_modal::ModalDialogHostObserver* observer) {}
 
-ProfilePickerView::ProfilePickerView(const GURL& on_select_profile_target_url)
+ProfilePickerView::ProfilePickerView()
     : keep_alive_(KeepAliveOrigin::USER_MANAGER_VIEW,
                   KeepAliveRestartOption::DISABLED),
-      extended_account_info_timeout_(kExtendedAccountInfoTimeout),
-      on_select_profile_target_url_(on_select_profile_target_url) {
+      extended_account_info_timeout_(kExtendedAccountInfoTimeout) {
   // Setup the WidgetDelegate.
   SetHasWindowSizeControls(true);
   SetTitle(IDS_PRODUCT_NAME);
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.h b/chrome/browser/ui/views/profiles/profile_picker_view.h
index 0e1fddb2..b2583e2 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.h
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.h
@@ -55,6 +55,11 @@
   // nothing.
   void DisplayErrorMessage();
 
+  // Sets the URL to be opened after the user selects a profile.
+  void set_on_select_profile_target_url(const GURL& url) {
+    on_select_profile_target_url_ = url;
+  }
+
   // ProfilePickerWebContentsHost:
   void ShowScreen(content::WebContents* contents,
                   const GURL& url,
@@ -90,7 +95,7 @@
   friend class ProfilePicker;
 
   // To display the Profile picker, use ProfilePicker::Show().
-  explicit ProfilePickerView(const GURL& on_select_profile_target_url);
+  ProfilePickerView();
   ~ProfilePickerView() override;
 
   enum State { kNotStarted = 0, kInitializing = 1, kReady = 2 };
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
index 8ae7a001..e8a3f50 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -346,6 +346,23 @@
     handler->HandleLaunchGuestProfile(&args);
   }
 
+  // Creates a new profile without opening a browser.
+  base::FilePath CreateNewProfileWithoutBrowser() {
+    // Create a second profile.
+    ProfileManager* profile_manager = g_browser_process->profile_manager();
+    base::FilePath path = profile_manager->GenerateNextProfileDirectoryPath();
+    base::RunLoop run_loop;
+    profile_manager->CreateProfileAsync(
+        path, base::BindLambdaForTesting(
+                  [&run_loop](Profile* profile, Profile::CreateStatus status) {
+                    if (status == Profile::CREATE_STATUS_INITIALIZED) {
+                      run_loop.Quit();
+                    }
+                  }));
+    run_loop.Run();
+    return path;
+  }
+
  private:
   base::CallbackListSubscription create_services_subscription_;
   base::test::ScopedFeatureList feature_list_;
@@ -728,19 +745,7 @@
       base::TimeDelta::FromSeconds(0));
   ASSERT_EQ(1u, BrowserList::GetInstance()->size());
   // Create a second profile.
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::FilePath other_path =
-      profile_manager->GenerateNextProfileDirectoryPath();
-  base::RunLoop run_loop;
-  profile_manager->CreateProfileAsync(
-      other_path,
-      base::BindLambdaForTesting(
-          [&run_loop](Profile* profile, Profile::CreateStatus status) {
-            if (status == Profile::CREATE_STATUS_INITIALIZED) {
-              run_loop.Quit();
-            }
-          }));
-  run_loop.Run();
+  base::FilePath other_path = CreateNewProfileWithoutBrowser();
   // Open the picker.
   ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
   WaitForLayoutWithoutToolbar();
@@ -762,19 +767,7 @@
       base::TimeDelta::FromSeconds(0));
   ASSERT_EQ(1u, BrowserList::GetInstance()->size());
   // Create a second profile.
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::FilePath other_path =
-      profile_manager->GenerateNextProfileDirectoryPath();
-  base::RunLoop run_loop;
-  profile_manager->CreateProfileAsync(
-      other_path,
-      base::BindLambdaForTesting(
-          [&run_loop](Profile* profile, Profile::CreateStatus status) {
-            if (status == Profile::CREATE_STATUS_INITIALIZED) {
-              run_loop.Quit();
-            }
-          }));
-  run_loop.Run();
+  base::FilePath other_path = CreateNewProfileWithoutBrowser();
   // Open the picker.
   ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
   WaitForLayoutWithoutToolbar();
@@ -790,6 +783,48 @@
   EXPECT_FALSE(ProfileSwitchPromoHasBeenShown(new_browser));
 }
 
+IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
+                       OpenURL_PickerClosed) {
+  ASSERT_EQ(1u, BrowserList::GetInstance()->size());
+  const GURL kTargetURL("chrome://settings/help");
+  // Create a profile.
+  base::FilePath profile_path = CreateNewProfileWithoutBrowser();
+  // Open the picker.
+  ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles,
+                      kTargetURL);
+  WaitForLayoutWithoutToolbar();
+  // Open the profile.
+  OpenProfileFromPicker(profile_path, /*open_settings=*/false);
+  // Browser for the profile is displayed.
+  Browser* new_browser = BrowserAddedWaiter(2u).Wait();
+  WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(),
+                    kTargetURL);
+  EXPECT_EQ(new_browser->profile()->GetPath(), profile_path);
+  WaitForPickerClosed();
+}
+
+IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
+                       OpenURL_PickerAlreadyOpen) {
+  ASSERT_EQ(1u, BrowserList::GetInstance()->size());
+  const GURL kTargetURL("chrome://settings/help");
+  // Create a profile.
+  base::FilePath profile_path = CreateNewProfileWithoutBrowser();
+  // Open the picker without target URL.
+  ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles);
+  WaitForLayoutWithoutToolbar();
+  // Request a URL when the picker is already open.
+  ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles,
+                      kTargetURL);
+  // Open the profile.
+  OpenProfileFromPicker(profile_path, /*open_settings=*/false);
+  // Browser for the profile is displayed.
+  Browser* new_browser = BrowserAddedWaiter(2u).Wait();
+  WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(),
+                    kTargetURL);
+  EXPECT_EQ(new_browser->profile()->GetPath(), profile_path);
+  WaitForPickerClosed();
+}
+
 // Regression test for https://crbug.com/1199035
 IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
                        OpenProfile_Guest) {
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index 8784d44..01e39c7 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -201,11 +201,11 @@
                                         ->system_web_app_manager()
                                         .GetSystemAppTypeForAppId(GetAppId())
                                   : base::nullopt),
-      // TODO(crbug.com/1061822): Generalise has_tab_strip_ as a SystemWebApp
-      // capability.
       has_tab_strip_(
-          system_app_type_ == SystemAppType::TERMINAL ||
-          system_app_type_ == SystemAppType::CROSH ||
+          (system_app_type_.has_value() &&
+           WebAppProvider::Get(browser->profile())
+               ->system_web_app_manager()
+               .ShouldHaveTabStrip(system_app_type_.value())) ||
           (base::FeatureList::IsEnabled(features::kDesktopPWAsTabStrip) &&
            HasAppId() &&
            WebAppProvider::Get(browser->profile())
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 349a855..2cdcf6e 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -509,6 +509,8 @@
                     login::ExtractSamlPasswordAttributesEnabled());
   params.SetBoolean("enableSyncTrustedVaultKeys",
                     IsSyncTrustedVaultKeysEnabled());
+  params.SetBoolean("enableCloseView",
+                    ash::features::IsGaiaCloseViewMessageEnabled());
 
   if (public_saml_url_fetcher_) {
     params.SetBoolean("startsOnSamlPage", true);
diff --git a/chrome/browser/web_applications/components/file_handler_manager.cc b/chrome/browser/web_applications/components/file_handler_manager.cc
index dce5809..7b445db 100644
--- a/chrome/browser/web_applications/components/file_handler_manager.cc
+++ b/chrome/browser/web_applications/components/file_handler_manager.cc
@@ -103,7 +103,7 @@
 void FileHandlerManager::DisableAndUnregisterOsFileHandlers(
     const AppId& app_id,
     std::unique_ptr<ShortcutInfo> info,
-    base::OnceCallback<void(bool)> callback) {
+    base::OnceCallback<void()> callback) {
   // Updating prefs must be done on the UI Thread.
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   UpdateBoolWebAppPref(profile()->GetPrefs(), app_id, kFileHandlersEnabled,
@@ -116,9 +116,6 @@
 
   if (!ShouldRegisterFileHandlersWithOs() || !file_handlers ||
       file_handlers->empty() || disable_os_integration_for_testing_) {
-    // This bool signals if there was not an error. Exiting early here is WAI,
-    // so this is a success.
-    std::move(callback).Run(true);
     return;
   }
 
diff --git a/chrome/browser/web_applications/components/file_handler_manager.h b/chrome/browser/web_applications/components/file_handler_manager.h
index 745a165f..d92125b 100644
--- a/chrome/browser/web_applications/components/file_handler_manager.h
+++ b/chrome/browser/web_applications/components/file_handler_manager.h
@@ -69,10 +69,9 @@
   // Disables file handlers for all OSs and unregisters OS specific file
   // handlers for OSs that need them. On Chrome OS file handlers are registered
   // separately but they are still enabled and disabled here.
-  void DisableAndUnregisterOsFileHandlers(
-      const AppId& app_id,
-      std::unique_ptr<ShortcutInfo> info,
-      base::OnceCallback<void(bool)> callback);
+  void DisableAndUnregisterOsFileHandlers(const AppId& app_id,
+                                          std::unique_ptr<ShortcutInfo> info,
+                                          base::OnceCallback<void()> callback);
 
   // Updates the file handling origin trial expiry timer based on a currently
   // open instance of the site. This will not update the expiry timer if
diff --git a/chrome/browser/web_applications/components/file_handler_manager_unittest.cc b/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
index 618697b0..e47ec63 100644
--- a/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
+++ b/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
@@ -164,8 +164,8 @@
   }
 
   // Ensure they can be disabled.
-  file_handler_manager().DisableAndUnregisterOsFileHandlers(
-      app_id, nullptr, base::DoNothing::Once<bool>());
+  file_handler_manager().DisableAndUnregisterOsFileHandlers(app_id, nullptr,
+                                                            base::DoNothing());
 
   {
     const auto* handlers =
diff --git a/chrome/browser/web_applications/components/os_integration_manager.cc b/chrome/browser/web_applications/components/os_integration_manager.cc
index cda0d82..5cc4f5b 100644
--- a/chrome/browser/web_applications/components/os_integration_manager.cc
+++ b/chrome/browser/web_applications/components/os_integration_manager.cc
@@ -10,11 +10,9 @@
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
@@ -212,13 +210,11 @@
           barrier->CreateBarrierCallbackForType(OsHookType::kShortcuts));
     }
   }
+  // TODO(https://crbug.com/1108109) we should return the result of file handler
   // unregistration and record errors during unregistration.
   // TODO(crbug.com/1076688): Retrieve shortcuts before they're unregistered.
-  if (os_hooks[OsHookType::kFileHandlers]) {
-    UnregisterFileHandlers(
-        app_id, nullptr,
-        barrier->CreateBarrierCallbackForType(OsHookType::kFileHandlers));
-  }
+  if (os_hooks[OsHookType::kFileHandlers])
+    UnregisterFileHandlers(app_id, nullptr, base::DoNothing());
 
   // TODO(https://crbug.com/1108109) we should return the result of protocol
   // handler unregistration and record errors during unregistration.
@@ -493,7 +489,7 @@
 void OsIntegrationManager::UnregisterFileHandlers(
     const AppId& app_id,
     std::unique_ptr<ShortcutInfo> info,
-    base::OnceCallback<void(bool)> callback) {
+    base::OnceCallback<void()> callback) {
   DCHECK(file_handler_manager_);
 
   file_handler_manager_->DisableAndUnregisterOsFileHandlers(
@@ -571,26 +567,18 @@
   if (!IsFileHandlingAPIAvailable(app_id))
     return;
 
-  base::OnceCallback<void(bool)> callback_after_removal;
+  base::OnceClosure callback_after_removal;
   switch (file_handlers_need_os_update) {
     case FileHandlerUpdateAction::kNoUpdate:
       return;
     case FileHandlerUpdateAction::kUpdate:
-      callback_after_removal = base::BindOnce(
-          [](base::WeakPtr<OsIntegrationManager> os_integration_manager,
-             const AppId& app_id, bool unregister_success) {
-            // Re-register file handlers regardless of `unregister_success`.
-            // TODO(https://crbug.com/1124047): Report `unregister_success` in
-            // an UMA metric.
-            if (!os_integration_manager)
-              return;
-            os_integration_manager->RegisterFileHandlers(
-                app_id, base::DoNothing::Once<bool>());
-          },
-          weak_ptr_factory_.GetWeakPtr(), app_id);
+      callback_after_removal =
+          base::BindOnce(&OsIntegrationManager::RegisterFileHandlers,
+                         weak_ptr_factory_.GetWeakPtr(), app_id,
+                         base::DoNothing::Once<bool>());
       break;
     case FileHandlerUpdateAction::kRemove:
-      callback_after_removal = base::DoNothing::Once<bool>();
+      callback_after_removal = base::DoNothing::Once();
       break;
   }
 
diff --git a/chrome/browser/web_applications/components/os_integration_manager.h b/chrome/browser/web_applications/components/os_integration_manager.h
index 9683f5dd..38a7e54 100644
--- a/chrome/browser/web_applications/components/os_integration_manager.h
+++ b/chrome/browser/web_applications/components/os_integration_manager.h
@@ -234,7 +234,7 @@
                                DeleteShortcutsCallback callback);
   virtual void UnregisterFileHandlers(const AppId& app_id,
                                       std::unique_ptr<ShortcutInfo> info,
-                                      base::OnceCallback<void(bool)> callback);
+                                      base::OnceCallback<void()> callback);
   virtual void UnregisterProtocolHandlers(const AppId& app_id);
   virtual void UnregisterUrlHandlers(const AppId& app_id);
   virtual void UnregisterWebAppOsUninstallation(const AppId& app_id);
diff --git a/chrome/browser/web_applications/components/os_integration_manager_unittest.cc b/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
index b466097..fa4e81d2 100644
--- a/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
+++ b/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
@@ -108,7 +108,7 @@
               UnregisterFileHandlers,
               (const AppId& app_id,
                std::unique_ptr<ShortcutInfo> info,
-               base::OnceCallback<void(bool)> callback),
+               base::OnceCallback<void()> callback),
               (override));
   MOCK_METHOD(void,
               UnregisterProtocolHandlers,
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration.cc
index 89e37a4..1eb15af 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration.cc
@@ -29,10 +29,10 @@
 void UnregisterFileHandlersWithOs(const AppId& app_id,
                                   Profile* profile,
                                   std::unique_ptr<ShortcutInfo> info,
-                                  base::OnceCallback<void(bool)> callback) {
+                                  base::OnceCallback<void()> callback) {
   DCHECK(ShouldRegisterFileHandlersWithOs());
   // Stub function for OS's which don't register file handlers with the OS.
-  std::move(callback).Run(true);
+  std::move(callback).Run();
 }
 #endif
 
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration.h b/chrome/browser/web_applications/components/web_app_file_handler_registration.h
index 83b63ac..788a767 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration.h
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration.h
@@ -40,7 +40,7 @@
 void UnregisterFileHandlersWithOs(const AppId& app_id,
                                   Profile* profile,
                                   std::unique_ptr<ShortcutInfo> info,
-                                  base::OnceCallback<void(bool)> callback);
+                                  base::OnceCallback<void()> callback);
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 using RegisterMimeTypesOnLinuxCallback =
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
index 44b44b3..4cfc5cb 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
@@ -55,21 +55,20 @@
   UMA_HISTOGRAM_ENUMERATION(kRegistrationResultMetric, result);
 }
 
-void OnCreateShortcut(base::OnceCallback<void(bool)> callback,
+void OnCreateShortcut(base::OnceCallback<void()> callback,
                       bool shortcut_created) {
   UMA_HISTOGRAM_ENUMERATION(
       kRecreateShortcutResultMetric,
       shortcut_created ? RecreateShortcutResult::kSuccess
                        : RecreateShortcutResult::kFailToCreateShortcut);
-  std::move(callback).Run(shortcut_created);
+  std::move(callback).Run();
 }
 
-void OnShortcutInfoReceived(base::OnceCallback<void(bool)> callback,
+void OnShortcutInfoReceived(base::OnceCallback<void()> callback,
                             std::unique_ptr<ShortcutInfo> info) {
   if (!info) {
     UMA_HISTOGRAM_ENUMERATION(kRecreateShortcutResultMetric,
                               RecreateShortcutResult::kFailToCreateShortcut);
-    std::move(callback).Run(false);
     return;
   }
 
@@ -84,11 +83,10 @@
       base::BindOnce(OnCreateShortcut, std::move(callback)));
 }
 
-void UpdateFileHandlerRegistrationInOs(
-    const AppId& app_id,
-    Profile* profile,
-    std::unique_ptr<ShortcutInfo> info,
-    base::OnceCallback<void(bool)> callback) {
+void UpdateFileHandlerRegistrationInOs(const AppId& app_id,
+                                       Profile* profile,
+                                       std::unique_ptr<ShortcutInfo> info,
+                                       base::OnceCallback<void()> callback) {
   if (info) {
     // `info` may be prepopulated for unregistration, to avoid updating file
     // handler registrations based on deleted shortcuts.
@@ -168,15 +166,13 @@
 void UnregisterFileHandlersWithOs(const AppId& app_id,
                                   Profile* profile,
                                   std::unique_ptr<ShortcutInfo> info,
-                                  base::OnceCallback<void(bool)> callback) {
+                                  base::OnceCallback<void()> callback) {
   // If this was triggered as part of the uninstallation process, nothing more
   // is needed. Uninstalling already cleans up shortcuts (and thus, file
   // handlers).
   auto* provider = WebAppProviderBase::GetProviderBase(profile);
-  if (!provider->registrar().IsInstalled(app_id)) {
-    std::move(callback).Run(false);
+  if (!provider->registrar().IsInstalled(app_id))
     return;
-  }
 
   // TODO(crbug.com/1076688): Fix file handlers unregistration. We can't update
   // registration here asynchronously because app_id is being uninstalled.
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_mac.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_mac.cc
index a12db077..eb171ae 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_mac.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_mac.cc
@@ -22,12 +22,12 @@
 void UnregisterFileHandlersWithOs(const AppId& app_id,
                                   Profile* profile,
                                   std::unique_ptr<ShortcutInfo> info,
-                                  base::OnceCallback<void(bool)> callback) {
+                                  base::OnceCallback<void()> callback) {
   // On MacOS, file associations are managed through app shims in the
   // Applications directory. File handler unregistration is handled via
   // shortcuts deletion on MacOS.
   NOTREACHED();
-  std::move(callback).Run(true);
+  std::move(callback).Run();
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
index 790a39c8a..96c3efc9 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
@@ -83,7 +83,7 @@
                      base::UTF8ToWide(app_name), profile->GetPath(),
                      file_extensions_wide, app_name_extension),
       base::BindOnce(&CheckAndUpdateExternalInstallations, profile->GetPath(),
-                     app_id, base::DoNothing::Once<bool>()));
+                     app_id, base::DoNothing::Once()));
 }
 
 void UnregisterFileHandlersWithOsTask(const AppId& app_id,
@@ -105,7 +105,7 @@
 void UnregisterFileHandlersWithOs(const AppId& app_id,
                                   Profile* profile,
                                   std::unique_ptr<ShortcutInfo> info,
-                                  base::OnceCallback<void(bool)> callback) {
+                                  base::OnceCallback<void()> callback) {
   base::ThreadPool::PostTaskAndReply(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
diff --git a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.cc b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.cc
index 3a97f8d..ce71fb6e 100644
--- a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.cc
+++ b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.cc
@@ -91,11 +91,10 @@
                            const base::FilePath& profile_path,
                            const std::wstring& prog_id,
                            const std::wstring& app_name_extension,
-                           base::OnceCallback<void(bool)> callback) {
+                           base::OnceCallback<void()> callback) {
   if (!base::DeleteFile(ShellUtil::GetApplicationPathForProgId(prog_id))) {
     web_app::RecordRegistration(
         web_app::RegistrationResult::kFailToDeleteExistingRegistration);
-    std::move(callback).Run(false);
     return;
   }
 
@@ -107,10 +106,8 @@
           app_name, app_name_extension,
           web_app::GetOsIntegrationResourcesDirectoryForApp(profile_path,
                                                             app_id, GURL()));
-  if (!app_launcher_path) {
-    std::move(callback).Run(false);
+  if (!app_launcher_path)
     return;
-  }
 
   base::CommandLine app_launch_cmd = web_app::GetAppLauncherCommand(
       app_id, app_launcher_path.value(), profile_path);
@@ -119,7 +116,7 @@
 
   ShellUtil::AddApplicationClass(prog_id, app_launch_cmd, user_visible_app_name,
                                  app_name, icon_path);
-  std::move(callback).Run(true);
+  std::move(callback).Run();
 }
 
 bool AppNameHasProfileExtension(const std::wstring& app_name,
@@ -244,10 +241,9 @@
   return app_specific_launcher_path;
 }
 
-void CheckAndUpdateExternalInstallations(
-    const base::FilePath& cur_profile_path,
-    const AppId& app_id,
-    base::OnceCallback<void(bool)> callback) {
+void CheckAndUpdateExternalInstallations(const base::FilePath& cur_profile_path,
+                                         const AppId& app_id,
+                                         base::OnceCallback<void()> callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   std::wstring prog_id = GetProgIdForApp(cur_profile_path, app_id);
@@ -259,12 +255,8 @@
                                         &external_installation_profile_path);
 
   // Naming updates are only required if a single external installation exists.
-  if (external_installation_profile_path.empty()) {
-    // This bool signals if there was not an error. Exiting early here is WAI,
-    // so this is a success.
-    std::move(callback).Run(true);
+  if (external_installation_profile_path.empty())
     return;
-  }
 
   std::wstring external_installation_prog_id =
       GetProgIdForApp(external_installation_profile_path, app_id);
@@ -281,9 +273,6 @@
     // profile-specific name.
     if (AppNameHasProfileExtension(external_installation_name,
                                    external_installation_profile_path)) {
-      // This bool signals if there was not an error. Exiting early here is WAI,
-      // so this is a success.
-      std::move(callback).Run(true);
       return;
     }
 
@@ -295,9 +284,6 @@
     // profile-specific name.
     if (!AppNameHasProfileExtension(external_installation_name,
                                     external_installation_profile_path)) {
-      // This bool signals if there was not an error. Exiting early here is WAI,
-      // so this is a success.
-      std::move(callback).Run(true);
       return;
     }
 
diff --git a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.h b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.h
index 0d49209d..6671abb 100644
--- a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.h
+++ b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win.h
@@ -42,10 +42,9 @@
 
 // Checks if there is an installation of this app in another profile that needs
 // to be updated with a profile specific name and executes required update.
-void CheckAndUpdateExternalInstallations(
-    const base::FilePath& cur_profile_path,
-    const AppId& app_id,
-    base::OnceCallback<void(bool)> callback);
+void CheckAndUpdateExternalInstallations(const base::FilePath& cur_profile_path,
+                                         const AppId& app_id,
+                                         base::OnceCallback<void()> callback);
 
 // Result of file handler registration process.
 // These values are persisted to logs. Entries should not be renumbered and
diff --git a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win_unittest.cc b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win_unittest.cc
index 5d21ef3a..a67b8651 100644
--- a/chrome/browser/web_applications/components/web_app_handler_registration_utils_win_unittest.cc
+++ b/chrome/browser/web_applications/components/web_app_handler_registration_utils_win_unittest.cc
@@ -172,7 +172,7 @@
 
   // Update installations external to profile 2 (i.e. profile1).
   CheckAndUpdateExternalInstallations(profile2->GetPath(), app_id(),
-                                      base::DoNothing::Once<bool>());
+                                      base::DoNothing());
   base::ThreadPoolInstance::Get()->FlushForTesting();
 
   // Test that the profile1 installation is updated with a profile-specific
@@ -193,7 +193,7 @@
   Profile* profile2 =
       testing_profile_manager()->CreateTestingProfile("Profile 2");
   CheckAndUpdateExternalInstallations(profile2->GetPath(), app_id(),
-                                      base::DoNothing::Once<bool>());
+                                      base::DoNothing());
   base::ThreadPoolInstance::Get()->FlushForTesting();
 
   // Ensure that after updating from profile2 (which has no installation),
@@ -220,7 +220,7 @@
   // in other profiles shouldn't change the original 2 installations since they
   // already have app-specific names.
   CheckAndUpdateExternalInstallations(profile3->GetPath(), app_id(),
-                                      base::DoNothing::Once<bool>());
+                                      base::DoNothing());
   base::ThreadPoolInstance::Get()->FlushForTesting();
 
   TestRegisteredApp(app_id(), app_name(), L" (Default)", profile1->GetPath());
diff --git a/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc b/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
index c84a015f..07e2805 100644
--- a/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
+++ b/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
@@ -113,7 +113,7 @@
                                  const web_app::AppId& app_id,
                                  base::OnceCallback<void(bool)> callback) {
   web_app::CheckAndUpdateExternalInstallations(cur_profile_path, app_id,
-                                               base::DoNothing::Once<bool>());
+                                               base::DoNothing::Once());
   std::move(callback).Run(true);
 }
 
@@ -158,7 +158,7 @@
       base::BindOnce(&UnregisterProtocolHandlersWithOsInBackground, app_id,
                      profile->GetPath()),
       base::BindOnce(&CheckAndUpdateExternalInstallations, profile->GetPath(),
-                     app_id, base::DoNothing::Once<bool>()));
+                     app_id, base::DoNothing::Once()));
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
index cb40bf15..4e2bf0d 100644
--- a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
@@ -178,6 +178,7 @@
   infos.at(SystemAppType::CROSH).single_window = false;
   infos.at(SystemAppType::CROSH).show_in_launcher = false;
   infos.at(SystemAppType::CROSH).show_in_search = false;
+  infos.at(SystemAppType::CROSH).has_tab_strip = true;
 
   infos.emplace(
       SystemAppType::TERMINAL,
@@ -185,6 +186,7 @@
           "Terminal", GURL(chrome::kChromeUIUntrustedTerminalURL),
           base::BindRepeating(&CreateWebAppInfoForTerminalSystemWebApp)));
   infos.at(SystemAppType::TERMINAL).single_window = false;
+  infos.at(SystemAppType::TERMINAL).has_tab_strip = true;
 
   if (SystemWebAppManager::IsAppEnabled(SystemAppType::HELP)) {
     infos.emplace(
@@ -756,6 +758,14 @@
   return it->second.allow_scripts_to_close_windows;
 }
 
+bool SystemWebAppManager::ShouldHaveTabStrip(SystemAppType type) const {
+  auto it = system_app_infos_.find(type);
+  if (it == system_app_infos_.end())
+    return false;
+
+  return it->second.has_tab_strip;
+}
+
 base::Optional<SystemAppType> SystemWebAppManager::GetCapturingSystemAppForURL(
     const GURL& url) const {
   if (!HasSystemWebAppScheme(url))
diff --git a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.h b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.h
index 3187752..0f031d3bb 100644
--- a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.h
+++ b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.h
@@ -113,6 +113,9 @@
   // If set to false, the surface of app will can be non-maximizable.
   bool is_maximizable = true;
 
+  // If set to true, the App's window will have a tab-strip.
+  bool has_tab_strip = false;
+
   // If set to false, the app will not have the reload button in minimal ui
   // mode.
   bool should_have_reload_button_in_minimal_ui = true;
@@ -221,6 +224,9 @@
   // Returns whether the app is allowed to close the window through scripts.
   bool AllowScriptsToCloseWindows(SystemAppType type) const;
 
+  // Returns whether the app window should have the tab-strip.
+  bool ShouldHaveTabStrip(SystemAppType type) const;
+
   // Returns the SystemAppType that should capture the navigation to |url|.
   base::Optional<SystemAppType> GetCapturingSystemAppForURL(
       const GURL& url) const;
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
index a91abc6..84cba6c 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
@@ -939,6 +939,42 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
+class SystemWebAppManagerHasTabStripTest
+    : public SystemWebAppManagerBrowserTest {
+ public:
+  SystemWebAppManagerHasTabStripTest()
+      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+    maybe_installation_ =
+        TestSystemWebAppInstallation::SetUpAppWithTabStrip(true);
+  }
+};
+
+IN_PROC_BROWSER_TEST_P(SystemWebAppManagerHasTabStripTest, HasTabStrip) {
+  WaitForTestSystemAppInstall();
+
+  Browser* browser;
+  EXPECT_TRUE(LaunchApp(GetMockAppType(), &browser));
+  EXPECT_TRUE(browser->app_controller()->has_tab_strip());
+}
+
+class SystemWebAppManagerHasNoTabStripTest
+    : public SystemWebAppManagerBrowserTest {
+ public:
+  SystemWebAppManagerHasNoTabStripTest()
+      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+    maybe_installation_ =
+        TestSystemWebAppInstallation::SetUpAppWithTabStrip(false);
+  }
+};
+
+IN_PROC_BROWSER_TEST_P(SystemWebAppManagerHasNoTabStripTest, HasNoTabStrip) {
+  WaitForTestSystemAppInstall();
+
+  Browser* browser;
+  EXPECT_TRUE(LaunchApp(GetMockAppType(), &browser));
+  EXPECT_FALSE(browser->app_controller()->has_tab_strip());
+}
+
 // Tests that SWA are correctly uninstalled across restarts.
 class SystemWebAppManagerUninstallBrowserTest
     : public SystemWebAppManagerBrowserTest {
@@ -1521,4 +1557,10 @@
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
     SystemWebAppManagerBackgroundTaskTest);
 
+INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
+    SystemWebAppManagerHasTabStripTest);
+
+INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
+    SystemWebAppManagerHasNoTabStripTest);
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
index 5e5cc75b..db8b803 100644
--- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
@@ -150,6 +150,7 @@
       "Terminal", GURL("chrome://test-system-app/pwa.html"),
       base::BindRepeating(&GenerateWebApplicationInfoForTestApp));
   terminal_system_app_info.single_window = false;
+  terminal_system_app_info.has_tab_strip = true;
 
   return base::WrapUnique(new TestSystemWebAppInstallation(
       SystemAppType::TERMINAL, terminal_system_app_info));
@@ -330,6 +331,18 @@
       SystemAppType::SAMPLE, std::move(app_info)));
 }
 
+// static
+std::unique_ptr<TestSystemWebAppInstallation>
+TestSystemWebAppInstallation::SetUpAppWithTabStrip(bool has_tab_strip) {
+  SystemAppInfo app_info(
+      "Test", GURL("chrome://test-system-app/pwa.html"),
+      base::BindRepeating(&GenerateWebApplicationInfoForTestApp));
+  app_info.has_tab_strip = has_tab_strip;
+
+  return base::WrapUnique(new TestSystemWebAppInstallation(
+      SystemAppType::SETTINGS, std::move(app_info)));
+}
+
 std::unique_ptr<KeyedService>
 TestSystemWebAppInstallation::CreateWebAppProvider(SystemAppInfo info,
                                                    Profile* profile) {
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
index 4fa46a0..c1328b3be 100644
--- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
+++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
@@ -68,6 +68,9 @@
   static std::unique_ptr<TestSystemWebAppInstallation>
   SetupAppWithAllowScriptsToCloseWindows(bool value);
 
+  static std::unique_ptr<TestSystemWebAppInstallation> SetUpAppWithTabStrip(
+      bool has_tab_strip);
+
   ~TestSystemWebAppInstallation();
 
   void WaitForAppInstall();
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index adfd0e0e8..4250574b 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1620615409-0b1b9d67156cb605d3b357c0b29ff581cd515794.profdata
+chrome-win32-master-1620647719-0e668f9bcc8c16d50756c67732bb69dbb7fa6ba1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index d9bc586..aa7e726 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1620604511-6724b285c0eaba1ec7f7a8d2abc46c41c146de6b.profdata
+chrome-win64-master-1620636116-7ab1475be05b96ecfa47457d5beb552ded629562.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 956ba5cc..623f557 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -320,6 +320,8 @@
 #       will always be place in $output_dir/locales
 #   additional_extra_paks: List of extra .pak sources for resources.pak.
 #   locale_allowlist: if set, override repack_allowlist for locale .pak files.
+#   files_to_hash: if set, a list of pak file names to generate SHA256 hashes
+#     for.
 #   copy_data_to_bundle:
 #   deps:
 #   output_dir:
@@ -409,4 +411,30 @@
       public_deps += invoker.public_deps
     }
   }
+
+  if (defined(invoker.files_to_hash)) {
+    _prefix = "$target_gen_dir/app/${target_name}_integrity"
+    _integrity_outputs = [
+      "$_prefix.cc",
+      "$_prefix.h",
+    ]
+
+    action("${target_name}_integrity_hash") {
+      script = "tools/build/sha256_file.py"
+      outputs = _integrity_outputs
+      inputs = []
+      foreach(file, invoker.files_to_hash) {
+        inputs += [ "${invoker.output_dir}/$file" ]
+      }
+
+      args = rebase_path([ _prefix ] + inputs, root_build_dir)
+
+      deps = [ ":${invoker.target_name}" ]
+    }
+
+    source_set("${target_name}_integrity") {
+      sources = _integrity_outputs
+      deps = [ ":${target_name}_hash" ]
+    }
+  }
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 83e00df..a9bf97b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4142,6 +4142,7 @@
       "../browser/policy/serial_allow_usb_devices_for_urls_policy_handler_unittest.cc",
       "../browser/profiles/profile_avatar_icon_util_unittest.cc",
       "../browser/profiles/profile_destroyer_unittest.cc",
+      "../browser/resources_integrity_unittest.cc",
       "../browser/safe_browsing/generated_safe_browsing_pref_unittest.cc",
       "../browser/speech/speech_recognition_service_factory_unittest.cc",
       "../browser/tab_contents/form_interaction_tab_helper_unittest.cc",
@@ -5092,6 +5093,7 @@
       "../browser/apps/app_service/file_utils_unittest.cc",
       "../browser/apps/app_service/intent_util_unittest.cc",
       "../browser/apps/app_service/webapk/webapk_install_task_unittest.cc",
+      "../browser/apps/app_service/webapk/webapk_manager_unittest.cc",
       "../browser/component_updater/cros_component_installer_chromeos_unittest.cc",
       "../browser/component_updater/metadata_table_chromeos_unittest.cc",
       "../browser/enterprise/reporting/android_app_info_generator_unittest.cc",
@@ -6014,6 +6016,7 @@
 
   if (enable_session_service) {
     sources += [
+      "../browser/sessions/session_data_service_unittest.cc",
       "../browser/sessions/session_restore_observer_unittest.cc",
       "../browser/sessions/session_restore_stats_collector_unittest.cc",
       "../browser/sessions/session_service_log_unittest.cc",
diff --git a/chrome/test/data/webui/bluetooth_internals/bluetooth_internals_test.js b/chrome/test/data/webui/bluetooth_internals/bluetooth_internals_test.js
index 969e78c..6e2f901 100644
--- a/chrome/test/data/webui/bluetooth_internals/bluetooth_internals_test.js
+++ b/chrome/test/data/webui/bluetooth_internals/bluetooth_internals_test.js
@@ -93,11 +93,13 @@
     var addressColumn = deviceRow.children[1];
     var rssiColumn = deviceRow.children[2];
     var servicesColumn = deviceRow.children[3];
+    var manufacturerDataColumn = deviceRow.children[4];
 
     expectTrue(!!nameForDisplayColumn);
     expectTrue(!!addressColumn);
     expectTrue(!!rssiColumn);
     expectTrue(!!servicesColumn);
+    expectTrue(!!manufacturerDataColumn);
 
     adapterBroker.deviceChanged(deviceInfo);
 
@@ -114,6 +116,28 @@
     } else {
       expectEquals('Unknown', servicesColumn.textContent);
     }
+
+    if (deviceInfo.manufacturerDataMap) {
+      expectEquals(
+          formatManufacturerDataMap(deviceInfo.manufacturerDataMap),
+          manufacturerDataColumn.textContent);
+    }
+  }
+
+  /**
+   * Format in a user readable way device manufacturer data map. Keys are
+   * Bluetooth company identifiers (unsigned short), values are bytes.
+   * @param {Map<string, array<number>>} manufacturerDataMap
+   * @return {string}
+   */
+  function formatManufacturerDataMap(manufacturerDataMap) {
+    return Object.entries(manufacturerDataMap)
+        .map(([key, value]) => {
+          const companyIdentifier = parseInt(key).toString(16).padStart(4, '0');
+          const data = value.map(v => v.toString(16).padStart(2, '0')).join('');
+          return `0x${companyIdentifier} 0x${data}`;
+        })
+        .join(' | ');
   }
 
   /**
@@ -454,6 +478,7 @@
      'isGattConnected',
      'rssi.value',
      'services.length',
+     'manufacturerDataMap',
     ].forEach(function(propName) {
       var valueCell =
           detailsPage.querySelector('fieldset [data-field="' + propName + '"]');
@@ -468,6 +493,8 @@
 
       if (propName === 'isGattConnected') {
         value = value ? 'Connected' : 'Not Connected';
+      } else if (propName === 'manufacturerDataMap') {
+        value = formatManufacturerDataMap(value);
       }
 
       if (typeof (value) === 'boolean') {
diff --git a/chrome/test/data/webui/bluetooth_internals/test_utils.js b/chrome/test/data/webui/bluetooth_internals/test_utils.js
index 92e6c62..83baebe 100644
--- a/chrome/test/data/webui/bluetooth_internals/test_utils.js
+++ b/chrome/test/data/webui/bluetooth_internals/test_utils.js
@@ -205,6 +205,7 @@
     nameForDisplay: 'AAA',
     rssi: {value: -40},
     isGattConnected: false,
+    manufacturerDataMap: {'1': [1, 2], '2': [3, 4]},
     serviceDataMap: {},
     services: [],
   };
@@ -221,6 +222,7 @@
     nameForDisplay: 'BBB',
     rssi: null,
     isGattConnected: false,
+    manufacturerDataMap: {},
     serviceDataMap: {},
     services: [],
   };
@@ -236,6 +238,7 @@
     address: 'CC:CC:84:96:92:84',
     name: 'CCC',
     nameForDisplay: 'CCC',
+    manufacturerDataMap: {},
     serviceDataMap: {},
     isGattConnected: false,
   };
diff --git a/chrome/tools/build/sha256_file.py b/chrome/tools/build/sha256_file.py
new file mode 100755
index 0000000..e0db751
--- /dev/null
+++ b/chrome/tools/build/sha256_file.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# 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.
+"""sha256_file.py takes one or more files, computes a SHA-256 hash over it,
+and writes a .h/.cc file pair containing variables with the digest bytes.
+
+Usage:
+    sha256_file.py path/to/hashes file1.txt file2.pak
+
+Which will create path/to/hashes.h and path/to/hashes.cc with two variable
+declarations, one for each of the specified input file's hash.
+"""
+
+import hashlib
+import os.path
+import sys
+
+
+def main(argv):
+    if len(argv) < 3:
+        print('Usage: {} output_path_prefix file1.pak...'.format(argv[0]),
+              file=sys.stderr)
+        return 1
+
+    output_path_prefix = argv[1]
+
+    h_guard = output_path_prefix.upper().replace('/', '_') + '_H_'
+    h_contents = '#ifndef {guard}\n#define {guard}\n\n'.format(guard=h_guard)
+    cc_contents = '#include "{}.h"\n\n'.format(
+        os.path.basename(output_path_prefix))
+    for (name, value) in _hash_files(argv[2:]):
+        name = 'kSha256_' + os.path.basename(name).replace('.', '_')
+        h_contents += 'extern const std::array<uint8_t, 32> {};\n\n'.format(
+            name)
+        cc_contents += 'const std::array<uint8_t, 32> {} = {{'.format(name)
+        cc_contents += ', '.join(map(hex, value))
+        cc_contents += '};\n\n'
+    h_contents += '#endif  // {}'.format(h_guard)
+
+    with open(output_path_prefix + '.h', 'w') as f:
+        f.write(FILE_TEMPLATE.format(contents=h_contents))
+
+    with open(output_path_prefix + '.cc', 'w') as f:
+        f.write(FILE_TEMPLATE.format(contents=cc_contents))
+
+
+def _hash_files(files):
+    for path in files:
+        with open(path, 'rb') as f:
+            yield path, _hash_file_contents(f)
+
+
+def _hash_file_contents(f):
+    sha2 = hashlib.sha256()
+    while True:
+        data = f.read(4096)
+        if not data:
+            break
+        sha2.update(data)
+    return sha2.digest()
+
+
+FILE_TEMPLATE = """// Generated by chrome/tools/build/sha256_file.py
+// !! DO NOT EDIT !!
+
+#include <stdint.h>
+
+#include <array>
+
+{contents}
+"""
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/chromeos/dbus/debug_daemon/debug_daemon_client.cc b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
index 23e4f5ff..9706a056 100644
--- a/chromeos/dbus/debug_daemon/debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
@@ -530,6 +530,28 @@
                        std::move(error_callback)));
   }
 
+  void GetKernelFeatureList(KernelFeatureListCallback callback) override {
+    dbus::MethodCall method_call(debugd::kDebugdInterface,
+                                 debugd::kKernelFeatureList);
+    dbus::MessageWriter writer(&method_call);
+    debugdaemon_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&DebugDaemonClientImpl::OnKernelFeatureList,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void KernelFeatureEnable(const std::string& name,
+                           KernelFeatureEnableCallback callback) override {
+    dbus::MethodCall method_call(debugd::kDebugdInterface,
+                                 debugd::kKernelFeatureEnable);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(name);
+    debugdaemon_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&DebugDaemonClientImpl::OnKernelFeatureEnable,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
   void StartPluginVmDispatcher(const std::string& owner_id,
                                const std::string& lang,
                                PluginVmDispatcherCallback callback) override {
@@ -692,6 +714,54 @@
     std::move(callback).Run(!sub_reader.HasMoreData() && !broken, logs);
   }
 
+  void OnKernelFeatureList(KernelFeatureListCallback callback,
+                           dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(false, "error: No Response");
+      return;
+    }
+
+    std::string csv;
+    bool result = false;
+
+    dbus::MessageReader reader(response);
+    if (!reader.PopBool(&result) || !reader.PopString(&csv)) {
+      std::move(callback).Run(false, "error: Failed to read response");
+      return;
+    }
+
+    if (!result) {
+      std::move(callback).Run(false, csv);
+      return;
+    }
+
+    std::move(callback).Run(true, csv);
+  }
+
+  void OnKernelFeatureEnable(KernelFeatureEnableCallback callback,
+                             dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(false, "error: No Response");
+      return;
+    }
+
+    std::string err_str;
+    bool result = false;
+
+    dbus::MessageReader reader(response);
+    if (!reader.PopBool(&result) || !reader.PopString(&err_str)) {
+      std::move(callback).Run(false, "error: Failed to read response");
+      return;
+    }
+
+    if (!result) {
+      std::move(callback).Run(false, err_str);
+      return;
+    }
+
+    std::move(callback).Run(true, err_str);
+  }
+
   void OnBigFeedbackLogsResponse(base::WeakPtr<PipeReaderWrapper> pipe_reader,
                                  dbus::Response* response) {
     if (!response && pipe_reader.get()) {
diff --git a/chromeos/dbus/debug_daemon/debug_daemon_client.h b/chromeos/dbus/debug_daemon/debug_daemon_client.h
index 4c2abcc..8055cda 100644
--- a/chromeos/dbus/debug_daemon/debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon/debug_daemon_client.h
@@ -236,6 +236,21 @@
                                  CupsRemovePrinterCallback callback,
                                  base::OnceClosure error_callback) = 0;
 
+  // Request a list of kernel features supported by device, passing it
+  // a |callback| on receiving the result. |result| is true on
+  // success.
+  using KernelFeatureListCallback =
+      base::OnceCallback<void(bool result, const std::string& feature_list)>;
+  virtual void GetKernelFeatureList(KernelFeatureListCallback callback) = 0;
+
+  // Request a kernel feature |name| to be enabled, passing it a
+  // |callback| which is invoked once on receiving the result. |result|
+  // is true on success. On failure, |err_str| contains the failure reason.
+  using KernelFeatureEnableCallback =
+      base::OnceCallback<void(bool result, const std::string& err_str)>;
+  virtual void KernelFeatureEnable(const std::string& name,
+                                   KernelFeatureEnableCallback callback) = 0;
+
   // A callback to handle the result of
   // StartPluginVmDispatcher/StopPluginVmDispatcher.
   using PluginVmDispatcherCallback = base::OnceCallback<void(bool success)>;
diff --git a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
index 5562125..74dc66e 100644
--- a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
@@ -300,4 +300,15 @@
       base::BindOnce(std::move(callback), base::make_optional(u2f_flags_)));
 }
 
+void FakeDebugDaemonClient::GetKernelFeatureList(
+    KernelFeatureListCallback callback) {
+  // Defined by test.
+}
+
+void FakeDebugDaemonClient::KernelFeatureEnable(
+    const std::string& name,
+    KernelFeatureListCallback callback) {
+  // Defined by test.
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
index 44341c9d..71e6453d 100644
--- a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
@@ -100,6 +100,9 @@
   void SetU2fFlags(const std::set<std::string>& flags,
                    VoidDBusMethodCallback callback) override;
   void GetU2fFlags(DBusMethodCallback<std::set<std::string>> callback) override;
+  void GetKernelFeatureList(KernelFeatureListCallback callback) override;
+  void KernelFeatureEnable(const std::string& name,
+                           KernelFeatureEnableCallback callback) override;
 
   // Sets debugging features mask for testing.
   virtual void SetDebuggingFeaturesStatus(int features_mask);
diff --git a/chromeos/strings/chromeos_strings_en-GB.xtb b/chromeos/strings/chromeos_strings_en-GB.xtb
index 2ad3f2e..01fad1d 100644
--- a/chromeos/strings/chromeos_strings_en-GB.xtb
+++ b/chromeos/strings/chromeos_strings_en-GB.xtb
@@ -105,6 +105,7 @@
 <translation id="3369013195428705271">Are you sure you want to clear all print history? Your ongoing print jobs will not be cleared.</translation>
 <translation id="3434107140712555581"><ph name="BATTERY_PERCENTAGE" />%</translation>
 <translation id="3435738964857648380">Security</translation>
+<translation id="3442340494009790209">Build a game</translation>
 <translation id="3456078764689556234">Printed page <ph name="PRINTED_PAGES" /> out of <ph name="TOTAL_PAGES" />.</translation>
 <translation id="345898999683440380">Scanning page <ph name="PAGE_NUM" />. <ph name="PERCENTAGE_VALUE" />% completed.</translation>
 <translation id="3459509316159669723">Printing</translation>
diff --git a/chromeos/strings/chromeos_strings_lo.xtb b/chromeos/strings/chromeos_strings_lo.xtb
index a1b2452..a7bb490 100644
--- a/chromeos/strings/chromeos_strings_lo.xtb
+++ b/chromeos/strings/chromeos_strings_lo.xtb
@@ -105,6 +105,7 @@
 <translation id="3369013195428705271">ທ່ານແນ່ໃຈບໍ່ວ່າທ່ານຕ້ອງການລຶບປະຫວັດການພິມທັງໝົດ? ວຽກການພິມທີ່ພວມດຳເນີນຢູ່ຂອງທ່ານຈະບໍ່ຖືກລຶບລ້າງ.</translation>
 <translation id="3434107140712555581"><ph name="BATTERY_PERCENTAGE" />%</translation>
 <translation id="3435738964857648380">ຄວາມ​ປອດ​ໄພ</translation>
+<translation id="3442340494009790209">ສ້າງເກມ</translation>
 <translation id="3456078764689556234">ພິມໜ້າ <ph name="PRINTED_PAGES" /> ຈາກທັງໝົດ <ph name="TOTAL_PAGES" />.</translation>
 <translation id="345898999683440380">ກຳລັງສະແກນໜ້າ <ph name="PAGE_NUM" />. ສຳເລັດແລ້ວ <ph name="PERCENTAGE_VALUE" />%.</translation>
 <translation id="3459509316159669723">ກໍາລັງພິມ</translation>
diff --git a/chromeos/strings/chromeos_strings_ms.xtb b/chromeos/strings/chromeos_strings_ms.xtb
index ea4d396b6..3c5bd0e 100644
--- a/chromeos/strings/chromeos_strings_ms.xtb
+++ b/chromeos/strings/chromeos_strings_ms.xtb
@@ -105,6 +105,7 @@
 <translation id="3369013195428705271">Adakah anda pasti anda ingin mengosongkan semua sejarah cetak? Tugas cetak anda yang masih dijalankan tidak akan dipadamkan.</translation>
 <translation id="3434107140712555581"><ph name="BATTERY_PERCENTAGE" />%</translation>
 <translation id="3435738964857648380">Keselamatan</translation>
+<translation id="3442340494009790209">Bina permainan</translation>
 <translation id="3456078764689556234">Mencetak halaman <ph name="PRINTED_PAGES" /> daripada <ph name="TOTAL_PAGES" />.</translation>
 <translation id="345898999683440380">Mengimbas halaman <ph name="PAGE_NUM" />. <ph name="PERCENTAGE_VALUE" />% selesai.</translation>
 <translation id="3459509316159669723">Mencetak</translation>
diff --git a/chromeos/strings/chromeos_strings_si.xtb b/chromeos/strings/chromeos_strings_si.xtb
index 11a8b9e..7223f0a 100644
--- a/chromeos/strings/chromeos_strings_si.xtb
+++ b/chromeos/strings/chromeos_strings_si.xtb
@@ -105,6 +105,7 @@
 <translation id="3369013195428705271">ඔබට මුද්‍රණ ඉතිහාස සියල්ල හිස් කිරීමට අවශ්‍ය බව ඔබට තහවුරුද? ඔබේ පවතින මුද්‍රණ වැඩ හිස් නොකෙරේ.</translation>
 <translation id="3434107140712555581"><ph name="BATTERY_PERCENTAGE" />%</translation>
 <translation id="3435738964857648380">ආරක්ෂක</translation>
+<translation id="3442340494009790209">ක්‍රීඩාවක් ගොඩනඟන්න</translation>
 <translation id="3456078764689556234"><ph name="TOTAL_PAGES" /> න් මුද්‍රණය කළ පිටුව <ph name="PRINTED_PAGES" /></translation>
 <translation id="345898999683440380"><ph name="PAGE_NUM" /> පිටුව ස්කෑන් කරමින්. <ph name="PERCENTAGE_VALUE" />% සම්පූර්ණයි.</translation>
 <translation id="3459509316159669723">මුද්‍රණය කරමින්</translation>
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 524bba8..756ce9d 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -75,6 +75,8 @@
     "autofill_observer.h",
     "autofill_profile_import_process.cc",
     "autofill_profile_import_process.h",
+    "autofill_profile_save_strike_database.cc",
+    "autofill_profile_save_strike_database.h",
     "autofill_profile_sync_util.cc",
     "autofill_profile_sync_util.h",
     "autofill_profile_validation_util.cc",
@@ -653,6 +655,7 @@
     "autofill_merge_unittest.cc",
     "autofill_metrics_unittest.cc",
     "autofill_profile_import_process_unittest.cc",
+    "autofill_profile_save_strike_database_unittest.cc",
     "autofill_profile_sync_util_unittest.cc",
     "autofill_profile_validation_util_unittest.cc",
     "autofill_profile_validator_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_profile_save_strike_database.cc b/components/autofill/core/browser/autofill_profile_save_strike_database.cc
new file mode 100644
index 0000000..0701db5
--- /dev/null
+++ b/components/autofill/core/browser/autofill_profile_save_strike_database.cc
@@ -0,0 +1,100 @@
+// 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 "components/autofill/core/browser/autofill_profile_save_strike_database.h"
+
+#include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+// Limit the number of domains for which the import of new profiles is disabled.
+constexpr size_t kMaxStrikeEntities = 200;
+
+// Once the limit of domains is reached, delete 50 to create a bit of headroom.
+constexpr size_t kMaxStrikeEntitiesAfterCleanup = 150;
+
+AutofillProfileSaveStrikeDatabase::AutofillProfileSaveStrikeDatabase(
+    StrikeDatabase* strike_database)
+    : StrikeDatabaseIntegratorBase(strike_database) {
+  RemoveExpiredStrikes();
+}
+
+AutofillProfileSaveStrikeDatabase::~AutofillProfileSaveStrikeDatabase() =
+    default;
+
+base::Optional<size_t> AutofillProfileSaveStrikeDatabase::GetMaximumEntries()
+    const {
+  return base::make_optional(kMaxStrikeEntities);
+}
+
+base::Optional<size_t>
+AutofillProfileSaveStrikeDatabase::GetMaximumEntriesAfterCleanup() const {
+  return base::make_optional(kMaxStrikeEntitiesAfterCleanup);
+}
+
+std::string AutofillProfileSaveStrikeDatabase::GetProjectPrefix() const {
+  return "AutofillProfileSave";
+}
+
+int AutofillProfileSaveStrikeDatabase::GetMaxStrikesLimit() const {
+  return 3;
+}
+
+base::Optional<base::TimeDelta>
+AutofillProfileSaveStrikeDatabase::GetExpiryTimeDelta() const {
+  // Expiry time is 6 months.
+  return base::TimeDelta::FromDays(183);
+}
+
+bool AutofillProfileSaveStrikeDatabase::UniqueIdsRequired() const {
+  return true;
+}
+
+void AutofillProfileSaveStrikeDatabase::RemoveStrikesByOriginAndTimeInternal(
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+    base::Time delete_begin,
+    base::Time delete_end) {
+  if (delete_begin.is_null()) {
+    delete_begin = base::Time::Min();
+  }
+
+  if (delete_end.is_null()) {
+    delete_end = base::Time::Max();
+  }
+
+  std::vector<std::string> keys_to_delete;
+  keys_to_delete.reserve(GetStrikeCache().size());
+
+  for (auto const& entry : GetStrikeCache()) {
+    std::string strike_id = GetIdFromKey(entry.first);
+    if (strike_id.empty()) {
+      continue;
+    }
+
+    GURL host = GURL(strike_id);
+
+    // If the id cannot be converted to a valid host delete it anyway.
+    if (!host.is_valid()) {
+      keys_to_delete.push_back(entry.first);
+      continue;
+    }
+
+    base::Time last_update = base::Time::FromDeltaSinceWindowsEpoch(
+        base::TimeDelta::FromMicroseconds(
+            entry.second.last_update_timestamp()));
+
+    // Check if the time stamp of the record is within deletion range and if
+    // either there is no origin filter, or if the filter returns true for the
+    // host.
+    if (last_update >= delete_begin && last_update <= delete_end &&
+        (origin_filter.is_null() || origin_filter.Run(host))) {
+      keys_to_delete.push_back(entry.first);
+    }
+  }
+
+  ClearStrikesForKeys(keys_to_delete);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_profile_save_strike_database.h b/components/autofill/core/browser/autofill_profile_save_strike_database.h
new file mode 100644
index 0000000..ef8452d78
--- /dev/null
+++ b/components/autofill/core/browser/autofill_profile_save_strike_database.h
@@ -0,0 +1,40 @@
+// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_SAVE_STRIKE_DATABASE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_SAVE_STRIKE_DATABASE_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "components/autofill/core/browser/strike_database.h"
+#include "components/autofill/core/browser/strike_database_integrator_base.h"
+
+class GURL;
+
+namespace autofill {
+
+// Implementation of StrikeDatabaseIntegratorBase for autofill profile imports.
+class AutofillProfileSaveStrikeDatabase : public StrikeDatabaseIntegratorBase {
+ public:
+  explicit AutofillProfileSaveStrikeDatabase(StrikeDatabase* strike_database);
+  ~AutofillProfileSaveStrikeDatabase() override;
+
+  void RemoveStrikesByOriginAndTimeInternal(
+      const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+      base::Time delete_begin,
+      base::Time delete_end);
+
+  base::Optional<size_t> GetMaximumEntries() const override;
+  base::Optional<size_t> GetMaximumEntriesAfterCleanup() const override;
+
+  std::string GetProjectPrefix() const override;
+  int GetMaxStrikesLimit() const override;
+  base::Optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+  bool UniqueIdsRequired() const override;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_SAVE_STRIKE_DATABASE_H_
diff --git a/components/autofill/core/browser/autofill_profile_save_strike_database_unittest.cc b/components/autofill/core/browser/autofill_profile_save_strike_database_unittest.cc
new file mode 100644
index 0000000..a81276f
--- /dev/null
+++ b/components/autofill/core/browser/autofill_profile_save_strike_database_unittest.cc
@@ -0,0 +1,176 @@
+// 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 "components/autofill/core/browser/strike_database_integrator_test_strike_database.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/autofill/core/browser/autofill_profile_save_strike_database.h"
+#include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+namespace {
+
+bool DeleteOrigin(const GURL& origin) {
+  if (origin.host() == "www.strikedhost.com") {
+    return true;
+  }
+  return false;
+}
+
+base::RepeatingCallback<bool(const GURL&)> GetDeletionFilter() {
+  return base::BindRepeating(&DeleteOrigin);
+}
+
+base::RepeatingCallback<bool(const GURL&)> GetDeletionNullFilter() {
+  return base::RepeatingCallback<bool(const GURL&)>();
+}
+
+class AutofillProfileSaveStrikeDatabaseTest : public ::testing::Test {
+ public:
+  AutofillProfileSaveStrikeDatabaseTest() = default;
+
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    strike_database_service_ = std::make_unique<StrikeDatabase>(
+        db_provider_.get(), temp_dir_.GetPath());
+
+    strike_database_ = std::make_unique<AutofillProfileSaveStrikeDatabase>(
+        strike_database_service_.get());
+  }
+
+  void TearDown() override {
+    // The destruction of |strike_database_service_|'s components is posted
+    // to a task runner, requires running the loop to complete.
+    strike_database_.reset();
+    strike_database_service_.reset();
+    db_provider_.reset();
+    task_environment_.RunUntilIdle();
+  }
+
+ protected:
+  base::ScopedTempDir temp_dir_;
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
+  std::unique_ptr<StrikeDatabase> strike_database_service_;
+  std::unique_ptr<AutofillProfileSaveStrikeDatabase> strike_database_;
+
+  std::string test_host1 = "https://www.strikedhost.com";
+  std::string test_host2 = "https://www.otherhost.com";
+  std::string test_host3 = "https://www.justanotherhost.com";
+};
+
+TEST_F(AutofillProfileSaveStrikeDatabaseTest, AddAndRemoveStrikes) {
+  strike_database_->AddStrike(test_host1);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 1);
+  EXPECT_FALSE(strike_database_->IsMaxStrikesLimitReached(test_host1));
+
+  strike_database_->AddStrikes(2, test_host1);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 3);
+  EXPECT_TRUE(strike_database_->IsMaxStrikesLimitReached(test_host1));
+
+  strike_database_->RemoveStrike(test_host1);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 2);
+  EXPECT_FALSE(strike_database_->IsMaxStrikesLimitReached(test_host1));
+}
+
+TEST_F(AutofillProfileSaveStrikeDatabaseTest, RemoveStrikesByOrigin) {
+  base::Time start_time = AutofillClock::Now();
+  // Both strikes are added within the deletion window, but the second should
+  // be ruled out by the filter.
+  strike_database_->AddStrike(test_host1);
+  strike_database_->AddStrike(test_host2);
+  base::Time end_time = AutofillClock::Now();
+
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 1);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host2), 1);
+
+  strike_database_->RemoveStrikesByOriginAndTimeInternal(GetDeletionFilter(),
+                                                         start_time, end_time);
+
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 0);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host2), 1);
+}
+
+TEST_F(AutofillProfileSaveStrikeDatabaseTest, RemoveStrikesWithNullFilter) {
+  TestAutofillClock test_autofill_clock;
+  test_autofill_clock.SetNow(AutofillClock::Now());
+
+  base::Time start_time = AutofillClock::Now();
+
+  strike_database_->AddStrike(test_host1);
+  strike_database_->AddStrike(test_host2);
+
+  base::Time end_time = AutofillClock::Now();
+
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 1);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host2), 1);
+
+  strike_database_->RemoveStrikesByOriginAndTimeInternal(
+      GetDeletionNullFilter(), start_time, end_time);
+
+  // Test that all strikes are removed with a null filter.
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 0);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host2), 0);
+}
+
+TEST_F(AutofillProfileSaveStrikeDatabaseTest,
+       DoNotRemoveStrikeAfterDeletionWindow) {
+  TestAutofillClock test_autofill_clock;
+  test_autofill_clock.SetNow(AutofillClock::Now());
+
+  base::Time start_time = AutofillClock::Now();
+  strike_database_->AddStrike(test_host1);
+  test_autofill_clock.Advance(base::TimeDelta::FromMinutes(1));
+  base::Time end_time = AutofillClock::Now();
+  test_autofill_clock.Advance(base::TimeDelta::FromMinutes(1));
+
+  // Now update the time stamp of this entry by adding another strike.
+  // By this, the entry should not be deleted.
+  strike_database_->AddStrike(test_host1);
+
+  strike_database_->RemoveStrikesByOriginAndTimeInternal(
+      GetDeletionNullFilter(), start_time, end_time);
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 2);
+}
+
+TEST_F(AutofillProfileSaveStrikeDatabaseTest,
+       DoNotRemoveStrikeBeforeDeletionWindow) {
+  // The strike is added before the deletion window.
+  TestAutofillClock test_autofill_clock;
+  test_autofill_clock.SetNow(AutofillClock::Now());
+
+  strike_database_->AddStrike(test_host1);
+  test_autofill_clock.Advance(base::TimeDelta::FromMinutes(1));
+
+  base::Time start_time = AutofillClock::Now();
+  test_autofill_clock.Advance(base::TimeDelta::FromMinutes(1));
+  base::Time end_time = AutofillClock::Now();
+
+  strike_database_->RemoveStrikesByOriginAndTimeInternal(
+      GetDeletionNullFilter(), start_time, end_time);
+
+  EXPECT_EQ(strike_database_->GetStrikes(test_host1), 1);
+}
+
+}  // namespace
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
index ea451bc..e8c4a5f 100644
--- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
+++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -22,8 +22,10 @@
     AutofillSaveUpdateAddressProfileDelegateIOS(
         const AutofillProfile& profile,
         const AutofillProfile* original_profile,
+        const std::string& locale,
         AutofillClient::AddressProfileSavePromptCallback callback)
-    : profile_(profile),
+    : locale_(locale),
+      profile_(profile),
       original_profile_(base::OptionalFromPtr(original_profile)),
       address_profile_save_prompt_callback_(std::move(callback)) {}
 
@@ -42,9 +44,8 @@
 }
 
 std::u16string
-AutofillSaveUpdateAddressProfileDelegateIOS::GetEnvelopeStyleAddress(
-    const std::string& ui_language_code) const {
-  return ::autofill::GetEnvelopeStyleAddress(profile_, ui_language_code,
+AutofillSaveUpdateAddressProfileDelegateIOS::GetEnvelopeStyleAddress() const {
+  return ::autofill::GetEnvelopeStyleAddress(profile_, locale_,
                                              /*include_country=*/true);
 }
 
@@ -58,10 +59,11 @@
   return profile_.GetRawInfo(EMAIL_ADDRESS);
 }
 
-std::u16string
-AutofillSaveUpdateAddressProfileDelegateIOS::GetMessageDescriptionText() const {
-  // TODO(crbug.com/1167062): Replace with proper localized string.
-  return std::u16string(u"Fill forms faster in Chrome");
+std::u16string AutofillSaveUpdateAddressProfileDelegateIOS::GetDescription()
+    const {
+  return original_profile_
+             ? GetDescriptionForProfileToUpdate(*original_profile_, locale_)
+             : GetDescriptionForProfileToSave(profile_, locale_);
 }
 
 std::u16string
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
index dcaf555..54b92feb 100644
--- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
+++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -22,6 +22,7 @@
   AutofillSaveUpdateAddressProfileDelegateIOS(
       const AutofillProfile& profile,
       const AutofillProfile* original_profile,
+      const std::string& locale,
       AutofillClient::AddressProfileSavePromptCallback callback);
   AutofillSaveUpdateAddressProfileDelegateIOS(
       const AutofillSaveUpdateAddressProfileDelegateIOS&) = delete;
@@ -34,12 +35,21 @@
   static AutofillSaveUpdateAddressProfileDelegateIOS* FromInfobarDelegate(
       infobars::InfoBarDelegate* delegate);
 
-  std::u16string GetEnvelopeStyleAddress(
-      const std::string& ui_language_code) const;
+  // Returns the address in envelope style in the |profile_|.
+  std::u16string GetEnvelopeStyleAddress() const;
+
+  // Returns the phone number in the |profile_|.
   std::u16string GetPhoneNumber() const;
+
+  // Returns the email address in the |profile_|.
   std::u16string GetEmailAddress() const;
-  std::u16string GetMessageDescriptionText() const;
+
+  // Returns the subtitle text to be displayed in the save/update banner.
+  std::u16string GetDescription() const;
+
+  // Returns the message button text.
   std::u16string GetMessageActionText() const;
+
   const autofill::AutofillProfile* GetProfile() const;
   const autofill::AutofillProfile* GetOriginalProfile() const;
   void set_modal_is_shown_to_true() { modal_is_shown_ = true; }
@@ -62,6 +72,9 @@
   void RunSaveAddressProfilePromptCallback(
       AutofillClient::SaveAddressProfileOfferUserDecision decision);
 
+  // The application locale.
+  std::string locale_;
+
   // The profile that will be saved if the user accepts.
   AutofillProfile profile_;
 
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
index a3139ba4..1213fcb1 100644
--- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
+++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
@@ -18,7 +18,8 @@
   AutofillProfile profile = test::GetFullProfile();
   base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
   auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>(
-      profile, /*original_profile=*/nullptr, callback.Get());
+      profile, /*original_profile=*/nullptr, /*locale=*/"en-US",
+      callback.Get());
 
   EXPECT_CALL(
       callback,
@@ -33,10 +34,13 @@
   AutofillProfile profile = test::GetFullProfile();
   base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
   auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>(
-      profile, /*original_profile=*/nullptr, callback.Get());
+      profile, /*original_profile=*/nullptr, /*locale=*/"en-US",
+      callback.Get());
 
   EXPECT_EQ(delegate->GetMessageActionText(), std::u16string(u"Save..."));
   EXPECT_EQ(delegate->GetMessageText(), std::u16string(u"Save Address?"));
+  EXPECT_EQ(delegate->GetDescription(),
+            std::u16string(u"John H. Doe, 666 Erebus St."));
 }
 
 // Tests that the delegate returns Update Address profile strings when the
@@ -46,10 +50,12 @@
   AutofillProfile profile = test::GetFullProfile();
   base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
   auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>(
-      profile, &profile, callback.Get());
+      profile, &profile, /*locale=*/"en-US", callback.Get());
 
   EXPECT_EQ(delegate->GetMessageActionText(), std::u16string(u"Update..."));
   EXPECT_EQ(delegate->GetMessageText(), std::u16string(u"Update Address?"));
+  EXPECT_EQ(delegate->GetDescription(),
+            std::u16string(u"John H. Doe \x2014 666 Erebus St."));
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index d063a35..ab54c32 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -678,6 +678,8 @@
 void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
                                                  bool known_success,
                                                  SubmissionSource source) {
+  base::UmaHistogramEnumeration("Autofill.FormSubmission.PerProfileType",
+                                client()->GetProfileType());
   if (log_manager()) {
     log_manager()->Log() << LoggingScope::kSubmission
                          << LogMessage::kFormSubmissionDetected << Br{}
@@ -712,9 +714,6 @@
   autocomplete_history_manager_->OnWillSubmitForm(
       form_for_autocomplete, client()->IsAutocompleteEnabled());
 
-  base::UmaHistogramEnumeration("Autofill.FormSubmission.PerProfileType",
-                                client()->GetProfileType());
-
   if (IsAutofillProfileEnabled()) {
     address_form_event_logger_->OnWillSubmitForm(sync_state_, *submitted_form);
   }
diff --git a/components/autofill/core/browser/payments/credit_card_save_strike_database.cc b/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
index 438e7e5..2848c81b 100644
--- a/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
@@ -14,22 +14,23 @@
   RemoveExpiredStrikes();
 }
 
-CreditCardSaveStrikeDatabase::~CreditCardSaveStrikeDatabase() {}
+CreditCardSaveStrikeDatabase::~CreditCardSaveStrikeDatabase() = default;
 
-std::string CreditCardSaveStrikeDatabase::GetProjectPrefix() {
+std::string CreditCardSaveStrikeDatabase::GetProjectPrefix() const {
   return "CreditCardSave";
 }
 
-int CreditCardSaveStrikeDatabase::GetMaxStrikesLimit() {
+int CreditCardSaveStrikeDatabase::GetMaxStrikesLimit() const {
   return 3;
 }
 
-base::Optional<int64_t> CreditCardSaveStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<base::TimeDelta>
+CreditCardSaveStrikeDatabase::GetExpiryTimeDelta() const {
   // Expiry time is 6 months.
-  return (int64_t)1000000 * 60 * 60 * 24 * 180;
+  return base::TimeDelta::FromDays(183);
 }
 
-bool CreditCardSaveStrikeDatabase::UniqueIdsRequired() {
+bool CreditCardSaveStrikeDatabase::UniqueIdsRequired() const {
   return true;
 }
 
diff --git a/components/autofill/core/browser/payments/credit_card_save_strike_database.h b/components/autofill/core/browser/payments/credit_card_save_strike_database.h
index cb228fd5..01c62d1 100644
--- a/components/autofill/core/browser/payments/credit_card_save_strike_database.h
+++ b/components/autofill/core/browser/payments/credit_card_save_strike_database.h
@@ -20,10 +20,10 @@
   explicit CreditCardSaveStrikeDatabase(StrikeDatabase* strike_database);
   ~CreditCardSaveStrikeDatabase() override;
 
-  std::string GetProjectPrefix() override;
-  int GetMaxStrikesLimit() override;
-  base::Optional<int64_t> GetExpiryTimeMicros() override;
-  bool UniqueIdsRequired() override;
+  std::string GetProjectPrefix() const override;
+  int GetMaxStrikesLimit() const override;
+  base::Optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+  bool UniqueIdsRequired() const override;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/fido_authentication_strike_database.cc b/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
index 08926ea..2df0e60 100644
--- a/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
+++ b/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
@@ -20,23 +20,23 @@
   RemoveExpiredStrikes();
 }
 
-FidoAuthenticationStrikeDatabase::~FidoAuthenticationStrikeDatabase() {}
+FidoAuthenticationStrikeDatabase::~FidoAuthenticationStrikeDatabase() = default;
 
-std::string FidoAuthenticationStrikeDatabase::GetProjectPrefix() {
+std::string FidoAuthenticationStrikeDatabase::GetProjectPrefix() const {
   return "FidoAuthentication";
 }
 
-int FidoAuthenticationStrikeDatabase::GetMaxStrikesLimit() {
+int FidoAuthenticationStrikeDatabase::GetMaxStrikesLimit() const {
   return 3;
 }
 
-base::Optional<int64_t>
-FidoAuthenticationStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<base::TimeDelta>
+FidoAuthenticationStrikeDatabase::GetExpiryTimeDelta() const {
   // Expiry time is six months.
-  return (int64_t)1000000 * 60 * 60 * 24 * 30 * 6;
+  return base::TimeDelta::FromDays(183);
 }
 
-bool FidoAuthenticationStrikeDatabase::UniqueIdsRequired() {
+bool FidoAuthenticationStrikeDatabase::UniqueIdsRequired() const {
   return false;
 }
 
diff --git a/components/autofill/core/browser/payments/fido_authentication_strike_database.h b/components/autofill/core/browser/payments/fido_authentication_strike_database.h
index 637feec..00b974f 100644
--- a/components/autofill/core/browser/payments/fido_authentication_strike_database.h
+++ b/components/autofill/core/browser/payments/fido_authentication_strike_database.h
@@ -28,10 +28,10 @@
   // Strikes to add when user opts-out from settings page.
   static const int kStrikesToAddWhenUserOptsOut;
 
-  std::string GetProjectPrefix() override;
-  int GetMaxStrikesLimit() override;
-  base::Optional<int64_t> GetExpiryTimeMicros() override;
-  bool UniqueIdsRequired() override;
+  std::string GetProjectPrefix() const override;
+  int GetMaxStrikesLimit() const override;
+  base::Optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+  bool UniqueIdsRequired() const override;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/local_card_migration_strike_database.cc b/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
index f277e894..8367a3b 100644
--- a/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
+++ b/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
@@ -20,25 +20,25 @@
   RemoveExpiredStrikes();
 }
 
-LocalCardMigrationStrikeDatabase::~LocalCardMigrationStrikeDatabase() {}
+LocalCardMigrationStrikeDatabase::~LocalCardMigrationStrikeDatabase() = default;
 
-std::string LocalCardMigrationStrikeDatabase::GetProjectPrefix() {
+std::string LocalCardMigrationStrikeDatabase::GetProjectPrefix() const {
   return "LocalCardMigration";
 }
 
-int LocalCardMigrationStrikeDatabase::GetMaxStrikesLimit() {
+int LocalCardMigrationStrikeDatabase::GetMaxStrikesLimit() const {
   return 6;
 }
 
-base::Optional<int64_t>
-LocalCardMigrationStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<base::TimeDelta>
+LocalCardMigrationStrikeDatabase::GetExpiryTimeDelta() const {
   // Ideally, we should be able to annotate cards deselected at migration time
   // as cards the user is not interested in uploading.  Until then, we have been
   // asked to not expire local card migration strikes.
   return base::nullopt;
 }
 
-bool LocalCardMigrationStrikeDatabase::UniqueIdsRequired() {
+bool LocalCardMigrationStrikeDatabase::UniqueIdsRequired() const {
   return false;
 }
 
diff --git a/components/autofill/core/browser/payments/local_card_migration_strike_database.h b/components/autofill/core/browser/payments/local_card_migration_strike_database.h
index f6f2ec5..c4c5b4ac 100644
--- a/components/autofill/core/browser/payments/local_card_migration_strike_database.h
+++ b/components/autofill/core/browser/payments/local_card_migration_strike_database.h
@@ -29,10 +29,10 @@
   // migration.
   static const int kStrikesToAddWhenCardsDeselectedAtMigration;
 
-  std::string GetProjectPrefix() override;
-  int GetMaxStrikesLimit() override;
-  base::Optional<int64_t> GetExpiryTimeMicros() override;
-  bool UniqueIdsRequired() override;
+  std::string GetProjectPrefix() const override;
+  int GetMaxStrikesLimit() const override;
+  base::Optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+  bool UniqueIdsRequired() const override;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_base.cc b/components/autofill/core/browser/strike_database_integrator_base.cc
index 22226d8c..83f580e 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.cc
+++ b/components/autofill/core/browser/strike_database_integrator_base.cc
@@ -24,10 +24,10 @@
     StrikeDatabase* strike_database)
     : strike_database_(strike_database) {}
 
-StrikeDatabaseIntegratorBase::~StrikeDatabaseIntegratorBase() {}
+StrikeDatabaseIntegratorBase::~StrikeDatabaseIntegratorBase() = default;
 
 bool StrikeDatabaseIntegratorBase::IsMaxStrikesLimitReached(
-    const std::string& id) {
+    const std::string& id) const {
   CheckIdUniqueness(id);
   return GetStrikes(id) >= GetMaxStrikesLimit();
 }
@@ -41,6 +41,12 @@
                                              const std::string& id) {
   CheckIdUniqueness(id);
   int num_strikes = strike_database_->AddStrikes(strikes_increase, GetKey(id));
+  // If a new strike entry was created, run the routine to limit the number of
+  // stored entries. This is a noop for most strike counters.
+  if (num_strikes == strikes_increase) {
+    LimitNumberOfStoredEntries();
+  }
+
   base::UmaHistogramCounts1000(
       "Autofill.StrikeDatabase.NthStrikeAdded." + GetProjectPrefix(),
       num_strikes);
@@ -58,7 +64,7 @@
   return strike_database_->RemoveStrikes(strike_decrease, GetKey(id));
 }
 
-int StrikeDatabaseIntegratorBase::GetStrikes(const std::string& id) {
+int StrikeDatabaseIntegratorBase::GetStrikes(const std::string& id) const {
   CheckIdUniqueness(id);
   return strike_database_->GetStrikes(GetKey(id));
 }
@@ -72,16 +78,69 @@
   strike_database_->ClearAllStrikesForProject(GetProjectPrefix());
 }
 
+size_t StrikeDatabaseIntegratorBase::CountEntries() const {
+  return base::ranges::count_if(GetStrikeCache(), [&](const auto& entry) {
+    return strike_database_->GetPrefixFromKey(entry.first) ==
+           GetProjectPrefix();
+  });
+}
+
+void StrikeDatabaseIntegratorBase::LimitNumberOfStoredEntries() {
+  if (!NumberOfEntriesExceedsLimits()) {
+    return;
+  }
+
+  DCHECK(GetMaximumEntries().has_value());
+  DCHECK(!GetMaximumEntriesAfterCleanup().has_value() ||
+         GetMaximumEntriesAfterCleanup() <= GetMaximumEntries());
+
+  size_t maximum_size = GetMaximumEntriesAfterCleanup().has_value()
+                            ? GetMaximumEntriesAfterCleanup().value()
+                            : GetMaximumEntries().value();
+
+  std::vector<std::pair<std::string, int64_t>> entries;
+  entries.reserve(GetStrikeCache().size());
+  for (const auto& entry : GetStrikeCache()) {
+    if (strike_database_->GetPrefixFromKey(entry.first) != GetProjectPrefix()) {
+      continue;
+    }
+    entries.emplace_back(entry.first, entry.second.last_update_timestamp());
+  }
+
+  if (entries.size() <= maximum_size) {
+    return;
+  }
+  size_t elements_to_delete = entries.size() - maximum_size;
+
+  std::vector<std::string> keys_to_delete;
+
+  // Sort by timestamp.
+  std::sort(entries.begin(), entries.end(),
+            [](auto& a, auto& b) { return a.second < b.second; });
+
+  for (size_t i = 0; i < elements_to_delete; i++) {
+    keys_to_delete.push_back(entries.at(i).first);
+  }
+
+  ClearStrikesForKeys(keys_to_delete);
+}
+
+bool StrikeDatabaseIntegratorBase::NumberOfEntriesExceedsLimits() const {
+  if (!GetMaximumEntries().has_value()) {
+    return false;
+  }
+
+  return CountEntries() > GetMaximumEntries();
+}
+
 void StrikeDatabaseIntegratorBase::RemoveExpiredStrikes() {
-  if (!GetExpiryTimeMicros().has_value()) {
+  if (!GetExpiryTimeDelta().has_value()) {
     // Strikes don't expire.
     return;
   }
   std::vector<std::string> expired_keys;
   for (auto entry : strike_database_->strike_map_cache_) {
-    if (AutofillClock::Now().ToDeltaSinceWindowsEpoch().InMicroseconds() -
-            entry.second.last_update_timestamp() >
-        GetExpiryTimeMicros().value()) {
+    if (GetEntryAge(entry.second) > GetExpiryTimeDelta().value()) {
       if (strike_database_->GetStrikes(entry.first) > 0) {
         expired_keys.push_back(entry.first);
         base::UmaHistogramCounts1000(
@@ -102,8 +161,38 @@
   }
 }
 
-std::string StrikeDatabaseIntegratorBase::GetKey(const std::string& id) {
+void StrikeDatabaseIntegratorBase::ClearStrikesForKeys(
+    const std::vector<std::string>& keys) {
+  strike_database_->ClearStrikesForKeys(keys);
+}
+
+std::string StrikeDatabaseIntegratorBase::GetIdFromKey(
+    const std::string& key) const {
+  std::string prefix = GetProjectPrefix() + kKeyDeliminator;
+  if (!base::StartsWith(key, prefix)) {
+    return std::string();
+  }
+  return key.substr(prefix.length(), std::string::npos);
+}
+
+base::TimeDelta StrikeDatabaseIntegratorBase::GetEntryAge(
+    const StrikeData& strike_data) {
+  return AutofillClock::Now() - base::Time::FromDeltaSinceWindowsEpoch(
+                                    base::TimeDelta::FromMicroseconds(
+                                        strike_data.last_update_timestamp()));
+}
+
+std::string StrikeDatabaseIntegratorBase::GetKey(const std::string& id) const {
   return GetProjectPrefix() + kKeyDeliminator + id;
 }
 
+base::Optional<size_t> StrikeDatabaseIntegratorBase::GetMaximumEntries() const {
+  return base::nullopt;
+}
+
+base::Optional<size_t>
+StrikeDatabaseIntegratorBase::GetMaximumEntriesAfterCleanup() const {
+  return base::nullopt;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_base.h b/components/autofill/core/browser/strike_database_integrator_base.h
index db76b433..977006aa 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.h
+++ b/components/autofill/core/browser/strike_database_integrator_base.h
@@ -26,7 +26,7 @@
 
   // Returns whether or not strike count for |id| has reached the strike limit
   // set by GetMaxStrikesLimit().
-  bool IsMaxStrikesLimitReached(const std::string& id = kSharedId);
+  bool IsMaxStrikesLimitReached(const std::string& id = kSharedId) const;
 
   // Increments in-memory cache and updates underlying ProtoDatabase.
   int AddStrike(const std::string& id = kSharedId);
@@ -44,7 +44,7 @@
   int RemoveStrikes(int strikes_decrease, const std::string& id = kSharedId);
 
   // Returns strike count from in-memory cache.
-  int GetStrikes(const std::string& id = kSharedId);
+  int GetStrikes(const std::string& id = kSharedId) const;
 
   // Removes all database entries from in-memory cache and underlying
   // ProtoDatabase.
@@ -54,11 +54,37 @@
   // ProtoDatabase for the whole project.
   void ClearAllStrikes();
 
+  // Count strike entries for this project.
+  size_t CountEntries() const;
+
  protected:
+  // Runs a cleanup routine to remove the stored strike elements with the oldest
+  // update timestamps when `NumberOfEntriesExceedsLimits()`. The number of
+  // elements should be reduced to `GetMaximumEntriesAfterCleanup()`.
+  void LimitNumberOfStoredEntries();
+
+  // Returns true if the number of stored entries exceeds the limit.
+  bool NumberOfEntriesExceedsLimits() const;
+
   // Removes one strike for each key where it has been longer than
   // GetExpiryTimeMicros() since |last_update_timestamp|.
   void RemoveExpiredStrikes();
 
+  // Removes all database entries from in-memory cache and underlying
+  // ProtoDatabase for keys in `keys`.
+  void ClearStrikesForKeys(const std::vector<std::string>& keys);
+
+  // Get a readonly reference to the cache.
+  const std::map<std::string, StrikeData>& GetStrikeCache() const {
+    return strike_database_->strike_map_cache_;
+  }
+
+  // Returns the id the key was built from with `GetKey(id)`.
+  std::string GetIdFromKey(const std::string& key) const;
+
+  // Returns the age of a strike entry.
+  static base::TimeDelta GetEntryAge(const StrikeData& strike_data);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest,
                            StrikeDatabaseEmptyOnAutofillRemoveEverything);
@@ -72,6 +98,10 @@
                            RemoveExpiredStrikesUniqueIdTest);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
                            RemoveExpiredStrikesTestLogsUMA);
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+                           IdFromKey);
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+                           ClearStrikesForKeys);
   friend class SaveCardInfobarEGTestHelper;
   friend class StrikeDatabaseTest;
   friend class StrikeDatabaseTester;
@@ -83,28 +113,37 @@
   // unique IDs always specify |id| instead of relying on the default shared
   // value, while projects where unique IDs are unnecessary always fall back to
   // the default shared value.
-  void CheckIdUniqueness(std::string id) {
+  void CheckIdUniqueness(const std::string& id) const {
     DCHECK(UniqueIdsRequired() == (id != kSharedId));
   }
 
   // Generates key based on project-specific string identifier.
-  std::string GetKey(const std::string& id);
+  std::string GetKey(const std::string& id) const;
+
+  // Returns the maximum number of entries that should be stored for this
+  // project prefix. base::nullopt means that there is no limit.
+  virtual base::Optional<size_t> GetMaximumEntries() const;
+
+  // Returns the maximum number of entries that should remain after a cleanup.
+  // This number should be smaller then `GetMaximumEntries()` to create some
+  // headroom. base::nullopt means that `GetMaximumEntries()` should be used.
+  virtual base::Optional<size_t> GetMaximumEntriesAfterCleanup() const;
 
   // Returns a prefix unique to each project, which will be used to create
   // database key.
-  virtual std::string GetProjectPrefix() = 0;
+  virtual std::string GetProjectPrefix() const = 0;
 
   // Returns the maximum number of strikes after which the project's Autofill
   // opportunity stops being offered.
-  virtual int GetMaxStrikesLimit() = 0;
+  virtual int GetMaxStrikesLimit() const = 0;
 
-  // Returns the time after which the most recent strike should expire. If the
-  // Optional is empty, then strikes don't expire.
-  virtual base::Optional<int64_t> GetExpiryTimeMicros() = 0;
+  // Returns the time delta after which the most recent strike should expire.
+  // If the Optional is empty, then strikes don't expire.
+  virtual base::Optional<base::TimeDelta> GetExpiryTimeDelta() const = 0;
 
   // Returns whether or not a unique string identifier is required for every
   // strike in this project.
-  virtual bool UniqueIdsRequired() = 0;
+  virtual bool UniqueIdsRequired() const = 0;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
index c9bc6be..a08e786 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
@@ -14,9 +14,9 @@
 StrikeDatabaseIntegratorTestStrikeDatabase::
     StrikeDatabaseIntegratorTestStrikeDatabase(
         StrikeDatabase* strike_database,
-        base::Optional<int64_t> expiry_time_micros)
+        base::Optional<base::TimeDelta> expiry_time_delta)
     : StrikeDatabaseIntegratorTestStrikeDatabase(strike_database) {
-  expiry_time_micros_ = expiry_time_micros;
+  expiry_time_delta_ = expiry_time_delta;
 }
 
 StrikeDatabaseIntegratorTestStrikeDatabase::
@@ -26,22 +26,23 @@
 }
 
 StrikeDatabaseIntegratorTestStrikeDatabase::
-    ~StrikeDatabaseIntegratorTestStrikeDatabase() {}
+    ~StrikeDatabaseIntegratorTestStrikeDatabase() = default;
 
-std::string StrikeDatabaseIntegratorTestStrikeDatabase::GetProjectPrefix() {
+std::string StrikeDatabaseIntegratorTestStrikeDatabase::GetProjectPrefix()
+    const {
   return kProjectPrefix;
 }
 
-int StrikeDatabaseIntegratorTestStrikeDatabase::GetMaxStrikesLimit() {
+int StrikeDatabaseIntegratorTestStrikeDatabase::GetMaxStrikesLimit() const {
   return kMaxStrikesLimit;
 }
 
-base::Optional<int64_t>
-StrikeDatabaseIntegratorTestStrikeDatabase::GetExpiryTimeMicros() {
-  return expiry_time_micros_;
+base::Optional<base::TimeDelta>
+StrikeDatabaseIntegratorTestStrikeDatabase::GetExpiryTimeDelta() const {
+  return expiry_time_delta_;
 }
 
-bool StrikeDatabaseIntegratorTestStrikeDatabase::UniqueIdsRequired() {
+bool StrikeDatabaseIntegratorTestStrikeDatabase::UniqueIdsRequired() const {
   return unique_ids_required_;
 }
 
@@ -50,4 +51,14 @@
   unique_ids_required_ = unique_ids_required;
 }
 
+base::Optional<size_t>
+StrikeDatabaseIntegratorTestStrikeDatabase::GetMaximumEntries() const {
+  return maximum_entries_;
+}
+
+base::Optional<size_t>
+StrikeDatabaseIntegratorTestStrikeDatabase::GetMaximumEntriesAfterCleanup()
+    const {
+  return maximum_entries_after_cleanup_;
+}
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
index 2a44cad..dd48451 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
@@ -20,23 +20,28 @@
  public:
   StrikeDatabaseIntegratorTestStrikeDatabase(
       StrikeDatabase* strike_database,
-      base::Optional<int64_t> expiry_time_micros);
+      base::Optional<base::TimeDelta> expiry_time_delta);
   explicit StrikeDatabaseIntegratorTestStrikeDatabase(
       StrikeDatabase* strike_database);
   ~StrikeDatabaseIntegratorTestStrikeDatabase() override;
 
-  std::string GetProjectPrefix() override;
-  int GetMaxStrikesLimit() override;
-  base::Optional<int64_t> GetExpiryTimeMicros() override;
-  bool UniqueIdsRequired() override;
+  base::Optional<size_t> GetMaximumEntries() const override;
+  base::Optional<size_t> GetMaximumEntriesAfterCleanup() const override;
+
+  std::string GetProjectPrefix() const override;
+  int GetMaxStrikesLimit() const override;
+  base::Optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+  bool UniqueIdsRequired() const override;
 
   void SetUniqueIdsRequired(bool unique_ids_required);
 
  private:
   bool unique_ids_required_ = false;
-  base::Optional<int64_t> expiry_time_micros_ =
-      static_cast<int64_t>(1000000) * 60 * 60 * 24 *
-      365;  // Default expiry time is 1 year.
+  base::Optional<base::TimeDelta> expiry_time_delta_ =
+      base::TimeDelta::FromDays(365);
+
+  base::Optional<size_t> maximum_entries_ = 10;
+  base::Optional<size_t> maximum_entries_after_cleanup_ = 5;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
index a56f448..64dc94c3 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -141,8 +142,8 @@
   EXPECT_EQ(2, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   // One strike should be removed.
   strike_database_->RemoveExpiredStrikes();
@@ -153,8 +154,8 @@
   EXPECT_EQ(11, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   // Strike count should be one less than the max limit.
   strike_database_->RemoveExpiredStrikes();
@@ -169,8 +170,8 @@
   EXPECT_EQ(2, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   // One strike should be removed.
   strike_database_->RemoveExpiredStrikes();
@@ -181,8 +182,8 @@
   EXPECT_EQ(11, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   // Strike count should be one less than the max limit.
   strike_database_->RemoveExpiredStrikes();
@@ -303,8 +304,8 @@
   strike_database_->AddStrike(unique_id_1);
 
   // Advance clock to past the entry for |unique_id_1|'s expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   strike_database_->AddStrike(unique_id_2);
   strike_database_->RemoveExpiredStrikes();
@@ -315,8 +316,8 @@
   EXPECT_EQ(1, strike_database_->GetStrikes(unique_id_2));
 
   // Advance clock to past |unique_id_2|'s expiry time.
-  test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_->GetExpiryTimeMicros().value() + 1));
+  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
+                     base::TimeDelta::FromMicroseconds(1));
 
   strike_database_->RemoveExpiredStrikes();
 
@@ -325,4 +326,73 @@
   EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_2));
 }
 
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest, CountEntries) {
+  strike_database_->SetUniqueIdsRequired(true);
+  const std::string unique_id_1 = "111";
+  const std::string unique_id_2 = "222";
+  const std::string unique_id_3 = "333";
+
+  EXPECT_EQ(0U, strike_database_->CountEntries());
+  strike_database_->AddStrike(unique_id_1);
+  EXPECT_EQ(1U, strike_database_->CountEntries());
+  strike_database_->AddStrike(unique_id_1);
+  EXPECT_EQ(1U, strike_database_->CountEntries());
+
+  strike_database_->AddStrike(unique_id_2);
+  strike_database_->AddStrike(unique_id_3);
+  EXPECT_EQ(3U, strike_database_->CountEntries());
+}
+
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest, ClearStrikesForKeys) {
+  strike_database_->SetUniqueIdsRequired(true);
+  const std::string unique_id_1 = "111";
+  const std::string unique_id_2 = "222";
+  const std::string unique_id_3 = "333";
+
+  strike_database_->AddStrike(unique_id_1);
+  strike_database_->AddStrike(unique_id_2);
+  strike_database_->AddStrike(unique_id_3);
+  EXPECT_EQ(3U, strike_database_->CountEntries());
+
+  std::vector<std::string> keys_to_clear = {
+      strike_database_->GetKey(unique_id_1),
+      strike_database_->GetKey(unique_id_2)};
+  strike_database_->ClearStrikesForKeys(keys_to_clear);
+
+  EXPECT_EQ(1U, strike_database_->CountEntries());
+
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_1));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_2));
+  EXPECT_EQ(1, strike_database_->GetStrikes(unique_id_3));
+}
+
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest, IdFromKey) {
+  strike_database_->SetUniqueIdsRequired(true);
+  const std::string unique_id = "111";
+  std::string key = strike_database_->GetKey(unique_id);
+  ASSERT_EQ(key, "StrikeDatabaseIntegratorTest__111");
+  EXPECT_EQ(unique_id, strike_database_->GetIdFromKey(key));
+}
+
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+       LimitTheNumberOfElements) {
+  strike_database_->SetUniqueIdsRequired(true);
+  for (size_t i = 1; i <= 10; i++) {
+    strike_database_->AddStrike(base::NumberToString(i));
+    EXPECT_EQ(i, strike_database_->CountEntries());
+  }
+  // Once the 11th element is added the cleanup should reduce the number of
+  // elements to 5. Note that the index here is chosen to be smaller than the
+  // previous indices. The purpose is to ensure that the deletion is actually
+  // done in the order of time stamp and not index.
+  strike_database_->AddStrike(base::NumberToString(0));
+  EXPECT_EQ(5U, strike_database_->CountEntries());
+
+  // Verify that the oldest 6 elements have been deleted.
+  for (size_t i = 1; i <= 10; i++) {
+    EXPECT_EQ(i <= 6 ? 0 : 1,
+              strike_database_->GetStrikes(base::NumberToString(i)));
+  }
+}
+
 }  // namespace autofill
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc b/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
index 2081b585..1238dbc 100644
--- a/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
+++ b/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/selector.h"
 #include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/web/element_store.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -85,6 +86,7 @@
   std::unique_ptr<content::WebContents> web_contents_;
   MockActionDelegate mock_action_delegate_;
   UserData user_data_;
+  UserModel user_model_;
   MockWebsiteLoginManager mock_website_login_manager_;
 };
 
@@ -317,7 +319,8 @@
                                                   autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(contact.get(), "John", /* middle name */ "",
                                  "Doe", "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] = std::move(contact);
+  user_model_.SetSelectedAutofillProfile("contact", std::move(contact),
+                                         &user_data_);
 
   TextValue text_value;
   auto* autofill_value = text_value.mutable_autofill_value();
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index 84ed3718..f541f93 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -606,7 +606,8 @@
   }
   for (const auto& profile_name :
        proto_.collect_user_data().clear_previous_profile_selection()) {
-    user_data->selected_addresses_.erase(profile_name);
+    delegate_->GetUserModel()->SetSelectedAutofillProfile(
+        profile_name, /* profile= */ nullptr, user_data);
   }
 
   // Add available profiles and start listening.
@@ -1279,11 +1280,9 @@
   }
 
   if (!found_profile && selected_profile != nullptr) {
-    auto it = user_data->selected_addresses_.find(
-        collect_user_data_options_->contact_details_name);
-    if (it != user_data->selected_addresses_.end()) {
-      user_data->selected_addresses_.erase(it);
-    }
+    delegate_->GetUserModel()->SetSelectedAutofillProfile(
+        collect_user_data_options_->contact_details_name,
+        /* profile= */ nullptr, user_data);
   }
 
   if (!user_data->has_selected_address(
@@ -1294,19 +1293,18 @@
     int default_selection = GetDefaultContactProfile(
         *collect_user_data_options_, user_data->available_profiles_);
     if (default_selection != -1) {
-      user_data->selected_addresses_.emplace(
+      delegate_->GetUserModel()->SetSelectedAutofillProfile(
           collect_user_data_options_->contact_details_name,
           MakeUniqueFromProfile(
-              *(user_data->available_profiles_[default_selection])));
+              *(user_data->available_profiles_[default_selection])),
+          user_data);
     }
   }
 
   if (!found_shipping_address && shipping_address != nullptr) {
-    auto it = user_data->selected_addresses_.find(
-        collect_user_data_options_->shipping_address_name);
-    if (it != user_data->selected_addresses_.end()) {
-      user_data->selected_addresses_.erase(it);
-    }
+    delegate_->GetUserModel()->SetSelectedAutofillProfile(
+        collect_user_data_options_->shipping_address_name,
+        /* profile= */ nullptr, user_data);
   }
   if (!user_data->has_selected_address(
           collect_user_data_options_->shipping_address_name) &&
@@ -1314,10 +1312,11 @@
     int default_selection = GetDefaultAddressProfile(
         *collect_user_data_options_, user_data->available_profiles_);
     if (default_selection != -1) {
-      user_data->selected_addresses_.emplace(
+      delegate_->GetUserModel()->SetSelectedAutofillProfile(
           collect_user_data_options_->shipping_address_name,
           MakeUniqueFromProfile(
-              *(user_data->available_profiles_[default_selection])));
+              *(user_data->available_profiles_[default_selection])),
+          user_data);
     }
   }
 
@@ -1367,11 +1366,9 @@
 
   if (!found_card) {
     user_data->selected_card_.reset();
-    auto it = user_data->selected_addresses_.find(
-        collect_user_data_options_->billing_address_name);
-    if (it != user_data->selected_addresses_.end()) {
-      user_data->selected_addresses_.erase(it);
-    }
+    delegate_->GetUserModel()->SetSelectedAutofillProfile(
+        collect_user_data_options_->billing_address_name,
+        /* profile= */ nullptr, user_data);
   }
   if (user_data->selected_card_ == nullptr &&
       collect_user_data_options_->request_payment_method) {
@@ -1383,10 +1380,11 @@
       user_data->selected_card_ = std::make_unique<autofill::CreditCard>(
           *(default_payment_instrument->card));
       if (default_payment_instrument->billing_address != nullptr) {
-        user_data->selected_addresses_.emplace(
+        delegate_->GetUserModel()->SetSelectedAutofillProfile(
             collect_user_data_options_->billing_address_name,
             std::make_unique<autofill::AutofillProfile>(
-                *(default_payment_instrument->billing_address)));
+                *(default_payment_instrument->billing_address)),
+            user_data);
       }
     }
   }
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index e57bc649..bfe4f234 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/autofill_assistant/browser/mock_personal_data_manager.h"
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/test_util.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
 #include "components/autofill_assistant/browser/user_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/test/browser_task_environment.h"
@@ -50,6 +51,7 @@
 using ::testing::Eq;
 using ::testing::Invoke;
 using ::testing::IsSupersetOf;
+using ::testing::NotNull;
 using ::testing::Property;
 using ::testing::Return;
 using ::testing::SizeIs;
@@ -70,6 +72,8 @@
         .WillByDefault(Return(&mock_website_login_manager_));
     ON_CALL(mock_action_delegate_, GetUserData)
         .WillByDefault(Return(&user_data_));
+    ON_CALL(mock_action_delegate_, GetUserModel)
+        .WillByDefault(Return(&user_model_));
     ON_CALL(mock_action_delegate_, WriteUserData(_))
         .WillByDefault(Invoke(
             [this](base::OnceCallback<void(UserData*, UserData::FieldChange*)>
@@ -93,6 +97,20 @@
         .WillByDefault(Return(web_contents_.get()));
   }
 
+  void ExpectSelectedProfileMatches(const std::string& profile_name,
+                                    const autofill::AutofillProfile* profile) {
+    if (profile == nullptr) {
+      EXPECT_EQ(user_data_.selected_address(profile_name), nullptr);
+      EXPECT_EQ(user_model_.GetSelectedAutofillProfile(profile_name), nullptr);
+      return;
+    }
+
+    EXPECT_EQ(user_data_.selected_address(profile_name)->Compare(*profile), 0);
+    EXPECT_EQ(
+        user_model_.GetSelectedAutofillProfile(profile_name)->Compare(*profile),
+        0);
+  }
+
  protected:
   content::BrowserTaskEnvironment task_environment_;
   content::RenderViewHostTestEnabler rvh_test_enabler_;
@@ -612,8 +630,10 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            user_data_.selected_addresses_[kMemoryLocation] =
-                std::make_unique<autofill::AutofillProfile>(contact_profile);
+            user_model_.SetSelectedAutofillProfile(
+                kMemoryLocation,
+                std::make_unique<autofill::AutofillProfile>(contact_profile),
+                &user_data_);
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, &user_model_);
           }));
@@ -745,8 +765,10 @@
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
             user_data_.selected_card_ =
                 std::make_unique<autofill::CreditCard>(credit_card);
-            user_data_.selected_addresses_["billing_address"] =
-                std::make_unique<autofill::AutofillProfile>(billing_profile);
+            user_model_.SetSelectedAutofillProfile(
+                "billing_address",
+                std::make_unique<autofill::AutofillProfile>(billing_profile),
+                &user_data_);
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, &user_model_);
           }));
@@ -792,8 +814,10 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            user_data_.selected_addresses_[kMemoryLocation] =
-                std::make_unique<autofill::AutofillProfile>(shipping_address);
+            user_model_.SetSelectedAutofillProfile(
+                kMemoryLocation,
+                std::make_unique<autofill::AutofillProfile>(shipping_address),
+                &user_data_);
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, &user_model_);
           }));
@@ -819,9 +843,9 @@
   action.ProcessAction(callback_.Get());
 
   EXPECT_TRUE(user_data_.has_selected_address(kMemoryLocation));
-  EXPECT_EQ(user_data_.selected_addresses_[kMemoryLocation]->Compare(
-                shipping_address),
-            0);
+  EXPECT_EQ(
+      user_data_.selected_address(kMemoryLocation)->Compare(shipping_address),
+      0);
 }
 
 TEST_F(CollectUserDataActionTest, MandatoryPostalCodeWithoutErrorMessageFails) {
@@ -859,8 +883,10 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            user_data_.selected_addresses_[kMemoryLocation] =
-                std::make_unique<autofill::AutofillProfile>(contact_profile);
+            user_model_.SetSelectedAutofillProfile(
+                kMemoryLocation,
+                std::make_unique<autofill::AutofillProfile>(contact_profile),
+                &user_data_);
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, &user_model_);
           }));
@@ -892,15 +918,20 @@
                                                         options));
 
   options.contact_details_name = "profile";
-  user_data.selected_addresses_["profile"] =
-      std::make_unique<autofill::AutofillProfile>(base::GenerateGUID(),
-                                                  kFakeUrl);
+  autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
+
   options.request_payer_email = true;
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["profile"]->SetRawInfo(
-      autofill::ServerFieldType::EMAIL_ADDRESS, u"joedoe@example.com");
+  profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
+                     u"joedoe@example.com");
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 
@@ -908,8 +939,10 @@
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["profile"]->SetRawInfo(
-      autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
+  profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 
@@ -917,8 +950,11 @@
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["profile"]->SetRawInfo(
-      autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER, u"+1 23 456 789 01");
+  profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+                     u"+1 23 456 789 01");
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 }
@@ -943,29 +979,37 @@
                                                          options));
 
   // Incomplete billing address.
-  user_data.selected_addresses_["billing_address"] =
-      std::make_unique<autofill::AutofillProfile>(base::GenerateGUID(),
-                                                  kFakeUrl);
-  autofill::test::SetProfileInfo(
-      user_data.selected_addresses_["billing_address"].get(), "Marion",
-      "Mitchell", "Morrison", "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
-      "Hollywood", "CA",
-      /* zipcode = */ "", "US", "16505678910");
+  autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
+
+  autofill::test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+                                 "marion@me.xyz", "Fox", "123 Zoo St.",
+                                 "unit 5", "Hollywood", "CA",
+                                 /* zipcode = */ "", "US", "16505678910");
+
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   user_data.selected_card_->set_billing_address_id(
-      user_data.selected_addresses_["billing_address"]->guid());
+      user_data.selected_address("billing_address")->guid());
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["billing_address"]->SetRawInfo(
-      autofill::ADDRESS_HOME_ZIP, u"91601");
+  profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, u"91601");
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 
   // Zip code is optional in Argentinian address.
-  user_data.selected_addresses_["billing_address"]->SetRawInfo(
-      autofill::ADDRESS_HOME_ZIP, u"");
-  user_data.selected_addresses_["billing_address"]->SetRawInfo(
-      autofill::ADDRESS_HOME_COUNTRY, u"AR");
+  profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, u"");
+  profile.SetRawInfo(autofill::ADDRESS_HOME_COUNTRY, u"AR");
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 
@@ -973,8 +1017,10 @@
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["billing_address"]->SetRawInfo(
-      autofill::ADDRESS_HOME_ZIP, u"B1675");
+  profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, u"B1675");
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 
@@ -1024,19 +1070,24 @@
                                                          options));
 
   // Incomplete address.
-  user_data.selected_addresses_["shipping_address"] =
-      std::make_unique<autofill::AutofillProfile>(base::GenerateGUID(),
-                                                  kFakeUrl);
-  autofill::test::SetProfileInfo(
-      user_data.selected_addresses_["shipping_address"].get(), "Marion",
-      "Mitchell", "Morrison", "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
-      "Hollywood", "CA",
-      /* zipcode = */ "", "US", "16505678910");
+  autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
+  autofill::test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+                                 "marion@me.xyz", "Fox", "123 Zoo St.",
+                                 "unit 5", "Hollywood", "CA",
+                                 /* zipcode = */ "", "US", "16505678910");
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
-  user_data.selected_addresses_["shipping_address"]->SetRawInfo(
-      autofill::ADDRESS_HOME_ZIP, u"91601");
+  profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, u"91601");
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
   EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                         options));
 }
@@ -1473,21 +1524,22 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([this](CollectUserDataOptions* collect_user_data_options) {
-            user_data_.selected_addresses_["billing_address"] =
-                std::make_unique<autofill::AutofillProfile>(
-                    base::GenerateGUID(), kFakeUrl);
-            autofill::test::SetProfileInfo(
-                user_data_.selected_addresses_["billing_address"].get(),
-                "Marion", "Mitchell", "Morrison", "marion@me.xyz", "Fox",
-                "123 Zoo St.", "unit 5", "Hollywood", "CA", "96043", "US",
-                "16505678910");
+            autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+            autofill::test::SetProfileInfo(&profile, "Marion", "Mitchell",
+                                           "Morrison", "marion@me.xyz", "Fox",
+                                           "123 Zoo St.", "unit 5", "Hollywood",
+                                           "CA", "96043", "US", "16505678910");
+            user_model_.SetSelectedAutofillProfile(
+                "billing_address",
+                std::make_unique<autofill::AutofillProfile>(profile),
+                &user_data_);
 
             user_data_.selected_card_ = std::make_unique<autofill::CreditCard>(
                 base::GenerateGUID(), kFakeUrl);
             autofill::test::SetCreditCardInfo(
                 user_data_.selected_card_.get(), "Marion Mitchell",
                 "4111 1111 1111 1111", "01", "2050",
-                user_data_.selected_addresses_["billing_address"]->guid());
+                user_data_.selected_address("billing_address")->guid());
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, &user_model_);
@@ -1587,8 +1639,10 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            user_data_.selected_addresses_[kMemoryLocation] =
-                std::make_unique<autofill::AutofillProfile>(profile);
+            user_model_.SetSelectedAutofillProfile(
+                kMemoryLocation,
+                std::make_unique<autofill::AutofillProfile>(profile),
+                &user_data_);
 
             EXPECT_THAT(user_data_.available_profiles_, SizeIs(1));
             EXPECT_EQ(user_data_.available_profiles_[0]->Compare(profile), 0);
@@ -1627,12 +1681,8 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            EXPECT_EQ(
-                user_data_.selected_addresses_["profile"]->Compare(profile), 0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["shipping-address"]->Compare(
-                    profile),
-                0);
+            ExpectSelectedProfileMatches("profile", &profile);
+            ExpectSelectedProfileMatches("shipping-address", &profile);
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, nullptr);
@@ -1750,9 +1800,7 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            EXPECT_EQ(
-                user_data_.selected_addresses_["profile"]->Compare(profile_b),
-                0);
+            ExpectSelectedProfileMatches("profile", &profile_b);
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, nullptr);
@@ -1792,12 +1840,8 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            EXPECT_EQ(
-                user_data_.selected_addresses_["profile"]->Compare(profile), 0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["shipping_address"]->Compare(
-                    profile),
-                0);
+            ExpectSelectedProfileMatches("profile", &profile);
+            ExpectSelectedProfileMatches("shipping_address", &profile);
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, nullptr);
@@ -1812,10 +1856,12 @@
   contact_details->set_contact_details_name("profile");
 
   // Set previous user data.
-  user_data_.selected_addresses_["profile"] =
-      std::make_unique<autofill::AutofillProfile>(profile);
-  user_data_.selected_addresses_["shipping_address"] =
-      std::make_unique<autofill::AutofillProfile>(profile);
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data_);
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data_);
 
   EXPECT_CALL(
       callback_,
@@ -1840,11 +1886,8 @@
   ON_CALL(mock_action_delegate_, CollectUserData(_))
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
-            EXPECT_EQ(user_data_.selected_addresses_["profile"], nullptr);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["shipping_address"]->Compare(
-                    profile),
-                0);
+            ExpectSelectedProfileMatches("profile", nullptr);
+            ExpectSelectedProfileMatches("shipping_address", &profile);
 
             // Do not call the callback. We're only interested in the state.
           }));
@@ -1863,10 +1906,13 @@
                                  "berta.west@gmail.com", "", "", "", "", "", "",
                                  "", "");
 
-  user_data_.selected_addresses_["profile"] =
-      std::make_unique<autofill::AutofillProfile>(selected_profile);
-  user_data_.selected_addresses_["shipping_address"] =
-      std::make_unique<autofill::AutofillProfile>(selected_profile);
+  user_model_.SetSelectedAutofillProfile(
+      "profile", std::make_unique<autofill::AutofillProfile>(selected_profile),
+      &user_data_);
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address",
+      std::make_unique<autofill::AutofillProfile>(selected_profile),
+      &user_data_);
 
   CollectUserDataAction action(&mock_action_delegate_, action_proto);
   action.ProcessAction(callback_.Get());
@@ -2032,10 +2078,7 @@
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
             EXPECT_EQ(user_data_.selected_card_->Compare(card_with_address), 0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["billing_address"]->Compare(
-                    billing_address),
-                0);
+            ExpectSelectedProfileMatches("billing_address", &billing_address);
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, nullptr);
@@ -2082,10 +2125,7 @@
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
             EXPECT_EQ(user_data_.selected_card_->Compare(card_with_address), 0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["billing_address"]->Compare(
-                    billing_address),
-                0);
+            ExpectSelectedProfileMatches("billing_address", &billing_address);
 
             std::move(collect_user_data_options->confirm_callback)
                 .Run(&user_data_, nullptr);
@@ -2100,8 +2140,11 @@
   // Set previous user data.
   user_data_.selected_card_ =
       std::make_unique<autofill::CreditCard>(card_with_address);
-  user_data_.selected_addresses_["billing_address"] =
-      std::make_unique<autofill::AutofillProfile>(billing_address);
+
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address",
+      std::make_unique<autofill::AutofillProfile>(billing_address),
+      &user_data_);
 
   EXPECT_CALL(
       callback_,
@@ -2137,8 +2180,7 @@
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
             EXPECT_EQ(user_data_.selected_card_, nullptr);
-            EXPECT_EQ(user_data_.selected_addresses_["billing_address"],
-                      nullptr);
+            ExpectSelectedProfileMatches("billing_address", nullptr);
 
             // Do not call the callback. We're only interested in the state.
           }));
@@ -2161,8 +2203,10 @@
 
   user_data_.selected_card_ =
       std::make_unique<autofill::CreditCard>(selected_card);
-  user_data_.selected_addresses_["billing_address"] =
-      std::make_unique<autofill::AutofillProfile>(selected_address);
+  user_model_.SetSelectedAutofillProfile(
+      "billing_address",
+      std::make_unique<autofill::AutofillProfile>(selected_address),
+      &user_data_);
 
   CollectUserDataAction action(&mock_action_delegate_, action_proto);
   action.ProcessAction(callback_.Get());
@@ -2281,15 +2325,9 @@
       .WillByDefault(
           Invoke([=](CollectUserDataOptions* collect_user_data_options) {
             EXPECT_EQ(user_data_.selected_card_->Compare(card_a), 0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["billing"]->Compare(address_a),
-                0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["contact"]->Compare(address_a),
-                0);
-            EXPECT_EQ(
-                user_data_.selected_addresses_["shipping"]->Compare(address_a),
-                0);
+            ExpectSelectedProfileMatches("billing", &address_a);
+            ExpectSelectedProfileMatches("contact", &address_a);
+            ExpectSelectedProfileMatches("shipping", &address_a);
             EXPECT_EQ(user_data_.selected_login_, base::nullopt);
 
             // Do not call the callback. We're only interested in the state.
@@ -2314,12 +2352,15 @@
   // Set previous user data to the second card/profile. If clear works
   // correctly, the action should default to the first card/profile.
   user_data_.selected_card_ = std::make_unique<autofill::CreditCard>(card_b);
-  user_data_.selected_addresses_["billing"] =
-      std::make_unique<autofill::AutofillProfile>(address_b);
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(address_b);
-  user_data_.selected_addresses_["shipping"] =
-      std::make_unique<autofill::AutofillProfile>(address_b);
+  user_model_.SetSelectedAutofillProfile(
+      "billing", std::make_unique<autofill::AutofillProfile>(address_b),
+      &user_data_);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(address_b),
+      &user_data_);
+  user_model_.SetSelectedAutofillProfile(
+      "shipping", std::make_unique<autofill::AutofillProfile>(address_b),
+      &user_data_);
   user_data_.selected_login_ =
       WebsiteLoginManager::Login(GURL("http://www.example.com"), "username");
 
diff --git a/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc b/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
index a330171e..ea92301 100644
--- a/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/selector.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -81,6 +82,7 @@
   base::MockCallback<Action::ProcessActionCallback> callback_;
   GetElementStatusProto proto_;
   UserData user_data_;
+  UserModel user_model_;
   MockWebsiteLoginManager mock_website_login_manager_;
 };
 
@@ -597,8 +599,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   AutofillValue autofill_value;
   autofill_value.mutable_profile()->set_identifier("contact");
diff --git a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
index a8a2a4f..217454c 100644
--- a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/selector.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -56,6 +57,7 @@
   base::MockCallback<Action::ProcessActionCallback> callback_;
   SelectOptionProto proto_;
   UserData user_data_;
+  UserModel user_model_;
 };
 
 TEST_F(SelectOptionActionTest, NoValueToSelectFails) {
@@ -148,8 +150,10 @@
   // Middle name is expected to be empty.
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   Selector selector({"#select"});
   *proto_.mutable_element() = selector.proto;
@@ -171,8 +175,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
                                  "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   InSequence sequence;
 
@@ -235,8 +240,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
                                  "", "", "", "", "+41791234567");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   InSequence sequence;
 
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
index 99dbe2b..400c4e5 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/autofill_assistant/browser/client_status.h"
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/string_conversions_util.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -107,6 +108,7 @@
   ActionProto proto_;
   SetFormFieldValueProto* set_form_field_proto_;
   UserData user_data_;
+  UserModel user_model_;
 };
 
 TEST_F(SetFormFieldValueActionTest, RequestedUsernameButNoLoginInClientMemory) {
@@ -721,8 +723,9 @@
   // Middle name is expected to be empty.
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
   value->mutable_profile()->set_identifier("contact");
@@ -743,8 +746,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
                                  "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
   value->mutable_profile()->set_identifier("contact");
diff --git a/components/autofill_assistant/browser/actions/show_details_action_unittest.cc b/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
index dfb40e0..aeff7fe 100644
--- a/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
@@ -11,6 +11,7 @@
 #include "components/autofill/core/browser/geo/country_names.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
@@ -57,6 +58,7 @@
   }
 
   UserData user_data_;
+  UserModel user_model_;
   CollectUserDataOptions user_data_options_;
   MockActionDelegate mock_action_delegate_;
   base::MockCallback<Action::ProcessActionCallback> callback_;
@@ -83,7 +85,8 @@
 
 TEST_F(ShowDetailsActionTest, ContactDetailsCase) {
   proto_.set_contact_details("contact");
-  user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("contact", MakeAutofillProfile(),
+                                         &user_data_);
   user_data_options_.request_payer_name = true;
 
   EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
@@ -95,7 +98,8 @@
 
 TEST_F(ShowDetailsActionTest, ShippingAddressCase) {
   proto_.set_shipping_address("shipping");
-  user_data_.selected_addresses_["shipping"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("shipping", MakeAutofillProfile(),
+                                         &user_data_);
 
   EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
diff --git a/components/autofill_assistant/browser/actions/use_address_action_unittest.cc b/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
index af351ee..1e1b10ec 100644
--- a/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
@@ -50,8 +50,9 @@
     autofill::test::SetProfileInfo(&profile_, kFirstName, "", kLastName, kEmail,
                                    "", "", "", "", "", "", "", kPhoneNumber);
     // Store copies of |profile_| in |user_data_| and |user_model_|.
-    user_data_.selected_addresses_[kAddressName] =
-        std::make_unique<autofill::AutofillProfile>(profile_);
+    user_model_.SetSelectedAutofillProfile(
+        kAddressName, std::make_unique<autofill::AutofillProfile>(profile_),
+        &user_data_);
     auto profiles = std::make_unique<
         std::vector<std::unique_ptr<autofill::AutofillProfile>>>();
     profiles->emplace_back(
@@ -217,8 +218,12 @@
   InSequence seq;
 
   ActionProto action_proto = CreateUseAddressAction();
-  user_data_.selected_addresses_[kAddressName] = nullptr;
-  user_data_.selected_addresses_["one_more"] = nullptr;
+  user_model_.SetSelectedAutofillProfile(kAddressName, nullptr, &user_data_);
+  user_model_.SetSelectedAutofillProfile(
+      "one_more",
+      std::make_unique<autofill::AutofillProfile>(base::GenerateGUID(),
+                                                  "www.example.com"),
+      &user_data_);
 
   UseAddressAction action(&mock_action_delegate_, action_proto);
 
@@ -230,8 +235,7 @@
             processed_action.status());
   const auto& error_info =
       processed_action.status_details().autofill_error_info();
-  EXPECT_EQ(base::JoinString({kAddressName, "one_more"}, ","),
-            error_info.client_memory_address_key_names());
+  EXPECT_EQ("one_more", error_info.client_memory_address_key_names());
   EXPECT_EQ(kAddressName, error_info.address_key_requested());
   EXPECT_TRUE(error_info.address_pointee_was_null());
 }
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index d16d9d1..3016dbef 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -23,6 +23,7 @@
 #include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/url_utils.h"
 #include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
 #include "components/autofill_assistant/browser/view_layout.pb.h"
 #include "components/autofill_assistant/browser/web/element_store.h"
 #include "components/google/core/common/google_util.h"
@@ -1588,13 +1589,8 @@
     return;
   }
 
-  auto it = user_data_->selected_addresses_.find(key);
-  if (it != user_data_->selected_addresses_.end()) {
-    user_data_->selected_addresses_.erase(it);
-  }
-  if (profile != nullptr) {
-    user_data_->selected_addresses_.emplace(key, std::move(profile));
-  }
+  user_model_.SetSelectedAutofillProfile(key, std::move(profile),
+                                         user_data_.get());
 
   for (ControllerObserver& observer : observers_) {
     observer.OnUserDataChanged(user_data_.get(), field_change);
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 3bdc1976..3d41b80 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -2089,8 +2089,9 @@
       std::make_unique<autofill::CreditCard>(*credit_card),
       std::make_unique<autofill::AutofillProfile>(*billing_address));
   EXPECT_THAT(GetUserData()->selected_card_->Compare(*credit_card), Eq(0));
-  EXPECT_THAT(GetUserData()->selected_addresses_["billing_address"]->Compare(
-                  *billing_address),
+  EXPECT_THAT(GetUserData()
+                  ->selected_address("billing_address")
+                  ->Compare(*billing_address),
               Eq(0));
 }
 
@@ -2130,11 +2131,11 @@
                                   Property(&UserAction::enabled, Eq(false)))))
       .Times(1);
   // Can be called by a PDM update.
-  controller_->WriteUserData(base::BindOnce(
-      [](UserData* user_data, UserData::FieldChange* field_change) {
-        auto it = user_data->selected_addresses_.find("selected_profile");
-        if (it != user_data->selected_addresses_.end()) {
-          user_data->selected_addresses_.erase(it);
+  controller_->WriteUserData(base::BindLambdaForTesting(
+      [this](UserData* user_data, UserData::FieldChange* field_change) {
+        if (user_data->has_selected_address("selected_profile")) {
+          controller_->GetUserModel()->SetSelectedAutofillProfile(
+              "selected_profile", nullptr, user_data);
           *field_change = UserData::FieldChange::CONTACT_PROFILE;
         }
       }));
@@ -2213,8 +2214,9 @@
       .Times(1);
   controller_->SetShippingAddress(
       std::make_unique<autofill::AutofillProfile>(*shipping_address));
-  EXPECT_THAT(GetUserData()->selected_addresses_["shipping_address"]->Compare(
-                  *shipping_address),
+  EXPECT_THAT(GetUserData()
+                  ->selected_address("shipping_address")
+                  ->Compare(*shipping_address),
               Eq(0));
 }
 
diff --git a/components/autofill_assistant/browser/details_unittest.cc b/components/autofill_assistant/browser/details_unittest.cc
index a0d1e0641..2b369d4a 100644
--- a/components/autofill_assistant/browser/details_unittest.cc
+++ b/components/autofill_assistant/browser/details_unittest.cc
@@ -11,6 +11,7 @@
 #include "components/autofill_assistant/browser/details.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -59,6 +60,7 @@
   }
 
   UserData user_data_;
+  UserModel user_model_;
   CollectUserDataOptions user_data_options_;
 };
 
@@ -140,7 +142,8 @@
 TEST_F(DetailsTest, UpdateFromContactDetailsNoContactInfoRequested) {
   ShowDetailsProto proto;
   proto.set_contact_details("contact");
-  user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("contact", MakeAutofillProfile(),
+                                         &user_data_);
   user_data_options_.request_payer_name = false;
   user_data_options_.request_payer_email = false;
   EXPECT_FALSE(Details::UpdateFromContactDetails(proto, &user_data_,
@@ -150,7 +153,8 @@
 TEST_F(DetailsTest, UpdateFromContactDetails) {
   ShowDetailsProto proto;
   proto.set_contact_details("contact");
-  user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("contact", MakeAutofillProfile(),
+                                         &user_data_);
   user_data_options_.request_payer_name = true;
   user_data_options_.request_payer_email = true;
 
@@ -167,7 +171,8 @@
 TEST_F(DetailsTest, UpdateFromContactOnlyName) {
   ShowDetailsProto proto;
   proto.set_contact_details("contact");
-  user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("contact", MakeAutofillProfile(),
+                                         &user_data_);
   user_data_options_.request_payer_name = true;
   user_data_options_.request_payer_email = false;
 
@@ -184,7 +189,8 @@
 TEST_F(DetailsTest, UpdateFromContactOnlyEmail) {
   ShowDetailsProto proto;
   proto.set_contact_details("contact");
-  user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("contact", MakeAutofillProfile(),
+                                         &user_data_);
   user_data_options_.request_payer_name = false;
   user_data_options_.request_payer_email = true;
 
@@ -206,7 +212,8 @@
 TEST_F(DetailsTest, UpdateFromShippingAddress) {
   ShowDetailsProto proto;
   proto.set_shipping_address("shipping");
-  user_data_.selected_addresses_["shipping"] = MakeAutofillProfile();
+  user_model_.SetSelectedAutofillProfile("shipping", MakeAutofillProfile(),
+                                         &user_data_);
 
   Details details;
   EXPECT_TRUE(Details::UpdateFromShippingAddress(proto, &user_data_, &details));
diff --git a/components/autofill_assistant/browser/features.cc b/components/autofill_assistant/browser/features.cc
index 8ab1acd..7059aac 100644
--- a/components/autofill_assistant/browser/features.cc
+++ b/components/autofill_assistant/browser/features.cc
@@ -36,10 +36,15 @@
     "AutofillAssistantDisableProactiveHelpTiedToMSBB",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Whether Autofill Assistant should enable in-Chrome triggering, i.e., without
-// requiring first party trigger surfaces.
-const base::Feature kAutofillAssistantInChromeTriggering{
-    "AutofillAssistantInChromeTriggering", base::FEATURE_DISABLED_BY_DEFAULT};
+// Whether Autofill Assistant should enable in-CCT triggering, i.e., requesting
+// and showing trigger scripts in CCTs without explicit user request.
+const base::Feature kAutofillAssistantInCCTTriggering{
+    "AutofillAssistantInCctTriggering", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Whether Autofill Assistant should enable in-tab triggering, i.e., requesting
+// and showing trigger scripts in regular tabs without explicit user request.
+const base::Feature kAutofillAssistantInTabTriggering{
+    "AutofillAssistantInTabTriggering", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Controls whether to show the "Send feedback" chip while in an error state.
 const base::Feature kAutofillAssistantFeedbackChip{
diff --git a/components/autofill_assistant/browser/features.h b/components/autofill_assistant/browser/features.h
index aaf8c82..7a92f27 100644
--- a/components/autofill_assistant/browser/features.h
+++ b/components/autofill_assistant/browser/features.h
@@ -19,7 +19,8 @@
 extern const base::Feature kAutofillAssistantDirectActions;
 extern const base::Feature kAutofillAssistantDisableOnboardingFlow;
 extern const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB;
-extern const base::Feature kAutofillAssistantInChromeTriggering;
+extern const base::Feature kAutofillAssistantInCCTTriggering;
+extern const base::Feature kAutofillAssistantInTabTriggering;
 extern const base::Feature kAutofillAssistantFeedbackChip;
 extern const base::Feature kAutofillAssistantLoadDFMForTriggerScripts;
 extern const base::Feature kAutofillAssistantProactiveHelp;
diff --git a/components/autofill_assistant/browser/metrics.cc b/components/autofill_assistant/browser/metrics.cc
index 4bb1419..53b9f56 100644
--- a/components/autofill_assistant/browser/metrics.cc
+++ b/components/autofill_assistant/browser/metrics.cc
@@ -149,59 +149,58 @@
 }
 
 // static
-void Metrics::RecordLiteScriptStarted(ukm::UkmRecorder* ukm_recorder,
-                                      ukm::SourceId source_id,
-                                      LiteScriptStarted event) {
+void Metrics::RecordTriggerScriptStarted(ukm::UkmRecorder* ukm_recorder,
+                                         ukm::SourceId source_id,
+                                         TriggerScriptStarted event) {
   ukm::builders::AutofillAssistant_LiteScriptStarted(source_id)
       .SetLiteScriptStarted(static_cast<int64_t>(event))
       .Record(ukm_recorder);
 }
 
 // static
-void Metrics::RecordLiteScriptStarted(ukm::UkmRecorder* ukm_recorder,
-                                      ukm::SourceId source_id,
-                                      StartupUtil::StartupMode startup_mode,
-                                      bool feature_module_installed,
-                                      bool is_first_time_user) {
-  LiteScriptStarted event;
+void Metrics::RecordTriggerScriptStarted(ukm::UkmRecorder* ukm_recorder,
+                                         ukm::SourceId source_id,
+                                         StartupUtil::StartupMode startup_mode,
+                                         bool feature_module_installed,
+                                         bool is_first_time_user) {
+  TriggerScriptStarted event;
   switch (startup_mode) {
     case StartupUtil::StartupMode::FEATURE_DISABLED:
       if (base::FeatureList::IsEnabled(
               features::kAutofillAssistantProactiveHelp) &&
           !feature_module_installed) {
-        event = LiteScriptStarted::LITE_SCRIPT_DFM_UNAVAILABLE;
+        event = TriggerScriptStarted::DFM_UNAVAILABLE;
       } else {
-        event = LiteScriptStarted::LITE_SCRIPT_FEATURE_DISABLED;
+        event = TriggerScriptStarted::FEATURE_DISABLED;
       }
       break;
     case StartupUtil::StartupMode::SETTING_DISABLED:
-      event = LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED;
+      event = TriggerScriptStarted::PROACTIVE_TRIGGERING_DISABLED;
       break;
     case StartupUtil::StartupMode::NO_INITIAL_URL:
-      event = LiteScriptStarted::LITE_SCRIPT_NO_INITIAL_URL;
+      event = TriggerScriptStarted::NO_INITIAL_URL;
       break;
     case StartupUtil::StartupMode::MANDATORY_PARAMETERS_MISSING:
-      event = LiteScriptStarted::LITE_SCRIPT_MANDATORY_PARAMETER_MISSING;
+      event = TriggerScriptStarted::MANDATORY_PARAMETER_MISSING;
       break;
     case StartupUtil::StartupMode::START_BASE64_TRIGGER_SCRIPT:
     case StartupUtil::StartupMode::START_RPC_TRIGGER_SCRIPT:
-      event = is_first_time_user
-                  ? LiteScriptStarted::LITE_SCRIPT_FIRST_TIME_USER
-                  : LiteScriptStarted::LITE_SCRIPT_RETURNING_USER;
+      event = is_first_time_user ? TriggerScriptStarted::FIRST_TIME_USER
+                                 : TriggerScriptStarted::RETURNING_USER;
       break;
     case StartupUtil::StartupMode::START_REGULAR:
-      // Regular starts do not record impressions for |LiteScriptStarted|.
+      // Regular starts do not record impressions for |TriggerScriptStarted|.
       return;
   }
 
-  RecordLiteScriptStarted(ukm_recorder, source_id, event);
+  RecordTriggerScriptStarted(ukm_recorder, source_id, event);
 }
 
 // static
-void Metrics::RecordLiteScriptFinished(ukm::UkmRecorder* ukm_recorder,
-                                       ukm::SourceId source_id,
-                                       TriggerUIType trigger_ui_type,
-                                       LiteScriptFinishedState event) {
+void Metrics::RecordTriggerScriptFinished(ukm::UkmRecorder* ukm_recorder,
+                                          ukm::SourceId source_id,
+                                          TriggerUIType trigger_ui_type,
+                                          TriggerScriptFinishedState event) {
   ukm::builders::AutofillAssistant_LiteScriptFinished(source_id)
       .SetTriggerUIType(static_cast<int64_t>(trigger_ui_type))
       .SetLiteScriptFinished(static_cast<int64_t>(event))
@@ -209,10 +208,10 @@
 }
 
 // static
-void Metrics::RecordLiteScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
-                                          ukm::SourceId source_id,
-                                          TriggerUIType trigger_ui_type,
-                                          LiteScriptShownToUser event) {
+void Metrics::RecordTriggerScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
+                                             ukm::SourceId source_id,
+                                             TriggerUIType trigger_ui_type,
+                                             TriggerScriptShownToUser event) {
   ukm::builders::AutofillAssistant_LiteScriptShownToUser(source_id)
       .SetTriggerUIType(static_cast<int64_t>(trigger_ui_type))
       .SetLiteScriptShownToUser(static_cast<int64_t>(event))
@@ -220,10 +219,10 @@
 }
 
 // static
-void Metrics::RecordLiteScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
-                                         ukm::SourceId source_id,
-                                         TriggerUIType trigger_ui_type,
-                                         LiteScriptOnboarding event) {
+void Metrics::RecordTriggerScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+                                            ukm::SourceId source_id,
+                                            TriggerUIType trigger_ui_type,
+                                            TriggerScriptOnboarding event) {
   ukm::builders::AutofillAssistant_LiteScriptOnboarding(source_id)
       .SetTriggerUIType(static_cast<int64_t>(trigger_ui_type))
       .SetLiteScriptOnboarding(static_cast<int64_t>(event))
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h
index 31b3b69..99563c9e 100644
--- a/components/autofill_assistant/browser/metrics.h
+++ b/components/autofill_assistant/browser/metrics.h
@@ -60,7 +60,7 @@
 
   // The different ways that autofill assistant can stop. Note that this only
   // covers regular onboarding. Trigger script onboarding is covered by
-  // LiteScriptOnboarding.
+  // TriggerScriptOnboarding.
   //
   // GENERATED_JAVA_ENUM_PACKAGE: (
   // org.chromium.chrome.browser.autofill_assistant.metrics)
@@ -149,200 +149,190 @@
     kMaxValue = DFM_ALREADY_INSTALLED
   };
 
-  // Whether a lite script was running invisibly or visible to the user.
-  //
-  // GENERATED_JAVA_ENUM_PACKAGE: (
-  // org.chromium.chrome.browser.autofill_assistant.metrics)
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: LiteScriptShownToUser
+  // Whether a trigger script was running invisibly or visible to the user.
   //
   // This enum is used in UKM metrics, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantLiteScriptShownToUser enum listing in
+  // AutofillAssistantTriggerScriptShownToUser enum listing in
   // tools/metrics/histograms/enums.xml and the description in
   // tools/metrics/ukm/ukm.xml as necessary.
-  enum class LiteScriptShownToUser {
-    // The number of times a lite script was successfully fetched and started.
+  enum class TriggerScriptShownToUser {
+    // The number of times a trigger script was successfully fetched and
+    // started.
     // Can happen multiple times per run (in case of tab switch).
-    LITE_SCRIPT_RUNNING = 0,
-    // The number of times a lite script was shown to the user. Can happen
+    RUNNING = 0,
+    // The number of times a trigger script was shown to the user. Can happen
     // multiple times per run.
-    LITE_SCRIPT_SHOWN_TO_USER = 1,
+    SHOWN_TO_USER = 1,
     // Since Chrome M-88. The user tapped the 'not now' button. Can happen
     // multiple times per run.
-    LITE_SCRIPT_NOT_NOW = 2,
-    // Since Chrome M-88. The lite script was automatically hidden due to the
+    NOT_NOW = 2,
+    // Since Chrome M-88. The trigger script was automatically hidden due to the
     // trigger condition no longer being true. Can happen multiple times per
     // run.
-    LITE_SCRIPT_HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE = 3,
+    HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE = 3,
     // Since Chrome M-88. The user swipe-dismissed the bottom sheet. Depending
     // on configuration, this may happen multiple times per run.
-    LITE_SCRIPT_SWIPE_DISMISSED = 4,
+    SWIPE_DISMISSED = 4,
 
-    kMaxValue = LITE_SCRIPT_SWIPE_DISMISSED
+    kMaxValue = SWIPE_DISMISSED
   };
 
-  // The different ways a user might have opted out of the lite script
+  // The different ways a user might have opted out of the trigger script
   // experience.
   //
   // This enum is used in UKM metrics, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantLiteScriptStarted enum listing in
+  // AutofillAssistantTriggerScriptStarted enum listing in
   // tools/metrics/histograms/enums.xml and the description in
   // tools/metrics/ukm/ukm.xml as necessary.
-  enum class LiteScriptStarted {
+  enum class TriggerScriptStarted {
     // Device did not have DFM downloaded.
-    LITE_SCRIPT_DFM_UNAVAILABLE = 0,
-    // User has not seen the lite script before and will see first time
+    DFM_UNAVAILABLE = 0,
+    // User has not seen the trigger script before and will see first time
     // experience.
-    LITE_SCRIPT_FIRST_TIME_USER = 3,
+    FIRST_TIME_USER = 3,
     // User has seen the first-time experience before and will see returning
     // user experience.
-    LITE_SCRIPT_RETURNING_USER = 4,
+    RETURNING_USER = 4,
     // Since Chrome M-88. The proactive trigger setting is disabled. The user
     // has either chosen 'never show again' in the prompt or manually disabled
     // the setting in Chrome settings.
-    LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED = 5,
+    PROACTIVE_TRIGGERING_DISABLED = 5,
     // Since Chrome M-88. Intended as a catch-all. This is reported as soon as a
     // lite-script intent is received (of course, only for people with MSBB
     // enabled).
-    LITE_SCRIPT_INTENT_RECEIVED = 6,
+    INTENT_RECEIVED = 6,
     // Since Chrome M-91. A required Chrome feature was disabled.
-    LITE_SCRIPT_FEATURE_DISABLED = 7,
+    FEATURE_DISABLED = 7,
     // Since Chrome M-91. No initial url was set, neither in ORIGINAL_DEEPLINK
     // nor in the intent data.
-    LITE_SCRIPT_NO_INITIAL_URL = 8,
+    NO_INITIAL_URL = 8,
     // Since Chrome M-91. A mandatory script parameter was missing.
-    LITE_SCRIPT_MANDATORY_PARAMETER_MISSING = 9,
+    MANDATORY_PARAMETER_MISSING = 9,
     // Since Chrome M-92. The user never navigated to a different domain.
-    LITE_SCRIPT_NAVIGATED_AWAY = 10,
+    NAVIGATED_AWAY = 10,
     // Since Chrome M-92. The navigation to the target domain failed.
-    LITE_SCRIPT_NAVIGATION_ERROR = 11,
+    NAVIGATION_ERROR = 11,
 
     // DEPRECATED, only sent by Chrome M-86 and M-87.
     //
-    // User has explicitly rejected the lite script two times and thus opted
+    // User has explicitly rejected the trigger script two times and thus opted
     // out of  the experience.
-    LITE_SCRIPT_CANCELED_TWO_TIMES = 1,
+    CANCELED_TWO_TIMES = 1,
     // User has rejected the onboarding and thus opted out of the experience.
-    LITE_SCRIPT_ONBOARDING_REJECTED = 2,
+    ONBOARDING_REJECTED = 2,
 
-    kMaxValue = LITE_SCRIPT_NAVIGATION_ERROR
+    kMaxValue = NAVIGATION_ERROR
   };
 
-  // The different ways in which a lite script may finish.
-  //
-  // GENERATED_JAVA_ENUM_PACKAGE: (
-  // org.chromium.chrome.browser.autofill_assistant.metrics)
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: LiteScriptFinishedState
+  // The different ways in which a trigger script may finish.
   //
   // This enum is used in UKM metrics, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantLiteScriptFinished enum listing in
+  // AutofillAssistantTriggerScriptFinished enum listing in
   // tools/metrics/histograms/enums.xml and the description in
   // tools/metrics/ukm/ukm.xml as necessary.
-  enum class LiteScriptFinishedState {
+  enum class TriggerScriptFinishedState {
     // Communication with backend failed.
-    LITE_SCRIPT_GET_ACTIONS_FAILED = 3,
+    GET_ACTIONS_FAILED = 3,
     // Failed to parse the proto sent by the backend.
-    LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR = 4,
-    // Lite script failed due to a navigation event to a non-allowed domain.
-    LITE_SCRIPT_PROMPT_FAILED_NAVIGATE = 9,
-    // Lite script succeeded. The user accepted the prompt.
-    LITE_SCRIPT_PROMPT_SUCCEEDED = 13,
+    GET_ACTIONS_PARSE_ERROR = 4,
+    // Trigger script failed due to a navigation event to a non-allowed domain.
+    PROMPT_FAILED_NAVIGATE = 9,
+    // Trigger script succeeded. The user accepted the prompt.
+    PROMPT_SUCCEEDED = 13,
     // Since Chrome M-88. The user tapped the 'cancel for this session' button.
-    LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION = 14,
+    PROMPT_FAILED_CANCEL_SESSION = 14,
     // Since Chrome M-88. The user tapped the 'never show again' button.
-    LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER = 15,
+    PROMPT_FAILED_CANCEL_FOREVER = 15,
     // Since Chrome M-88. The trigger script has timed out. This indicates that
     // trigger conditions were evaluated for >= timeout without success. Time is
-    // only counted while the tab is visible and the lite script is invisible.
+    // only counted while the tab is visible and the trigger script is
+    // invisible.
     // The timeout resets on tab change.
-    LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT = 17,
+    TRIGGER_CONDITION_TIMEOUT = 17,
     // Since Chrome M-88. A navigation error occurred, leading to Chrome showing
     // an error page.
-    LITE_SCRIPT_NAVIGATION_ERROR = 18,
+    NAVIGATION_ERROR = 18,
     // Since Chrome M-88. The tab was closed while the prompt was visible.
-    LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE = 19,
+    WEB_CONTENTS_DESTROYED_WHILE_VISIBLE = 19,
     // Since Chrome M-88. The tab was closed while the prompt was invisible.
-    LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE = 20,
+    WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE = 20,
     // Since Chrome M-88. The RPC to fetch the trigger scripts returned with an
     // empty response.
-    LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE = 21,
+    NO_TRIGGER_SCRIPT_AVAILABLE = 21,
     // Since Chrome M-88. The trigger script failed to show. This can happen,
     // for example, if the activity was changed after triggering (e.g.,
     // switching from CCT to regular tab).
-    LITE_SCRIPT_FAILED_TO_SHOW = 22,
+    FAILED_TO_SHOW = 22,
     // Since Chrome M-88. The proactive help switch was enabled at start, but
     // then manually disabled in the Chrome settings.
-    LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING = 23,
+    DISABLED_PROACTIVE_HELP_SETTING = 23,
     // Since Chrome M-88. The client failed to base64-decode the trigger script
     // specified in the script parameters.
-    LITE_SCRIPT_BASE64_DECODING_ERROR = 24,
+    BASE64_DECODING_ERROR = 24,
     // The user rejected the bottom sheet onboarding
-    LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED = 25,
+    BOTTOMSHEET_ONBOARDING_REJECTED = 25,
     // Transitioning from CCT to regular tab is currently not supported.
-    LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED = 26,
+    CCT_TO_TAB_NOT_SUPPORTED = 26,
     // The current trigger script was canceled. This typically happens when a
     // new startup request takes precedence.
-    LITE_SCRIPT_CANCELED = 27,
+    CANCELED = 27,
 
     // NOTE: All values in this block are DEPRECATED and will only be sent by
     // Chrome M-86 and M-87.
     //
-    // The lite script failed for an unknown reason.
-    LITE_SCRIPT_UNKNOWN_FAILURE = 0,
+    // The trigger script failed for an unknown reason.
+    UNKNOWN_FAILURE = 0,
     // Can happen when users close the tab or similar.
-    LITE_SCRIPT_SERVICE_DELETED = 1,
+    SERVICE_DELETED = 1,
     // |GetActions| was asked to retrieve a wrong script path.
-    LITE_SCRIPT_PATH_MISMATCH = 2,
+    PATH_MISMATCH = 2,
     // One or multiple unsafe actions were contained in script.
-    LITE_SCRIPT_UNSAFE_ACTIONS = 5,
+    UNSAFE_ACTIONS = 5,
     // The mini script is invalid. A valid script must contain a prompt
     // (browse=true) action and end in a prompt(browse=false) action.
-    LITE_SCRIPT_INVALID_SCRIPT = 6,
+    INVALID_SCRIPT = 6,
     // The prompt(browse) action failed due to a navigation event to a
     // non-allowed domain.
-    LITE_SCRIPT_BROWSE_FAILED_NAVIGATE = 7,
+    BROWSE_FAILED_NAVIGATE = 7,
     // The prompt(browse) action failed for an unknown reason.
-    LITE_SCRIPT_BROWSE_FAILED_OTHER = 8,
+    BROWSE_FAILED_OTHER = 8,
     // The prompt(regular) action failed because the condition to show it was no
     // longer true.
-    LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE = 10,
+    PROMPT_FAILED_CONDITION_NO_LONGER_TRUE = 10,
     // The prompt(regular) action failed because the user tapped the close chip.
-    LITE_SCRIPT_PROMPT_FAILED_CLOSE = 11,
+    PROMPT_FAILED_CLOSE = 11,
     // The prompt(regular) action failed for an unknown reason.
-    LITE_SCRIPT_PROMPT_FAILED_OTHER = 12,
+    PROMPT_FAILED_OTHER = 12,
     // Since Chrome M-88. The bottom sheet was swipe-dismissed by the user.
-    LITE_SCRIPT_PROMPT_SWIPE_DISMISSED = 16,
+    PROMPT_SWIPE_DISMISSED = 16,
 
-    kMaxValue = LITE_SCRIPT_CANCELED
+    kMaxValue = CANCELED
   };
 
   // The different ways a user who has successfully completed a light script may
   // accept or reject the onboarding
   //
-  // GENERATED_JAVA_ENUM_PACKAGE: (
-  // org.chromium.chrome.browser.autofill_assistant.metrics)
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: LiteScriptOnboarding
-  //
   // This enum is used in UKM metrics, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantLiteScriptOnboarding enum listing in
+  // AutofillAssistantTriggerScriptOnboarding enum listing in
   // tools/metrics/histograms/enums.xml and the description in
   // tools/metrics/ukm/ukm.xml as necessary.
-  enum class LiteScriptOnboarding {
+  enum class TriggerScriptOnboarding {
     // The user has seen and accepted the onboarding.
-    LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED = 0,
+    ONBOARDING_SEEN_AND_ACCEPTED = 0,
     // The user has seen and rejected the onboarding.
-    LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED = 1,
+    ONBOARDING_SEEN_AND_REJECTED = 1,
     // The user has already accepted the onboarding in the past.
-    LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED = 2,
+    ONBOARDING_ALREADY_ACCEPTED = 2,
     // The user has seen and dismissed the onboarding.
-    LITE_SCRIPT_ONBOARDING_SEEN_AND_DISMISSED = 3,
+    ONBOARDING_SEEN_AND_DISMISSED = 3,
     // The onboarding was interrupted by a website navigation.
-    LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION = 4,
+    ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION = 4,
 
-    kMaxValue = LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION
+    kMaxValue = ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION
   };
 
   static void RecordDropOut(DropOutReason reason, const std::string& intent);
@@ -353,26 +343,26 @@
   static void RecordPaymentRequestMandatoryPostalCode(bool required,
                                                       bool initially_right,
                                                       bool success);
-  static void RecordLiteScriptStarted(ukm::UkmRecorder* ukm_recorder,
-                                      ukm::SourceId source_id,
-                                      LiteScriptStarted event);
-  static void RecordLiteScriptStarted(ukm::UkmRecorder* ukm_recorder,
-                                      ukm::SourceId source_id,
-                                      StartupUtil::StartupMode startup_mode,
-                                      bool feature_module_installed,
-                                      bool is_first_time_user);
-  static void RecordLiteScriptFinished(ukm::UkmRecorder* ukm_recorder,
-                                       ukm::SourceId source_id,
-                                       TriggerUIType trigger_ui_type,
-                                       LiteScriptFinishedState event);
-  static void RecordLiteScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
+  static void RecordTriggerScriptStarted(ukm::UkmRecorder* ukm_recorder,
+                                         ukm::SourceId source_id,
+                                         TriggerScriptStarted event);
+  static void RecordTriggerScriptStarted(ukm::UkmRecorder* ukm_recorder,
+                                         ukm::SourceId source_id,
+                                         StartupUtil::StartupMode startup_mode,
+                                         bool feature_module_installed,
+                                         bool is_first_time_user);
+  static void RecordTriggerScriptFinished(ukm::UkmRecorder* ukm_recorder,
                                           ukm::SourceId source_id,
                                           TriggerUIType trigger_ui_type,
-                                          LiteScriptShownToUser event);
-  static void RecordLiteScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
-                                         ukm::SourceId source_id,
-                                         TriggerUIType trigger_ui_type,
-                                         LiteScriptOnboarding event);
+                                          TriggerScriptFinishedState event);
+  static void RecordTriggerScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
+                                             ukm::SourceId source_id,
+                                             TriggerUIType trigger_ui_type,
+                                             TriggerScriptShownToUser event);
+  static void RecordTriggerScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+                                            ukm::SourceId source_id,
+                                            TriggerUIType trigger_ui_type,
+                                            TriggerScriptOnboarding event);
   static void RecordOnboardingResult(OnBoarding event);
   static void RecordFeatureModuleInstallation(FeatureModuleInstallation event);
 
@@ -507,7 +497,7 @@
   }
 
   friend std::ostream& operator<<(std::ostream& out,
-                                  const LiteScriptFinishedState& state) {
+                                  const TriggerScriptFinishedState& state) {
 #ifdef NDEBUG
     // Non-debugging builds write the enum number.
     out << static_cast<int>(state);
@@ -515,92 +505,89 @@
 #else
     // Debugging builds write a string representation of |state|.
     switch (state) {
-      case LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED:
-        out << "LITE_SCRIPT_GET_ACTIONS_FAILED";
+      case TriggerScriptFinishedState::GET_ACTIONS_FAILED:
+        out << "GET_ACTIONS_FAILED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR:
-        out << "LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR";
+      case TriggerScriptFinishedState::GET_ACTIONS_PARSE_ERROR:
+        out << "GET_ACTIONS_PARSE_ERROR";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE:
-        out << "LITE_SCRIPT_PROMPT_FAILED_NAVIGATE";
+      case TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE:
+        out << "PROMPT_FAILED_NAVIGATE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED:
-        out << "LITE_SCRIPT_PROMPT_SUCCEEDED";
+      case TriggerScriptFinishedState::PROMPT_SUCCEEDED:
+        out << "PROMPT_SUCCEEDED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION:
-        out << "LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION";
+      case TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_SESSION:
+        out << "PROMPT_FAILED_CANCEL_SESSION";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER:
-        out << "LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER";
+      case TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_FOREVER:
+        out << "PROMPT_FAILED_CANCEL_FOREVER";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT:
-        out << "LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT";
+      case TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT:
+        out << "TRIGGER_CONDITION_TIMEOUT";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_NAVIGATION_ERROR:
-        out << "LITE_SCRIPT_NAVIGATION_ERROR";
+      case TriggerScriptFinishedState::NAVIGATION_ERROR:
+        out << "NAVIGATION_ERROR";
         break;
-      case LiteScriptFinishedState::
-          LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE:
-        out << "LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE";
+      case TriggerScriptFinishedState::WEB_CONTENTS_DESTROYED_WHILE_VISIBLE:
+        out << "WEB_CONTENTS_DESTROYED_WHILE_VISIBLE";
         break;
-      case LiteScriptFinishedState::
-          LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE:
-        out << "LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE";
+      case TriggerScriptFinishedState::WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE:
+        out << "WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE:
-        out << "LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE";
+      case TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE:
+        out << "NO_TRIGGER_SCRIPT_AVAILABLE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW:
-        out << "LITE_SCRIPT_FAILED_TO_SHOW";
+      case TriggerScriptFinishedState::FAILED_TO_SHOW:
+        out << "FAILED_TO_SHOW";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING:
-        out << "LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING";
+      case TriggerScriptFinishedState::DISABLED_PROACTIVE_HELP_SETTING:
+        out << "DISABLED_PROACTIVE_HELP_SETTING";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_BASE64_DECODING_ERROR:
-        out << "LITE_SCRIPT_BASE64_DECODING_ERROR";
+      case TriggerScriptFinishedState::BASE64_DECODING_ERROR:
+        out << "BASE64_DECODING_ERROR";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED:
-        out << "LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED";
+      case TriggerScriptFinishedState::BOTTOMSHEET_ONBOARDING_REJECTED:
+        out << "BOTTOMSHEET_ONBOARDING_REJECTED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_UNKNOWN_FAILURE:
-        out << "LITE_SCRIPT_UNKNOWN_FAILURE";
+      case TriggerScriptFinishedState::UNKNOWN_FAILURE:
+        out << "UNKNOWN_FAILURE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_SERVICE_DELETED:
-        out << "LITE_SCRIPT_SERVICE_DELETED";
+      case TriggerScriptFinishedState::SERVICE_DELETED:
+        out << "SERVICE_DELETED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PATH_MISMATCH:
-        out << "LITE_SCRIPT_PATH_MISMATCH";
+      case TriggerScriptFinishedState::PATH_MISMATCH:
+        out << "PATH_MISMATCH";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_UNSAFE_ACTIONS:
-        out << "LITE_SCRIPT_UNSAFE_ACTIONS";
+      case TriggerScriptFinishedState::UNSAFE_ACTIONS:
+        out << "UNSAFE_ACTIONS";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_INVALID_SCRIPT:
-        out << "LITE_SCRIPT_INVALID_SCRIPT";
+      case TriggerScriptFinishedState::INVALID_SCRIPT:
+        out << "INVALID_SCRIPT";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_BROWSE_FAILED_NAVIGATE:
-        out << "LITE_SCRIPT_BROWSE_FAILED_NAVIGATE";
+      case TriggerScriptFinishedState::BROWSE_FAILED_NAVIGATE:
+        out << "BROWSE_FAILED_NAVIGATE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_BROWSE_FAILED_OTHER:
-        out << "LITE_SCRIPT_BROWSE_FAILED_OTHER";
+      case TriggerScriptFinishedState::BROWSE_FAILED_OTHER:
+        out << "BROWSE_FAILED_OTHER";
         break;
-      case LiteScriptFinishedState::
-          LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE:
-        out << "LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE";
+      case TriggerScriptFinishedState::PROMPT_FAILED_CONDITION_NO_LONGER_TRUE:
+        out << "PROMPT_FAILED_CONDITION_NO_LONGER_TRUE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CLOSE:
-        out << "LITE_SCRIPT_PROMPT_FAILED_CLOSE";
+      case TriggerScriptFinishedState::PROMPT_FAILED_CLOSE:
+        out << "PROMPT_FAILED_CLOSE";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_OTHER:
-        out << "LITE_SCRIPT_PROMPT_FAILED_OTHER";
+      case TriggerScriptFinishedState::PROMPT_FAILED_OTHER:
+        out << "PROMPT_FAILED_OTHER";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SWIPE_DISMISSED:
-        out << "LITE_SCRIPT_PROMPT_SWIPE_DISMISSED";
+      case TriggerScriptFinishedState::PROMPT_SWIPE_DISMISSED:
+        out << "PROMPT_SWIPE_DISMISSED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED:
-        out << "LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED";
+      case TriggerScriptFinishedState::CCT_TO_TAB_NOT_SUPPORTED:
+        out << "CCT_TO_TAB_NOT_SUPPORTED";
         break;
-      case LiteScriptFinishedState::LITE_SCRIPT_CANCELED:
-        out << "LITE_SCRIPT_CANCELED";
+      case TriggerScriptFinishedState::CANCELED:
+        out << "CANCELED";
         break;
         // Do not add default case to force compilation error for new values.
     }
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 757d5b25..87856f4 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -545,7 +545,7 @@
 
   // The amount of time a trigger script may evaluate trigger conditions while
   // invisible. If a trigger script is invisible for this amount of time, it
-  // will automatically finish with LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT.
+  // will automatically finish with TRIGGER_CONDITION_TIMEOUT.
   // If not specified, there is no automatic timeout.
   //
   // This is only counted while no trigger script is shown, and the time is
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc
index cdf4645c..74e146c 100644
--- a/components/autofill_assistant/browser/starter.cc
+++ b/components/autofill_assistant/browser/starter.cc
@@ -40,10 +40,23 @@
 // mark users as being in either the control or the experiment group to allow
 // for aggregation of UKM metrics.
 const char kTriggerScriptExperimentSyntheticFieldTrialName[] =
-    "AutofillAssistantLiteScriptExperiment";
+    "AutofillAssistantTriggerScriptExperiment";
 const char kTriggerScriptExperimentGroup[] = "Experiment";
 const char kTriggerScriptControlGroup[] = "Control";
 
+// The maximum number of items to be kept in the cache. If this number is
+// exceeded, the entry that hasn't been accessed the longest is automatically
+// removed.
+constexpr size_t kMaxFailedTriggerScriptsCacheSize = 100;
+constexpr size_t kMaxUserDenylistedCacheSize = 100;
+
+// The duration for which cache entries are considered fresh. Stale entries in
+// the cache are ignored.
+constexpr base::TimeDelta kMaxFailedTriggerScriptsCacheDuration =
+    base::TimeDelta::FromHours(1);
+constexpr base::TimeDelta kMaxUserDenylistedCacheDuration =
+    base::TimeDelta::FromHours(1);
+
 // Creates a service request sender that serves the pre-specified response.
 // Creation may fail (return null) if the parameter fails to decode.
 std::unique_ptr<ServiceRequestSender> CreateBase64TriggerScriptRequestSender(
@@ -87,18 +100,57 @@
   return *starter_heuristic;
 }
 
+// The cache of failed trigger script fetches is shared across all instances and
+// initialized on first use.
+base::HashingMRUCache<std::string, base::TimeTicks>*
+GetOrCreateFailedTriggerScriptFetchesCache() {
+  static base::NoDestructor<base::HashingMRUCache<std::string, base::TimeTicks>>
+      cached_failed_trigger_script_fetches(kMaxFailedTriggerScriptsCacheSize);
+  return cached_failed_trigger_script_fetches.get();
+}
+
+// Goes through the |cache| and removes entries that have gone stale, i.e.,
+// entries that were added before |cutoff_ticks|.
+void ClearStaleCacheEntries(
+    base::HashingMRUCache<std::string, base::TimeTicks>* cache,
+    base::TimeTicks cutoff_ticks) {
+  // Go in reverse order until the oldest entry is younger than |cutoff_ticks|.
+  for (auto it = cache->rbegin(); it != cache->rend();) {
+    if (it->second > cutoff_ticks) {
+      return;
+    }
+    it = cache->Erase(it);
+  }
+}
+
+// Returns true if |cache| has an entry for |url| that is younger than
+// |cutoff_ticks|, false otherwise. Does not change the order of the cache.
+bool HasFreshCacheEntry(
+    const base::HashingMRUCache<std::string, base::TimeTicks>& cache,
+    const GURL& url,
+    base::TimeTicks cutoff_ticks) {
+  std::string domain = url_utils::GetOrganizationIdentifyingDomain(url);
+  auto it = cache.Peek(domain);
+  return (it != cache.end() && (it->second > cutoff_ticks));
+}
+
 }  // namespace
 
 Starter::Starter(content::WebContents* web_contents,
                  StarterPlatformDelegate* platform_delegate,
                  ukm::UkmRecorder* ukm_recorder,
-                 base::WeakPtr<RuntimeManagerImpl> runtime_manager)
+                 base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+                 const base::TickClock* tick_clock)
     : content::WebContentsObserver(web_contents),
       next_ukm_source_id_(ukm::GetSourceIdForWebContentsDocument(web_contents)),
+      cached_failed_trigger_script_fetches_(
+          GetOrCreateFailedTriggerScriptFetchesCache()),
+      user_denylisted_domains_(kMaxUserDenylistedCacheSize),
       platform_delegate_(platform_delegate),
       ukm_recorder_(ukm_recorder),
       runtime_manager_(runtime_manager),
-      starter_heuristic_(GetOrCreateStarterHeuristic()) {
+      starter_heuristic_(GetOrCreateStarterHeuristic()),
+      tick_clock_(tick_clock) {
   CheckSettings();
 }
 
@@ -143,11 +195,11 @@
       }
       // Note: this will record for the current domain, not the target domain.
       // There seems to be no way to avoid this.
-      Metrics::RecordLiteScriptStarted(
+      Metrics::RecordTriggerScriptStarted(
           ukm_recorder_, next_ukm_source_id_,
           navigation_handle->IsErrorPage()
-              ? Metrics::LiteScriptStarted::LITE_SCRIPT_NAVIGATION_ERROR
-              : Metrics::LiteScriptStarted::LITE_SCRIPT_NAVIGATED_AWAY);
+              ? Metrics::TriggerScriptStarted::NAVIGATION_ERROR
+              : Metrics::TriggerScriptStarted::NAVIGATED_AWAY);
       CancelPendingStartup(base::nullopt);
     } else {
       // Regular startup was interrupted (most likely during the onboarding).
@@ -176,6 +228,16 @@
     return;
   }
 
+  // If we have failed to fetch a trigger script for this domain before, or if
+  // the user has denylisted the domain, don't try again.
+  base::TimeTicks now_ticks = tick_clock_->NowTicks();
+  if (HasFreshCacheEntry(*cached_failed_trigger_script_fetches_, url,
+                         now_ticks - kMaxFailedTriggerScriptsCacheDuration) ||
+      HasFreshCacheEntry(user_denylisted_domains_, url,
+                         now_ticks - kMaxUserDenylistedCacheDuration)) {
+    return;
+  }
+
   // Run the heuristic in a separate task.
   starter_heuristic_->RunHeuristicAsync(
       url, base::BindOnce(&Starter::OnHeuristicMatch,
@@ -234,8 +296,12 @@
   bool prev_fetch_trigger_scripts_on_navigation =
       fetch_trigger_scripts_on_navigation_;
   fetch_trigger_scripts_on_navigation_ =
-      base::FeatureList::IsEnabled(
-          features::kAutofillAssistantInChromeTriggering) &&
+      ((base::FeatureList::IsEnabled(
+            features::kAutofillAssistantInCCTTriggering) &&
+        is_custom_tab_) ||
+       (base::FeatureList::IsEnabled(
+            features::kAutofillAssistantInTabTriggering) &&
+        !is_custom_tab_)) &&
       proactive_help_setting_enabled && msbb_setting_enabled;
 
   // If there is a pending startup, re-check that the settings are still
@@ -255,12 +321,12 @@
         }
         // Trigger scripts are not allowed to persist when transitioning from
         // CCT to regular tab.
-        CancelPendingStartup(Metrics::LiteScriptFinishedState::
-                                 LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED);
+        CancelPendingStartup(
+            Metrics::TriggerScriptFinishedState::CCT_TO_TAB_NOT_SUPPORTED);
         return;
       default:
-        CancelPendingStartup(Metrics::LiteScriptFinishedState::
-                                 LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING);
+        CancelPendingStartup(Metrics::TriggerScriptFinishedState::
+                                 DISABLED_PROACTIVE_HELP_SETTING);
         return;
     }
   } else if (!prev_fetch_trigger_scripts_on_navigation &&
@@ -272,7 +338,7 @@
 void Starter::Start(std::unique_ptr<TriggerContext> trigger_context) {
   DCHECK(trigger_context);
   DCHECK(!trigger_context->GetDirectAction());
-  CancelPendingStartup(Metrics::LiteScriptFinishedState::LITE_SCRIPT_CANCELED);
+  CancelPendingStartup(Metrics::TriggerScriptFinishedState::CANCELED);
   pending_trigger_context_ = std::move(trigger_context);
 
   if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
@@ -298,9 +364,9 @@
       !startup_url.has_value()) {
     // Fail immediately if there is no deeplink domain to wait for.
     // Note: this will record the impression for the current domain.
-    Metrics::RecordLiteScriptStarted(
+    Metrics::RecordTriggerScriptStarted(
         ukm_recorder_, next_ukm_source_id_,
-        Metrics::LiteScriptStarted::LITE_SCRIPT_NO_INITIAL_URL);
+        Metrics::TriggerScriptStarted::NO_INITIAL_URL);
     OnStartDone(/* start_regular_script = */ false);
     return;
   }
@@ -315,7 +381,7 @@
   // Record startup metrics for trigger scripts as soon as possible to establish
   // a baseline.
   if (IsTriggerScriptContext(*pending_trigger_context_)) {
-    Metrics::RecordLiteScriptStarted(
+    Metrics::RecordTriggerScriptStarted(
         ukm_recorder_, next_ukm_source_id_, startup_mode,
         platform_delegate_->GetFeatureModuleInstalled(),
         platform_delegate_->GetIsFirstTimeUser());
@@ -337,7 +403,7 @@
 }
 
 void Starter::CancelPendingStartup(
-    base::Optional<Metrics::LiteScriptFinishedState> state) {
+    base::Optional<Metrics::TriggerScriptFinishedState> state) {
   if (!IsStartupPending()) {
     return;
   }
@@ -415,12 +481,11 @@
       service_request_sender = CreateBase64TriggerScriptRequestSender(
           script_parameters.GetBase64TriggerScriptsResponseProto().value());
       if (!service_request_sender) {
-        Metrics::RecordLiteScriptFinished(
+        Metrics::RecordTriggerScriptFinished(
             ukm_recorder_, next_ukm_source_id_, UNSPECIFIED_TRIGGER_UI_TYPE,
-            Metrics::LiteScriptFinishedState::
-                LITE_SCRIPT_BASE64_DECODING_ERROR);
+            Metrics::TriggerScriptFinishedState::BASE64_DECODING_ERROR);
         OnTriggerScriptFinished(
-            Metrics::LiteScriptFinishedState::LITE_SCRIPT_BASE64_DECODING_ERROR,
+            Metrics::TriggerScriptFinishedState::BASE64_DECODING_ERROR,
             std::move(pending_trigger_context_), base::nullopt);
         return;
       }
@@ -459,16 +524,45 @@
 }
 
 void Starter::OnTriggerScriptFinished(
-    Metrics::LiteScriptFinishedState state,
+    Metrics::TriggerScriptFinishedState state,
     std::unique_ptr<TriggerContext> trigger_context,
     base::Optional<TriggerScriptProto> trigger_script) {
+  // Update caches on error or user-cancel.
+  if (trigger_script_coordinator_) {
+    std::string domain = url_utils::GetOrganizationIdentifyingDomain(
+        trigger_script_coordinator_->GetDeeplink());
+    switch (state) {
+      case Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE:
+      case Metrics::TriggerScriptFinishedState::GET_ACTIONS_FAILED:
+        cached_failed_trigger_script_fetches_->Put(domain,
+                                                   tick_clock_->NowTicks());
+        ClearStaleCacheEntries(
+            cached_failed_trigger_script_fetches_,
+            tick_clock_->NowTicks() - kMaxFailedTriggerScriptsCacheDuration);
+        break;
+      case Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_SESSION:
+        user_denylisted_domains_.Put(domain, tick_clock_->NowTicks());
+        ClearStaleCacheEntries(
+            &user_denylisted_domains_,
+            tick_clock_->NowTicks() - kMaxUserDenylistedCacheDuration);
+        break;
+      default: {
+        auto cache_it = cached_failed_trigger_script_fetches_->Peek(domain);
+        if (cache_it != cached_failed_trigger_script_fetches_->end()) {
+          cached_failed_trigger_script_fetches_->Erase(cache_it);
+        }
+        break;
+      }
+    }
+  }
+
   // Delete the coordinator asynchronously, to give this notification time to
   // end gracefully.
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&Starter::DeleteTriggerScriptCoordinator,
                                 weak_ptr_factory_.GetWeakPtr()));
 
-  if (state != Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED) {
+  if (state != Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED) {
     OnStartDone(/* start_regular_script = */ false);
     return;
   }
diff --git a/components/autofill_assistant/browser/starter.h b/components/autofill_assistant/browser/starter.h
index d788a36..d983aa2 100644
--- a/components/autofill_assistant/browser/starter.h
+++ b/components/autofill_assistant/browser/starter.h
@@ -7,9 +7,12 @@
 
 #include <memory>
 
+#include "base/containers/mru_cache.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
 #include "components/autofill_assistant/browser/controller.h"
 #include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
@@ -29,7 +32,8 @@
   explicit Starter(content::WebContents* web_contents,
                    StarterPlatformDelegate* platform_delegate,
                    ukm::UkmRecorder* ukm_recorder,
-                   base::WeakPtr<RuntimeManagerImpl> runtime_manager);
+                   base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+                   const base::TickClock* tick_clock);
   ~Starter() override;
   Starter(const Starter&) = delete;
   Starter& operator=(const Starter&) = delete;
@@ -63,6 +67,8 @@
   void CheckSettings();
 
  private:
+  friend class StarterTest;
+
   // Starts a flow for |url| if possible. Will fail (do nothing) if the feature
   // is disabled or if there is already a pending startup.
   void MaybeStartImplicitlyForUrl(const GURL& url);
@@ -72,7 +78,7 @@
   // This will also hide any currently shown UI (such as a trigger script or the
   // onboarding).
   void CancelPendingStartup(
-      base::Optional<Metrics::LiteScriptFinishedState> state);
+      base::Optional<Metrics::TriggerScriptFinishedState> state);
 
   // Installs the feature module if necessary, otherwise directly invokes
   // |OnFeatureModuleInstalled|.
@@ -90,7 +96,7 @@
   // Stops the startup if the trigger script failed or was user-cancelled.
   // Otherwise, proceeds with the start of the regular script.
   void OnTriggerScriptFinished(
-      Metrics::LiteScriptFinishedState state,
+      Metrics::TriggerScriptFinishedState state,
       std::unique_ptr<TriggerContext> trigger_context,
       base::Optional<TriggerScriptProto> trigger_script);
 
@@ -116,6 +122,7 @@
   // Returns whether there is a currently pending call to |Start| or not.
   bool IsStartupPending() const;
 
+  // Deletes the trigger script coordinator.
   void DeleteTriggerScriptCoordinator();
 
   // Returns a pointer to the currently pending trigger context, or nullptr.
@@ -129,6 +136,26 @@
   // the source id that the finished navigation will eventually have.
   ukm::SourceId next_ukm_source_id_ = ukm::kInvalidSourceId;
 
+  // Pointer to the global cache of trigger script requests that failed (one
+  // entry per organization-identifying domain), along with the time of entry.
+  // This is used to limit network traffic incurred for in-chrome triggering
+  // only. This cache does not affect explicit startup requests.
+  //
+  // This cache is shared across all tabs. It is size-limited and entries only
+  // last for a limited amount of time before they go stale. Made available in
+  // the header for easier unit-testing.
+  base::HashingMRUCache<std::string, base::TimeTicks>*
+      cached_failed_trigger_script_fetches_;
+
+  // The list of organization-identifying domains that a user has temporarily
+  // opted out of for receiving implicit autofill-assistant prompts, along
+  // with the time of entry.
+  //
+  // This is a per-tab cache. This cache does not affect explicit startup
+  // requests. The cache is size-limited and entries only last for a limited
+  // amount of time before they go stale.
+  base::HashingMRUCache<std::string, base::TimeTicks> user_denylisted_domains_;
+
   bool waiting_for_onboarding_ = false;
   bool waiting_for_deeplink_navigation_ = false;
   bool is_custom_tab_ = false;
@@ -139,6 +166,7 @@
   std::unique_ptr<TriggerContext> pending_trigger_context_;
   std::unique_ptr<TriggerScriptCoordinator> trigger_script_coordinator_;
   const scoped_refptr<StarterHeuristic> starter_heuristic_;
+  const base::TickClock* tick_clock_;
   base::WeakPtrFactory<Starter> weak_ptr_factory_{this};
 };
 
diff --git a/components/autofill_assistant/browser/starter_unittest.cc b/components/autofill_assistant/browser/starter_unittest.cc
index 38d800b1..cc01637 100644
--- a/components/autofill_assistant/browser/starter_unittest.cc
+++ b/components/autofill_assistant/browser/starter_unittest.cc
@@ -8,11 +8,13 @@
 #include <memory>
 #include <string>
 #include "base/base64url.h"
+#include "base/containers/mru_cache.h"
 #include "base/strings/string_piece.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/time/tick_clock.h"
 #include "components/autofill_assistant/browser/fake_starter_platform_delegate.h"
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
@@ -35,15 +37,17 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
-namespace {
 
 using ::base::test::RunOnceCallback;
 using ::testing::_;
 using ::testing::Eq;
+using ::testing::IsEmpty;
 using ::testing::NiceMock;
 using ::testing::Optional;
+using ::testing::Pair;
 using ::testing::Pointee;
 using ::testing::Property;
+using ::testing::UnorderedElementsAre;
 using ::testing::WithArg;
 using ::testing::WithArgs;
 
@@ -51,6 +55,12 @@
 
 class StarterTest : public content::RenderViewHostTestHarness {
  public:
+  StarterTest()
+      : content::RenderViewHostTestHarness(
+            base::test::TaskEnvironment::MainThreadType::UI,
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+  ~StarterTest() override = default;
+
   void SetUp() override {
     RenderViewHostTestHarness::SetUp();
     ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
@@ -66,16 +76,30 @@
 
     starter_ = std::make_unique<Starter>(
         web_contents(), &fake_platform_delegate_, &ukm_recorder_,
-        mock_runtime_manager_.GetWeakPtr());
+        mock_runtime_manager_.GetWeakPtr(),
+        task_environment()->GetMockTickClock());
   }
 
   void TearDown() override {
+    // We need to clear the static cache to avoid cross-talk between tests.
+    GetFailedTriggerFetchesCacheForTest()->Clear();
+
     // Note: it is important to reset the starter explicitly here to ensure that
     // destructors are called on the right thread, as required by devtools.
     starter_.reset();
     RenderViewHostTestHarness::TearDown();
   }
 
+  base::HashingMRUCache<std::string, base::TimeTicks>*
+  GetFailedTriggerFetchesCacheForTest() {
+    return starter_->cached_failed_trigger_script_fetches_;
+  }
+
+  base::HashingMRUCache<std::string, base::TimeTicks>*
+  GetUserDenylistedCacheForTest() const {
+    return &starter_->user_denylisted_domains_;
+  }
+
  protected:
   void SetupPlatformDelegateForFirstTimeUser() {
     fake_platform_delegate_.feature_module_installed_ = false;
@@ -139,37 +163,39 @@
     return !ukm_recorder_.GetEntriesByName(entry_name).empty();
   }
 
-  bool UkmLiteScriptStarted(Metrics::LiteScriptStarted state,
-                            const GURL& source_url = GURL(kExampleDeeplink)) {
+  bool UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted state,
+      const GURL& source_url = GURL(kExampleDeeplink)) {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptStarted",
                              "LiteScriptStarted", static_cast<int64_t>(state),
                              source_url);
   }
 
-  bool UkmLiteScriptFinished(Metrics::LiteScriptFinishedState state,
-                             const GURL& source_url = GURL(kExampleDeeplink)) {
+  bool UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState state,
+      const GURL& source_url = GURL(kExampleDeeplink)) {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptFinished",
                              "LiteScriptFinished", static_cast<int64_t>(state),
                              source_url);
   }
 
-  bool UkmLiteScriptOnboarding(
-      Metrics::LiteScriptOnboarding result,
+  bool UkmTriggerScriptOnboarding(
+      Metrics::TriggerScriptOnboarding result,
       const GURL& source_url = GURL(kExampleDeeplink)) {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptOnboarding",
                              "LiteScriptOnboarding",
                              static_cast<int64_t>(result), source_url);
   }
 
-  bool UkmLiteScriptStarted() {
+  bool UkmTriggerScriptStarted() {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptStarted");
   }
 
-  bool UkmLiteScriptFinished() {
+  bool UkmTriggerScriptFinished() {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptFinished");
   }
 
-  bool UkmLiteScriptOnboarding() {
+  bool UkmTriggerScriptOnboarding() {
     return RecordedUkmMetric("AutofillAssistant.LiteScriptOnboarding");
   }
 
@@ -247,9 +273,9 @@
   starter_->Start(std::make_unique<TriggerContext>(
       std::make_unique<ScriptParameters>(params), options));
 
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -267,10 +293,10 @@
   starter_->Start(std::make_unique<TriggerContext>(
       std::make_unique<ScriptParameters>(params), options));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_NO_INITIAL_URL));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::NO_INITIAL_URL));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -288,10 +314,10 @@
   starter_->Start(std::make_unique<TriggerContext>(
       std::make_unique<ScriptParameters>(params), options));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_MANDATORY_PARAMETER_MISSING));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted::MANDATORY_PARAMETER_MISSING));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -313,10 +339,10 @@
   starter_->Start(std::make_unique<TriggerContext>(
       std::make_unique<ScriptParameters>(params), options));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_FEATURE_DISABLED));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::FEATURE_DISABLED));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -344,9 +370,9 @@
               Eq(0));
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(0));
   EXPECT_THAT(fake_platform_delegate_.GetOnboardingAccepted(), Eq(true));
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -377,9 +403,9 @@
               Eq(1));
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1));
   EXPECT_THAT(fake_platform_delegate_.GetOnboardingAccepted(), Eq(true));
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_FOREGROUND_INSTALLATION_SUCCEEDED,
@@ -471,9 +497,9 @@
               Eq(1));
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(0));
   EXPECT_THAT(fake_platform_delegate_.GetOnboardingAccepted(), Eq(false));
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_FOREGROUND_INSTALLATION_FAILED,
@@ -499,9 +525,9 @@
       std::make_unique<ScriptParameters>(script_parameters), options));
 
   EXPECT_THAT(fake_platform_delegate_.GetOnboardingAccepted(), Eq(false));
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -528,10 +554,10 @@
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options()));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted::PROACTIVE_TRIGGERING_DISABLED));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -555,10 +581,10 @@
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options()));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted::PROACTIVE_TRIGGERING_DISABLED));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -608,12 +634,12 @@
       std::make_unique<ScriptParameters>(script_parameters), options));
 
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1));
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_FIRST_TIME_USER));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED));
-  EXPECT_TRUE(UkmLiteScriptOnboarding(
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED));
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::FIRST_TIME_USER));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED));
+  EXPECT_TRUE(UkmTriggerScriptOnboarding(
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_ACCEPTED));
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -638,11 +664,11 @@
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options()));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_BASE64_DECODING_ERROR));
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::RETURNING_USER));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::BASE64_DECODING_ERROR));
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -668,10 +694,10 @@
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options()));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted::PROACTIVE_TRIGGERING_DISABLED));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -711,12 +737,12 @@
       std::make_unique<ScriptParameters>(script_parameters), options));
 
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1));
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_FIRST_TIME_USER));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED));
-  EXPECT_TRUE(UkmLiteScriptOnboarding(
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED));
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::FIRST_TIME_USER));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED));
+  EXPECT_TRUE(UkmTriggerScriptOnboarding(
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_ACCEPTED));
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -745,11 +771,11 @@
   EXPECT_CALL(*mock_trigger_script_ui_delegate_, HideTriggerScript);
   fake_platform_delegate_.is_custom_tab_ = false;
   starter_->CheckSettings();
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_CCT_TO_TAB_NOT_SUPPORTED));
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::RETURNING_USER));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::CCT_TO_TAB_NOT_SUPPORTED));
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
 }
 
 TEST_F(StarterTest, CancelPendingTriggerScriptWhenHandlingNewStartupRequest) {
@@ -774,8 +800,8 @@
   starter_->Start(std::make_unique<TriggerContext>(
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options{}));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_CANCELED));
+  EXPECT_TRUE(
+      UkmTriggerScriptFinished(Metrics::TriggerScriptFinishedState::CANCELED));
 }
 
 TEST_F(StarterTest, RegularStartupFailsIfNavigationDuringOnboarding) {
@@ -796,9 +822,9 @@
 
   content::WebContentsTester::For(web_contents())
       ->NavigateAndCommit(GURL("https://www.different.com"));
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -836,13 +862,13 @@
   content::WebContentsTester::For(web_contents())
       ->NavigateAndCommit(GURL("https://www.different.com"));
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_FIRST_TIME_USER));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE));
-  EXPECT_TRUE(UkmLiteScriptOnboarding(
-      Metrics::LiteScriptOnboarding::
-          LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION));
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::FIRST_TIME_USER));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE));
+  EXPECT_TRUE(UkmTriggerScriptOnboarding(
+      Metrics::TriggerScriptOnboarding::
+          ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION));
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -877,9 +903,9 @@
   content::WebContentsTester::For(web_contents())
       ->NavigateAndCommit(GURL("https://www.different.com"));
 
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -910,9 +936,9 @@
       std::make_unique<ScriptParameters>(script_parameters),
       TriggerContext::Options{}));
 
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -924,7 +950,7 @@
   SetupPlatformDelegateForReturningUser();
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_list->InitAndEnableFeature(
-      features::kAutofillAssistantInChromeTriggering);
+      features::kAutofillAssistantInCCTTriggering);
   starter_->CheckSettings();
 
   EXPECT_CALL(*mock_trigger_script_service_request_sender_,
@@ -956,14 +982,14 @@
       ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
   task_environment()->RunUntilIdle();
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER,
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::RETURNING_USER,
+                              GURL("https://www.some-website.com/cart")));
+  EXPECT_TRUE(UkmTriggerScriptFinished(
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED,
       GURL("https://www.some-website.com/cart")));
-  EXPECT_TRUE(UkmLiteScriptFinished(
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED,
-      GURL("https://www.some-website.com/cart")));
-  EXPECT_TRUE(UkmLiteScriptOnboarding(
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED,
+  EXPECT_TRUE(UkmTriggerScriptOnboarding(
+      Metrics::TriggerScriptOnboarding::ONBOARDING_ALREADY_ACCEPTED,
       GURL("https://www.some-website.com/cart")));
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
@@ -976,7 +1002,7 @@
   SetupPlatformDelegateForReturningUser();
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_list->InitAndEnableFeature(
-      features::kAutofillAssistantInChromeTriggering);
+      features::kAutofillAssistantInCCTTriggering);
   fake_platform_delegate_.proactive_help_enabled_ = false;
   starter_->CheckSettings();
 
@@ -992,7 +1018,7 @@
   fake_platform_delegate_.proactive_help_enabled_ = false;
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_list->InitAndEnableFeature(
-      features::kAutofillAssistantInChromeTriggering);
+      features::kAutofillAssistantInCCTTriggering);
   starter_->CheckSettings();
 
   EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
@@ -1013,11 +1039,11 @@
   starter_->CheckSettings();
   task_environment()->RunUntilIdle();
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER,
-      GURL("https://www.some-website.com/cart")));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::RETURNING_USER,
+                              GURL("https://www.some-website.com/cart")));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -1064,11 +1090,11 @@
   simulator->Redirect(GURL("https://signin.example.com"));
   simulator->Commit();
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER,
-      GURL("https://signin.example.com")));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::RETURNING_USER,
+                              GURL("https://signin.example.com")));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -1112,11 +1138,11 @@
   // Note that this impression is recorded for the last URL that a navigation-
   // start event occurred for. We never reached the target domain, so this is
   // unfortunately the best we can do.
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_NAVIGATION_ERROR,
-      GURL("https://redirect.com/to/www/example/com")));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(
+      UkmTriggerScriptStarted(Metrics::TriggerScriptStarted::NAVIGATION_ERROR,
+                              GURL("https://redirect.com/to/www/example/com")));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -1156,11 +1182,10 @@
   simulator->Redirect(GURL(kExampleDeeplink));
   simulator->Commit();
 
-  EXPECT_TRUE(UkmLiteScriptStarted(
-      Metrics::LiteScriptStarted::LITE_SCRIPT_RETURNING_USER,
-      GURL(kExampleDeeplink)));
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_TRUE(UkmTriggerScriptStarted(
+      Metrics::TriggerScriptStarted::RETURNING_USER, GURL(kExampleDeeplink)));
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -1196,9 +1221,9 @@
   simulator->Redirect(GURL(kExampleDeeplink));
   simulator->Commit();
 
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
@@ -1213,7 +1238,7 @@
   fake_platform_delegate_.is_regular_script_running_ = true;
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_list->InitAndEnableFeature(
-      features::kAutofillAssistantInChromeTriggering);
+      features::kAutofillAssistantInCCTTriggering);
   starter_->CheckSettings();
   std::map<std::string, std::string> script_parameters = {
       {"ENABLED", "true"},
@@ -1226,9 +1251,9 @@
       ->NavigateAndCommit(GURL("https://www.example.com/cart"));
 
   task_environment()->RunUntilIdle();
-  EXPECT_FALSE(UkmLiteScriptStarted());
-  EXPECT_FALSE(UkmLiteScriptFinished());
-  EXPECT_FALSE(UkmLiteScriptOnboarding());
+  EXPECT_FALSE(UkmTriggerScriptStarted());
+  EXPECT_FALSE(UkmTriggerScriptFinished());
+  EXPECT_FALSE(UkmTriggerScriptOnboarding());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
   histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
@@ -1237,8 +1262,392 @@
                                      0u);
 }
 
+TEST_F(StarterTest, FailedTriggerScriptFetchesForImplicitStartupAreCached) {
+  SetupPlatformDelegateForReturningUser();
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_,
+              OnSendRequest(
+                  GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+      .WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, std::string()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript).Times(0);
+  EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0);
+
+  // Implicit startup by navigating to an autofill-assistant-enabled site.
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+  EXPECT_THAT(*GetFailedTriggerFetchesCacheForTest(),
+              UnorderedElementsAre(
+                  Pair("some-website.com",
+                       task_environment()->GetMockTickClock()->NowTicks())));
+
+  // Since we failed to communicate with the backend, we won't try again for the
+  // same domain or sub-domain.
+  PrepareTriggerScriptRequestSender();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/checkout"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://some-website.com/signin"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://signin.some-website.com"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // Navigations to different autofill-assistant-enabled URLs will still trigger
+  // implicit startup.
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(1);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.different-website.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
+TEST_F(StarterTest,
+       CancelingTriggerScriptsDenylistsTheDomainForImplicitStartup) {
+  SetupPlatformDelegateForReturningUser();
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_,
+              OnSendRequest(
+                  GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK,
+                                   CreateTriggerScriptResponseForTest()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
+      .WillOnce([&]() {
+        ASSERT_TRUE(trigger_script_coordinator_ != nullptr);
+        trigger_script_coordinator_->PerformTriggerScriptAction(
+            TriggerScriptProto::CANCEL_SESSION);
+      });
+
+  // Implicit startup by navigating to an autofill-assistant-enabled site.
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+  EXPECT_THAT(*GetUserDenylistedCacheForTest(),
+              UnorderedElementsAre(
+                  Pair("some-website.com",
+                       task_environment()->GetMockTickClock()->NowTicks())));
+
+  // Since the user chose CANCEL_SESSION, subsequent navigations to the same
+  // domain or sub-domains should not trigger implicit startup.
+  PrepareTriggerScriptRequestSender();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/checkout"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://some-website.com/signin"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://signin.some-website.com"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // Navigations to different autofill-assistant-enabled URLs will still trigger
+  // implicit startup.
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(1);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.different-website.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
+TEST_F(StarterTest, EmptyTriggerScriptFetchesForImplicitStartupAreCached) {
+  SetupPlatformDelegateForReturningUser();
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_,
+              OnSendRequest(
+                  GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+      .WillOnce(
+          WithArg<2>([&](ServiceRequestSender::ResponseCallback& callback) {
+            // Empty response == no trigger scripts available.
+            std::move(callback).Run(net::HTTP_OK, std::string());
+          }));
+
+  // Implicit startup by navigating to an autofill-assistant-enabled site.
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+  EXPECT_THAT(*GetFailedTriggerFetchesCacheForTest(),
+              UnorderedElementsAre(
+                  Pair("some-website.com",
+                       task_environment()->GetMockTickClock()->NowTicks())));
+
+  // Subsequent navigations to the same domain should not talk to the backend
+  // again. This includes navigations to subdomains etc.
+  PrepareTriggerScriptRequestSender();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/checkout"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://some-website.com/signin"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://signin.some-website.com"));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.some-website.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // However, explicit requests still communicate with the backend.
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(1);
+  std::map<std::string, std::string> script_parameters = {
+      {"ENABLED", "true"},
+      {"START_IMMEDIATELY", "false"},
+      {"REQUEST_TRIGGER_SCRIPT", "true"},
+      {"ORIGINAL_DEEPLINK", "https://www.some-website.com/cart"}};
+  starter_->Start(std::make_unique<TriggerContext>(
+      std::make_unique<ScriptParameters>(script_parameters),
+      TriggerContext::Options{}));
+}
+
+TEST_F(StarterTest, FailedExplicitTriggerFetchesAreCached) {
+  std::map<std::string, std::string> script_parameters = {
+      {"ENABLED", "true"},
+      {"START_IMMEDIATELY", "false"},
+      {"REQUEST_TRIGGER_SCRIPT", "true"}};
+  std::vector<std::string> unsupported_sites = {
+      "https://www.example.com", "https://signing.example.com",
+      "https://different.com", "https://different.com/test?q=12345"};
+  for (const auto& url : unsupported_sites) {
+    content::WebContentsTester::For(web_contents())
+        ->NavigateAndCommit(GURL(url));
+    PrepareTriggerScriptRequestSender();
+    PrepareTriggerScriptUiDelegate();
+    // Send empty response == no trigger script available. Note that explicit
+    // start requests like these will always attempt to talk to the backend, no
+    // matter the cache contents.
+    EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+        .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string()));
+    script_parameters["ORIGINAL_DEEPLINK"] = url;
+    starter_->Start(std::make_unique<TriggerContext>(
+        std::make_unique<ScriptParameters>(script_parameters),
+        TriggerContext::Options{}));
+  }
+  // Cache should contain one entry per organization-identifying domain.
+  base::TimeTicks now_ticks =
+      task_environment()->GetMockTickClock()->NowTicks();
+  EXPECT_THAT(*GetFailedTriggerFetchesCacheForTest(),
+              UnorderedElementsAre(Pair("example.com", now_ticks),
+                                   Pair("different.com", now_ticks)));
+}
+
+TEST_F(StarterTest, FailedImplicitTriggerFetchesAreCached) {
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  std::vector<std::string> implicit_unsupported_sites = {
+      "https://www.example-shopping-site.com/cart",
+      "https://different-shopping-site.com/cart"};
+  for (const auto& url : implicit_unsupported_sites) {
+    PrepareTriggerScriptRequestSender();
+    PrepareTriggerScriptUiDelegate();
+    // Send empty response == no trigger script available.
+    EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+        .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string()));
+    content::WebContentsTester::For(web_contents())
+        ->NavigateAndCommit(GURL(url));
+    task_environment()->RunUntilIdle();
+  }
+  // Failed attempts to start implicitly are added to the cache.
+  base::TimeTicks now_ticks =
+      task_environment()->GetMockTickClock()->NowTicks();
+  EXPECT_THAT(
+      *GetFailedTriggerFetchesCacheForTest(),
+      UnorderedElementsAre(Pair("example-shopping-site.com", now_ticks),
+                           Pair("different-shopping-site.com", now_ticks)));
+}
+
+TEST_F(StarterTest, FailedTriggerFetchesCacheEntriesExpire) {
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  GetFailedTriggerFetchesCacheForTest()->Put(
+      "example.com", task_environment()->GetMockTickClock()->NowTicks());
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string()));
+  task_environment()->FastForwardBy(base::TimeDelta::FromHours(1));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // Since the request failed again, the cache entry should be updated with the
+  // new time.
+  EXPECT_THAT(
+      *GetFailedTriggerFetchesCacheForTest(),
+      UnorderedElementsAre(Pair(
+          "example.com", task_environment()->GetMockTickClock()->NowTicks())));
+}
+
+TEST_F(StarterTest, UserDenylistedCacheUpdateAndExpire) {
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK,
+                                   CreateTriggerScriptResponseForTest()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
+      .WillOnce([&]() {
+        trigger_script_coordinator_->PerformTriggerScriptAction(
+            TriggerScriptProto::CANCEL_SESSION);
+      });
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+  EXPECT_THAT(
+      *GetUserDenylistedCacheForTest(),
+      UnorderedElementsAre(Pair(
+          "example.com", task_environment()->GetMockTickClock()->NowTicks())));
+
+  PrepareTriggerScriptRequestSender();
+  PrepareTriggerScriptUiDelegate();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK,
+                                   CreateTriggerScriptResponseForTest()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
+      .WillOnce([&]() {
+        trigger_script_coordinator_->PerformTriggerScriptAction(
+            TriggerScriptProto::CANCEL_SESSION);
+      });
+  task_environment()->FastForwardBy(base::TimeDelta::FromHours(1));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // Since the request was cancelled again, the cache entry should have been
+  // updated with the new time.
+  EXPECT_THAT(
+      *GetUserDenylistedCacheForTest(),
+      UnorderedElementsAre(Pair(
+          "example.com", task_environment()->GetMockTickClock()->NowTicks())));
+}
+
+TEST_F(StarterTest, RemoveEntryFromCacheOnSuccessForExplicitRequest) {
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+  GetFailedTriggerFetchesCacheForTest()->Put(
+      "example.com", task_environment()->GetMockTickClock()->NowTicks());
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK,
+                                   CreateTriggerScriptResponseForTest()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
+      .WillOnce([&]() {
+        trigger_script_coordinator_->PerformTriggerScriptAction(
+            TriggerScriptProto::ACCEPT);
+      });
+  std::map<std::string, std::string> script_parameters = {
+      {"ENABLED", "true"},
+      {"START_IMMEDIATELY", "false"},
+      {"REQUEST_TRIGGER_SCRIPT", "true"},
+      {"ORIGINAL_DEEPLINK", "https://www.example.com"}};
+  starter_->Start(std::make_unique<TriggerContext>(
+      std::make_unique<ScriptParameters>(script_parameters),
+      TriggerContext::Options{}));
+  EXPECT_THAT(*GetFailedTriggerFetchesCacheForTest(), IsEmpty());
+}
+
+TEST_F(StarterTest, ImplicitInCctTriggeringSmokeTest) {
+  SetupPlatformDelegateForReturningUser();
+  fake_platform_delegate_.is_custom_tab_ = true;
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
+TEST_F(StarterTest, ImplicitInTabTriggeringSmokeTest) {
+  SetupPlatformDelegateForReturningUser();
+  fake_platform_delegate_.is_custom_tab_ = false;
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInTabTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
+TEST_F(StarterTest, ImplicitInCctTriggeringDoesNotTriggerInTab) {
+  SetupPlatformDelegateForReturningUser();
+  fake_platform_delegate_.is_custom_tab_ = false;
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
+TEST_F(StarterTest, ImplicitInTabTriggeringDoesNotTriggerInCct) {
+  SetupPlatformDelegateForReturningUser();
+  fake_platform_delegate_.is_custom_tab_ = true;
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInTabTriggering);
+  starter_->CheckSettings();
+
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .Times(0);
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+}
+
 TEST(MultipleStarterTest, HeuristicUsedByMultipleInstances) {
-  content::BrowserTaskEnvironment task_environment;
+  content::BrowserTaskEnvironment task_environment(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
   content::RenderViewHostTestEnabler rvh_test_enabler;
   content::TestBrowserContext browser_context;
   ukm::TestAutoSetUkmRecorder ukm_recorder;
@@ -1255,11 +1664,13 @@
 
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_list->InitAndEnableFeature(
-      features::kAutofillAssistantInChromeTriggering);
+      features::kAutofillAssistantInCCTTriggering);
   Starter starter_01(web_contents_01.get(), &fake_platform_delegate_01,
-                     &ukm_recorder, mock_runtime_manager.GetWeakPtr());
+                     &ukm_recorder, mock_runtime_manager.GetWeakPtr(),
+                     task_environment.GetMockTickClock());
   Starter starter_02(web_contents_02.get(), &fake_platform_delegate_02,
-                     &ukm_recorder, mock_runtime_manager.GetWeakPtr());
+                     &ukm_recorder, mock_runtime_manager.GetWeakPtr(),
+                     task_environment.GetMockTickClock());
 
   auto service_request_sender_01 =
       std::make_unique<NiceMock<MockServiceRequestSender>>();
@@ -1281,5 +1692,65 @@
   task_environment.RunUntilIdle();
 }
 
-}  // namespace
+TEST_F(StarterTest, StaleCacheEntriesAreRemovedOnInsertingNewEntries) {
+  auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list->InitAndEnableFeature(
+      features::kAutofillAssistantInCCTTriggering);
+  starter_->CheckSettings();
+  base::TimeTicks t0 = task_environment()->GetMockTickClock()->NowTicks();
+  GetFailedTriggerFetchesCacheForTest()->Put("failed-t0.com", t0);
+  GetUserDenylistedCacheForTest()->Put("denylisted-t0.com", t0);
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(30));
+  base::TimeTicks t1 = task_environment()->GetMockTickClock()->NowTicks();
+  EXPECT_THAT(*GetFailedTriggerFetchesCacheForTest(),
+              UnorderedElementsAre(Pair("failed-t0.com", t0)));
+  EXPECT_THAT(*GetUserDenylistedCacheForTest(),
+              UnorderedElementsAre(Pair("denylisted-t0.com", t0)));
+  GetFailedTriggerFetchesCacheForTest()->Put("failed-t1.com", t1);
+  GetUserDenylistedCacheForTest()->Put("denylisted-t1.com", t1);
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(30));
+  base::TimeTicks t2 = task_environment()->GetMockTickClock()->NowTicks();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string()));
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // failed-t0.com should have been removed from the cache due to going stale.
+  EXPECT_THAT(
+      *GetFailedTriggerFetchesCacheForTest(),
+      UnorderedElementsAre(Pair("failed-t1.com", t1), Pair("example.com", t2)));
+  // denylisted-t0.com is stale and will be removed the next time a domain is
+  // denylisted.
+  EXPECT_THAT(*GetUserDenylistedCacheForTest(),
+              UnorderedElementsAre(Pair("denylisted-t0.com", t0),
+                                   Pair("denylisted-t1.com", t1)));
+
+  PrepareTriggerScriptRequestSender();
+  PrepareTriggerScriptUiDelegate();
+  EXPECT_CALL(*mock_trigger_script_service_request_sender_, OnSendRequest)
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK,
+                                   CreateTriggerScriptResponseForTest()));
+  EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
+      .WillOnce([&]() {
+        ASSERT_TRUE(trigger_script_coordinator_ != nullptr);
+        trigger_script_coordinator_->PerformTriggerScriptAction(
+            TriggerScriptProto::CANCEL_SESSION);
+      });
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://supported.com/cart"));
+  task_environment()->RunUntilIdle();
+
+  // No change to the failed fetches cache.
+  EXPECT_THAT(
+      *GetFailedTriggerFetchesCacheForTest(),
+      UnorderedElementsAre(Pair("failed-t1.com", t1), Pair("example.com", t2)));
+  // denylisted-t0.com should have been removed due to going stale.
+  EXPECT_THAT(*GetUserDenylistedCacheForTest(),
+              UnorderedElementsAre(Pair("denylisted-t1.com", t1),
+                                   Pair("supported.com", t2)));
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
index 655b050..0a595842 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -57,7 +57,7 @@
 void TriggerScriptCoordinator::Start(
     const GURL& deeplink_url,
     std::unique_ptr<TriggerContext> trigger_context,
-    base::OnceCallback<void(Metrics::LiteScriptFinishedState,
+    base::OnceCallback<void(Metrics::TriggerScriptFinishedState,
                             std::unique_ptr<TriggerContext>,
                             base::Optional<TriggerScriptProto>)> callback) {
   DCHECK(!callback_);
@@ -84,7 +84,7 @@
     int http_status,
     const std::string& response) {
   if (http_status != net::HTTP_OK) {
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
+    Stop(Metrics::TriggerScriptFinishedState::GET_ACTIONS_FAILED);
     return;
   }
 
@@ -95,12 +95,11 @@
   if (!ProtocolUtils::ParseTriggerScripts(response, &trigger_scripts_,
                                           &additional_allowed_domains_,
                                           &check_interval_ms, &timeout_ms)) {
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR);
+    Stop(Metrics::TriggerScriptFinishedState::GET_ACTIONS_PARSE_ERROR);
     return;
   }
   if (trigger_scripts_.empty()) {
-    Stop(Metrics::LiteScriptFinishedState::
-             LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+    Stop(Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE);
     return;
   }
   trigger_condition_check_interval_ =
@@ -117,9 +116,9 @@
   remaining_trigger_condition_evaluations_ =
       initial_trigger_condition_evaluations_;
 
-  Metrics::RecordLiteScriptShownToUser(
+  Metrics::RecordTriggerScriptShownToUser(
       ukm_recorder_, ukm_source_id_, UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptShownToUser::LITE_SCRIPT_RUNNING);
+      Metrics::TriggerScriptShownToUser::RUNNING);
   ui_delegate_->Attach(this);
   StartCheckingTriggerConditions();
 }
@@ -129,22 +128,20 @@
   switch (action) {
     case TriggerScriptProto::NOT_NOW:
       if (visible_trigger_script_ != -1) {
-        Metrics::RecordLiteScriptShownToUser(
+        Metrics::RecordTriggerScriptShownToUser(
             ukm_recorder_, ukm_source_id_, GetTriggerUiTypeForVisibleScript(),
-            Metrics::LiteScriptShownToUser::LITE_SCRIPT_NOT_NOW);
+            Metrics::TriggerScriptShownToUser::NOT_NOW);
         trigger_scripts_[visible_trigger_script_]
             ->waiting_for_precondition_no_longer_true(true);
         HideTriggerScript();
       }
       return;
     case TriggerScriptProto::CANCEL_SESSION:
-      Stop(Metrics::LiteScriptFinishedState::
-               LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION);
+      Stop(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_SESSION);
       return;
     case TriggerScriptProto::CANCEL_FOREVER:
       starter_delegate_->SetProactiveHelpSettingEnabled(false);
-      Stop(Metrics::LiteScriptFinishedState::
-               LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER);
+      Stop(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_FOREVER);
       return;
     case TriggerScriptProto::SHOW_CANCEL_POPUP:
       NOTREACHED();
@@ -175,35 +172,31 @@
     if (onboardingShown) {
       switch (result) {
         case OnboardingResult::DISMISSED:
-          Metrics::RecordLiteScriptOnboarding(
+          Metrics::RecordTriggerScriptOnboarding(
               ukm_recorder_, ukm_source_id_, trigger_ui_type,
-              Metrics::LiteScriptOnboarding::
-                  LITE_SCRIPT_ONBOARDING_SEEN_AND_DISMISSED);
+              Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_DISMISSED);
           break;
         case OnboardingResult::REJECTED:
-          Metrics::RecordLiteScriptOnboarding(
+          Metrics::RecordTriggerScriptOnboarding(
               ukm_recorder_, ukm_source_id_, trigger_ui_type,
-              Metrics::LiteScriptOnboarding::
-                  LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED);
+              Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_REJECTED);
           break;
         case OnboardingResult::NAVIGATION:
-          Metrics::RecordLiteScriptOnboarding(
+          Metrics::RecordTriggerScriptOnboarding(
               ukm_recorder_, ukm_source_id_, trigger_ui_type,
-              Metrics::LiteScriptOnboarding::
-                  LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION);
+              Metrics::TriggerScriptOnboarding::
+                  ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION);
           break;
         case OnboardingResult::ACCEPTED:
-          Metrics::RecordLiteScriptOnboarding(
+          Metrics::RecordTriggerScriptOnboarding(
               ukm_recorder_, ukm_source_id_, trigger_ui_type,
-              Metrics::LiteScriptOnboarding::
-                  LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED);
+              Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_ACCEPTED);
           break;
       }
     } else {
-      Metrics::RecordLiteScriptOnboarding(
+      Metrics::RecordTriggerScriptOnboarding(
           ukm_recorder_, ukm_source_id_, trigger_ui_type,
-          Metrics::LiteScriptOnboarding::
-              LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED);
+          Metrics::TriggerScriptOnboarding::ONBOARDING_ALREADY_ACCEPTED);
     }
 
     trigger_context_->SetOnboardingShown(onboardingShown);
@@ -213,13 +206,12 @@
       StopCheckingTriggerConditions();
       starter_delegate_->SetOnboardingAccepted(true);
       ui_delegate_->Detach();
-      RunCallback(
-          trigger_ui_type,
-          Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED,
-          trigger_scripts_[visible_trigger_script_]->AsProto());
+      RunCallback(trigger_ui_type,
+                  Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED,
+                  trigger_scripts_[visible_trigger_script_]->AsProto());
     } else if (!IsDialogOnboardingEnabled()) {
-      Stop(Metrics::LiteScriptFinishedState::
-               LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED);
+      Stop(
+          Metrics::TriggerScriptFinishedState::BOTTOMSHEET_ONBOARDING_REJECTED);
     }
   }
 }
@@ -227,12 +219,12 @@
 void TriggerScriptCoordinator::OnBottomSheetClosedWithSwipe() {
   if (visible_trigger_script_ == -1) {
     NOTREACHED();
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_UNKNOWN_FAILURE);
+    Stop(Metrics::TriggerScriptFinishedState::UNKNOWN_FAILURE);
     return;
   }
-  Metrics::RecordLiteScriptShownToUser(
+  Metrics::RecordTriggerScriptShownToUser(
       ukm_recorder_, ukm_source_id_, GetTriggerUiTypeForVisibleScript(),
-      Metrics::LiteScriptShownToUser::LITE_SCRIPT_SWIPE_DISMISSED);
+      Metrics::TriggerScriptShownToUser::SWIPE_DISMISSED);
   PerformTriggerScriptAction(trigger_scripts_[visible_trigger_script_]
                                  ->AsProto()
                                  .on_swipe_to_dismiss());
@@ -257,7 +249,7 @@
 
 void TriggerScriptCoordinator::OnTriggerScriptShown(bool success) {
   if (!success) {
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW);
+    Stop(Metrics::TriggerScriptFinishedState::FAILED_TO_SHOW);
     return;
   }
   // Note: do not update the static trigger conditions here! We should ignore
@@ -266,21 +258,20 @@
   starter_delegate_->SetIsFirstTimeUser(false);
 }
 
-void TriggerScriptCoordinator::Stop(Metrics::LiteScriptFinishedState state) {
+void TriggerScriptCoordinator::Stop(Metrics::TriggerScriptFinishedState state) {
   VLOG(2) << "Stopping with status " << state;
   TriggerUIType trigger_ui_type = GetTriggerUiTypeForVisibleScript();
   HideTriggerScript();
   StopCheckingTriggerConditions();
   ui_delegate_->Detach();
 
-  if (waiting_for_onboarding_ && state ==
-                                     Metrics::LiteScriptFinishedState::
-                                         LITE_SCRIPT_PROMPT_FAILED_NAVIGATE) {
+  if (waiting_for_onboarding_ &&
+      state == Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE) {
     starter_delegate_->HideOnboarding();
-    Metrics::RecordLiteScriptOnboarding(
+    Metrics::RecordTriggerScriptOnboarding(
         ukm_recorder_, ukm_source_id_, trigger_ui_type,
-        Metrics::LiteScriptOnboarding::
-            LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION);
+        Metrics::TriggerScriptOnboarding::
+            ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION);
   }
   waiting_for_onboarding_ = false;
 
@@ -304,7 +295,7 @@
   // (e.g., network connection lost). This will cancel the current trigger
   // script session.
   if (navigation_handle->IsErrorPage()) {
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_NAVIGATION_ERROR);
+    Stop(Metrics::TriggerScriptFinishedState::NAVIGATION_ERROR);
     return;
   }
 
@@ -321,7 +312,7 @@
       VLOG(2) << "\t" << domain;
     }
 #endif
-    Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE);
+    Stop(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE);
     return;
   }
 
@@ -365,8 +356,8 @@
     DCHECK(visible_trigger_script_ == -1);
     // While the tab was invisible, the user may have disabled proactive help.
     if (!starter_delegate_->GetProactiveHelpSettingEnabled()) {
-      Stop(Metrics::LiteScriptFinishedState::
-               LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING);
+      Stop(
+          Metrics::TriggerScriptFinishedState::DISABLED_PROACTIVE_HELP_SETTING);
       return;
     }
     VLOG(2) << "Restarting after tab became visible again";
@@ -381,13 +372,13 @@
 
 void TriggerScriptCoordinator::WebContentsDestroyed() {
   if (!finished_state_recorded_) {
-    Metrics::RecordLiteScriptFinished(
+    Metrics::RecordTriggerScriptFinished(
         ukm_recorder_, ukm_source_id_, GetTriggerUiTypeForVisibleScript(),
         visible_trigger_script_ == -1
-            ? Metrics::LiteScriptFinishedState::
-                  LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE
-            : Metrics::LiteScriptFinishedState::
-                  LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE);
+            ? Metrics::TriggerScriptFinishedState::
+                  WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE
+            : Metrics::TriggerScriptFinishedState::
+                  WEB_CONTENTS_DESTROYED_WHILE_VISIBLE);
     finished_state_recorded_ = true;
   }
 }
@@ -427,9 +418,9 @@
   // GetTriggerUiTypeForVisibleScript() requires visible_trigger_script_ to be
   // set first thing.
 
-  Metrics::RecordLiteScriptShownToUser(
+  Metrics::RecordTriggerScriptShownToUser(
       ukm_recorder_, ukm_source_id_, GetTriggerUiTypeForVisibleScript(),
-      Metrics::LiteScriptShownToUser::LITE_SCRIPT_SHOWN_TO_USER);
+      Metrics::TriggerScriptShownToUser::SHOWN_TO_USER);
   ui_delegate_->ShowTriggerScript(
       trigger_scripts_[index]->AsProto().user_interface());
 }
@@ -474,10 +465,10 @@
   // Trigger condition for the currently shown trigger script is no longer true.
   if (visible_trigger_script_ != -1 &&
       !evaluated_trigger_conditions[visible_trigger_script_]) {
-    Metrics::RecordLiteScriptShownToUser(
+    Metrics::RecordTriggerScriptShownToUser(
         ukm_recorder_, ukm_source_id_, GetTriggerUiTypeForVisibleScript(),
-        Metrics::LiteScriptShownToUser::
-            LITE_SCRIPT_HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE);
+        Metrics::TriggerScriptShownToUser::
+            HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE);
     HideTriggerScript();
     // Do not return here: a different trigger script may have become eligible
     // at the same time.
@@ -525,8 +516,7 @@
     remaining_trigger_condition_evaluations_--;
   }
   if (remaining_trigger_condition_evaluations_ == 0) {
-    Stop(Metrics::LiteScriptFinishedState::
-             LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+    Stop(Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT);
     return;
   }
   content::GetUIThreadTaskRunner({})->PostDelayedTask(
@@ -542,12 +532,12 @@
 
 void TriggerScriptCoordinator::RunCallback(
     TriggerUIType trigger_ui_type,
-    Metrics::LiteScriptFinishedState state,
+    Metrics::TriggerScriptFinishedState state,
     const base::Optional<TriggerScriptProto>& trigger_script) {
   if (!finished_state_recorded_) {
     finished_state_recorded_ = true;
-    Metrics::RecordLiteScriptFinished(ukm_recorder_, ukm_source_id_,
-                                      trigger_ui_type, state);
+    Metrics::RecordTriggerScriptFinished(ukm_recorder_, ukm_source_id_,
+                                         trigger_ui_type, state);
   }
   std::move(callback_).Run(state, std::move(trigger_context_), trigger_script);
 }
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
index 69ca094..ff3bfca 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
@@ -80,14 +80,14 @@
   void Start(const GURL& deeplink_url,
              std::unique_ptr<TriggerContext> trigger_context,
              base::OnceCallback<void(
-                 Metrics::LiteScriptFinishedState result,
+                 Metrics::TriggerScriptFinishedState result,
                  std::unique_ptr<TriggerContext> trigger_context,
                  base::Optional<TriggerScriptProto> trigger_script)> callback);
 
   // Stops the currently running trigger script. Hides any currently shown UI
   // (both trigger script UI and onboarding, if applicable) and returns |state|
   // as the reason for stopping in the pending callback.
-  void Stop(Metrics::LiteScriptFinishedState state);
+  void Stop(Metrics::TriggerScriptFinishedState state);
 
   // Performs |action|. This is usually invoked by the UI as a result of user
   // interactions.
@@ -146,7 +146,7 @@
   void RunOutOfScheduleTriggerConditionCheck();
 
   void RunCallback(TriggerUIType trigger_ui_type,
-                   Metrics::LiteScriptFinishedState state,
+                   Metrics::TriggerScriptFinishedState state,
                    const base::Optional<TriggerScriptProto>& trigger_script);
 
   // Value of trigger_ui_type for the currently visible script, if there is one.
@@ -162,7 +162,7 @@
   std::unique_ptr<UiDelegate> ui_delegate_;
 
   // The callback to run once the current trigger script flow has finished.
-  base::OnceCallback<void(Metrics::LiteScriptFinishedState,
+  base::OnceCallback<void(Metrics::TriggerScriptFinishedState,
                           std::unique_ptr<TriggerContext> trigger_context,
                           base::Optional<TriggerScriptProto>)>
       callback_;
@@ -217,7 +217,7 @@
       base::TimeDelta::FromMilliseconds(1000);
 
   // The number of times the trigger condition may be evaluated. If this reaches
-  // 0, the trigger script stops with |LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT|.
+  // 0, the trigger script stops with |TRIGGER_CONDITION_TIMEOUT|.
   // -1 means no limit.
   //
   // This number is defined by the timeout (specified in proto) divided by
@@ -233,7 +233,7 @@
   ukm::UkmRecorder* const ukm_recorder_;
   const ukm::SourceId ukm_source_id_;
 
-  // Flag to ensure that we only get one LiteScriptFinished event per run.
+  // Flag to ensure that we only get one TriggerScriptFinished event per run.
   bool finished_state_recorded_ = false;
 
   // True while the onboarding is being displayed.
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
index acb9aca..0a605609 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -120,7 +120,7 @@
   }
 
   void AssertRecordedFinishedState(TriggerUIType type,
-                                   Metrics::LiteScriptFinishedState state) {
+                                   Metrics::TriggerScriptFinishedState state) {
     auto entries =
         ukm_recorder_.GetEntriesByName("AutofillAssistant.LiteScriptFinished");
     ASSERT_THAT(entries.size(), Eq(1u));
@@ -134,7 +134,7 @@
   // Make sure that an UKM entry with |state| has been recorded
   // |expected_times|, and has been associated each time with |type|.
   void AssertRecordedShownToUserState(TriggerUIType type,
-                                      Metrics::LiteScriptShownToUser state,
+                                      Metrics::TriggerScriptShownToUser state,
                                       int expected_times) {
     auto entries = ukm_recorder_.GetEntriesByName(
         "AutofillAssistant.LiteScriptShownToUser");
@@ -151,9 +151,9 @@
     EXPECT_EQ(expected_times, actual_times);
   }
 
-  void AssertRecordedLiteScriptOnboardingState(
+  void AssertRecordedTriggerScriptOnboardingState(
       TriggerUIType type,
-      Metrics::LiteScriptOnboarding state,
+      Metrics::TriggerScriptOnboarding state,
       int expected_times) {
     auto entries = ukm_recorder_.GetEntriesByName(
         "AutofillAssistant.LiteScriptOnboarding");
@@ -175,7 +175,7 @@
   NiceMock<MockServiceRequestSender>* mock_request_sender_;
   NiceMock<MockWebController>* mock_web_controller_;
   base::MockCallback<base::OnceCallback<void(
-      Metrics::LiteScriptFinishedState result,
+      Metrics::TriggerScriptFinishedState result,
       std::unique_ptr<TriggerContext> trigger_context,
       base::Optional<TriggerScriptProto> trigger_script)>>
       mock_callback_;
@@ -241,13 +241,12 @@
       .WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, ""));
   EXPECT_CALL(
       mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED, _,
-          _));
+      Run(Metrics::TriggerScriptFinishedState::GET_ACTIONS_FAILED, _, _));
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
   AssertRecordedFinishedState(
       UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
+      Metrics::TriggerScriptFinishedState::GET_ACTIONS_FAILED);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, StopOnParsingError) {
@@ -255,26 +254,26 @@
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "invalid"));
   EXPECT_CALL(
       mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR,
-          _, _));
+      Run(Metrics::TriggerScriptFinishedState::GET_ACTIONS_PARSE_ERROR, _, _));
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
   AssertRecordedFinishedState(
       UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR);
+      Metrics::TriggerScriptFinishedState::GET_ACTIONS_PARSE_ERROR);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, StopOnNoTriggerScriptsAvailable) {
   EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE, _,
+          _));
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
-  AssertRecordedFinishedState(UNSPECIFIED_TRIGGER_UI_TYPE,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+  AssertRecordedFinishedState(
+      UNSPECIFIED_TRIGGER_UI_TYPE,
+      Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, StartChecksStaticAndDynamicConditions) {
@@ -440,14 +439,15 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_SESSION, _,
+          _));
   EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(1);
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::CANCEL_SESSION);
-  AssertRecordedFinishedState(CART_RETURNING_USER,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION);
+  AssertRecordedFinishedState(
+      CART_RETURNING_USER,
+      Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_SESSION);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionCancelForever) {
@@ -469,14 +469,15 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_FOREVER, _,
+          _));
   EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(1);
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::CANCEL_FOREVER);
-  AssertRecordedFinishedState(CART_RETURNING_USER,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER);
+  AssertRecordedFinishedState(
+      CART_RETURNING_USER,
+      Metrics::TriggerScriptFinishedState::PROMPT_FAILED_CANCEL_FOREVER);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionAccept) {
@@ -537,12 +538,11 @@
   // Navigating to non-whitelisted domain is not ok.
   EXPECT_CALL(
       mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE,
-          _, _));
+      Run(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE, _, _));
   SimulateNavigateToUrl(GURL("https://example.different.com/page"));
   AssertRecordedFinishedState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE);
+      Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, IgnoreNavigationEventsWhileNotStarted) {
@@ -580,13 +580,14 @@
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, /* response = */ ""));
   // However, when the tab becomes visible again, the trigger script is
   // restarted and thus fails if the tab is still on an unsupported domain.
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE, _,
+          _));
   SimulateWebContentsVisibilityChanged(content::Visibility::VISIBLE);
-  AssertRecordedFinishedState(UNSPECIFIED_TRIGGER_UI_TYPE,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+  AssertRecordedFinishedState(
+      UNSPECIFIED_TRIGGER_UI_TYPE,
+      Metrics::TriggerScriptFinishedState::NO_TRIGGER_SCRIPT_AVAILABLE);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, BottomSheetClosedWithSwipe) {
@@ -608,8 +609,8 @@
   EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(1);
   coordinator_->OnBottomSheetClosedWithSwipe();
   AssertRecordedShownToUserState(
-      CART_RETURNING_USER,
-      Metrics::LiteScriptShownToUser::LITE_SCRIPT_SWIPE_DISMISSED, 1);
+      CART_RETURNING_USER, Metrics::TriggerScriptShownToUser::SWIPE_DISMISSED,
+      1);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, TimeoutAfterInvisibleForTooLong) {
@@ -639,13 +640,14 @@
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
 
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT, _,
+          _));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   AssertRecordedFinishedState(
       UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+      Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, TimeoutResetsAfterTriggerScriptShown) {
@@ -684,13 +686,14 @@
 
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT, _,
+          _));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   AssertRecordedFinishedState(
       UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+      Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, NoTimeoutByDefault) {
@@ -757,13 +760,14 @@
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
 
-  EXPECT_CALL(mock_callback_, Run(Metrics::LiteScriptFinishedState::
-                                      LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT,
-                                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT, _,
+          _));
   task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
   AssertRecordedFinishedState(
       UNSPECIFIED_TRIGGER_UI_TYPE,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+      Metrics::TriggerScriptFinishedState::TRIGGER_CONDITION_TIMEOUT);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, UrlChangeOutOfScheduleCheckPathMatch) {
@@ -848,8 +852,7 @@
 
   EXPECT_CALL(
       mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE,
-          _, _));
+      Run(Metrics::TriggerScriptFinishedState::PROMPT_FAILED_NAVIGATE, _, _));
   SimulateNavigateToUrl(GURL("http://example.different.com/page"));
 }
 
@@ -869,14 +872,12 @@
   EXPECT_CALL(*mock_ui_delegate_, ShowTriggerScript).WillOnce([&]() {
     coordinator_->OnTriggerScriptShown(/* success = */ false);
   });
-  EXPECT_CALL(
-      mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW, _, _));
+  EXPECT_CALL(mock_callback_,
+              Run(Metrics::TriggerScriptFinishedState::FAILED_TO_SHOW, _, _));
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
   AssertRecordedFinishedState(
-      CART_RETURNING_USER,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW);
+      CART_RETURNING_USER, Metrics::TriggerScriptFinishedState::FAILED_TO_SHOW);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, OnProactiveHelpSettingDisabled) {
@@ -895,16 +896,16 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(mock_callback_,
-              Run(Metrics::LiteScriptFinishedState::
-                      LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING,
-                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::DISABLED_PROACTIVE_HELP_SETTING,
+          _, _));
   fake_platform_delegate_.proactive_help_enabled_ = false;
   SimulateWebContentsInteractabilityChanged(false);
   SimulateWebContentsInteractabilityChanged(true);
-  AssertRecordedFinishedState(UNSPECIFIED_TRIGGER_UI_TYPE,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING);
+  AssertRecordedFinishedState(
+      UNSPECIFIED_TRIGGER_UI_TYPE,
+      Metrics::TriggerScriptFinishedState::DISABLED_PROACTIVE_HELP_SETTING);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabSwitch) {
@@ -968,20 +969,18 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(
-      mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED, _,
-          testing::Optional(response.trigger_scripts(0))));
+  EXPECT_CALL(mock_callback_,
+              Run(Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED, _,
+                  testing::Optional(response.trigger_scripts(0))));
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
 
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1));
-  AssertRecordedLiteScriptOnboardingState(
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED,
-      1);
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_ACCEPTED, 1);
   AssertRecordedFinishedState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED);
 }
 
 TEST_F(TriggerScriptCoordinatorTest,
@@ -1018,32 +1017,29 @@
   fake_platform_delegate_.show_onboarding_result_shown_ = true;
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
 
-  EXPECT_CALL(
-      mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED, _,
-          testing::Optional(response.trigger_scripts(0))));
+  EXPECT_CALL(mock_callback_,
+              Run(Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED, _,
+                  testing::Optional(response.trigger_scripts(0))));
   EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(0);
   fake_platform_delegate_.show_onboarding_result_ = OnboardingResult::ACCEPTED;
   fake_platform_delegate_.show_onboarding_result_shown_ = true;
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
 
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(4));
-  AssertRecordedLiteScriptOnboardingState(
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED,
-      1);
-  AssertRecordedLiteScriptOnboardingState(
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_REJECTED, 1);
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED,
-      1);
-  AssertRecordedLiteScriptOnboardingState(
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_ACCEPTED, 1);
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::
-          LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION,
+      Metrics::TriggerScriptOnboarding::
+          ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION,
       1);
   AssertRecordedFinishedState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED);
 }
 
 TEST_F(TriggerScriptCoordinatorTest,
@@ -1065,10 +1061,10 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(mock_callback_,
-              Run(Metrics::LiteScriptFinishedState::
-                      LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED,
-                  _, _));
+  EXPECT_CALL(
+      mock_callback_,
+      Run(Metrics::TriggerScriptFinishedState::BOTTOMSHEET_ONBOARDING_REJECTED,
+          _, _));
   EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(1);
   EXPECT_CALL(*mock_ui_delegate_, ShowTriggerScript).Times(0);
   fake_platform_delegate_.show_onboarding_result_ = OnboardingResult::REJECTED;
@@ -1076,13 +1072,12 @@
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
 
   EXPECT_THAT(fake_platform_delegate_.num_show_onboarding_called_, Eq(1));
-  AssertRecordedLiteScriptOnboardingState(
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED,
-      1);
-  AssertRecordedFinishedState(CART_RETURNING_USER,
-                              Metrics::LiteScriptFinishedState::
-                                  LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED);
+      Metrics::TriggerScriptOnboarding::ONBOARDING_SEEN_AND_REJECTED, 1);
+  AssertRecordedFinishedState(
+      CART_RETURNING_USER,
+      Metrics::TriggerScriptFinishedState::BOTTOMSHEET_ONBOARDING_REJECTED);
 }
 
 TEST_F(TriggerScriptCoordinatorTest, OnboardingNotShown) {
@@ -1101,22 +1096,19 @@
   coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
                       mock_callback_.Get());
 
-  EXPECT_CALL(
-      mock_callback_,
-      Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED, _,
-          _));
+  EXPECT_CALL(mock_callback_,
+              Run(Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED, _, _));
   EXPECT_CALL(*mock_ui_delegate_, ShowTriggerScript).Times(0);
   fake_platform_delegate_.onboarding_accepted_ = true;
   fake_platform_delegate_.show_onboarding_result_shown_ = false;
   coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
 
-  AssertRecordedLiteScriptOnboardingState(
+  AssertRecordedTriggerScriptOnboardingState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED,
-      1);
+      Metrics::TriggerScriptOnboarding::ONBOARDING_ALREADY_ACCEPTED, 1);
   AssertRecordedFinishedState(
       CART_RETURNING_USER,
-      Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+      Metrics::TriggerScriptFinishedState::PROMPT_SUCCEEDED);
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/user_data.h b/components/autofill_assistant/browser/user_data.h
index e3fc8f0..d2880f1 100644
--- a/components/autofill_assistant/browser/user_data.h
+++ b/components/autofill_assistant/browser/user_data.h
@@ -127,10 +127,6 @@
   std::vector<std::unique_ptr<PaymentInstrument>>
       available_payment_instruments_;
 
-  // The address key requested by the autofill action.
-  std::map<std::string, std::unique_ptr<autofill::AutofillProfile>>
-      selected_addresses_;
-
   base::Optional<WebsiteLoginManager::Login> selected_login_;
 
   // Return true if address has been selected, otherwise return false.
@@ -156,6 +152,13 @@
   base::Optional<autofill::FormData> password_form_data_;
 
   std::string GetAllAddressKeyNames() const;
+
+ private:
+  friend class UserModel;
+  // The address key requested by the autofill action.
+  // Written by |UserModel| to ensure that it stays in sync
+  std::map<std::string, std::unique_ptr<autofill::AutofillProfile>>
+      selected_addresses_;
 };
 
 // Struct for holding the payment request options.
diff --git a/components/autofill_assistant/browser/user_data_util_unittest.cc b/components/autofill_assistant/browser/user_data_util_unittest.cc
index bf19cc3..4db0083 100644
--- a/components/autofill_assistant/browser/user_data_util_unittest.cc
+++ b/components/autofill_assistant/browser/user_data_util_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_model.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_renderer_host.h"
@@ -713,6 +714,7 @@
   std::unique_ptr<content::WebContents> web_contents_;
   MockActionDelegate mock_action_delegate_;
   UserData user_data_;
+  UserModel user_model_;
   MockWebsiteLoginManager mock_website_login_manager_;
 };
 
@@ -744,8 +746,9 @@
   // Middle name is expected to be empty.
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   AutofillValue autofill_value;
   autofill_value.mutable_profile()->set_identifier("contact");
@@ -768,8 +771,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   AutofillValue autofill_value;
   autofill_value.mutable_profile()->set_identifier("contact");
@@ -791,8 +795,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "Jo.h*n", /* middle name */ "",
                                  "Doe", "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   AutofillValueRegexp autofill_value;
   autofill_value.mutable_profile()->set_identifier("contact");
@@ -949,8 +954,9 @@
                                     autofill::test::kEmptyOrigin);
   autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
                                  "", "", "", "", "", "", "", "", "");
-  user_data_.selected_addresses_["contact"] =
-      std::make_unique<autofill::AutofillProfile>(contact);
+  user_model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(contact),
+      &user_data_);
 
   TextValue text_value;
   AutofillValue* autofill_value = text_value.mutable_autofill_value();
diff --git a/components/autofill_assistant/browser/user_model.cc b/components/autofill_assistant/browser/user_model.cc
index f7c2c94..ba125fb0 100644
--- a/components/autofill_assistant/browser/user_model.cc
+++ b/components/autofill_assistant/browser/user_model.cc
@@ -168,6 +168,32 @@
   current_url_ = current_url;
 }
 
+void UserModel::SetSelectedAutofillProfile(
+    const std::string& profile_name,
+    std::unique_ptr<autofill::AutofillProfile> profile,
+    UserData* user_data) {
+  // Set the profile in the UserModel.
+  auto user_model_it = selected_profiles_.find(profile_name);
+  if (user_model_it != selected_profiles_.end()) {
+    selected_profiles_.erase(user_model_it);
+  }
+  if (profile != nullptr) {
+    selected_profiles_.emplace(
+        profile_name, std::make_unique<autofill::AutofillProfile>(*profile));
+  }
+
+  // Set the profile in the UserData.
+  // TODO(b/187286050): migrate to UserModel so that we can avoid this
+  // duplication.
+  auto user_data_it = user_data->selected_addresses_.find(profile_name);
+  if (user_data_it != user_data->selected_addresses_.end()) {
+    user_data->selected_addresses_.erase(user_data_it);
+  }
+  if (profile != nullptr) {
+    user_data->selected_addresses_.emplace(profile_name, std::move(profile));
+  }
+}
+
 const autofill::CreditCard* UserModel::GetCreditCard(
     const std::string& guid) const {
   auto it = credit_cards_.find(guid);
@@ -186,6 +212,15 @@
   return it->second.get();
 }
 
+const autofill::AutofillProfile* UserModel::GetSelectedAutofillProfile(
+    const std::string& profile_name) const {
+  auto it = selected_profiles_.find(profile_name);
+  if (it == selected_profiles_.end()) {
+    return nullptr;
+  }
+  return it->second.get();
+}
+
 GURL UserModel::GetCurrentURL() const {
   return current_url_;
 }
diff --git a/components/autofill_assistant/browser/user_model.h b/components/autofill_assistant/browser/user_model.h
index c1c88811..8f787d0 100644
--- a/components/autofill_assistant/browser/user_model.h
+++ b/components/autofill_assistant/browser/user_model.h
@@ -16,6 +16,7 @@
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill_assistant/browser/model.pb.h"
+#include "components/autofill_assistant/browser/user_data.h"
 #include "components/autofill_assistant/browser/value_util.h"
 #include "url/gurl.h"
 
@@ -86,6 +87,14 @@
       std::unique_ptr<std::vector<std::unique_ptr<autofill::AutofillProfile>>>
           profiles);
 
+  // Sets the selected autofill profile for |profile_name|. A nullptr |profile|
+  // will clear the entry. The profile is also set in |user_data|.
+  // TODO(b/187286050) complete the migration to UserModel and remove UserData.
+  void SetSelectedAutofillProfile(
+      const std::string& profile_name,
+      std::unique_ptr<autofill::AutofillProfile> profile,
+      UserData* user_data);
+
   void SetCurrentURL(GURL current_url);
 
   // Returns the credit card with |guid| or nullptr if there is no such card.
@@ -94,6 +103,11 @@
   // Returns the profile with |guid| or nullptr if there is no such profile.
   const autofill::AutofillProfile* GetProfile(const std::string& guid) const;
 
+  // Returns the selected profile for the specified |profile_name| or nullptr if
+  // there is no such profile.
+  const autofill::AutofillProfile* GetSelectedAutofillProfile(
+      const std::string& profile_name) const;
+
   GURL GetCurrentURL() const;
 
   void AddObserver(Observer* observer);
@@ -113,8 +127,13 @@
   friend class UserModelTest;
 
   std::map<std::string, ValueProto> values_;
+  // Guid to credit card map.
   std::map<std::string, std::unique_ptr<autofill::CreditCard>> credit_cards_;
+  // Guid to profile map.
   std::map<std::string, std::unique_ptr<autofill::AutofillProfile>> profiles_;
+  // Profile name to profile map.
+  std::map<std::string, std::unique_ptr<autofill::AutofillProfile>>
+      selected_profiles_;
   GURL current_url_;
   base::ObserverList<Observer> observers_;
   base::WeakPtrFactory<UserModel> weak_ptr_factory_{this};
diff --git a/components/autofill_assistant/browser/user_model_unittest.cc b/components/autofill_assistant/browser/user_model_unittest.cc
index 799d606..1e58192 100644
--- a/components/autofill_assistant/browser/user_model_unittest.cc
+++ b/components/autofill_assistant/browser/user_model_unittest.cc
@@ -14,6 +14,7 @@
 using ::testing::_;
 using ::testing::Eq;
 using ::testing::InSequence;
+using ::testing::IsNull;
 using ::testing::Pair;
 using ::testing::Property;
 using ::testing::SizeIs;
@@ -366,4 +367,22 @@
   EXPECT_TRUE(GetValues().at("identifier").is_client_side_only());
 }
 
+TEST_F(UserModelTest, SetSelectedAutofillProfile) {
+  autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+  autofill::test::SetProfileInfo(
+      &profile, "Marion", "Mitchell", "Morrison", "marion@me.xyz", "Fox",
+      "123 Zoo St.", "unit 5", "Hollywood", "CA", "91601", "US", "16505678910");
+
+  UserData user_data;
+  model_.SetSelectedAutofillProfile(
+      "contact", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
+  EXPECT_THAT(model_.GetSelectedAutofillProfile("contact")->Compare(profile),
+              Eq(0));
+  EXPECT_THAT(user_data.selected_address("contact")->Compare(profile), Eq(0));
+  model_.SetSelectedAutofillProfile("contact", nullptr, &user_data);
+  EXPECT_THAT(model_.GetSelectedAutofillProfile("contact"), IsNull());
+  EXPECT_THAT(user_data.selected_address("contact"), IsNull());
+}
+
 }  // namespace autofill_assistant
diff --git a/components/browser_ui/site_settings/android/features.cc b/components/browser_ui/site_settings/android/features.cc
index 4a6a5e9..1ea52af 100644
--- a/components/browser_ui/site_settings/android/features.cc
+++ b/components/browser_ui/site_settings/android/features.cc
@@ -10,6 +10,6 @@
 namespace browser_ui {
 
 const base::Feature kActionableContentSettings{
-    "ActionableContentSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+    "ActionableContentSettings", base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace browser_ui
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
index b3db4a4..6c82eb7 100644
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -506,9 +506,6 @@
       <message name="IDS_PAGE_INFO_INSTANT_APP_BUTTON" desc="Text in the button that opens an Android Instant app that is associated with the website's URL.">
         Open Instant App
       </message>
-      <message name="IDS_PAGE_INFO_PREVIEW_MESSAGE" desc="This text is displayed in the page info bubble when the currently viewed page has been modified by Google to be a lighter and faster version of the original page. The word 'Lite' should match the translation in TC ID 1019734090540434451">
-        Lite page provided by Google
-      </message>
       <message name="IDS_PAGE_INFO_LITE_MODE_HTTPS_IMAGE_COMPRESSION" desc="This text is displayed in the page info bubble when the currently viewed page has https images that were optimized by Google">
         To save you data, this page's images have been optimized by Google.
       </message>
diff --git a/components/components_strings.grd b/components/components_strings.grd
index 1894ac7..346579e 100644
--- a/components/components_strings.grd
+++ b/components/components_strings.grd
@@ -293,6 +293,7 @@
       <part file="browsing_data_strings.grdp" />
       <part file="live_caption_strings.grdp" />
       <part file="components_settings_strings.grdp" />
+      <part file="content_creation_strings.grdp" />
       <part file="crash_strings.grdp" />
       <part file="dialog_strings.grdp" />
       <part file="dom_distiller_strings.grdp" />
diff --git a/components/content_creation_strings.grdp b/components/content_creation_strings.grdp
new file mode 100644
index 0000000..7c97e48
--- /dev/null
+++ b/components/content_creation_strings.grdp
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+
+<if expr="is_android">
+  <!-- Note Template Names, currently only used on Android. -->
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_CLASSIC" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Classic
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRIENDLY" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Friendly
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRESH" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Fresh
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_POWERFUL" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Powerful
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_IMPACTFUL" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Impactful
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_LOVELY" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Lovely
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_GROOVY" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Groovy
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_MONOCHROME" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Monochrome
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_BOLD" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Bold
+  </message>
+  <message name="IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_DREAMY" desc="Name for a styled template which creates a nice looking note from text. The name is loosely connected with the font and color of the template. [CHAR_LIMIT=25]">
+    Dreamy
+  </message>
+</if>
+
+</grit-part>
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_BOLD.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_BOLD.png.sha1
new file mode 100644
index 0000000..3bce3c4
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_BOLD.png.sha1
@@ -0,0 +1 @@
+fe59f2de1e18f6fe91cb1f01c5c8937f9ec1fa27
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_CLASSIC.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_CLASSIC.png.sha1
new file mode 100644
index 0000000..fe40425
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_CLASSIC.png.sha1
@@ -0,0 +1 @@
+af50f1404d15631c99e56eed776219be2cc8cbb2
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_DREAMY.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_DREAMY.png.sha1
new file mode 100644
index 0000000..b4daf51
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_DREAMY.png.sha1
@@ -0,0 +1 @@
+f6f8ef6e099496dc9e32bf86663fe2b7b8aa5db3
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRESH.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRESH.png.sha1
new file mode 100644
index 0000000..c812ef2
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRESH.png.sha1
@@ -0,0 +1 @@
+433f4d040b9688535c32ffc08210345aaf9b51e6
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRIENDLY.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRIENDLY.png.sha1
new file mode 100644
index 0000000..fbe1b843
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_FRIENDLY.png.sha1
@@ -0,0 +1 @@
+00c65bdebb3c76db095bd1fea74b16aef9f3cca9
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_GROOVY.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_GROOVY.png.sha1
new file mode 100644
index 0000000..a4026b7
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_GROOVY.png.sha1
@@ -0,0 +1 @@
+06201317a487f27b40f04de4a15577e6240d6b54
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_IMPACTFUL.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_IMPACTFUL.png.sha1
new file mode 100644
index 0000000..e5d4402
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_IMPACTFUL.png.sha1
@@ -0,0 +1 @@
+b4dd462e915eef684826514e6aebdd8c7c353655
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_LOVELY.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_LOVELY.png.sha1
new file mode 100644
index 0000000..3e60819
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_LOVELY.png.sha1
@@ -0,0 +1 @@
+52c280faaef8fb439342573f5ee8a13652f52fab
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_MONOCHROME.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_MONOCHROME.png.sha1
new file mode 100644
index 0000000..094812a
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_MONOCHROME.png.sha1
@@ -0,0 +1 @@
+b7f1a4e5640f98b4cc232c8e4f1ce7afa057f61f
\ No newline at end of file
diff --git a/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_POWERFUL.png.sha1 b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_POWERFUL.png.sha1
new file mode 100644
index 0000000..84e1eba
--- /dev/null
+++ b/components/content_creation_strings_grdp/IDS_CONTENT_CREATION_NOTE_TEMPLATE_NAME_POWERFUL.png.sha1
@@ -0,0 +1 @@
+8619cdbfc0d0adb077032ecffb9842d8392c3312
\ No newline at end of file
diff --git a/components/cronet/OWNERS b/components/cronet/OWNERS
index 15c012eb..ace4d68 100644
--- a/components/cronet/OWNERS
+++ b/components/cronet/OWNERS
@@ -1,2 +1,5 @@
+cleborgne@google.com
+danstahr@google.com
+sporeba@google.com
 torne@chromium.org
 file://net/OWNERS
diff --git a/components/cronet/ios/test/cronet_test_base.mm b/components/cronet/ios/test/cronet_test_base.mm
index 36e3562..79455ed0 100644
--- a/components/cronet/ios/test/cronet_test_base.mm
+++ b/components/cronet/ios/test/cronet_test_base.mm
@@ -41,6 +41,7 @@
 }
 
 - (void)reset {
+  _semaphores = [NSMutableDictionary dictionaryWithCapacity:0];
   _responseDataPerTask = [NSMutableDictionary dictionaryWithCapacity:0];
   _errorPerTask = [NSMutableDictionary dictionaryWithCapacity:0];
   _totalBytesReceivedPerTask = [NSMutableDictionary dictionaryWithCapacity:0];
@@ -107,11 +108,12 @@
 // nanoseconds, a value of 0 or less means do not ever time out.
 - (BOOL)waitForDone:(NSURLSessionDataTask*)task
         withTimeout:(int64_t)timeout_ns {
-  dispatch_semaphore_t _semaphore = [self getSemaphoreForTask:task];
+  BOOL request_completed = NO;
+  dispatch_semaphore_t semaphore = [self getSemaphoreForTask:task];
   if (timeout_ns > 0) {
-    BOOL request_completed =
+    request_completed =
         dispatch_semaphore_wait(
-            _semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout_ns)) == 0;
+            semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout_ns)) == 0;
     if (!request_completed) {
       // Cancel the pending request; otherwise, the request is still active and
       // may invoke the delegate methods later.
@@ -120,11 +122,18 @@
       // Give the canceled request some time to execute didCompleteWithError
       // method with NSURLErrorCancelled error code.
       dispatch_semaphore_wait(
-          _semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
+          semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
     }
-    return request_completed;
+  } else {
+    request_completed =
+        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) == 0;
   }
-  return dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER) == 0;
+  @synchronized(_semaphores) {
+    if (request_completed) {
+      [_semaphores removeObjectForKey:task];
+    }
+  }
+  return request_completed;
 }
 
 - (void)URLSession:(NSURLSession*)session
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
index ffccd0ef..f8765ae6 100644
--- a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
+++ b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -321,6 +321,9 @@
     // at least one span from the free lists.
     MemoryUsageChanged(heap_->GetSize(), heap_->GetFreelistSize());
 
+    // Memory in this span is no longer held in the freelist, so we don't want
+    // to count it towards the total of dirty freelist memory.
+    heap_->dirty_freed_memory_page_count_ -= free_span->MarkAsClean();
     auto discardable_memory =
         std::make_unique<DiscardableMemoryImpl>(this, std::move(free_span));
     allocated_memory_.insert(discardable_memory.get());
@@ -373,7 +376,7 @@
             reinterpret_cast<size_t>(leftover->shared_memory()->memory()),
         leftover->length() * base::GetPageSize());
     leftover->set_is_locked(false);
-    heap_->MergeIntoFreeLists(std::move(leftover));
+    heap_->MergeIntoFreeListsClean(std::move(leftover));
   }
 
   if (pages >= allocation_pages) {
@@ -405,6 +408,11 @@
     base::UmaHistogramCounts1M("Memory.Discardable.Size.Foreground",
                                total_size - freelist_size);
   }
+
+  base::UmaHistogramCounts1M(
+      "Memory.Discardable.FreelistSize.Dirty",
+      heap_->dirty_freed_memory_page_count_ * base::GetPageSize() / 1024);
+
   return heap_->OnMemoryDump(args, pmd);
 }
 
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc b/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
index 1d425615..8e150a4 100644
--- a/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
+++ b/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
@@ -65,6 +65,11 @@
     return heap_->GetFreelistSize();
   }
 
+  size_t GetDirtyFreedMemoryPageCount() const {
+    base::AutoLock lock(lock_);
+    return heap_->dirty_freed_memory_page_count_;
+  }
+
   bool IsPurgeScheduled() const {
     base::AutoLock lock(lock_);
     return is_purge_scheduled_;
@@ -458,5 +463,79 @@
   EXPECT_FALSE(client->IsPurgeScheduled());
 }
 
+TEST_F(ClientDiscardableSharedMemoryManagerTest, MarkDirtyFreelistPages) {
+  auto client =
+      base::MakeRefCounted<TestClientDiscardableSharedMemoryManager>();
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  auto mem1 = client->AllocateLockedDiscardableMemory(base::GetPageSize() / 2u);
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  auto mem2 =
+      client->AllocateLockedDiscardableMemory(base::GetPageSize() * 1.2);
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  // Allocate 5 MiB. This is to test large allocations, which are special-cased
+  // when allocating.
+  auto mem3 = client->AllocateLockedDiscardableMemory(5 * 1024 * 1024);
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  mem1 = nullptr;
+
+  ASSERT_EQ(1u, client->GetDirtyFreedMemoryPageCount());
+
+  mem2 = nullptr;
+
+  // Allocations on done in multiples of the page size, so we have 3 pages
+  // dirtied, even though we only actually touched 1.7 pages (since the 0.5 page
+  // allocation used 1 page, and the 1.2 page allocation used 2).
+  ASSERT_EQ(3u, client->GetDirtyFreedMemoryPageCount());
+
+  mem3 = nullptr;
+
+  ASSERT_EQ(1283u, client->GetDirtyFreedMemoryPageCount());
+
+  client->ReleaseFreeMemory();
+
+  // All pages should be freed now, so there are no dirty pages in the freelist.
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+}
+
+TEST_F(ClientDiscardableSharedMemoryManagerTest,
+       MarkDirtyFreelistPagesReleaseFreeListPages) {
+  base::test::ScopedFeatureList fl;
+  fl.InitAndEnableFeature(discardable_memory::kReleaseDiscardableFreeListPages);
+  auto client =
+      base::MakeRefCounted<TestClientDiscardableSharedMemoryManager>();
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  auto mem1 = client->AllocateLockedDiscardableMemory(base::GetPageSize() / 2u);
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  auto mem2 =
+      client->AllocateLockedDiscardableMemory(base::GetPageSize() * 1.2);
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  mem1 = nullptr;
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  mem2 = nullptr;
+
+  // Freelist memory is released immediately, so there's no dirty memory.
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+
+  client->ReleaseFreeMemory();
+
+  ASSERT_EQ(0u, client->GetDirtyFreedMemoryPageCount());
+}
+
 }  // namespace
 }  // namespace discardable_memory
diff --git a/components/discardable_memory/common/discardable_shared_memory_heap.cc b/components/discardable_memory/common/discardable_shared_memory_heap.cc
index b0751f27..5a80323 100644
--- a/components/discardable_memory/common/discardable_shared_memory_heap.cc
+++ b/components/discardable_memory/common/discardable_shared_memory_heap.cc
@@ -36,31 +36,70 @@
 DiscardableSharedMemoryHeap::Span::Span(
     base::DiscardableSharedMemory* shared_memory,
     size_t start,
-    size_t length)
-    : shared_memory_(shared_memory),
+    size_t length,
+    DiscardableSharedMemoryHeap::ScopedMemorySegment* memory_segment)
+    : memory_segment_(memory_segment),
+      shared_memory_(shared_memory),
       start_(start),
       length_(length),
       is_locked_(false) {}
 
-DiscardableSharedMemoryHeap::Span::~Span() {}
-
 DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment(
     DiscardableSharedMemoryHeap* heap,
     std::unique_ptr<base::DiscardableSharedMemory> shared_memory,
     size_t size,
     int32_t id,
     base::OnceClosure deleted_callback)
-    : heap_(heap),
+    : dirty_pages_(std::vector<bool>(size / base::GetPageSize())),
+      heap_(heap),
       shared_memory_(std::move(shared_memory)),
       size_(size),
       id_(id),
       deleted_callback_(std::move(deleted_callback)) {}
 
+size_t DiscardableSharedMemoryHeap::Span::MarkAsClean() {
+  return memory_segment_->MarkPages(start_, length_, false);
+}
+
+size_t DiscardableSharedMemoryHeap::Span::MarkAsDirty() {
+  return memory_segment_->MarkPages(start_, length_, true);
+}
+
+DiscardableSharedMemoryHeap::ScopedMemorySegment*
+DiscardableSharedMemoryHeap::Span::GetScopedMemorySegmentForTesting() const {
+  return memory_segment_;
+}
+
 DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() {
+  heap_->dirty_freed_memory_page_count_ -= MarkPages(
+      reinterpret_cast<size_t>(shared_memory_->memory()) / base::GetPageSize(),
+      dirty_pages_.size(), false);
   heap_->ReleaseMemory(shared_memory_.get(), size_);
   std::move(deleted_callback_).Run();
 }
 
+size_t DiscardableSharedMemoryHeap::ScopedMemorySegment::MarkPages(
+    size_t start,
+    size_t length,
+    bool value) {
+  if (!shared_memory_)
+    return 0;
+
+  const size_t offset =
+      start -
+      reinterpret_cast<size_t>(shared_memory_->memory()) / base::GetPageSize();
+
+  size_t tmp = 0;
+  for (size_t i = offset; i < offset + length; i++) {
+    if (dirty_pages_[i] != value) {
+      dirty_pages_[i] = value;
+      tmp++;
+    }
+  }
+
+  return tmp;
+}
+
 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const {
   return heap_->IsMemoryUsed(shared_memory_.get(), size_);
 }
@@ -74,6 +113,11 @@
   return shared_memory_.get() == span->shared_memory();
 }
 
+size_t DiscardableSharedMemoryHeap::ScopedMemorySegment::CountMarkedPages()
+    const {
+  return std::count(dirty_pages_.begin(), dirty_pages_.end(), true);
+}
+
 base::trace_event::MemoryAllocatorDump*
 DiscardableSharedMemoryHeap::ScopedMemorySegment::CreateMemoryAllocatorDump(
     Span* span,
@@ -124,10 +168,13 @@
   DCHECK(base::IsAligned(shared_memory->memory(), block_size_));
   DCHECK(base::IsAligned(size, block_size_));
 
-  std::unique_ptr<Span> span(
-      new Span(shared_memory.get(),
-               reinterpret_cast<size_t>(shared_memory->memory()) / block_size_,
-               size / block_size_));
+  auto* raw_shared_memory = shared_memory.get();
+  auto scoped_memory_segment = std::make_unique<ScopedMemorySegment>(
+      this, std::move(shared_memory), size, id, std::move(deleted_callback));
+  std::unique_ptr<Span> span(new Span(
+      raw_shared_memory,
+      reinterpret_cast<size_t>(raw_shared_memory->memory()) / block_size_,
+      size / block_size_, scoped_memory_segment.get()));
   DCHECK(spans_.find(span->start_) == spans_.end());
   DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end());
   RegisterSpan(span.get());
@@ -135,18 +182,22 @@
   num_blocks_ += span->length_;
 
   // Start tracking if segment is resident by adding it to |memory_segments_|.
-  memory_segments_.push_back(std::make_unique<ScopedMemorySegment>(
-      this, std::move(shared_memory), size, id, std::move(deleted_callback)));
+  memory_segments_.push_back(std::move(scoped_memory_segment));
 
   return span;
 }
 
 void DiscardableSharedMemoryHeap::MergeIntoFreeLists(
     std::unique_ptr<Span> span) {
-  DCHECK(span->shared_memory_);
+  if (!base::FeatureList::IsEnabled(kReleaseDiscardableFreeListPages)) {
+    dirty_freed_memory_page_count_ += span->MarkAsDirty();
+  }
+  MergeIntoFreeListsClean(std::move(span));
+}
 
-  // First add length of |span| to |num_free_blocks_|.
-  num_free_blocks_ += span->length_;
+void DiscardableSharedMemoryHeap::MergeIntoFreeListsClean(
+    std::unique_ptr<Span> span) {
+  DCHECK(span->shared_memory_);
 
   if (base::FeatureList::IsEnabled(kReleaseDiscardableFreeListPages)) {
     SCOPED_UMA_HISTOGRAM_SHORT_TIMER("Memory.Discardable.FreeListReleaseTime");
@@ -167,6 +218,9 @@
         offset, span->length_ * base::GetPageSize());
   }
 
+  // First add length of |span| to |num_free_blocks_|.
+  num_free_blocks_ += span->length_;
+
   // Merge with previous span if possible.
   auto prev_it = spans_.find(span->start_ - 1);
   if (prev_it != spans_.end() && IsInFreeList(prev_it->second)) {
@@ -200,8 +254,9 @@
   DCHECK(blocks);
   DCHECK_LT(blocks, span->length_);
 
-  std::unique_ptr<Span> leftover(new Span(
-      span->shared_memory_, span->start_ + blocks, span->length_ - blocks));
+  std::unique_ptr<Span> leftover(
+      new Span(span->shared_memory_, span->start_ + blocks,
+               span->length_ - blocks, span->memory_segment_));
   DCHECK(leftover->length_ == 1 ||
          spans_.find(leftover->start_) == spans_.end());
   RegisterSpan(leftover.get());
@@ -363,8 +418,9 @@
 
   const size_t extra = serving->length_ - blocks;
   if (extra) {
-    std::unique_ptr<Span> leftover(
-        new Span(serving->shared_memory_, serving->start_ + blocks, extra));
+    std::unique_ptr<Span> leftover(new Span(serving->shared_memory_,
+                                            serving->start_ + blocks, extra,
+                                            serving->memory_segment_));
     leftover->set_is_locked(false);
     DCHECK(extra == 1 || spans_.find(leftover->start_) == spans_.end());
     RegisterSpan(leftover.get());
diff --git a/components/discardable_memory/common/discardable_shared_memory_heap.h b/components/discardable_memory/common/discardable_shared_memory_heap.h
index d4de3fe..60561900 100644
--- a/components/discardable_memory/common/discardable_shared_memory_heap.h
+++ b/components/discardable_memory/common/discardable_shared_memory_heap.h
@@ -14,6 +14,7 @@
 
 #include "base/callback.h"
 #include "base/containers/linked_list.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "components/discardable_memory/common/discardable_memory_export.h"
@@ -24,26 +25,43 @@
 
 namespace discardable_memory {
 
+DISCARDABLE_MEMORY_EXPORT extern const base::Feature
+    kReleaseDiscardableFreeListPages;
+
 // Implements a heap of discardable shared memory. An array of free lists
 // is used to keep track of free blocks.
 class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryHeap {
+ private:
+  class ScopedMemorySegment;
+
  public:
   class DISCARDABLE_MEMORY_EXPORT Span : public base::LinkNode<Span> {
    public:
-    ~Span();
+    ~Span() = default;
 
     base::DiscardableSharedMemory* shared_memory() { return shared_memory_; }
     size_t start() const { return start_; }
     size_t length() const { return length_; }
     void set_is_locked(bool is_locked) { is_locked_ = is_locked; }
 
+    // Marks all bytes in this Span as dirty, returns the number of pages
+    // marked as dirty this way.
+    size_t MarkAsDirty();
+    // Marks all bytes in this Span as non-dirty, returning the number of
+    // pages marked as non-dirty this way.
+    size_t MarkAsClean();
+
+    ScopedMemorySegment* GetScopedMemorySegmentForTesting() const;
+
    private:
     friend class DiscardableSharedMemoryHeap;
 
     Span(base::DiscardableSharedMemory* shared_memory,
          size_t start,
-         size_t length);
+         size_t length,
+         DiscardableSharedMemoryHeap::ScopedMemorySegment* memory_segment);
 
+    DiscardableSharedMemoryHeap::ScopedMemorySegment* const memory_segment_;
     base::DiscardableSharedMemory* shared_memory_;
     size_t start_;
     size_t length_;
@@ -69,6 +87,11 @@
   // neighboring free spans when possible.
   void MergeIntoFreeLists(std::unique_ptr<Span> span);
 
+  // Same as |MergeIntoFreeLists|, but doesn't mark the memory in the span as
+  // dirtied (this is used for keeping track of how much memory is dirtied in
+  // the freelist at any given time.
+  void MergeIntoFreeListsClean(std::unique_ptr<Span> span);
+
   // Split an allocated span into two spans, one of length |blocks| followed
   // by another span of length "span->length - blocks" blocks. Modifies |span|
   // to point to the first span of length |blocks|. Return second span.
@@ -104,8 +127,10 @@
       const char* name,
       base::trace_event::ProcessMemoryDump* pmd) const;
 
+  size_t dirty_freed_memory_page_count_ = 0;
+
  private:
-  class ScopedMemorySegment {
+  class DISCARDABLE_MEMORY_EXPORT ScopedMemorySegment {
    public:
     ScopedMemorySegment(
         DiscardableSharedMemoryHeap* heap,
@@ -120,6 +145,8 @@
 
     bool ContainsSpan(Span* span) const;
 
+    size_t CountMarkedPages() const;
+
     base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
         Span* span,
         size_t block_size,
@@ -129,7 +156,10 @@
     // Used for dumping memory statistics from the segment to chrome://tracing.
     void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) const;
 
+    size_t MarkPages(size_t start, size_t length, bool value);
+
    private:
+    std::vector<bool> dirty_pages_;
     DiscardableSharedMemoryHeap* const heap_;
     std::unique_ptr<base::DiscardableSharedMemory> shared_memory_;
     const size_t size_;
diff --git a/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc b/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
index f4ff0ec..94a6ed0 100644
--- a/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
+++ b/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
@@ -441,5 +441,52 @@
   heap.MergeIntoFreeLists(std::move(span));
 }
 
+TEST(DiscardableSharedMemoryHeapTest, MarkSpans) {
+  DiscardableSharedMemoryHeap heap;
+
+  const size_t block_size = base::GetPageSize();
+
+  auto memory = std::make_unique<base::DiscardableSharedMemory>();
+  ASSERT_TRUE(memory->CreateAndMap(block_size));
+  auto span = heap.Grow(std::move(memory), block_size, 1, base::DoNothing());
+
+  auto* memory_segment = span->GetScopedMemorySegmentForTesting();
+
+  ASSERT_EQ(0u, memory_segment->CountMarkedPages());
+  ASSERT_EQ(0u, heap.dirty_freed_memory_page_count_);
+
+  heap.MergeIntoFreeLists(std::move(span));
+
+  ASSERT_EQ(1u, memory_segment->CountMarkedPages());
+  ASSERT_EQ(1u, heap.dirty_freed_memory_page_count_);
+
+  memory = std::make_unique<base::DiscardableSharedMemory>();
+  ASSERT_TRUE(memory->CreateAndMap(2 * block_size));
+  span = heap.Grow(std::move(memory), 2 * block_size, 1, base::DoNothing());
+
+  ASSERT_EQ(1u, heap.dirty_freed_memory_page_count_);
+
+  memory_segment = span->GetScopedMemorySegmentForTesting();
+
+  ASSERT_EQ(0u, memory_segment->CountMarkedPages());
+
+  ASSERT_EQ(1u, heap.dirty_freed_memory_page_count_);
+  ASSERT_EQ(1 * block_size, heap.GetFreelistSize());
+
+  heap.ReleaseFreeMemory();
+
+  ASSERT_EQ(0 * block_size, heap.GetFreelistSize());
+  ASSERT_EQ(0u, heap.dirty_freed_memory_page_count_);
+
+  heap.MergeIntoFreeLists(std::move(span));
+
+  ASSERT_EQ(2u, memory_segment->CountMarkedPages());
+  ASSERT_EQ(2u, heap.dirty_freed_memory_page_count_);
+
+  heap.ReleaseFreeMemory();
+
+  ASSERT_EQ(0u, heap.dirty_freed_memory_page_count_);
+}
+
 }  // namespace
 }  // namespace discardable_memory
diff --git a/components/history/core/browser/top_sites_impl.cc b/components/history/core/browser/top_sites_impl.cc
index 59c89ab3..f604963 100644
--- a/components/history/core/browser/top_sites_impl.cc
+++ b/components/history/core/browser/top_sites_impl.cc
@@ -371,7 +371,7 @@
 
   const base::DictionaryValue* blocked_urls =
       pref_service_->GetDictionary(kBlockedUrlsPrefsKey);
-  return kTopSitesNumber + (blocked_urls ? blocked_urls->size() : 0);
+  return kTopSitesNumber + (blocked_urls ? blocked_urls->DictSize() : 0);
 }
 
 void TopSitesImpl::MoveStateToLoaded() {
diff --git a/components/invalidation/impl/invalidator_registrar_with_memory.cc b/components/invalidation/impl/invalidator_registrar_with_memory.cc
index 8ac91cd4..8d188da1 100644
--- a/components/invalidation/impl/invalidator_registrar_with_memory.cc
+++ b/components/invalidation/impl/invalidator_registrar_with_memory.cc
@@ -32,7 +32,7 @@
 // Added in M76.
 void MigratePrefs(PrefService* prefs, const std::string& sender_id) {
   auto* old_prefs = prefs->GetDictionary(kTopicsToHandlerDeprecated);
-  if (old_prefs->empty()) {
+  if (old_prefs->DictEmpty()) {
     return;
   }
   {
diff --git a/components/keep_alive_registry/keep_alive_types.cc b/components/keep_alive_registry/keep_alive_types.cc
index 9755309..bdb31eb 100644
--- a/components/keep_alive_registry/keep_alive_types.cc
+++ b/components/keep_alive_registry/keep_alive_types.cc
@@ -68,6 +68,8 @@
       return out << "NATIVE_MESSAGING_HOST_ERROR_REPORT";
     case KeepAliveOrigin::WEB_APP_INTENT_PICKER:
       return out << "WEB_APP_INTENT_PICKER";
+    case KeepAliveOrigin::SESSION_DATA_DELETER:
+      return out << "SESSION_DATA_DELETER";
   }
 
   NOTREACHED();
diff --git a/components/keep_alive_registry/keep_alive_types.h b/components/keep_alive_registry/keep_alive_types.h
index e7e945a..6a2ec7d 100644
--- a/components/keep_alive_registry/keep_alive_types.h
+++ b/components/keep_alive_registry/keep_alive_types.h
@@ -65,6 +65,9 @@
 
   // c/b/web_applications
   APP_START_URL_MIGRATION,
+
+  // c/b/sessions
+  SESSION_DATA_DELETER,
 };
 
 // Restart: Allow Chrome to restart when all the registered KeepAlives allow
diff --git a/components/metrics/net/net_metrics_log_uploader.cc b/components/metrics/net/net_metrics_log_uploader.cc
index 29c11c26..49baad6 100644
--- a/components/metrics/net/net_metrics_log_uploader.cc
+++ b/components/metrics/net/net_metrics_log_uploader.cc
@@ -9,14 +9,10 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/statistics_recorder.h"
-#include "base/rand_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
-#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/encrypted_messages/encrypted_message.pb.h"
 #include "components/encrypted_messages/message_encrypter.h"
 #include "components/metrics/metrics_log_uploader.h"
@@ -36,26 +32,6 @@
 const base::Feature kHttpRetryFeature{"UMAHttpRetry",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Run ablation on UMA collector connectivity to client. This study will
-// ablate a clients upload of all logs that use |metrics::ReportingService|
-// to upload logs. This include |metrics::MetricsReportingService| for uploading
-// UMA logs. |ukm::UKMReportionService| for uploading UKM logs.
-// To restrict the study to UMA or UKM, set the "service-affected" param.
-const base::Feature kAblateMetricsLogUploadFeature{
-    "AblateMetricsLogUpload", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Fraction of Collector uploads that should be failed artificially.
-constexpr base::FeatureParam<int> kParamFailureRate{
-    &kAblateMetricsLogUploadFeature, "failure-rate", 100};
-
-// HTTP Error code to pass when artificially failing uploads.
-constexpr base::FeatureParam<int> kParamErrorCode{
-    &kAblateMetricsLogUploadFeature, "error-code", 503};
-
-// Service type to ablate. Can be "UMA" or "UKM". Leave it empty to ablate all.
-constexpr base::FeatureParam<std::string> kParamAblateServiceType{
-    &kAblateMetricsLogUploadFeature, "service-type", ""};
-
 // Constants used for encrypting logs that are sent over HTTP. The
 // corresponding private key is used by the metrics server to decrypt logs.
 const char kEncryptedMessageLabel[] = "metrics log";
@@ -365,25 +341,6 @@
     url_loader_->AttachStringForUpload(compressed_log_data, mime_type_);
   }
 
-  if (base::FeatureList::IsEnabled(kAblateMetricsLogUploadFeature)) {
-    int failure_rate = kParamFailureRate.Get();
-    std::string service_restrict = kParamAblateServiceType.Get();
-    bool should_ablate =
-        service_restrict.empty() ||
-        (service_type_ == MetricsLogUploader::UMA &&
-         service_restrict == "UMA") ||
-        (service_type_ == MetricsLogUploader::UKM && service_restrict == "UKM");
-    if (should_ablate && base::RandInt(0, 99) < failure_rate) {
-      // Simulate collector outage by not actually trying to upload the
-      // logs but instead call on_upload_complete_ immediately.
-      bool was_https = url.SchemeIs(url::kHttpsScheme);
-      url_loader_.reset();
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(on_upload_complete_, kParamErrorCode.Get(),
-                                    net::ERR_FAILED, was_https));
-      return;
-    }
-  }
   // It's safe to use |base::Unretained(this)| here, because |this| owns
   // the |url_loader_|, and the callback will be cancelled if the |url_loader_|
   // is destroyed.
diff --git a/components/offline_pages/core/offline_page_feature.cc b/components/offline_pages/core/offline_page_feature.cc
index f291f46..b582556 100644
--- a/components/offline_pages/core/offline_page_feature.cc
+++ b/components/offline_pages/core/offline_page_feature.cc
@@ -23,6 +23,9 @@
 const base::Feature kOffliningRecentPagesFeature{
     "OfflineRecentPages", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kOfflinePagesCTFeature{"OfflinePagesCT",
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kOfflinePagesLivePageSharingFeature{
     "OfflinePagesLivePageSharing", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -56,6 +59,10 @@
   return base::FeatureList::IsEnabled(kOffliningRecentPagesFeature);
 }
 
+bool IsOfflinePagesCTEnabled() {
+  return base::FeatureList::IsEnabled(kOfflinePagesCTFeature);
+}
+
 bool IsOfflinePagesLivePageSharingEnabled() {
   return base::FeatureList::IsEnabled(kOfflinePagesLivePageSharingFeature);
 }
diff --git a/components/offline_pages/core/offline_page_feature.h b/components/offline_pages/core/offline_page_feature.h
index 04cfb57..53d8dd67 100644
--- a/components/offline_pages/core/offline_page_feature.h
+++ b/components/offline_pages/core/offline_page_feature.h
@@ -11,6 +11,7 @@
 namespace offline_pages {
 
 extern const base::Feature kOffliningRecentPagesFeature;
+extern const base::Feature kOfflinePagesCTFeature;
 extern const base::Feature kOfflinePagesLivePageSharingFeature;
 extern const base::Feature kBackgroundLoaderForDownloadsFeature;
 extern const base::Feature kPrefetchingOfflinePagesFeature;
@@ -30,6 +31,9 @@
 // Returns true if offlining of recent pages (aka 'Last N pages') is enabled.
 bool IsOffliningRecentPagesEnabled();
 
+// Returns true if offline CT features are enabled.  See crbug.com/620421.
+bool IsOfflinePagesCTEnabled();
+
 // Returns true if live page sharing of offline page is enabled.
 bool IsOfflinePagesLivePageSharingEnabled();
 
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 9d5eedf..4c8e234 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -211,10 +211,6 @@
                            PopupStepSelectionWithHiddenGroupIds);
   FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelTest,
                            PopupInlineAutocompleteAndTemporaryText);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelSuggestionButtonRowTest,
-                           PopupStepSelectionWithButtonRow);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelSuggestionButtonRowTest,
-                           PopupStepSelectionWithButtonRowAndKeywordButton);
   FRIEND_TEST_ALL_PREFIXES(OmniboxPopupContentsViewTest,
                            EmitSelectedChildrenChangedAccessibilityEvent);
 
diff --git a/components/omnibox/browser/keyword_provider_unittest.cc b/components/omnibox/browser/keyword_provider_unittest.cc
index da702c4..6f859c59 100644
--- a/components/omnibox/browser/keyword_provider_unittest.cc
+++ b/components/omnibox/browser/keyword_provider_unittest.cc
@@ -15,11 +15,13 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_scheme_classifier.h"
 #include "components/omnibox/browser/mock_autocomplete_provider_client.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/omnibox_focus_type.h"
 #include "components/search_engines/search_engines_switches.h"
 #include "components/search_engines/template_url.h"
@@ -380,10 +382,12 @@
 }
 
 TEST_F(KeywordProviderTest, GetKeywordForInput) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(omnibox::kOmniboxKeywordSearchButton);
   SetUpClientAndKeywordProvider();
   EXPECT_EQ(u"aa", kw_provider_->GetKeywordForText(u"aa"));
   EXPECT_EQ(std::u16string(), kw_provider_->GetKeywordForText(u"aafoo"));
-  EXPECT_EQ(std::u16string(), kw_provider_->GetKeywordForText(u"aa foo"));
+  EXPECT_EQ(u"aa", kw_provider_->GetKeywordForText(u"aa foo"));
   EXPECT_EQ(u"cleantestv1.com",
             kw_provider_->GetKeywordForText(u"http://cleantestv1.com"));
   EXPECT_EQ(u"cleantestv1.com",
diff --git a/components/omnibox/browser/omnibox_popup_model_unittest.cc b/components/omnibox/browser/omnibox_popup_model_unittest.cc
index 1ae7054..c58f32f 100644
--- a/components/omnibox/browser/omnibox_popup_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_popup_model_unittest.cc
@@ -102,29 +102,6 @@
   OmniboxPopupModel popup_model_;
 };
 
-// A test fixture that enables the #omnibox-suggestion-button-row field trial.
-class OmniboxPopupModelSuggestionButtonRowTest : public OmniboxPopupModelTest {
- public:
-  OmniboxPopupModelSuggestionButtonRowTest() = default;
-  OmniboxPopupModelSuggestionButtonRowTest(
-      const OmniboxPopupModelSuggestionButtonRowTest&) = delete;
-  OmniboxPopupModelSuggestionButtonRowTest& operator=(
-      const OmniboxPopupModelSuggestionButtonRowTest&) = delete;
-
- protected:
-  // testing::Test:
-  void TearDown() override { scoped_feature_list_.reset(); }
-
-  void InitKeywordButtonFeature() {
-    scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
-    scoped_feature_list_->InitWithFeatures(
-        {omnibox::kOmniboxKeywordSearchButton}, {});
-  }
-
- private:
-  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
-};
-
 // This verifies that the new treatment of the user's selected match in
 // |SetSelectedLine()| with removed |AutocompleteResult::Selection::empty()|
 // is correct in the face of various replacement versions of |empty()|.
@@ -211,8 +188,11 @@
 }
 
 TEST_F(OmniboxPopupModelTest, PopupStepSelection) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(omnibox::kOmniboxKeywordSearchButton);
+
   ACMatches matches;
-  for (size_t i = 0; i < 4; ++i) {
+  for (size_t i = 0; i < 5; ++i) {
     AutocompleteMatch match(nullptr, 1000, false,
                             AutocompleteMatchType::URL_WHAT_YOU_TYPED);
     match.keyword = u"match";
@@ -221,14 +201,19 @@
   }
   // Make match index 1 deletable to verify we can step to that.
   matches[1].deletable = true;
-  // Make match index 2 have an associated keyword for irregular state stepping.
-  // Make it deleteable also to verify that we correctly handle matches with
-  // keywords that are ALSO deleteable (this is an edge case that was broken).
+  // Make match index 2 only have an associated keyword to verify we can step
+  // backwards into keyword search mode if keyword search button is enabled.
   matches[2].associated_keyword =
       std::make_unique<AutocompleteMatch>(matches.back());
-  matches[2].deletable = true;
-  // Make match index 3 have a suggestion_group_id to test header behavior.
-  matches[3].suggestion_group_id = 7;
+  // Make match index 3 have an associated keyword, tab match, and deletable to
+  // verify keyword mode doesn't override tab match and remove suggestion
+  // buttons (as it does with button row disabled)
+  matches[3].associated_keyword =
+      std::make_unique<AutocompleteMatch>(matches.back());
+  matches[3].has_tab_match = true;
+  matches[3].deletable = true;
+  // Make match index 4 have a suggestion_group_id to test header behavior.
+  matches[4].suggestion_group_id = 7;
 
   auto* result = &model()->autocomplete_controller()->result_;
   AutocompleteInput input(u"match", metrics::OmniboxEventProto::NTP,
@@ -240,44 +225,53 @@
   EXPECT_EQ(0u, model()->popup_model()->selected_line());
 
   // Step by lines forward.
-  for (size_t n : {1, 2, 3, 0}) {
+  for (size_t n : {1, 2, 3, 4, 0}) {
     popup_model()->StepSelection(OmniboxPopupModel::kForward,
                                  OmniboxPopupModel::kWholeLine);
     EXPECT_EQ(n, model()->popup_model()->selected_line());
   }
   // Step by lines backward.
-  for (size_t n : {3, 2, 1, 0}) {
+  for (size_t n : {4, 3, 2, 1, 0}) {
     popup_model()->StepSelection(OmniboxPopupModel::kBackward,
                                  OmniboxPopupModel::kWholeLine);
     EXPECT_EQ(n, model()->popup_model()->selected_line());
   }
+
   // Step by states forward.
   for (auto selection : {
            Selection(1, OmniboxPopupModel::NORMAL),
            Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
            Selection(2, OmniboxPopupModel::NORMAL),
            Selection(2, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
            Selection(3, OmniboxPopupModel::NORMAL),
+           Selection(3, OmniboxPopupModel::KEYWORD_MODE),
+           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
+           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
+           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
+           Selection(4, OmniboxPopupModel::NORMAL),
            Selection(0, OmniboxPopupModel::NORMAL),
        }) {
     popup_model()->StepSelection(OmniboxPopupModel::kForward,
                                  OmniboxPopupModel::kStateOrLine);
     EXPECT_EQ(selection, model()->popup_model()->selection());
   }
-  // Step by states backward.
-  // Note the lack of KEYWORD. This is by design. Stepping forward
-  // should land on KEYWORD, but stepping backward should not.
+  // Step by states backward. Unlike prior to suggestion button row, there is
+  // no difference in behavior for KEYWORD mode moving forward or backward.
   for (auto selection : {
+           Selection(4, OmniboxPopupModel::NORMAL),
+           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
+           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
+           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
+           Selection(3, OmniboxPopupModel::KEYWORD_MODE),
            Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
+           Selection(2, OmniboxPopupModel::KEYWORD_MODE),
            Selection(2, OmniboxPopupModel::NORMAL),
            Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
            Selection(1, OmniboxPopupModel::NORMAL),
            Selection(0, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(2, OmniboxPopupModel::NORMAL),
+           Selection(4, OmniboxPopupModel::NORMAL),
+           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
+           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
        }) {
     popup_model()->StepSelection(OmniboxPopupModel::kBackward,
                                  OmniboxPopupModel::kStateOrLine);
@@ -291,7 +285,7 @@
             model()->popup_model()->selection());
   popup_model()->StepSelection(OmniboxPopupModel::kForward,
                                OmniboxPopupModel::kAllLines);
-  EXPECT_EQ(Selection(3, OmniboxPopupModel::NORMAL),
+  EXPECT_EQ(Selection(4, OmniboxPopupModel::NORMAL),
             model()->popup_model()->selection());
 }
 
@@ -366,199 +360,6 @@
   }
 }
 
-TEST_F(OmniboxPopupModelSuggestionButtonRowTest,
-       PopupStepSelectionWithButtonRow) {
-  ACMatches matches;
-  for (size_t i = 0; i < 4; ++i) {
-    AutocompleteMatch match(nullptr, 1000, false,
-                            AutocompleteMatchType::URL_WHAT_YOU_TYPED);
-    match.keyword = u"match";
-    match.allowed_to_be_default_match = true;
-    matches.push_back(match);
-  }
-  // Make match index 1 have a tab match and be deletable to verify we can step
-  // to each.
-  matches[1].has_tab_match = true;
-  matches[1].deletable = true;
-  // Make match index 2 have an associated keyword for irregular state stepping.
-  // Make it deleteable and with a tab match to verify that we correctly skip
-  // those on matches with an associated keyword.
-  matches[2].associated_keyword =
-      std::make_unique<AutocompleteMatch>(matches.back());
-  matches[2].deletable = true;
-  matches[2].has_tab_match = true;
-  // Make match index 3 have a suggestion_group_id to test header behavior.
-  matches[3].suggestion_group_id = 7;
-
-  auto* result = &model()->autocomplete_controller()->result_;
-  AutocompleteInput input(u"match", metrics::OmniboxEventProto::NTP,
-                          TestSchemeClassifier());
-  result->AppendMatches(input, matches);
-  result->MergeHeadersMap({{7, u"header"}});
-  result->SortAndCull(input, nullptr);
-  popup_model()->OnResultChanged();
-  EXPECT_EQ(0u, model()->popup_model()->selected_line());
-
-  // Step by lines forward.
-  for (size_t n : {1, 2, 3, 0}) {
-    popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                                 OmniboxPopupModel::kWholeLine);
-    EXPECT_EQ(n, model()->popup_model()->selected_line());
-  }
-  // Step by lines backward.
-  for (size_t n : {3, 2, 1, 0}) {
-    popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                                 OmniboxPopupModel::kWholeLine);
-    EXPECT_EQ(n, model()->popup_model()->selected_line());
-  }
-  // Step by states forward.
-  for (auto selection : {
-           Selection(1, OmniboxPopupModel::NORMAL),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(2, OmniboxPopupModel::NORMAL),
-           Selection(2, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(0, OmniboxPopupModel::NORMAL),
-       }) {
-    popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                                 OmniboxPopupModel::kStateOrLine);
-    EXPECT_EQ(selection, model()->popup_model()->selection());
-  }
-  // Step by states backward.
-  // Note the lack of KEYWORD. This is by design. Stepping forward
-  // should land on KEYWORD, but stepping backward should not.
-  for (auto selection : {
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(2, OmniboxPopupModel::NORMAL),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
-           Selection(1, OmniboxPopupModel::NORMAL),
-           Selection(0, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(2, OmniboxPopupModel::NORMAL),
-       }) {
-    popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                                 OmniboxPopupModel::kStateOrLine);
-    EXPECT_EQ(selection, model()->popup_model()->selection());
-  }
-
-  // Try the kAllLines step behavior.
-  popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                               OmniboxPopupModel::kAllLines);
-  EXPECT_EQ(Selection(0, OmniboxPopupModel::NORMAL),
-            model()->popup_model()->selection());
-  popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                               OmniboxPopupModel::kAllLines);
-  EXPECT_EQ(Selection(3, OmniboxPopupModel::NORMAL),
-            model()->popup_model()->selection());
-}
-
-TEST_F(OmniboxPopupModelSuggestionButtonRowTest,
-       PopupStepSelectionWithButtonRowAndKeywordButton) {
-  InitKeywordButtonFeature();
-
-  ACMatches matches;
-  for (size_t i = 0; i < 5; ++i) {
-    AutocompleteMatch match(nullptr, 1000, false,
-                            AutocompleteMatchType::URL_WHAT_YOU_TYPED);
-    match.keyword = u"match";
-    match.allowed_to_be_default_match = true;
-    matches.push_back(match);
-  }
-  // Make match index 1 deletable to verify we can step to that.
-  matches[1].deletable = true;
-  // Make match index 2 only have an associated keyword to verify we can step
-  // backwards into keyword search mode.
-  matches[2].associated_keyword =
-      std::make_unique<AutocompleteMatch>(matches.back());
-  // Make match index 3 have an associated keyword, tab match, and deletable to
-  // verify keyword mode doesn't override tab match and remove suggestion
-  // buttons (as it does with button row disabled)
-  matches[3].associated_keyword =
-      std::make_unique<AutocompleteMatch>(matches.back());
-  matches[3].has_tab_match = true;
-  matches[3].deletable = true;
-  // Make match index 4 have a suggestion_group_id to test header behavior.
-  matches[4].suggestion_group_id = 7;
-
-  auto* result = &model()->autocomplete_controller()->result_;
-  AutocompleteInput input(u"match", metrics::OmniboxEventProto::NTP,
-                          TestSchemeClassifier());
-  result->AppendMatches(input, matches);
-  result->MergeHeadersMap({{7, u"header"}});
-  result->SortAndCull(input, nullptr);
-  popup_model()->OnResultChanged();
-  EXPECT_EQ(0u, model()->popup_model()->selected_line());
-
-  // Step by lines forward.
-  for (size_t n : {1, 2, 3, 4, 0}) {
-    popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                                 OmniboxPopupModel::kWholeLine);
-    EXPECT_EQ(n, model()->popup_model()->selected_line());
-  }
-  // Step by lines backward.
-  for (size_t n : {4, 3, 2, 1, 0}) {
-    popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                                 OmniboxPopupModel::kWholeLine);
-    EXPECT_EQ(n, model()->popup_model()->selected_line());
-  }
-  // Step by states forward.
-  for (auto selection : {
-           Selection(1, OmniboxPopupModel::NORMAL),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(2, OmniboxPopupModel::NORMAL),
-           Selection(2, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(3, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(4, OmniboxPopupModel::NORMAL),
-           Selection(0, OmniboxPopupModel::NORMAL),
-       }) {
-    popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                                 OmniboxPopupModel::kStateOrLine);
-    EXPECT_EQ(selection, model()->popup_model()->selection());
-  }
-
-  // Step by states backward. Unlike without suggestion button row, there is no
-  // difference in behavior for KEYWORD mode moving forward or backward.
-  for (auto selection : {
-           Selection(4, OmniboxPopupModel::NORMAL),
-           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH),
-           Selection(3, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(3, OmniboxPopupModel::NORMAL),
-           Selection(2, OmniboxPopupModel::KEYWORD_MODE),
-           Selection(2, OmniboxPopupModel::NORMAL),
-           Selection(1, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-           Selection(1, OmniboxPopupModel::NORMAL),
-           Selection(0, OmniboxPopupModel::NORMAL),
-           Selection(4, OmniboxPopupModel::NORMAL),
-           Selection(4, OmniboxPopupModel::FOCUSED_BUTTON_HEADER),
-           Selection(3, OmniboxPopupModel::FOCUSED_BUTTON_REMOVE_SUGGESTION),
-       }) {
-    popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                                 OmniboxPopupModel::kStateOrLine);
-    EXPECT_EQ(selection, model()->popup_model()->selection());
-  }
-
-  // Try the kAllLines step behavior.
-  popup_model()->StepSelection(OmniboxPopupModel::kBackward,
-                               OmniboxPopupModel::kAllLines);
-  EXPECT_EQ(Selection(0, OmniboxPopupModel::NORMAL),
-            model()->popup_model()->selection());
-  popup_model()->StepSelection(OmniboxPopupModel::kForward,
-                               OmniboxPopupModel::kAllLines);
-  EXPECT_EQ(Selection(4, OmniboxPopupModel::NORMAL),
-            model()->popup_model()->selection());
-}
-
 TEST_F(OmniboxPopupModelTest, PopupInlineAutocompleteAndTemporaryText) {
   // Create a set of three matches "a|1" (inline autocompleted), "a2", "a3".
   // The third match has a suggestion group ID.
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 6ea76f2..f43c7d1 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -270,7 +270,7 @@
 
 // Feature used to enable the keyword search button.
 const base::Feature kOmniboxKeywordSearchButton{
-    "OmniboxKeywordSearchButton", base::FEATURE_DISABLED_BY_DEFAULT};
+    "OmniboxKeywordSearchButton", enabled_by_default_desktop_only};
 
 // Enables new UI changes indicating focus and hover states.
 const base::Feature kOmniboxRefinedFocusState{"OmniboxRefinedFocusState",
diff --git a/components/page_info/android/BUILD.gn b/components/page_info/android/BUILD.gn
index 79d6baf..ee0d834 100644
--- a/components/page_info/android/BUILD.gn
+++ b/components/page_info/android/BUILD.gn
@@ -50,8 +50,6 @@
     "java/res/drawable/ic_tune_24dp.xml",
     "java/res/drawable/page_info_bg.xml",
     "java/res/layout/connection_info.xml",
-    "java/res/layout/connection_info_v2.xml",
-    "java/res/layout/page_info.xml",
     "java/res/layout/page_info_container.xml",
     "java/res/layout/page_info_row.xml",
     "java/res/layout/page_info_summary.xml",
@@ -59,7 +57,6 @@
     "java/res/values/colors.xml",
     "java/res/values/dimens.xml",
     "java/res/values/ids.xml",
-    "java/res/values/styles.xml",
     "java/res/xml/page_info_cookie_preference.xml",
   ]
   deps = [
@@ -75,6 +72,7 @@
     "java/src/org/chromium/components/page_info/CertificateChainHelper.java",
     "java/src/org/chromium/components/page_info/CertificateViewer.java",
     "java/src/org/chromium/components/page_info/ConnectionInfoView.java",
+    "java/src/org/chromium/components/page_info/ElidedUrlTextView.java",
     "java/src/org/chromium/components/page_info/PageInfoConnectionController.java",
     "java/src/org/chromium/components/page_info/PageInfoContainer.java",
     "java/src/org/chromium/components/page_info/PageInfoController.java",
@@ -88,7 +86,6 @@
     "java/src/org/chromium/components/page_info/PageInfoPermissionsController.java",
     "java/src/org/chromium/components/page_info/PageInfoRowView.java",
     "java/src/org/chromium/components/page_info/PageInfoSubpageController.java",
-    "java/src/org/chromium/components/page_info/PageInfoView.java",
     "java/src/org/chromium/components/page_info/PageInfoViewV2.java",
     "java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java",
     "java/src/org/chromium/components/page_info/SystemSettingsActivityRequiredListener.java",
diff --git a/components/page_info/android/java/res/layout/connection_info.xml b/components/page_info/android/java/res/layout/connection_info.xml
index 25ad2ce..7dfc5fe4 100644
--- a/components/page_info/android/java/res/layout/connection_info.xml
+++ b/components/page_info/android/java/res/layout/connection_info.xml
@@ -1,21 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-   Copyright 2015 The Chromium Authors. All rights reserved.
+   Copyright 2020 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.
 -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="horizontal" >
 
-    <ImageView
+    <org.chromium.ui.widget.ChromeImageView
         android:id="@+id/connection_info_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginEnd="32dp"
         tools:ignore="ContentDescription" />
 
     <LinearLayout
@@ -23,22 +25,14 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical"
-        android:paddingBottom="@dimen/connection_info_padding_thin"
-        android:paddingStart="@dimen/connection_info_padding_thin" >
-
-        <TextView
-            android:id="@+id/connection_info_headline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/connection_info_padding_thin"
-            android:textAppearance="@style/TextAppearance.ConnectionInfoHeadline" />
+        android:paddingBottom="@dimen/page_info_popup_padding_vertical">
 
         <TextView
             android:id="@+id/connection_info_description"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:lineSpacingExtra="6dp"
-            android:textAppearance="@style/TextAppearance.TextSmall.Primary" />
+            android:textAppearance="@style/TextAppearance.TextSmall.Secondary" />
     </LinearLayout>
 
 </LinearLayout>
diff --git a/components/page_info/android/java/res/layout/connection_info_v2.xml b/components/page_info/android/java/res/layout/connection_info_v2.xml
deleted file mode 100644
index 7dfc5fe4..0000000
--- a/components/page_info/android/java/res/layout/connection_info_v2.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2020 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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal" >
-
-    <org.chromium.ui.widget.ChromeImageView
-        android:id="@+id/connection_info_icon"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginEnd="32dp"
-        tools:ignore="ContentDescription" />
-
-    <LinearLayout
-        android:id="@+id/connection_info_text_layout"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="@dimen/page_info_popup_padding_vertical">
-
-        <TextView
-            android:id="@+id/connection_info_description"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:lineSpacingExtra="6dp"
-            android:textAppearance="@style/TextAppearance.TextSmall.Secondary" />
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/components/page_info/android/java/res/layout/page_info.xml b/components/page_info/android/java/res/layout/page_info.xml
deleted file mode 100644
index 3347f59..0000000
--- a/components/page_info/android/java/res/layout/page_info.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2013 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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:paddingBottom="8dp"
-    android:orientation="vertical"
-    android:background="@color/sheet_bg_color">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="12dp"
-        android:paddingEnd="@dimen/page_info_popup_padding_sides"
-        android:paddingStart="@dimen/page_info_popup_padding_sides" >
-
-        <view class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
-            android:id="@+id/page_info_url"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:lineSpacingExtra="6dp"
-            android:paddingTop="16dp"
-            android:textAlignment="viewStart"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
-
-        <TextView
-            android:id="@+id/page_info_connection_summary"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:lineSpacingExtra="3dp"
-            android:paddingTop="16dp"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-            android:visibility="gone" />
-
-        <TextView
-            android:id="@+id/page_info_connection_message"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:lineSpacingExtra="3dp"
-            android:paddingTop="8dp"
-            android:textAppearance="@style/TextAppearance.TextMedium.Primary"
-            android:visibility="gone" />
-
-        <View
-            android:id="@+id/page_info_preview_separator"
-            android:layout_marginTop="16dp"
-            style="@style/HorizontalDivider"
-            android:visibility="gone" />
-
-        <TextView
-            android:id="@+id/page_info_preview_message"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="14dp"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-            android:text="@string/page_info_preview_message"
-            android:visibility="gone" />
-
-        <TextView
-            android:id="@+id/page_info_preview_load_original"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="12dp"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-            android:visibility="gone" />
-
-        <TextView
-            android:id="@+id/page_info_lite_mode_https_image_compression_message"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="12dp"
-            android:textAppearance="@style/TextAppearance.TextMedium.Primary"
-            android:text="@string/page_info_lite_mode_https_image_compression"
-            android:visibility="gone" />
-    </LinearLayout>
-
-    <org.chromium.ui.widget.ButtonCompat
-        android:id="@+id/page_info_instant_app_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="start"
-        android:layout_marginEnd="@dimen/page_info_popup_padding_sides"
-        android:layout_marginStart="@dimen/page_info_popup_padding_sides"
-        android:layout_marginTop="12dp"
-        android:layout_marginBottom="4dp"
-        android:paddingEnd="@dimen/page_info_popup_button_padding_sides"
-        android:paddingStart="@dimen/page_info_popup_button_padding_sides"
-        android:text="@string/page_info_instant_app_button"
-        app:buttonColor="@color/app_banner_install_button_bg"
-        style="@style/FilledButton" />
-
-    <org.chromium.ui.widget.ButtonCompat
-        android:id="@+id/page_info_open_online_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:layout_marginEnd="@dimen/page_info_popup_padding_sides"
-        android:layout_marginStart="@dimen/page_info_popup_padding_sides"
-        android:layout_marginTop="2dp"
-        android:paddingEnd="@dimen/page_info_popup_button_padding_sides"
-        android:paddingStart="@dimen/page_info_popup_button_padding_sides"
-        android:text="@string/page_info_open_online_button"
-        style="@style/TextButton" />
-</LinearLayout>
diff --git a/components/page_info/android/java/res/layout/page_info_container.xml b/components/page_info/android/java/res/layout/page_info_container.xml
index c01468e4..7c7d5f9 100644
--- a/components/page_info/android/java/res/layout/page_info_container.xml
+++ b/components/page_info/android/java/res/layout/page_info_container.xml
@@ -41,7 +41,7 @@
 
             <view
                 android:id="@+id/page_info_url"
-                class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
+                class="org.chromium.components.page_info.ElidedUrlTextView"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:ellipsize="end"
@@ -66,28 +66,6 @@
     </LinearLayout>
 
     <LinearLayout
-        android:id="@+id/page_info_preview_message_wrapper"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp"
-        android:gravity="center"
-        android:paddingVertical="@dimen/page_info_popup_padding_vertical"
-        android:paddingHorizontal="@dimen/page_info_popup_padding_sides"
-        android:visibility="gone">
-
-        <org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables
-            android:id="@+id/page_info_preview_message"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:drawablePadding="@dimen/page_info_popup_button_padding_sides"
-            android:includeFontPadding="false"
-            android:lineSpacingExtra="6dp"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-            app:drawableHeight="@dimen/page_info_favicon_size"
-            app:drawableWidth="@dimen/page_info_favicon_size" />
-    </LinearLayout>
-
-    <LinearLayout
         android:id="@+id/page_info_wrapper"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/components/page_info/android/java/res/layout/page_info_v2.xml b/components/page_info/android/java/res/layout/page_info_v2.xml
index 2252b52c..96fcc93 100644
--- a/components/page_info/android/java/res/layout/page_info_v2.xml
+++ b/components/page_info/android/java/res/layout/page_info_v2.xml
@@ -55,15 +55,6 @@
         style="@style/TextButton"/>
 
     <TextView
-        android:id="@+id/page_info_preview_load_original"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginVertical="@dimen/page_info_popup_padding_vertical"
-        android:layout_marginHorizontal="@dimen/page_info_popup_padding_sides"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-        android:visibility="gone" />
-
-    <TextView
         android:id="@+id/page_info_lite_mode_https_image_compression_message"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/components/page_info/android/java/res/values/dimens.xml b/components/page_info/android/java/res/values/dimens.xml
index 96c8b55..afbabd1 100644
--- a/components/page_info/android/java/res/values/dimens.xml
+++ b/components/page_info/android/java/res/values/dimens.xml
@@ -5,10 +5,6 @@
 <resources>
     <dimen name="page_info_favicon_size">16dp</dimen>
 
-    <!-- Connection info popup dimensions -->
-    <dimen name="connection_info_padding_thin">16dp</dimen>
-    <dimen name="connection_info_padding_wide">24dp</dimen>
-
     <!-- Page Info Popup Dimensions -->
     <dimen name="page_info_popup_padding_sides">16dp</dimen>
     <dimen name="page_info_popup_padding_vertical">12dp</dimen>
diff --git a/components/page_info/android/java/res/values/styles.xml b/components/page_info/android/java/res/values/styles.xml
deleted file mode 100644
index 55ce810..0000000
--- a/components/page_info/android/java/res/values/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 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. -->
-
-<resources>
-    <style name="TextAppearance.ConnectionInfoHeadline" parent="TextAppearance.RobotoMediumStyle">
-        <item name="android:textColor">@color/default_text_color</item>
-        <item name="android:textSize">@dimen/text_size_large</item>
-    </style>
-</resources>
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/CertificateViewer.java b/components/page_info/android/java/src/org/chromium/components/page_info/CertificateViewer.java
index 55a3fce..b904b4c 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/CertificateViewer.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/CertificateViewer.java
@@ -55,7 +55,7 @@
     public CertificateViewer(Context context) {
         mContext = context;
         mPadding =
-                (int) context.getResources().getDimension(R.dimen.connection_info_padding_wide) / 2;
+                (int) context.getResources().getDimension(R.dimen.page_info_popup_padding_vertical);
         mDialog = null;
     }
 
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java b/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java
index 4eb7501..619545c 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java
@@ -45,8 +45,8 @@
     private ConnectionInfoDelegate mDelegate;
     private final LinearLayout mContainer;
     private final WebContents mWebContents;
-    private final int mPaddingWide;
-    private final int mPaddingThin;
+    private final int mPaddingSides;
+    private final int mPaddingVertical;
     private final long mNativeConnectionInfoView;
     private final CertificateViewer mCertificateViewer;
     private TextView mCertificateViewerTextView;
@@ -56,7 +56,6 @@
     private Button mResetCertDecisionsButton;
     private String mLinkUrl;
     private VrHandler mVrHandler;
-    private final boolean mIsV2Enabled;
 
     /**
      * Delegate that embeds the ConnectionInfoView. Must call ConnectionInfoView::onDismiss when
@@ -76,7 +75,6 @@
 
     private ConnectionInfoView(Context context, WebContents webContents,
             ConnectionInfoDelegate delegate, VrHandler vrHandler) {
-        mIsV2Enabled = PageInfoFeatures.PAGE_INFO_V2.isEnabled();
         mContext = context;
         mDelegate = delegate;
         mWebContents = webContents;
@@ -86,23 +84,11 @@
 
         mContainer = new LinearLayout(mContext);
         mContainer.setOrientation(LinearLayout.VERTICAL);
-        // TODO(crbug.com/1077766): Rename mPaddingWide and mPaddingThin to mPaddingSides and
-        // mPaddingVertical respectively when cleaning up V2 enabled tags
-        if (mIsV2Enabled) {
-            mPaddingWide = context.getResources().getDimensionPixelSize(
-                    R.dimen.page_info_popup_padding_sides);
-            mPaddingThin = context.getResources().getDimensionPixelSize(
-                    R.dimen.page_info_popup_padding_vertical);
-            mContainer.setPadding(mPaddingWide, mPaddingThin, mPaddingWide, 0);
-
-        } else {
-            mPaddingWide =
-                    (int) context.getResources().getDimension(R.dimen.connection_info_padding_wide);
-            mPaddingThin =
-                    (int) context.getResources().getDimension(R.dimen.connection_info_padding_thin);
-            mContainer.setPadding(
-                    mPaddingWide, mPaddingWide, mPaddingWide, mPaddingWide - mPaddingThin);
-        }
+        mPaddingSides =
+                context.getResources().getDimensionPixelSize(R.dimen.page_info_popup_padding_sides);
+        mPaddingVertical = context.getResources().getDimensionPixelSize(
+                R.dimen.page_info_popup_padding_vertical);
+        mContainer.setPadding(mPaddingSides, mPaddingVertical, mPaddingSides, 0);
 
         // This needs to come after other member initialization.
         mNativeConnectionInfoView = ConnectionInfoViewJni.get().init(this, mWebContents);
@@ -136,21 +122,11 @@
     }
 
     private View addSection(int iconId, String headline, String description, int iconColorId) {
-        View section = mIsV2Enabled
-                ? LayoutInflater.from(mContext).inflate(R.layout.connection_info_v2, null)
-                : LayoutInflater.from(mContext).inflate(R.layout.connection_info, null);
+        View section = LayoutInflater.from(mContext).inflate(R.layout.connection_info, null);
         ImageView i = section.findViewById(R.id.connection_info_icon);
         i.setImageResource(iconId);
-        if (mIsV2Enabled) {
-            ApiCompatibilityUtils.setImageTintList(
-                    i, ColorStateList.valueOf(mContext.getResources().getColor(iconColorId)));
-        }
-
-        if (!mIsV2Enabled) {
-            TextView h = section.findViewById(R.id.connection_info_headline);
-            h.setText(headline);
-            if (TextUtils.isEmpty(headline)) h.setVisibility(View.GONE);
-        }
+        ApiCompatibilityUtils.setImageTintList(
+                i, ColorStateList.valueOf(mContext.getResources().getColor(iconColorId)));
 
         TextView d = section.findViewById(R.id.connection_info_description);
         d.setText(description);
@@ -167,7 +143,7 @@
         ApiCompatibilityUtils.setTextAppearance(
                 mCertificateViewerTextView, R.style.TextAppearance_TextSmall_Blue);
         mCertificateViewerTextView.setOnClickListener(this);
-        mCertificateViewerTextView.setPadding(0, mPaddingThin, 0, 0);
+        mCertificateViewerTextView.setPadding(0, mPaddingVertical, 0, 0);
         mCertificateLayout.addView(mCertificateViewerTextView);
     }
 
@@ -182,7 +158,7 @@
         LinearLayout container = new LinearLayout(mContext);
         container.setOrientation(LinearLayout.VERTICAL);
         container.addView(mResetCertDecisionsButton);
-        container.setPadding(0, 0, 0, mPaddingWide);
+        container.setPadding(0, 0, 0, mPaddingSides);
         mContainer.addView(container);
     }
 
@@ -193,7 +169,7 @@
         mMoreInfoLink.setText(linkText);
         ApiCompatibilityUtils.setTextAppearance(
                 mMoreInfoLink, R.style.TextAppearance_TextSmall_Blue);
-        mMoreInfoLink.setPadding(0, mPaddingThin, 0, 0);
+        mMoreInfoLink.setPadding(0, mPaddingVertical, 0, 0);
         mMoreInfoLink.setOnClickListener(this);
         mDescriptionLayout.addView(mMoreInfoLink);
     }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/ElidedUrlTextView.java b/components/page_info/android/java/src/org/chromium/components/page_info/ElidedUrlTextView.java
new file mode 100644
index 0000000..a8e94a9
--- /dev/null
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/ElidedUrlTextView.java
@@ -0,0 +1,128 @@
+// 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.components.page_info;
+
+import android.content.Context;
+import android.text.Layout;
+import android.util.AttributeSet;
+
+import androidx.appcompat.widget.AppCompatTextView;
+
+/**
+ * A TextView which truncates and displays a URL such that the origin is always visible.
+ * The URL can be expanded by clicking on the it.
+ */
+public class ElidedUrlTextView extends AppCompatTextView {
+    // The number of lines to display when the URL is truncated. This number
+    // should still allow the origin to be displayed. NULL before
+    // setUrlAfterLayout() is called.
+    private Integer mTruncatedUrlLinesToDisplay;
+
+    // The number of lines to display when the URL is expanded. This should be enough to display
+    // at most two lines of the fragment if there is one in the URL.
+    private Integer mFullLinesToDisplay;
+
+    // If true, the text view will show the truncated text. If false, it
+    // will show the full, expanded text.
+    private boolean mIsShowingTruncatedText = true;
+
+    // The length of the URL's origin in number of characters.
+    private int mOriginLength = -1;
+
+    // The maximum number of lines currently shown in the view
+    private int mCurrentMaxLines = Integer.MAX_VALUE;
+
+    /** Constructor for inflating from XML. */
+    public ElidedUrlTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void setMaxLines(int maxlines) {
+        super.setMaxLines(maxlines);
+        mCurrentMaxLines = maxlines;
+    }
+
+    /**
+     * Find the number of lines of text which must be shown in order to display the character at
+     * a given index.
+     */
+    private int getLineForIndex(int index) {
+        Layout layout = getLayout();
+        int endLine = 0;
+        while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) {
+            endLine++;
+        }
+        // Since endLine is an index, add 1 to get the number of lines.
+        return endLine + 1;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMaxLines(Integer.MAX_VALUE);
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        assert mOriginLength >= 0 : "setUrl() must be called before layout.";
+        String urlText = getText().toString();
+
+        // Find the range of lines containing the origin.
+        int originEndLine = getLineForIndex(mOriginLength);
+
+        // Display an extra line so we don't accidentally hide the origin with
+        // ellipses
+        mTruncatedUrlLinesToDisplay = originEndLine + 1;
+
+        // Find the line where the fragment starts. Since # is a reserved character, it is safe
+        // to just search for the first # to appear in the url.
+        int fragmentStartIndex = urlText.indexOf('#');
+        if (fragmentStartIndex == -1) fragmentStartIndex = urlText.length();
+
+        int fragmentStartLine = getLineForIndex(fragmentStartIndex);
+        mFullLinesToDisplay = fragmentStartLine + 1;
+
+        // If there is no origin (according to OmniboxUrlEmphasizer), make sure the fragment is
+        // still hidden correctly.
+        if (mFullLinesToDisplay < mTruncatedUrlLinesToDisplay) {
+            mTruncatedUrlLinesToDisplay = mFullLinesToDisplay;
+        }
+
+        if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    /**
+     * Sets the URL and the length of the URL's origin.
+     * Must be called before layout.
+     *
+     * @param url The URL.
+     * @param originLength The length of the URL's origin in number of characters.
+     */
+    public void setUrl(CharSequence url, int originLength) {
+        assert originLength >= 0 && originLength <= url.length();
+        setText(url);
+        mOriginLength = originLength;
+    }
+
+    /**
+     * Toggles truncating/expanding the URL text. If the URL text is not
+     * truncated, has no effect.
+     */
+    public void toggleTruncation() {
+        mIsShowingTruncatedText = !mIsShowingTruncatedText;
+        if (mFullLinesToDisplay != null) {
+            updateMaxLines();
+        }
+    }
+
+    private boolean updateMaxLines() {
+        int maxLines = mFullLinesToDisplay;
+        if (mIsShowingTruncatedText) {
+            maxLines = mTruncatedUrlLinesToDisplay;
+        }
+        if (maxLines != mCurrentMaxLines) {
+            setMaxLines(maxLines);
+            return true;
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
index 16a3837..504a5c2d 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
@@ -4,12 +4,17 @@
 
 package org.chromium.components.page_info;
 
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import androidx.annotation.ColorRes;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.components.omnibox.SecurityStatusIcon;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.components.security_state.SecurityStateModel;
@@ -22,18 +27,25 @@
         implements PageInfoSubpageController, ConnectionInfoView.ConnectionInfoDelegate {
     private PageInfoMainController mMainController;
     private final WebContents mWebContents;
+    private final PageInfoRowView mRowView;
+    private final PageInfoControllerDelegate mDelegate;
     private final VrHandler mVrHandler;
-    private PageInfoRowView mRowView;
+    private final String mContentPublisher;
+    private final boolean mIsInternalPage;
     private String mTitle;
     private ConnectionInfoView mInfoView;
     private ViewGroup mContainer;
 
     public PageInfoConnectionController(PageInfoMainController mainController, PageInfoRowView view,
-            WebContents webContents, VrHandler vrHandler) {
+            WebContents webContents, PageInfoControllerDelegate delegate, String publisher,
+            boolean isInternalPage) {
         mMainController = mainController;
-        mWebContents = webContents;
-        mVrHandler = vrHandler;
         mRowView = view;
+        mWebContents = webContents;
+        mDelegate = delegate;
+        mVrHandler = mDelegate.getVrHandler();
+        mContentPublisher = publisher;
+        mIsInternalPage = isInternalPage;
     }
 
     private void launchSubpage() {
@@ -76,18 +88,77 @@
         }
     }
 
-    public void setConnectionInfo(PageInfoView.ConnectionInfoParams params) {
+    /**
+     * Whether to show a 'Details' link to the connection info popup.
+     */
+    private boolean isConnectionDetailsLinkVisible() {
+        // If Paint Preview is being shown, it completely obstructs the WebContents and users
+        // cannot interact with it. Hence, showing connection details is not relevant.
+        return mContentPublisher == null && !mDelegate.isShowingOfflinePage()
+                && !mDelegate.isShowingPaintPreviewPage() && !mIsInternalPage;
+    }
+
+    /**
+     * Sets the connection security summary and detailed description strings. These strings may be
+     * overridden based on the state of the Android UI.
+     */
+    public void setSecurityDescription(String summary, String details) {
+        // Display the appropriate connection message.
+        SpannableStringBuilder messageBuilder = new SpannableStringBuilder();
+        CharSequence title = null;
+        CharSequence subtitle = null;
+        boolean hasClickCallback;
+
+        assert mRowView.getContext() != null;
+        if (mContentPublisher != null) {
+            messageBuilder.append(mRowView.getContext().getString(
+                    R.string.page_info_domain_hidden, mContentPublisher));
+        } else if (mDelegate.isShowingPaintPreviewPage()) {
+            messageBuilder.append(mDelegate.getPaintPreviewPageConnectionMessage());
+        } else if (mDelegate.getOfflinePageConnectionMessage() != null) {
+            messageBuilder.append(mDelegate.getOfflinePageConnectionMessage());
+        } else {
+            if (!summary.isEmpty()) {
+                title = summary;
+            }
+            messageBuilder.append(details);
+        }
+
+        if (isConnectionDetailsLinkVisible() && messageBuilder.length() > 0) {
+            messageBuilder.append(" ");
+            SpannableString detailsText =
+                    new SpannableString(mRowView.getContext().getString(R.string.details_link));
+            final ForegroundColorSpan blueSpan =
+                    new ForegroundColorSpan(ApiCompatibilityUtils.getColor(
+                            mRowView.getContext().getResources(), R.color.default_text_color_link));
+            detailsText.setSpan(
+                    blueSpan, 0, detailsText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+            messageBuilder.append(detailsText);
+        }
+
+        // When a preview is being shown for a secure page, the security message is not shown. Thus,
+        // messageBuilder maybe empty.
+        if (messageBuilder.length() > 0) {
+            subtitle = messageBuilder;
+        }
+        hasClickCallback = isConnectionDetailsLinkVisible();
+
+        setConnectionInfo(title, subtitle, hasClickCallback);
+    }
+
+    private void setConnectionInfo(
+            CharSequence title, CharSequence subtitle, boolean hasClickCallback) {
         PageInfoRowView.ViewParams rowParams = new PageInfoRowView.ViewParams();
-        mTitle = params.summary != null ? params.summary.toString() : null;
+        mTitle = title != null ? title.toString() : null;
         rowParams.title = mTitle;
-        rowParams.subtitle = params.message;
+        rowParams.subtitle = subtitle;
         rowParams.visible = rowParams.title != null || rowParams.subtitle != null;
         int securityLevel = SecurityStateModel.getSecurityLevelForWebContents(mWebContents);
         rowParams.iconResId = SecurityStatusIcon.getSecurityIconResource(securityLevel,
                 /*isSmallDevice=*/false,
                 /*skipIconForNeutralState=*/false);
         rowParams.iconTint = getSecurityIconColor(securityLevel);
-        if (params.clickCallback != null) rowParams.clickCallback = this::launchSubpage;
+        if (hasClickCallback) rowParams.clickCallback = this::launchSubpage;
         mRowView.setParams(rowParams);
     }
 
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
index b53772d..73441e5 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
@@ -26,18 +26,12 @@
 
     /**  Parameters to configure the view of page info subpage. */
     public static class Params {
-        // Whether the URL title should be shown.
-        public boolean urlTitleShown;
         // The URL to be shown at the top of the page.
         public CharSequence url;
         // The length of the URL's origin in number of characters.
         public int urlOriginLength;
         // The URL to show in truncated state.
         public String truncatedUrl;
-        // If the page has preview UI shown.
-        public boolean previewUIShown;
-        // The icon used for preview UI.
-        public Drawable previewUIIcon;
         // Whether the close button is displayed.
         public boolean showCloseButton;
 
@@ -46,9 +40,8 @@
         public Runnable backButtonClickCallback;
         public Runnable closeButtonClickCallback;
     }
-    private PageInfoView.ElidedUrlTextView mExpandedUrlTitle;
+    private ElidedUrlTextView mExpandedUrlTitle;
     private TextView mTruncatedUrlTitle;
-    private TextView mPreviewMessage;
 
     private final ViewGroup mWrapper;
     private final ViewGroup mContent;
@@ -79,16 +72,6 @@
         mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
         mTruncatedUrlTitle.setText(params.truncatedUrl);
 
-        View urlWrapper = findViewById(R.id.page_info_url_wrapper);
-        urlWrapper.setVisibility(params.urlTitleShown ? VISIBLE : GONE);
-
-        mPreviewMessage = findViewById(R.id.page_info_preview_message);
-        mPreviewMessage.setText(R.string.page_info_preview_message);
-        mPreviewMessage.setCompoundDrawablesRelative(params.previewUIIcon, null, null, null);
-
-        View previewWrapper = findViewById(R.id.page_info_preview_message_wrapper);
-        previewWrapper.setVisibility(params.previewUIShown ? VISIBLE : GONE);
-
         ChromeImageButton closeButton = findViewById(R.id.page_info_close);
         closeButton.setVisibility(params.showCloseButton ? VISIBLE : GONE);
         closeButton.setOnClickListener(v -> params.closeButtonClickCallback.run());
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
index 09b88f9..c52770e 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -13,9 +13,7 @@
 import android.net.Uri;
 import android.provider.Settings;
 import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
-import android.text.style.ForegroundColorSpan;
 import android.text.style.TextAppearanceSpan;
 import android.view.View;
 import android.view.Window;
@@ -26,7 +24,6 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.core.view.ViewCompat;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.metrics.RecordUserAction;
@@ -38,8 +35,6 @@
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.omnibox.AutocompleteSchemeClassifier;
 import org.chromium.components.omnibox.OmniboxUrlEmphasizer;
-import org.chromium.components.page_info.PageInfoView.ConnectionInfoParams;
-import org.chromium.components.page_info.PageInfoView.PageInfoViewParams;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.components.security_state.SecurityStateModel;
 import org.chromium.components.url_formatter.UrlFormatter;
@@ -85,7 +80,7 @@
     private long mNativePageInfoController;
 
     // The view inside the popup or the main PageInfo view.
-    private PageInfoView mView;
+    private PageInfoViewV2 mView;
 
     // The view inside the popup (V2).
     private PageInfoContainer mContainer;
@@ -104,9 +99,6 @@
     // The security level of the page (a valid ConnectionSecurityLevel).
     private int mSecurityLevel;
 
-    // The name of the content publisher, if any.
-    private String mContentPublisher;
-
     // Observer for dismissing dialog if web contents get destroyed, navigate etc.
     private WebContentsObserver mWebContentsObserver;
 
@@ -117,9 +109,6 @@
     // Reference to last created PageInfoController for testing.
     private static WeakReference<PageInfoController> sLastPageInfoControllerForTesting;
 
-    // Whether Version 2 of the PageInfoView is enabled.
-    private boolean mIsV2Enabled;
-
     // Used to show Site settings from Page Info UI.
     private final PermissionParamsListBuilder mPermissionParamsListBuilder;
 
@@ -159,20 +148,8 @@
         mWebContents = webContents;
         mSecurityLevel = securityLevel;
         mDelegate = delegate;
-        mIsV2Enabled = PageInfoFeatures.PAGE_INFO_V2.isEnabled();
-        PageInfoViewParams viewParams = new PageInfoViewParams();
-
         mWindowAndroid = webContents.getTopLevelNativeWindow();
         mContext = mWindowAndroid.getContext().get();
-        mContentPublisher = publisher;
-
-        viewParams.urlTitleClickCallback = () -> {
-            // Expand/collapse the displayed URL title.
-            mView.toggleUrlTruncation();
-        };
-        // Long press the url text to copy it to the clipboard.
-        viewParams.urlTitleLongClickCallback =
-                () -> Clipboard.getInstance().copyUrlToClipboard(mFullUrl);
 
         // Work out the URL and connection message and status visibility.
         // TODO(crbug.com/1033178): dedupe the DomDistillerUrlUtils#getOriginalUrlFromDistillerUrl()
@@ -207,22 +184,37 @@
             }
         }
 
+        // Setup Container.
+        mContainer = new PageInfoContainer(mContext);
+        PageInfoContainer.Params containerParams = new PageInfoContainer.Params();
         boolean useDarkText = !ColorUtils.inNightMode(mContext);
         OmniboxUrlEmphasizer.emphasizeUrl(displayUrlBuilder, mContext.getResources(),
                 autocompleteSchemeClassifier, mSecurityLevel, mIsInternalPage, useDarkText,
                 /*emphasizeScheme=*/true);
-        viewParams.url = displayUrlBuilder;
-        viewParams.urlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex(
+        containerParams.url = displayUrlBuilder;
+        containerParams.urlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex(
                 displayUrlBuilder.toString(), autocompleteSchemeClassifier);
         autocompleteSchemeClassifier.destroy();
+        containerParams.truncatedUrl =
+                UrlFormatter.formatUrlForDisplayOmitSchemePathAndTrivialSubdomains(mFullUrl);
+        containerParams.backButtonClickCallback = this::exitSubpage;
+        containerParams.urlTitleClickCallback = mContainer::toggleUrlTruncation;
+        // Long press the url text to copy it to the clipboard.
+        containerParams.urlTitleLongClickCallback =
+                () -> Clipboard.getInstance().copyUrlToClipboard(mFullUrl);
+        // Show close button for tablets and when accessibility is enabled to make it easier
+        // to close the UI.
+        containerParams.showCloseButton = !isSheet(mContext) || mDelegate.isAccessibilityEnabled();
+        containerParams.closeButtonClickCallback = this::dismiss;
+        mContainer.setParams(containerParams);
 
+        // Setup View.
+        PageInfoViewV2.Params viewParams = new PageInfoViewV2.Params();
         viewParams.onUiClosingCallback = () -> {
             // |this| may have already been destroyed by the time this is called.
             if (mCookiesController != null) mCookiesController.onUiClosing();
         };
-
         mDelegate.initOfflinePageUiParams(viewParams, this::runAfterDismiss);
-
         if (!mIsInternalPage && !mDelegate.isShowingOfflinePage()
                 && mDelegate.isInstantAppAvailable(mFullUrl.getSpec())) {
             final Intent instantAppIntent = mDelegate.getInstantAppIntentForUrl(mFullUrl.getSpec());
@@ -238,25 +230,9 @@
         } else {
             viewParams.instantAppButtonShown = false;
         }
-
-        mView = mIsV2Enabled ? new PageInfoViewV2(mContext, viewParams)
-                             : new PageInfoView(mContext, viewParams);
+        viewParams.httpsImageCompressionMessageShown = mDelegate.isHttpsImageCompressionApplied();
+        mView = new PageInfoViewV2(mContext, viewParams);
         if (isSheet(mContext)) mView.setBackgroundColor(Color.WHITE);
-        mContainer = new PageInfoContainer(mContext);
-        PageInfoContainer.Params containerParams = new PageInfoContainer.Params();
-        containerParams.url = viewParams.url;
-        containerParams.urlOriginLength = viewParams.urlOriginLength;
-        containerParams.truncatedUrl =
-                UrlFormatter.formatUrlForDisplayOmitSchemePathAndTrivialSubdomains(mFullUrl);
-        containerParams.backButtonClickCallback = this::exitSubpage;
-        containerParams.urlTitleClickCallback = mContainer::toggleUrlTruncation;
-        containerParams.urlTitleLongClickCallback = viewParams.urlTitleLongClickCallback;
-        containerParams.urlTitleShown = viewParams.urlTitleShown;
-        // Show close button for tablets and when accessibility is enabled to make it easier
-        // to close the UI.
-        containerParams.showCloseButton = !isSheet(mContext) || mDelegate.isAccessibilityEnabled();
-        containerParams.closeButtonClickCallback = this::dismiss;
-        mContainer.setParams(containerParams);
         mDelegate.getFavicon(mFullUrl.getSpec(), favicon -> {
             // Return early if PageInfo has been dismissed.
             if (mContext == null) return;
@@ -270,23 +246,20 @@
         });
         mContainer.showPage(mView, null, null);
 
-        PageInfoViewV2 view2 = (PageInfoViewV2) mView;
-        mConnectionController = new PageInfoConnectionController(
-                this, view2.getConnectionRowView(), mWebContents, mDelegate.getVrHandler());
+        // Create Subcontrollers.
+        mConnectionController = new PageInfoConnectionController(this, mView.getConnectionRowView(),
+                mWebContents, mDelegate, publisher, mIsInternalPage);
         mPermissionsController =
-                new PageInfoPermissionsController(this, view2.getPermissionsRowView(), mDelegate,
+                new PageInfoPermissionsController(this, mView.getPermissionsRowView(), mDelegate,
                         mFullUrl.getSpec(), highlightedPermission);
         mCookiesController = new PageInfoCookiesController(
-                this, view2.getCookiesRowView(), mDelegate, mFullUrl.getSpec());
-
+                this, mView.getCookiesRowView(), mDelegate, mFullUrl.getSpec());
         if (PageInfoFeatures.PAGE_INFO_HISTORY.isEnabled()) {
             mHistoryController = mDelegate.createHistoryController(
-                    this, view2.getHistoryRowView(), mFullUrl.getSpec());
-            setupForgetSiteButton(view2.getForgetSiteButton());
+                    this, mView.getHistoryRowView(), mFullUrl.getSpec());
+            setupForgetSiteButton(mView.getForgetSiteButton());
         }
 
-        mView.showHttpsImageCompressionInfo(mDelegate.isHttpsImageCompressionApplied());
-
         mPermissionParamsListBuilder = new PermissionParamsListBuilder(mContext, mWindowAndroid);
         mNativePageInfoController = PageInfoControllerJni.get().init(this, mWebContents);
 
@@ -320,7 +293,7 @@
             }
         };
 
-        mDialog = new PageInfoDialog(mContext, mView, mContainer,
+        mDialog = new PageInfoDialog(mContext, mContainer,
                 webContents.getViewAndroidDelegate().getContainerView(), isSheet(mContext),
                 delegate.getModalDialogManager(), this);
         mDialog.show();
@@ -347,16 +320,6 @@
         }
     }
 
-    /**
-     * Whether to show a 'Details' link to the connection info popup.
-     */
-    private boolean isConnectionDetailsLinkVisible() {
-        // If Paint Preview is being shown, it completely obstructs the WebContents and users
-        // cannot interact with it. Hence, showing connection details is not relevant.
-        return mContentPublisher == null && !mDelegate.isShowingOfflinePage()
-                && !mDelegate.isShowingPaintPreviewPage() && !mIsInternalPage;
-    }
-
     private void setupForgetSiteButton(Button button) {
         button.setOnClickListener((View v) -> {
             recordAction(PageInfoAction.PAGE_INFO_FORGET_SITE_OPENED);
@@ -410,59 +373,7 @@
      */
     @CalledByNative
     private void setSecurityDescription(String summary, String details) {
-        ConnectionInfoParams connectionInfoParams = new ConnectionInfoParams();
-
-        // Display the appropriate connection message.
-        SpannableStringBuilder messageBuilder = new SpannableStringBuilder();
-        assert mContext != null;
-        if (mContentPublisher != null) {
-            messageBuilder.append(
-                    mContext.getString(R.string.page_info_domain_hidden, mContentPublisher));
-        } else if (mDelegate.isShowingPaintPreviewPage()) {
-            messageBuilder.append(mDelegate.getPaintPreviewPageConnectionMessage());
-        } else if (mDelegate.getOfflinePageConnectionMessage() != null) {
-            messageBuilder.append(mDelegate.getOfflinePageConnectionMessage());
-        } else {
-            if (!summary.isEmpty()) {
-                connectionInfoParams.summary = summary;
-            }
-            messageBuilder.append(details);
-        }
-
-        if (isConnectionDetailsLinkVisible() && messageBuilder.length() > 0) {
-            messageBuilder.append(" ");
-            SpannableString detailsText =
-                    new SpannableString(mContext.getString(R.string.details_link));
-            final ForegroundColorSpan blueSpan =
-                    new ForegroundColorSpan(ApiCompatibilityUtils.getColor(
-                            mContext.getResources(), R.color.default_text_color_link));
-            detailsText.setSpan(
-                    blueSpan, 0, detailsText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
-            messageBuilder.append(detailsText);
-        }
-
-        // When a preview is being shown for a secure page, the security message is not shown. Thus,
-        // messageBuilder maybe empty.
-        if (messageBuilder.length() > 0) {
-            connectionInfoParams.message = messageBuilder;
-        }
-        if (isConnectionDetailsLinkVisible()) {
-            connectionInfoParams.clickCallback = () -> {
-                runAfterDismiss(() -> {
-                    if (!mWebContents.isDestroyed()) {
-                        recordAction(PageInfoAction.PAGE_INFO_SECURITY_DETAILS_OPENED);
-                        ConnectionInfoView.show(mContext, mWebContents,
-                                mDelegate.getModalDialogManager(), mDelegate.getVrHandler());
-                    }
-                });
-            };
-        }
-
-        if (mIsV2Enabled) {
-            mConnectionController.setConnectionInfo(connectionInfoParams);
-        } else {
-            mView.setConnectionInfo(connectionInfoParams);
-        }
+        mConnectionController.setSecurityDescription(summary, details);
     }
 
     @Override
@@ -533,8 +444,7 @@
 
     @VisibleForTesting
     public View getPageInfoViewForTesting() {
-        if (mContainer != null) return mContainer;
-        return mView;
+        return mContainer;
     }
 
     @VisibleForTesting
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java
index 5fe4aae..299d5dd 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java
@@ -19,7 +19,6 @@
 import org.chromium.components.content_settings.CookieControlsObserver;
 import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
 import org.chromium.components.omnibox.AutocompleteSchemeClassifier;
-import org.chromium.components.page_info.PageInfoView.PageInfoViewParams;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
 import java.lang.annotation.Retention;
@@ -129,11 +128,11 @@
 
     /**
      * Initialize viewParams with Offline Page UI info, if any.
-     * @param viewParams The PageInfoViewParams to set state on.
+     * @param viewParams The PageInfoViewV2.Params to set state on.
      * @param runAfterDismiss Used to set "open Online" button callback for offline page.
      */
     public void initOfflinePageUiParams(
-            PageInfoViewParams viewParams, Consumer<Runnable> runAfterDismiss) {
+            PageInfoViewV2.Params viewParams, Consumer<Runnable> runAfterDismiss) {
         viewParams.openOnlineButtonShown = false;
     }
 
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
index 46cf10191..0d1d3ee 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
@@ -20,7 +20,6 @@
 import android.widget.LinearLayout;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.appcompat.content.res.AppCompatResources;
 
 import org.chromium.components.browser_ui.widget.FadingEdgeScrollView;
@@ -39,8 +38,6 @@
     private static final int CLOSE_CLEANUP_DELAY_MS = 10;
 
     @NonNull
-    private final PageInfoView mPageInfoView;
-    @Nullable
     private final PageInfoContainer mPageInfoContainer;
     @NonNull
     private final ViewGroup mScrollView;
@@ -65,18 +62,15 @@
      * standard dialog (using modal dialogs).
      *
      * @param context The context used for creating the dialog.
-     * @param pageInfoView The pageInfoView shown inside the dialog.
-     * @param containerView The pageInfoContainer the dialog is shown in (only in the new UI).
+     * @param containerView The pageInfoContainer the dialog is shown in.
      * @param isSheet Whether the dialog should appear as a sheet.
      * @param manager The dialog's manager used for modal dialogs.
      * @param controller The dialog's controller.
      *
      */
-    public PageInfoDialog(Context context, @NonNull PageInfoView pageInfoView,
-            @Nullable PageInfoContainer pageInfoContainer, View containerView, boolean isSheet,
-            @NonNull ModalDialogManager manager,
+    public PageInfoDialog(Context context, @NonNull PageInfoContainer pageInfoContainer,
+            View containerView, boolean isSheet, @NonNull ModalDialogManager manager,
             @NonNull ModalDialogProperties.Controller controller) {
-        mPageInfoView = pageInfoView;
         mPageInfoContainer = pageInfoContainer;
         mIsSheet = isSheet;
         mManager = manager;
@@ -99,11 +93,11 @@
                 // a height.
                 mScrollView.removeOnLayoutChangeListener(this);
                 mScrollView.setVisibility(View.VISIBLE);
-                createAllAnimations(true, null).start();
+                createDialogSlideAnimaton(true, null).start();
             }
         });
 
-        mScrollView.addView(pageInfoContainer != null ? pageInfoContainer : pageInfoView);
+        mScrollView.addView(pageInfoContainer);
 
         if (isSheet) {
             mSheetDialog = createSheetDialog(context, mScrollView);
@@ -162,7 +156,7 @@
                     // Dismiss the modal dialogs without any custom animations.
                     super.dismiss();
                 } else {
-                    createAllAnimations(false, () -> {
+                    createDialogSlideAnimaton(false, () -> {
                         // onAnimationEnd is called during the final frame of the animation.
                         // Delay the cleanup by a tiny amount to give this frame a chance to
                         // be displayed before we destroy the dialog.
@@ -225,35 +219,30 @@
     }
 
     /**
-     * Create an animator to slide in the entire dialog from the top of the screen.
+     * Create an animator to show/hide the entire dialog as a slide animation.
+     * On phones the dialog is slid in as a sheet. Otherwise, the default fade-in is used.
      */
-    private Animator createDialogSlideAnimaton(boolean isEnter, View view) {
-        final float animHeight = -view.getHeight();
-        ObjectAnimator translateAnim;
-        if (isEnter) {
-            view.setTranslationY(animHeight);
-            translateAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0f);
-            translateAnim.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+    private Animator createDialogSlideAnimaton(boolean isEnter, Runnable onAnimationEnd) {
+        Animator dialogAnimation;
+        if (mIsSheet) {
+            final float animHeight = -mScrollView.getHeight();
+            ObjectAnimator translateAnim;
+            if (isEnter) {
+                mScrollView.setTranslationY(animHeight);
+                translateAnim = ObjectAnimator.ofFloat(mScrollView, View.TRANSLATION_Y, 0f);
+                translateAnim.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+            } else {
+                translateAnim = ObjectAnimator.ofFloat(mScrollView, View.TRANSLATION_Y, animHeight);
+                translateAnim.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            }
+            translateAnim.setDuration(ENTER_EXIT_DURATION_MS);
+            dialogAnimation = translateAnim;
         } else {
-            translateAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, animHeight);
-            translateAnim.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            dialogAnimation = new AnimatorSet();
         }
-        translateAnim.setDuration(ENTER_EXIT_DURATION_MS);
-        return translateAnim;
-    }
 
-    /**
-     * Create an animator to show/hide the entire dialog. On phones the dialog is slid in as a
-     * sheet. Otherwise, the default fade-in is used.
-     */
-    private Animator createAllAnimations(boolean isEnter, Runnable onAnimationEnd) {
-        Animator dialogAnimation = mIsSheet ? createDialogSlideAnimaton(isEnter, (View) mScrollView)
-                                            : new AnimatorSet();
-        Animator viewAnimation = mPageInfoView.createEnterExitAnimation(isEnter);
-        AnimatorSet allAnimations = new AnimatorSet();
-        if (isEnter) allAnimations.setStartDelay(ENTER_START_DELAY_MS);
-        allAnimations.playTogether(dialogAnimation, viewAnimation);
-        allAnimations.addListener(new AnimatorListenerAdapter() {
+        if (isEnter) dialogAnimation.setStartDelay(ENTER_START_DELAY_MS);
+        dialogAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 mCurrentAnimation = null;
@@ -262,7 +251,7 @@
             }
         });
         if (mCurrentAnimation != null) mCurrentAnimation.cancel();
-        mCurrentAnimation = allAnimations;
-        return allAnimations;
+        mCurrentAnimation = dialogAnimation;
+        return dialogAnimation;
     }
 }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
deleted file mode 100644
index ca4a2dc3..0000000
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2018 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.components.page_info;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.text.Layout;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.appcompat.widget.AppCompatTextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents the view inside the page info popup.
- */
-public class PageInfoView extends FrameLayout implements OnClickListener {
-    /**
-     * A TextView which truncates and displays a URL such that the origin is always visible.
-     * The URL can be expanded by clicking on the it.
-     */
-    public static class ElidedUrlTextView extends AppCompatTextView {
-        // The number of lines to display when the URL is truncated. This number
-        // should still allow the origin to be displayed. NULL before
-        // setUrlAfterLayout() is called.
-        private Integer mTruncatedUrlLinesToDisplay;
-
-        // The number of lines to display when the URL is expanded. This should be enough to display
-        // at most two lines of the fragment if there is one in the URL.
-        private Integer mFullLinesToDisplay;
-
-        // If true, the text view will show the truncated text. If false, it
-        // will show the full, expanded text.
-        private boolean mIsShowingTruncatedText = true;
-
-        // The length of the URL's origin in number of characters.
-        private int mOriginLength = -1;
-
-        // The maximum number of lines currently shown in the view
-        private int mCurrentMaxLines = Integer.MAX_VALUE;
-
-        /** Constructor for inflating from XML. */
-        public ElidedUrlTextView(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        @Override
-        public void setMaxLines(int maxlines) {
-            super.setMaxLines(maxlines);
-            mCurrentMaxLines = maxlines;
-        }
-
-        /**
-         * Find the number of lines of text which must be shown in order to display the character at
-         * a given index.
-         */
-        private int getLineForIndex(int index) {
-            Layout layout = getLayout();
-            int endLine = 0;
-            while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) {
-                endLine++;
-            }
-            // Since endLine is an index, add 1 to get the number of lines.
-            return endLine + 1;
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            setMaxLines(Integer.MAX_VALUE);
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            assert mOriginLength >= 0 : "setUrl() must be called before layout.";
-            String urlText = getText().toString();
-
-            // Find the range of lines containing the origin.
-            int originEndLine = getLineForIndex(mOriginLength);
-
-            // Display an extra line so we don't accidentally hide the origin with
-            // ellipses
-            mTruncatedUrlLinesToDisplay = originEndLine + 1;
-
-            // Find the line where the fragment starts. Since # is a reserved character, it is safe
-            // to just search for the first # to appear in the url.
-            int fragmentStartIndex = urlText.indexOf('#');
-            if (fragmentStartIndex == -1) fragmentStartIndex = urlText.length();
-
-            int fragmentStartLine = getLineForIndex(fragmentStartIndex);
-            mFullLinesToDisplay = fragmentStartLine + 1;
-
-            // If there is no origin (according to OmniboxUrlEmphasizer), make sure the fragment is
-            // still hidden correctly.
-            if (mFullLinesToDisplay < mTruncatedUrlLinesToDisplay) {
-                mTruncatedUrlLinesToDisplay = mFullLinesToDisplay;
-            }
-
-            if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-
-        /**
-         * Sets the URL and the length of the URL's origin.
-         * Must be called before layout.
-         *
-         * @param url The URL.
-         * @param originLength The length of the URL's origin in number of characters.
-         */
-        public void setUrl(CharSequence url, int originLength) {
-            assert originLength >= 0 && originLength <= url.length();
-            setText(url);
-            mOriginLength = originLength;
-        }
-
-        /**
-         * Toggles truncating/expanding the URL text. If the URL text is not
-         * truncated, has no effect.
-         */
-        public void toggleTruncation() {
-            mIsShowingTruncatedText = !mIsShowingTruncatedText;
-            if (mFullLinesToDisplay != null) {
-                updateMaxLines();
-            }
-        }
-
-        private boolean updateMaxLines() {
-            int maxLines = mFullLinesToDisplay;
-            if (mIsShowingTruncatedText) {
-                maxLines = mTruncatedUrlLinesToDisplay;
-            }
-            if (maxLines != mCurrentMaxLines) {
-                setMaxLines(maxLines);
-                return true;
-            }
-            return false;
-        }
-    }
-
-    /**  Parameters to configure the view of the page info popup. */
-    public static class PageInfoViewParams {
-        public boolean urlTitleShown = true;
-        public boolean connectionMessageShown = true;
-        public boolean instantAppButtonShown = true;
-        public boolean openOnlineButtonShown = true;
-
-        public Runnable urlTitleClickCallback;
-        public Runnable urlTitleLongClickCallback;
-        public Runnable instantAppButtonClickCallback;
-        public Runnable openOnlineButtonClickCallback;
-        public Runnable onUiClosingCallback;
-
-        public CharSequence url;
-        public int urlOriginLength;
-    }
-
-    /**  Parameters to configure the view of the connection message. */
-    public static class ConnectionInfoParams {
-        public CharSequence message;
-        public CharSequence summary;
-        public Runnable clickCallback;
-    }
-
-    protected static final int FADE_DURATION_MS = 200;
-    protected static final int FADE_IN_BASE_DELAY_MS = 150;
-    protected static final int FADE_IN_DELAY_OFFSET_MS = 20;
-
-    // Shared UI components between PageInfoView and PageInfoViewV2. This list should shrink as
-    // these components are replaced with different UI and eventually this class will be replaced
-    // completely.
-    protected ElidedUrlTextView mUrlTitle;
-    protected Button mInstantAppButton;
-    protected Button mOpenOnlineButton;
-    protected Runnable mOnUiClosingCallback;
-
-    // Components specific to this PageInfoView
-    private TextView mConnectionSummary;
-    private TextView mConnectionMessage;
-    private TextView mHttpsImageCompressionMessage;
-
-    public PageInfoView(Context context) {
-        super(context);
-    }
-
-    public PageInfoView(Context context, PageInfoViewParams params) {
-        super(context);
-        LayoutInflater.from(context).inflate(R.layout.page_info, this, true);
-        init(params);
-    }
-
-    protected void init(PageInfoViewParams params) {
-        initUrlTitle(params);
-        initConnection(params);
-        initHttpsImageCompression(params);
-        initPermissions(params);
-        initCookies(params);
-        initInstantApp(params);
-        initOpenOnline(params);
-    }
-
-    protected void initUrlTitle(PageInfoViewParams params) {
-        mUrlTitle = findViewById(R.id.page_info_url);
-        mUrlTitle.setUrl(params.url, params.urlOriginLength);
-        if (params.urlTitleLongClickCallback != null) {
-            mUrlTitle.setOnLongClickListener(v -> {
-                params.urlTitleLongClickCallback.run();
-                return true;
-            });
-        }
-        initializePageInfoViewChild(mUrlTitle, params.urlTitleShown, params.urlTitleClickCallback);
-    }
-
-    protected void initConnection(PageInfoViewParams params) {
-        mConnectionSummary = findViewById(R.id.page_info_connection_summary);
-        mConnectionMessage = findViewById(R.id.page_info_connection_message);
-        // Hide the connection summary until its text is set.
-        initializePageInfoViewChild(mConnectionSummary, false, null);
-        initializePageInfoViewChild(mConnectionMessage, params.connectionMessageShown, null);
-    }
-
-    protected void initHttpsImageCompression(PageInfoViewParams params) {
-        mHttpsImageCompressionMessage =
-                findViewById(R.id.page_info_lite_mode_https_image_compression_message);
-        initializePageInfoViewChild(mHttpsImageCompressionMessage, false, null);
-    }
-
-    protected void initPermissions(PageInfoViewParams params) {
-        // TODO(crbug.com/1182193): Remove function and restructure init at the end of cleanup.
-    }
-
-    protected void initCookies(PageInfoViewParams params) {
-        // TODO(crbug.com/1182193): Remove function and restructure init at the end of cleanup.
-    }
-
-    protected void initInstantApp(PageInfoViewParams params) {
-        mInstantAppButton = findViewById(R.id.page_info_instant_app_button);
-        initializePageInfoViewChild(mInstantAppButton, params.instantAppButtonShown,
-                params.instantAppButtonClickCallback);
-    }
-
-    protected void initOpenOnline(PageInfoViewParams params) {
-        mOpenOnlineButton = findViewById(R.id.page_info_open_online_button);
-        // The open online button should not fade in.
-        initializePageInfoViewChild(mOpenOnlineButton, params.openOnlineButtonShown,
-                params.openOnlineButtonClickCallback);
-    }
-
-    // FrameLayout:
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mOnUiClosingCallback.run();
-    }
-
-    public void setConnectionInfo(ConnectionInfoParams params) {
-        if (params.summary != null) {
-            mConnectionSummary.setVisibility(View.VISIBLE);
-            mConnectionSummary.setText(params.summary);
-        }
-        if (params.message != null) {
-            mConnectionMessage.setVisibility(View.VISIBLE);
-            mConnectionMessage.setText(params.message);
-            if (params.clickCallback != null) {
-                mConnectionMessage.setTag(R.id.page_info_click_callback, params.clickCallback);
-                mConnectionMessage.setOnClickListener(this);
-            }
-        }
-    }
-
-    public void showHttpsImageCompressionInfo(boolean show) {
-        if (show) {
-            mHttpsImageCompressionMessage.setVisibility(View.VISIBLE);
-        } else {
-            mHttpsImageCompressionMessage.setVisibility(View.GONE);
-        }
-    }
-
-    public Animator createEnterExitAnimation(boolean isEnter) {
-        return createFadeAnimations(isEnter);
-    }
-
-    public void toggleUrlTruncation() {
-        mUrlTitle.toggleTruncation();
-    }
-
-    public void disableInstantAppButton() {
-        mInstantAppButton.setEnabled(false);
-    }
-
-    @Override
-    public void onClick(View view) {
-        Object clickCallbackObj = view.getTag(R.id.page_info_click_callback);
-        if (!(clickCallbackObj instanceof Runnable)) {
-            throw new IllegalStateException("Unable to find click callback for view: " + view);
-        }
-        Runnable clickCallback = (Runnable) clickCallbackObj;
-        clickCallback.run();
-    }
-
-    protected void initializePageInfoViewChild(View child, boolean shown, Runnable clickCallback) {
-        child.setVisibility(shown ? View.VISIBLE : View.GONE);
-        child.setTag(R.id.page_info_click_callback, clickCallback);
-        if (clickCallback == null) return;
-        child.setOnClickListener(this);
-    }
-
-    /**
-     * Create a list of all the views which we want to individually fade in.
-     */
-    protected List<View> collectAnimatableViews() {
-        List<View> animatableViews = new ArrayList<>();
-        animatableViews.add(mUrlTitle);
-        animatableViews.add(mConnectionSummary);
-        animatableViews.add(mConnectionMessage);
-        animatableViews.add(mHttpsImageCompressionMessage);
-        animatableViews.add(mInstantAppButton);
-
-        return animatableViews;
-    }
-
-    /**
-     * Create an animator to fade an individual dialog element.
-     */
-    protected Animator createInnerFadeAnimation(final View view, int position, boolean isEnter) {
-        ObjectAnimator alphaAnim;
-
-        if (isEnter) {
-            view.setAlpha(0f);
-            alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 1f);
-            alphaAnim.setStartDelay(FADE_IN_BASE_DELAY_MS + FADE_IN_DELAY_OFFSET_MS * position);
-        } else {
-            alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0f);
-        }
-
-        alphaAnim.setDuration(FADE_DURATION_MS);
-        return alphaAnim;
-    }
-
-    /**
-     * Create animations for fading the view in/out.
-     */
-    protected Animator createFadeAnimations(boolean isEnter) {
-        AnimatorSet animation = new AnimatorSet();
-        AnimatorSet.Builder builder = animation.play(new AnimatorSet());
-
-        List<View> animatableViews = collectAnimatableViews();
-        for (int i = 0; i < animatableViews.size(); i++) {
-            View view = animatableViews.get(i);
-            if (view.getVisibility() == View.VISIBLE) {
-                Animator anim = createInnerFadeAnimation(view, i, isEnter);
-                builder.with(anim);
-            }
-        }
-
-        return animation;
-    }
-}
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
index 7c9cf74..0c22129d 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
@@ -7,64 +7,97 @@
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
-
-import java.util.Collections;
-import java.util.List;
+import android.widget.TextView;
 
 /**
- * Represents the view inside the second version of the page info popup.
+ * Represents the view inside the page info popup.
  */
-public class PageInfoViewV2 extends PageInfoView {
-    // Components specific to this PageInfoView
+public class PageInfoViewV2 extends FrameLayout implements OnClickListener {
     private LinearLayout mRowWrapper;
     private PageInfoRowView mConnectionRow;
     private PageInfoRowView mPermissionsRow;
     private PageInfoRowView mCookiesRow;
     private PageInfoRowView mHistoryRow;
     private Button mForgetSiteButton;
+    private TextView mHttpsImageCompressionMessage;
+    private Button mInstantAppButton;
+    private Button mOpenOnlineButton;
+    private Runnable mOnUiClosingCallback;
 
-    public PageInfoViewV2(Context context, PageInfoView.PageInfoViewParams params) {
+    /**  Parameters to configure the view of the page info popup. */
+    public static class Params {
+        public boolean instantAppButtonShown = true;
+        public boolean openOnlineButtonShown = true;
+        public boolean httpsImageCompressionMessageShown;
+        public Runnable instantAppButtonClickCallback;
+        public Runnable openOnlineButtonClickCallback;
+        public Runnable onUiClosingCallback;
+    }
+
+    public PageInfoViewV2(Context context, Params params) {
         super(context);
         LayoutInflater.from(context).inflate(R.layout.page_info_v2, this, true);
         init(params);
     }
 
-    @Override
-    protected void init(PageInfoView.PageInfoViewParams params) {
-        super.init(params);
+    private void init(Params params) {
+        initRowWrapper();
+        initConnection();
+        initPermissions();
+        initCookies(params);
+        initHistory();
+        initHttpsImageCompression(params);
+        initInstantApp(params);
+        initOpenOnline(params);
+    }
+
+    private void initRowWrapper() {
         mRowWrapper = findViewById(R.id.page_info_row_wrapper);
         initializePageInfoViewChild(mRowWrapper, true, null);
-        initHistory(params);
     }
 
-    @Override
-    protected void initUrlTitle(PageInfoView.PageInfoViewParams params) {
-        // URL is initialized in PageInfoContainer.
-    }
-
-    @Override
-    protected void initConnection(PageInfoView.PageInfoViewParams params) {
+    private void initConnection() {
         mConnectionRow = findViewById(R.id.page_info_connection_row);
     }
 
-    @Override
-    protected void initPermissions(PageInfoView.PageInfoViewParams params) {
+    private void initPermissions() {
         mPermissionsRow = findViewById(R.id.page_info_permissions_row);
     }
 
-    @Override
-    protected void initCookies(PageInfoView.PageInfoViewParams params) {
+    private void initCookies(Params params) {
         mCookiesRow = findViewById(R.id.page_info_cookies_row);
         mOnUiClosingCallback = params.onUiClosingCallback;
     }
 
-    protected void initHistory(PageInfoView.PageInfoViewParams params) {
+    private void initHistory() {
         mHistoryRow = findViewById(R.id.page_info_history_row);
         mForgetSiteButton = findViewById(R.id.page_info_forget_site_button);
     }
 
+    private void initHttpsImageCompression(Params params) {
+        mHttpsImageCompressionMessage =
+                findViewById(R.id.page_info_lite_mode_https_image_compression_message);
+        initializePageInfoViewChild(
+                mHttpsImageCompressionMessage, params.httpsImageCompressionMessageShown, null);
+    }
+
+    private void initInstantApp(Params params) {
+        mInstantAppButton = findViewById(R.id.page_info_instant_app_button);
+        initializePageInfoViewChild(mInstantAppButton, params.instantAppButtonShown,
+                params.instantAppButtonClickCallback);
+    }
+
+    private void initOpenOnline(Params params) {
+        mOpenOnlineButton = findViewById(R.id.page_info_open_online_button);
+        // The open online button should not fade in.
+        initializePageInfoViewChild(mOpenOnlineButton, params.openOnlineButtonShown,
+                params.openOnlineButtonClickCallback);
+    }
+
     public PageInfoRowView getConnectionRowView() {
         return mConnectionRow;
     }
@@ -85,13 +118,32 @@
         return mForgetSiteButton;
     }
 
-    @Override
-    public void toggleUrlTruncation() {
-        throw new RuntimeException();
+    public void disableInstantAppButton() {
+        mInstantAppButton.setEnabled(false);
     }
 
+    private void initializePageInfoViewChild(View child, boolean shown, Runnable clickCallback) {
+        child.setVisibility(shown ? View.VISIBLE : View.GONE);
+        child.setTag(R.id.page_info_click_callback, clickCallback);
+        if (clickCallback == null) return;
+        child.setOnClickListener(this);
+    }
+
+    // FrameLayout override.
     @Override
-    protected List<View> collectAnimatableViews() {
-        return Collections.emptyList();
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mOnUiClosingCallback.run();
+    }
+
+    // OnClickListener interface.
+    @Override
+    public void onClick(View view) {
+        Object clickCallbackObj = view.getTag(R.id.page_info_click_callback);
+        if (!(clickCallbackObj instanceof Runnable)) {
+            throw new IllegalStateException("Unable to find click callback for view: " + view);
+        }
+        Runnable clickCallback = (Runnable) clickCallbackObj;
+        clickCallback.run();
     }
 }
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
index 3c35420..da3ae3e 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -100,12 +100,6 @@
                    handle->GetFrameTreeNodeId());
 }
 
-// TODO(crbug.com/1194678): Remove this level of abstraction.
-void RecordFeatureUsage(content::RenderFrameHost* rfh,
-                        blink::mojom::WebFeature web_feature) {
-  MetricsWebContentsObserver::RecordFeatureUsage(rfh, web_feature);
-}
-
 std::string GetHeavyAdReportMessage(const FrameTreeData& frame_data,
                                     bool will_unload_adframe) {
   const char kChromeStatusMessage[] =
@@ -1274,8 +1268,8 @@
 
   // Record this UMA regardless of if we actually unload or not, as sending
   // reports is subject to the same noise and throttling as the intervention.
-  RecordFeatureUsage(render_frame_host,
-                     blink::mojom::WebFeature::kHeavyAdIntervention);
+  MetricsWebContentsObserver::RecordFeatureUsage(
+      render_frame_host, blink::mojom::WebFeature::kHeavyAdIntervention);
 
   ADS_HISTOGRAM("HeavyAds.InterventionType2", UMA_HISTOGRAM_ENUMERATION,
                 FrameVisibility::kAnyVisibility,
diff --git a/components/password_manager/core/browser/ui/post_save_compromised_helper.cc b/components/password_manager/core/browser/ui/post_save_compromised_helper.cc
index a3ff3f7..d575039b 100644
--- a/components/password_manager/core/browser/ui/post_save_compromised_helper.cc
+++ b/components/password_manager/core/browser/ui/post_save_compromised_helper.cc
@@ -5,7 +5,9 @@
 #include "components/password_manager/core/browser/ui/post_save_compromised_helper.h"
 
 #include "base/containers/contains.h"
+#include "base/feature_list.h"
 #include "components/password_manager/core/browser/password_store.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"
 
@@ -61,6 +63,13 @@
     std::vector<InsecureCredential> insecure_credentials) {
   const bool compromised_password_changed =
       current_leak_ && !base::Contains(insecure_credentials, *current_leak_);
+  if (base::FeatureList::IsEnabled(features::kMutingCompromisedCredentials)) {
+    // We want to show bubble even if updated insecure credentials was muted,
+    // this is why muted credentials are erased after computing
+    // 'compromised_password_changed';
+    base::EraseIf(insecure_credentials,
+                  [](const auto& credential) { return credential.is_muted; });
+  }
   if (compromised_password_changed) {
     bubble_type_ = insecure_credentials.empty()
                        ? BubbleType::kPasswordUpdatedSafeState
diff --git a/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc b/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc
index da00ca7d..e03268d 100644
--- a/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc
+++ b/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc
@@ -4,11 +4,14 @@
 
 #include "components/password_manager/core/browser/ui/post_save_compromised_helper.h"
 
+#include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/password_manager/core/browser/mock_password_store.h"
 #include "components/password_manager/core/browser/password_form.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_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
@@ -26,13 +29,14 @@
 constexpr char kSignonRealm[] = "https://example.com/";
 constexpr char16_t kUsername[] = u"user";
 constexpr char16_t kUsername2[] = u"user2";
+constexpr char16_t kUsername3[] = u"user3";
 
 InsecureCredential CreateInsecureCredential(
     base::StringPiece16 username,
-    PasswordForm::Store store = PasswordForm::Store::kProfileStore) {
+    PasswordForm::Store store = PasswordForm::Store::kProfileStore,
+    IsMuted muted = IsMuted(false)) {
   InsecureCredential compromised(kSignonRealm, std::u16string(username),
-                                 base::Time(), InsecureType::kLeaked,
-                                 IsMuted(false));
+                                 base::Time(), InsecureType::kLeaked, muted);
   compromised.in_store = store;
   return compromised;
 }
@@ -189,6 +193,55 @@
   EXPECT_EQ(0u, helper.compromised_count());
 }
 
+TEST_F(PostSaveCompromisedHelperTest, BubbleShownEvenIfIssueIsMuted) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials,
+                                    true);
+
+  prefs()->SetDouble(
+      kLastTimePasswordCheckCompleted,
+      (base::Time::Now() - base::TimeDelta::FromMinutes(1)).ToDoubleT());
+  std::vector<InsecureCredential> saved = {CreateInsecureCredential(
+      kUsername, PasswordForm::Store::kProfileStore, IsMuted(true))};
+  PostSaveCompromisedHelper helper({saved}, kUsername);
+  base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+  EXPECT_CALL(callback, Run(BubbleType::kPasswordUpdatedSafeState, 0));
+  saved = {};
+  EXPECT_CALL(*profile_store(), GetAllInsecureCredentialsImpl)
+      .WillOnce(Return(saved));
+  helper.AnalyzeLeakedCredentials(profile_store(), account_store(), prefs(),
+                                  callback.Get());
+  WaitForPasswordStore();
+  EXPECT_EQ(BubbleType::kPasswordUpdatedSafeState, helper.bubble_type());
+  EXPECT_EQ(0u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, MutedIssuesNotIncludedToCount) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatureState(features::kMutingCompromisedCredentials,
+                                    true);
+
+  prefs()->SetDouble(
+      kLastTimePasswordCheckCompleted,
+      (base::Time::Now() - base::TimeDelta::FromMinutes(1)).ToDoubleT());
+  std::vector<InsecureCredential> saved = {CreateInsecureCredential(kUsername)};
+  PostSaveCompromisedHelper helper({saved}, kUsername);
+  base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+  EXPECT_CALL(callback, Run(BubbleType::kPasswordUpdatedWithMoreToFix, 1));
+  saved = {
+      CreateInsecureCredential(kUsername2),
+      CreateInsecureCredential(kUsername3, PasswordForm::Store::kProfileStore,
+                               IsMuted(true)),
+  };
+  EXPECT_CALL(*profile_store(), GetAllInsecureCredentialsImpl)
+      .WillOnce(Return(saved));
+  helper.AnalyzeLeakedCredentials(profile_store(), account_store(), prefs(),
+                                  callback.Get());
+  WaitForPasswordStore();
+  EXPECT_EQ(BubbleType::kPasswordUpdatedWithMoreToFix, helper.bubble_type());
+  EXPECT_EQ(1u, helper.compromised_count());
+}
+
 namespace {
 class PostSaveCompromisedHelperWithTwoStoreTest
     : public PostSaveCompromisedHelperTest {
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index d31afa7..35a690d 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/value_iterators.h"
 #include "components/policy/core/browser/policy_error_map.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
@@ -280,7 +281,8 @@
 
   for (const auto& mapping_entry : map_) {
     if (mapping_entry->enum_value == entry_value) {
-      return mapping_entry->mapped_value->CreateDeepCopy();
+      return base::Value::ToUniquePtrValue(
+          mapping_entry->mapped_value->Clone());
     }
   }
   return nullptr;
diff --git a/components/policy/core/common/BUILD.gn b/components/policy/core/common/BUILD.gn
index 2351407..10290f8 100644
--- a/components/policy/core/common/BUILD.gn
+++ b/components/policy/core/common/BUILD.gn
@@ -209,13 +209,6 @@
     "//components/policy:generated",
   ]
 
-  if (is_mac) {
-    sources += [
-      "management/platform_management_status_provider_mac.cc",
-      "management/platform_management_status_provider_mac.h",
-    ]
-  }
-
   if (is_win) {
     sources += [
       "management/platform_management_status_provider_win.cc",
diff --git a/components/policy/core/common/management/platform_management_service.cc b/components/policy/core/common/management/platform_management_service.cc
index 68594917..13f2c009 100644
--- a/components/policy/core/common/management/platform_management_service.cc
+++ b/components/policy/core/common/management/platform_management_service.cc
@@ -5,9 +5,7 @@
 #include "components/policy/core/common/management/platform_management_service.h"
 
 #include "build/build_config.h"
-#if defined(OS_MAC)
-#include "components/policy/core/common/management/platform_management_status_provider_mac.h"
-#elif defined(OS_WIN)
+#if defined(OS_WIN)
 #include "components/policy/core/common/management/platform_management_status_provider_win.h"
 #endif
 
@@ -28,7 +26,7 @@
 
 void PlatformManagementService::InitManagementStatusProviders() {
   std::vector<std::unique_ptr<ManagementStatusProvider>> providers;
-#if defined(OS_WIN) || defined(OS_MAC)
+#if defined(OS_WIN)
   providers.emplace_back(std::make_unique<DomainEnrollmentStatusProvider>());
   providers.emplace_back(
       std::make_unique<EnterpriseMDMManagementStatusProvider>());
diff --git a/components/policy/core/common/management/platform_management_status_provider_mac.cc b/components/policy/core/common/management/platform_management_status_provider_mac.cc
deleted file mode 100644
index ae73b08a..0000000
--- a/components/policy/core/common/management/platform_management_status_provider_mac.cc
+++ /dev/null
@@ -1,52 +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.
-
-#include "components/policy/core/common/management/platform_management_status_provider_mac.h"
-
-namespace policy {
-
-DomainEnrollmentStatusProvider::DomainEnrollmentStatusProvider() {
-  domain_join_state_ = base::AreDeviceAndUserJoinedToDomain();
-}
-
-DomainEnrollmentStatusProvider::~DomainEnrollmentStatusProvider() = default;
-
-bool DomainEnrollmentStatusProvider::IsManaged() {
-  return domain_join_state_.device_joined || domain_join_state_.user_joined;
-}
-
-EnterpriseManagementAuthority DomainEnrollmentStatusProvider::GetAuthority() {
-  return EnterpriseManagementAuthority::DOMAIN_LOCAL;
-}
-
-EnterpriseMDMManagementStatusProvider::EnterpriseMDMManagementStatusProvider() {
-  mdm_state_new_ = base::IsDeviceRegisteredWithManagementNew();
-  if (mdm_state_new_ ==
-      base::MacDeviceManagementStateNew::kFailureAPIUnavailable) {
-    mdm_state_old_ = base::IsDeviceRegisteredWithManagementOld();
-  }
-}
-
-EnterpriseMDMManagementStatusProvider::
-    ~EnterpriseMDMManagementStatusProvider() = default;
-
-bool EnterpriseMDMManagementStatusProvider::IsManaged() {
-  if (mdm_state_new_ ==
-      base::MacDeviceManagementStateNew::kFailureAPIUnavailable) {
-    return mdm_state_old_ == base::MacDeviceManagementStateOld::kMDMEnrollment;
-  }
-
-  return mdm_state_new_ ==
-             base::MacDeviceManagementStateNew::kLimitedMDMEnrollment ||
-         mdm_state_new_ ==
-             base::MacDeviceManagementStateNew::kFullMDMEnrollment ||
-         mdm_state_new_ == base::MacDeviceManagementStateNew::kDEPMDMEnrollment;
-}
-
-EnterpriseManagementAuthority
-EnterpriseMDMManagementStatusProvider::GetAuthority() {
-  return EnterpriseManagementAuthority::CLOUD;
-}
-
-}  // namespace policy
diff --git a/components/policy/core/common/management/platform_management_status_provider_mac.h b/components/policy/core/common/management/platform_management_status_provider_mac.h
deleted file mode 100644
index 8acfc1d..0000000
--- a/components/policy/core/common/management/platform_management_status_provider_mac.h
+++ /dev/null
@@ -1,47 +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.
-
-#ifndef COMPONENTS_POLICY_CORE_COMMON_MANAGEMENT_PLATFORM_MANAGEMENT_STATUS_PROVIDER_MAC_H_
-#define COMPONENTS_POLICY_CORE_COMMON_MANAGEMENT_PLATFORM_MANAGEMENT_STATUS_PROVIDER_MAC_H_
-
-#include "base/enterprise_util.h"
-#include "components/policy/core/common/management/management_service.h"
-#include "components/policy/policy_export.h"
-
-namespace policy {
-
-class POLICY_EXPORT DomainEnrollmentStatusProvider
-    : public ManagementStatusProvider {
- public:
-  DomainEnrollmentStatusProvider();
-  ~DomainEnrollmentStatusProvider() final;
-
-  // ManagementStatusProvider impl
-  bool IsManaged() final;
-  EnterpriseManagementAuthority GetAuthority() final;
-
- private:
-  base::DeviceUserDomainJoinState domain_join_state_;
-};
-
-class POLICY_EXPORT EnterpriseMDMManagementStatusProvider
-    : public ManagementStatusProvider {
- public:
-  EnterpriseMDMManagementStatusProvider();
-  ~EnterpriseMDMManagementStatusProvider() final;
-
-  // ManagementStatusProvider impl
-  bool IsManaged() final;
-  EnterpriseManagementAuthority GetAuthority() final;
-
- private:
-  base::MacDeviceManagementStateOld mdm_state_old_ =
-      base::MacDeviceManagementStateOld::kFailureAPIUnavailable;
-  base::MacDeviceManagementStateNew mdm_state_new_ =
-      base::MacDeviceManagementStateNew::kFailureAPIUnavailable;
-};
-
-}  // namespace policy
-
-#endif  // COMPONENTS_POLICY_CORE_COMMON_MANAGEMENT_PLATFORM_MANAGEMENT_STATUS_PROVIDER_MAC_H_
diff --git a/components/policy/core/common/management/platform_management_status_provider_win.cc b/components/policy/core/common/management/platform_management_status_provider_win.cc
index 0e317a3..7e6c9b9 100644
--- a/components/policy/core/common/management/platform_management_status_provider_win.cc
+++ b/components/policy/core/common/management/platform_management_status_provider_win.cc
@@ -5,11 +5,13 @@
 #include "components/policy/core/common/management/platform_management_status_provider_win.h"
 
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
+#if defined(OS_WIN)
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
+#endif
 
 namespace policy {
-
+#if defined(OS_WIN)
 DomainEnrollmentStatusProvider::DomainEnrollmentStatusProvider() = default;
 
 DomainEnrollmentStatusProvider::~DomainEnrollmentStatusProvider() = default;
@@ -25,6 +27,7 @@
 bool DomainEnrollmentStatusProvider::IsEnrolledToDomain() {
   return base::win::IsEnrolledToDomain();
 }
+#endif
 
 EnterpriseMDMManagementStatusProvider::EnterpriseMDMManagementStatusProvider() =
     default;
@@ -33,9 +36,12 @@
     ~EnterpriseMDMManagementStatusProvider() = default;
 
 bool EnterpriseMDMManagementStatusProvider::IsManaged() {
+#if defined(OS_WIN)
   return base::win::OSInfo::GetInstance()->version_type() !=
              base::win::SUITE_HOME &&
          base::win::IsDeviceRegisteredWithManagement();
+#endif
+  return false;
 }
 
 EnterpriseManagementAuthority
diff --git a/components/policy/core/common/management/platform_management_status_provider_win.h b/components/policy/core/common/management/platform_management_status_provider_win.h
index 6af9821..6ec597b8 100644
--- a/components/policy/core/common/management/platform_management_status_provider_win.h
+++ b/components/policy/core/common/management/platform_management_status_provider_win.h
@@ -6,11 +6,13 @@
 #define COMPONENTS_POLICY_CORE_COMMON_MANAGEMENT_PLATFORM_MANAGEMENT_STATUS_PROVIDER_WIN_H_
 
 #include "base/containers/flat_set.h"
+#include "build/build_config.h"
 #include "components/policy/core/common/management/management_service.h"
 #include "components/policy/policy_export.h"
 
 namespace policy {
 
+#if defined(OS_WIN)
 class POLICY_EXPORT DomainEnrollmentStatusProvider
     : public ManagementStatusProvider {
  public:
@@ -23,6 +25,7 @@
 
   static bool IsEnrolledToDomain();
 };
+#endif
 
 class POLICY_EXPORT EnterpriseMDMManagementStatusProvider
     : public ManagementStatusProvider {
diff --git a/components/policy/core/common/registry_dict.cc b/components/policy/core/common/registry_dict.cc
index 01b08cf..14e5088 100644
--- a/components/policy/core/common/registry_dict.cc
+++ b/components/policy/core/common/registry_dict.cc
@@ -231,7 +231,8 @@
 
   for (auto entry(other.values_.begin()); entry != other.values_.end();
        ++entry) {
-    SetValue(entry->first, entry->second->CreateDeepCopy());
+    SetValue(entry->first,
+             base::Value::ToUniquePtrValue(entry->second->Clone()));
   }
 }
 
diff --git a/components/policy/resources/policy_templates_ko.xtb b/components/policy/resources/policy_templates_ko.xtb
index 728ba9a..e2863754 100644
--- a/components/policy/resources/policy_templates_ko.xtb
+++ b/components/policy/resources/policy_templates_ko.xtb
@@ -2322,6 +2322,7 @@
 
       정책을 사용 중지하거나 설정하지 않으면 기기에서 <ph name="PLUGIN_VM_NAME" />이 사용 설정되지 않습니다.</translation>
 <translation id="3973371701361892765">실행기를 자동으로 숨기지 않음</translation>
+<translation id="3977304360459208438">TLS에서 3DES 암호화 스위트의 기본 설정 사용</translation>
 <translation id="3979738908158213640">SAML 인증을 하는 동안 기기 증명을 실행할 권한이 부여되는 URL입니다.</translation>
 <translation id="3984028218719007910"><ph name="PRODUCT_OS_NAME" />이(가) 로그아웃 뒤에 로컬 계정 데이터를 유지할 지를 결정합니다. true로 설정하면, <ph name="PRODUCT_OS_NAME" />이(가) 유지하는 영구 계정이 없으며 사용자 세션의 모든 데이터가 로그아웃 뒤에 삭제됩니다. 이 정책이 false로 설정되거나 구성되지 않으면 기기는 암호화된 로컬 사용자 데이터를 유지합니다.</translation>
 <translation id="398884292557092447">정책을 True로 설정하거나 설정하지 않으면 사용자가 UI에서 신용카드의 자동 완성 추천을 제어할 수 있습니다.
@@ -2812,6 +2813,7 @@
           정책이 설정되면 사용자가 변경하거나 재정의할 수 없습니다.
 
           정책이 설정되지 않은 경우 처음에는 모노 오디오가 사용 중지되어 있으나 사용자가 언제든지 사용 설정할 수 있습니다.</translation>
+<translation id="4768446404233019970">TLS에서 3DES 암호화 스위트 사용 설정</translation>
 <translation id="4770334626033858263">부모 액세스 코드를 생성하고 확인하는 데 사용되는 설정입니다.</translation>
 <translation id="4787763197941188108">기본 인쇄 페이지 크기를 재정의합니다.
 
@@ -4476,6 +4478,32 @@
 <translation id="6907778402784621686">이 사이트에서 안전하지 않은 콘텐츠 차단</translation>
 <translation id="6908640907898649429">기본 검색 공급자를 설정합니다. 사용자가 사용할 기본 검색 공급자를 지정하거나 기본 검색을 사용 중지하도록 선택할 수 있습니다.</translation>
 <translation id="6913068954484253496"><ph name="PRODUCT_NAME" />에서 모든 IP 주소의 Cast 기기에 연결하도록 허용</translation>
+<translation id="6922498040906800267"><ph name="PRODUCT_OS_NAME" />의 데이터 유출을 방지하기 위해 규칙 목록을 구성합니다.
+      데이터 복사 및 붙여넣기, 파일 전송, 인쇄, 화면 공유, 스크린샷 찍기 등으로 인해 데이터가 유출될 수 있습니다.
+
+      각 규칙은 다음으로 구성됩니다.
+      - URL로 정의된 소스의 목록. 소스의 모든 데이터는 기밀 데이터로 간주되며 여기에는 제한사항이 적용됩니다.
+      - 기밀 정보의 공유가 허용되거나 허용되지 않는 URL 또는 구성요소로 정의된 대상 목록
+      - 소스 데이터에 적용되는 제한사항 목록
+
+      규칙은 다음을 위해 추가될 수 있습니다.
+      - 소스와 대상 사이에 공유되는 클립보드 데이터의 제어
+      - 소스 스크린샷의 촬영 제어
+      - 소스의 인쇄 제어
+      - 소스가 표시될 경우 개인 정보 보호 화면의 제어
+      - 소스의 화면 공유 제어
+
+      제한 수준은 BLOCK, ALLOW, REPORT로 설정될 수 있습니다.
+      - 제한 수준이 BLOCK으로 설정되면 작업은 허용되지 않습니다. <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" />가 True로 설정되면 차단된 작업이 관리자에게 보고됩니다.
+      - 제한 수준이 ALLOW로 설정되면 작업이 허용됩니다.
+      - 제한 수준이 REPORT로 설정되고 <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" />가 True로 설정되면 작업이 관리자에게 보고됩니다.
+
+      참고:
+      - PRIVACY_SCREEN 제한은 개인 정보 보호 화면을 사용 설정하는 기능을 차단하지 않으며 제한 클래스가 BLOCK으로 설정되면 이 기능을 실행합니다.
+      - 제한 중 하나가 CLIPBOARD인 경우 대상은 비어 있을 수 없으나 나머지 제한에는 아무 영향이 없습니다.
+      - URL 패턴 형식을 https://www.chromium.org/administrators/url-blocklist-filter-format 형식에 따라 지정합니다.
+
+      정책이 설정되어 있지 않을 경우 제한사항이 적용되지 않습니다.</translation>
 <translation id="6922884955650325312"><ph name="FLASH_PLUGIN_NAME" /> 플러그인 차단</translation>
 <translation id="6923731550900440989">로그인 화면에서 캐럿 강조표시 사용</translation>
 <translation id="6924223708804692571">맞춤법 검사 언어를 강제로 사용 중지합니다. 목록에서 인식할 수 없는 언어는 무시됩니다.
@@ -5044,6 +5072,7 @@
 <translation id="7612157962821894603"><ph name="PRODUCT_NAME" /> 시작 시 시스템 전체 플래그 적용</translation>
 <translation id="7613115815080726221">사용자 입력이 없어서 유휴 작업이 실행되기까지 걸리는 시간(밀리초)입니다.</translation>
 <translation id="7614663184588396421">사용할 수 없는 프로토콜 스키마 목록</translation>
+<translation id="7616631530432070402">TLS에서 3DES 암호화 스위트 사용 설정 예정</translation>
 <translation id="7620869951155758729">이 정책은 부모 액세스 코드를 생성하고 확인하는 데 사용되는 설정을 지정합니다.
 
       액세스 코드를 생성할 때는 항상 |current_config|가 사용되며, |future_config|를 사용해 액세스 코드를 확인할 수 없는 경우에만 액세스 코드 확인에 사용해야 합니다.
@@ -5497,6 +5526,12 @@
 <translation id="8217664958939773083">정책을 <ph name="ENABLED" />로 설정하거나 설정하지 않으면 헤드리스 모드의 사용이 허용됩니다. 정책을 <ph name="DISABLED" />로 설정하면 헤드리스 모드 사용이 허용되지 않습니다.</translation>
 <translation id="8220023426952118761">원하는 다운로드 속도(kbit/초)입니다.</translation>
 <translation id="8220156281401380422">기본 메시지 허용 목록 구성</translation>
+<translation id="8234316309673661069">경고: 3DES는 버전 95(2021년 10월경)부터 <ph name="PRODUCT_NAME" />에서 완전히 삭제되고 그 이후에는 이 정책이 작동하지 않습니다.
+
+      정책이 true로 설정되면 TLS의 3DES 암호화 스위트가 사용 설정됩니다. false로 설정되면 사용 중지됩니다. 정책이 설정되지 않으면 3DES 암호화 스위트가 현재 버전에서 기본적으로 사용 설정됩니다. <ph name="PRODUCT_NAME" /> 93에서는 기본적으로 사용 중지됩니다.
+
+      <ph name="PRODUCT_NAME" /> 92에서 이 정책은 변경사항을 미리 보고 비호환성을 테스트하는 데 사용될 수 있습니다. <ph name="PRODUCT_NAME" /> 93 이후에서는 오래된 서버와 일시적으로 호환성을 유지하는 데 사용될 수 있습니다. 임시방편이므로 서버를 다시 구성해야 합니다.
+      </translation>
 <translation id="8238421250255592181">터치 키보드가 자동 완성을 지원할 수 있는지 나타내는 부울 플래그입니다.</translation>
 <translation id="8244171102276095471">TLS에서 RC4 암호화 기술을 사용 설정합니다.</translation>
 <translation id="8244525275280476362">정책 무효화 후 최대 가져오기 지연</translation>
@@ -6256,6 +6291,7 @@
       정책을 사용 안함으로 설정하면 <ph name="PRODUCT_NAME" />은 그러한 확장 프로그램의 신규 설치 및 업데이트를 허용하지 않습니다. 이 정책은 <ph name="PRODUCT_NAME" /> 78 이후에는 영향을 미치지 않습니다.
 
       정책을 설정하지 않으면 <ph name="PRODUCT_NAME" /> 73부터 75까지는 사용으로 설정되고 <ph name="PRODUCT_NAME" /> 76과 77에서는 사용 안함으로 설정됩니다.</translation>
+<translation id="93985900824506396">TLS에서 3DES 암호화 스위트 사용 중지 예정</translation>
 <translation id="940706688964479124">다운로드 시 자동으로 열려야 하는 파일 유형 목록</translation>
 <translation id="943865157632139008"><ph name="PRODUCT_FRAME_NAME" />이(가) 설치될 때 기본 HTML 렌더러를 설정할 수 있습니다.
       기본 설정은 호스트 브라우저가 렌더링을 실행하도록 허용하지만 원하는 경우 기본 설정을 무시하고 <ph name="PRODUCT_FRAME_NAME" />이(가) HTML 페이지를 기본적으로 렌더링하도록 할 수 있습니다.</translation>
diff --git a/components/policy/resources/policy_templates_nl.xtb b/components/policy/resources/policy_templates_nl.xtb
index 4a01626c..571f0e4f 100644
--- a/components/policy/resources/policy_templates_nl.xtb
+++ b/components/policy/resources/policy_templates_nl.xtb
@@ -3849,7 +3849,7 @@
       Waarschuwing: Als je dit beleid instelt, kan de toepassing van software-updates worden vertraagd.</translation>
 <translation id="6208896993204286313">Beleidsgegevens van <ph name="PRODUCT_NAME" /> rapporteren</translation>
 <translation id="6210259502936598222">OS- en <ph name="PRODUCT_NAME" />-versiegegevens rapporteren</translation>
-<translation id="6212868225782276239">Alle printers worden getoond, behalve printers op de zwarte lijst.</translation>
+<translation id="6212868225782276239">Alle printers worden getoond, behalve printers op de blokkeerlijst.</translation>
 <translation id="6220835555850906733">Als je het beleid toepast of niet instelt, is alle ondersteunde audio-uitvoer op de apparaten van gebruikers toegestaan.
 
       Als je het beleid niet toepast, is er geen audio-uitvoer toegestaan terwijl gebruikers zijn ingelogd.
diff --git a/components/policy/resources/policy_templates_vi.xtb b/components/policy/resources/policy_templates_vi.xtb
index 25b3a575..b3689db 100644
--- a/components/policy/resources/policy_templates_vi.xtb
+++ b/components/policy/resources/policy_templates_vi.xtb
@@ -2327,6 +2327,7 @@
 
       Nếu bạn đặt thành Tắt hoặc không đặt chính sách này, <ph name="PLUGIN_VM_NAME" /> sẽ không bật cho thiết bị.</translation>
 <translation id="3973371701361892765">Không bao giờ tự động ẩn giá</translation>
+<translation id="3977304360459208438">Dùng chế độ cài đặt mặc định cho bộ thuật toán mật mã 3DES trong TLS</translation>
 <translation id="3979738908158213640">Các URL sẽ được cấp quyền truy cập để chứng thực thiết bị trong khi xác thực SAML</translation>
 <translation id="3984028218719007910">Xác định liệu <ph name="PRODUCT_OS_NAME" /> có lưu dữ liệu tài khoản trên máy sau khi đăng xuất hay không. Nếu được đặt thành đúng, không có tài khoản lâu dài nào được <ph name="PRODUCT_OS_NAME" /> lưu và tất cả các dữ liệu từ phiên của người dùng sẽ bị hủy bỏ sau khi đăng xuất. Nếu chính sách này được đặt thành sai hoặc không được định cấu hình, thiết bị có thể lưu lại dữ liệu người dùng trên máy (được mã hóa).</translation>
 <translation id="398884292557092447">Nếu bạn đặt chính sách này thành True hoặc không đặt, thì người dùng có thể kiểm soát các nội dung đề xuất tự động điền cho thẻ tín dụng trong giao diện người dùng.
@@ -2817,6 +2818,7 @@
           Nếu bạn đặt chính sách này, thì người dùng sẽ không thể thay đổi hay ghi đè chính sách.
 
           Nếu bạn không đặt chính sách này, thì ban đầu, chế độ đơn âm sẽ tắt nhưng người dùng có thể bật bất cứ lúc nào.</translation>
+<translation id="4768446404233019970">Bật bộ thuật toán mật mã 3DES trong TLS</translation>
 <translation id="4770334626033858263">Cấu hình dùng để tạo và xác minh Mã truy cập dành cho cha mẹ.</translation>
 <translation id="4787763197941188108">Ghi đè kích thước trang in mặc định.
 
@@ -4484,6 +4486,32 @@
 <translation id="6907778402784621686">Chặn nội dung không an toàn trên các trang web này</translation>
 <translation id="6908640907898649429">Định cấu hình nhà cung cấp dịch vụ tìm kiếm mặc định. Bạn có thể chỉ định nhà cung cấp dịch vụ tìm kiếm mặc định mà người dùng sẽ sử dụng hoặc chọn tắt tìm kiếm mặc định.</translation>
 <translation id="6913068954484253496">Cho phép <ph name="PRODUCT_NAME" /> kết nối với Thiết bị truyền trên tất cả các địa chỉ IP.</translation>
+<translation id="6922498040906800267">Thiết lập danh sách các quy tắc để ngăn rò rỉ dữ liệu trên <ph name="PRODUCT_OS_NAME" />.
+      Sự cố rò rỉ dữ liệu có thể xảy ra khi bạn sao chép và dán dữ liệu, chuyển tệp, in, chia sẻ màn hình hoặc chụp ảnh màn hình, v.v.
+
+      Mỗi quy tắc bao gồm những nội dung sau:
+      – Một danh sách các nguồn được xác định là URL. Mọi dữ liệu trong những nguồn này đều được coi là dữ liệu mật. Sẽ có các mức hạn chế áp dụng cho những dữ liệu mật này.
+      – Một danh sách các đích đến được xác định là URL hoặc thành phần mà bạn được phép hoặc không được phép chia sẻ dữ liệu mật.
+      – Một danh sách các mức hạn chế được áp dụng cho dữ liệu của những nguồn này.
+
+      Bạn có thể thêm các quy tắc để:
+      – Kiểm soát dữ liệu trong bảng nhớ tạm được chia sẻ giữa các nguồn và đích đến.
+      – Kiểm soát việc chụp ảnh màn hình bất kỳ nguồn nào.
+      – Kiểm soát việc in bất kỳ nguồn nào.
+      – Kiểm soát màn hình bảo vệ quyền riêng tư khi bất kỳ nguồn nào hiện ra.
+      – Kiểm soát việc chia sẻ màn hình bất kỳ nguồn nào.
+
+      Bạn có thể đặt mức hạn chế thành BLOCK, ALLOW, REPORT.
+      – Nếu bạn đặt thành BLOCK, mức hạn chế này sẽ không cho phép thực hiện thao tác. Nếu bạn đặt chính sách <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" /> thành Bật, thì quản trị viên sẽ nhận được báo cáo về thao tác bị chặn.
+      – Nếu bạn đặt thành ALLOW, mức hạn chế này sẽ cho phép thực hiện thao tác.
+      – Nếu bạn đặt mức hạn chế này thành REPORT và đặt chính sách <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" /> thành Bật, thì quản trị viên sẽ nhận được báo cáo về thao tác.
+
+      Lưu ý:
+      – Mức hạn chế PRIVACY_SCREEN không chặn thao tác bật màn hình bảo vệ quyền riêng tư, mà sẽ thực thi điều này khi bạn đặt mức hạn chế thành BLOCK.
+      – Bạn không được để trống các đích đến trong trường hợp một trong những mức hạn chế là CLIPBOARD. Tuy nhiên, các đích đến này không tạo ra sự khác biệt nào đối với các mức hạn chế còn lại.
+      – Đặt định dạng mẫu URL theo định dạng này (https://www.chromium.org/administrators/url-blocklist-filter-format).
+
+      Nếu bạn không đặt chính sách này, sẽ không có mức hạn chế nào được áp dụng.</translation>
 <translation id="6922884955650325312">Chặn plugin <ph name="FLASH_PLUGIN_NAME" /></translation>
 <translation id="6923731550900440989">Bật tính năng làm nổi bật dấu chèn trên màn hình đăng nhập</translation>
 <translation id="6924223708804692571">Buộc tắt các ngôn ngữ có tính năng kiểm tra chính tả. Các ngôn ngữ không nhận dạng được trong danh sách đó sẽ bị bỏ qua.
@@ -5052,6 +5080,7 @@
 <translation id="7612157962821894603">Cờ trên toàn hệ thống được áp dụng khi khởi động <ph name="PRODUCT_NAME" /></translation>
 <translation id="7613115815080726221">Khoảng thời gian (tính bằng mili giây) kể từ khi không có hoạt động đầu vào của người dùng cho đến thời điểm hệ thống thực hiện hành động khi chuyển sang trạng thái rảnh</translation>
 <translation id="7614663184588396421">Danh sách các lược đồ giao thức bị vô hiệu hóa</translation>
+<translation id="7616631530432070402">Bộ thuật toán mật mã 3DES sẽ được bật trong TLS</translation>
 <translation id="7620869951155758729">Chính sách này chỉ định cấu hình dùng để tạo và xác minh Mã truy cập dành cho cha mẹ.
 
       |current_config| luôn dùng để tạo mã truy cập và chỉ nên dùng để xác thực mã truy cập khi không thể xác thực mã này bằng |future_config|.
@@ -5502,6 +5531,12 @@
 <translation id="8217664958939773083">Nếu bạn đặt chính sách này thành <ph name="ENABLED" /> hoặc không đặt chính sách này, thì người dùng sẽ sử dụng được chế độ không có giao diện người dùng. Nếu bạn đặt chính sách này thành <ph name="DISABLED" />, thì người dùng sẽ không sử dụng được chế độ không có giao diện người dùng.</translation>
 <translation id="8220023426952118761">Tốc độ tải xuống mong muốn (tính bằng kbit/giây).</translation>
 <translation id="8220156281401380422">Định cấu hình danh sách cho phép máy chủ nhắn tin gốc</translation>
+<translation id="8234316309673661069">Cảnh báo: Bộ thuật toán mật mã 3DES sẽ bị xóa hoàn toàn khỏi <ph name="PRODUCT_NAME" /> trong phiên bản 95 (vào khoảng tháng 10 năm 2021). Khi đó, chính sách này sẽ ngừng hoạt động.
+
+      Nếu bạn đặt chính sách này thành bật, bộ thuật toán mật mã 3DES trong TLS sẽ được bật. Bộ thuật toán mật mã sẽ bị tắt nếu bạn đặt chính sách này thành tắt. Nếu bạn không đặt chính sách này, bộ thuật toán mật mã 3DES sẽ được bật theo mặc định. Trong <ph name="PRODUCT_NAME" /> phiên bản 93, bộ thuật toán mật mã sẽ bị tắt theo mặc định.
+
+      Trong <ph name="PRODUCT_NAME" /> phiên bản 92, bạn có thể dùng chính sách này để xem trước sự thay đổi và kiểm tra xem có vấn đề không tương thích không. Trong <ph name="PRODUCT_NAME" /> phiên bản 93 trở lên, bạn có thể dùng chính sách này để tạm thời duy trì khả năng tương thích với một máy chủ lỗi thời. Đây chỉ là giải pháp thay thế tạm thời nên bạn cần thiết lập lại máy chủ.
+      </translation>
 <translation id="8238421250255592181">Một cờ boolean cho biết liệu bàn phím ảo có thể cung cấp tính năng tự động hoàn thành hay không.</translation>
 <translation id="8244171102276095471">Bật bộ mật mã RC4 trong TLS</translation>
 <translation id="8244525275280476362">Độ trễ tìm nạp tối đa sau khi hủy hiệu lực chính sách</translation>
@@ -6261,6 +6296,7 @@
       Nếu bạn đặt chính sách này thành Tắt, thì <ph name="PRODUCT_NAME" /> sẽ không cho phép cài đặt (và cập nhật) các tiện ích đó. Chính sách này không ảnh hưởng đến <ph name="PRODUCT_NAME" /> 78 trở lên.
 
       Nếu bạn không đặt chính sách này, thì chính sách này sẽ ở trạng thái Bật trong <ph name="PRODUCT_NAME" /> 73 đến 75 và Tắt trong <ph name="PRODUCT_NAME" /> 76 và 77.</translation>
+<translation id="93985900824506396">Bộ thuật toán mật mã 3DES sẽ bị tắt trong TLS</translation>
 <translation id="940706688964479124">Danh sách các loại tệp tự động mở khi tải xuống</translation>
 <translation id="943865157632139008">Cho phép bạn định cấu hình trình hiển thị HTML mặc định khi <ph name="PRODUCT_FRAME_NAME" /> được cài đặt.
       Tùy chọn cài đặt mặc định này cho phép trình duyệt máy chủ thực hiện chức năng hiển thị nhưng bạn có thể tùy ý ghi đè tùy chọn cài đặt này và yêu cầu <ph name="PRODUCT_FRAME_NAME" /> hiển thị các trang HTML theo mặc định.</translation>
diff --git a/components/policy/resources/policy_templates_zh-TW.xtb b/components/policy/resources/policy_templates_zh-TW.xtb
index c410bf2..e8b1a869 100644
--- a/components/policy/resources/policy_templates_zh-TW.xtb
+++ b/components/policy/resources/policy_templates_zh-TW.xtb
@@ -2286,6 +2286,7 @@
 
       如果將這項政策設為停用或不設定,則裝置不會啟用 <ph name="PLUGIN_VM_NAME" />。</translation>
 <translation id="3973371701361892765">永不自動隱藏檔案櫃</translation>
+<translation id="3977304360459208438">在傳輸層安全標準 (TLS) 中使用 3DES 加密套件的預設設定</translation>
 <translation id="3979738908158213640">可在 SAML 驗證期間取得執行裝置認證存取權的網址</translation>
 <translation id="3984028218719007910">決定登出後 <ph name="PRODUCT_OS_NAME" /> 是否要保留本機帳戶資料。如果設為 True,<ph name="PRODUCT_OS_NAME" /> 不會保留任何永久帳戶,並且在登出後會刪除使用者工作階段的所有資料。如果這項政策設為 False 或未設定,裝置會保留 (加密) 本機使用者資料。</translation>
 <translation id="398884292557092447">如果將這項政策設為 True 或不設定,使用者將可控管 UI 中的信用卡自動填入建議。
@@ -2774,6 +2775,7 @@
           設定這項政策後,使用者即無法變更或覆寫。
 
           如果不設定這項政策,系統預設會停用單聲道音訊,但使用者隨時可以啟用這項功能。</translation>
+<translation id="4768446404233019970">在傳輸層安全標準 (TLS) 中啟用 3DES 加密套件</translation>
 <translation id="4770334626033858263">用於產生及驗證家長存取碼的設定。</translation>
 <translation id="4787763197941188108">覆寫預設的列印頁面大小。
 
@@ -4387,6 +4389,32 @@
 <translation id="6907778402784621686">封鎖這些網站上的不安全內容</translation>
 <translation id="6908640907898649429">設定預設搜尋引擎。你可以指定使用者要使用的預設搜尋引擎或選擇停用預設搜尋。</translation>
 <translation id="6913068954484253496">允許 <ph name="PRODUCT_NAME" /> 連線至所有 IP 位址上的 Cast 裝置。</translation>
+<translation id="6922498040906800267">設定規則清單,避免 <ph name="PRODUCT_OS_NAME" />中發生資料外洩。
+      複製並貼上資料、傳輸檔案、列印、分享螢幕畫面或擷取螢幕畫面等動作都有可能導致資料外洩。
+
+      每條規則都包含下列項目:
+      - 定義為網址的來源清單。系統會將來源中的所有資料都視為機密資料並套用限制。
+      - 定義為網址或元件的目的地清單,可允許或禁止將機密資料分享到清單中的目的地。
+      - 要套用到來源資料的限制清單。
+
+      你可以透過新增規則控管下列項目:
+      - 來源與目的地共用的剪貼簿資料。
+      - 任何來源的螢幕畫面擷取動作設定。
+      - 任何來源的列印動作設定。
+      - 任何來源在顯示狀態下的隱私保護畫面設定。
+      - 任何來源的螢幕畫面分享動作設定。
+
+      限制等級可設為「BLOCK」、「ALLOW」或「REPORT」。
+      - 如果將限制等級設為「BLOCK」,將無法執行該動作。如果將 <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" /> 設為 True,系統會將遭禁止的動作回報給管理員。
+      - 如果將限制等級設為「ALLOW」,則可以執行該動作。
+      - 如果將限制等級設為「REPORT」,並將 <ph name="DATA_LEAK_PREVENTION_REPORTING_ENABLED" /> 設為 True,系統會將該動作回報給管理員。
+
+      注意:
+      - PRIVACY_SCREEN 限制等級設為「BLOCK」時,不會禁止啟用隱私保護畫面,而會強制執行該功能。
+      - 如果有任一限制是「CLIPBOARD」,請勿將目的地留空,但目的地對其餘限制沒有影響。
+      - 網址格式如下:https://www.chromium.org/administrators/url-blocklist-filter-format。
+
+      如未設定這項政策,系統不會套用任何限制。</translation>
 <translation id="6922884955650325312">封鎖 <ph name="FLASH_PLUGIN_NAME" /> 外掛程式</translation>
 <translation id="6923731550900440989">在登入畫面上啟用插入點醒目顯示功能</translation>
 <translation id="6924223708804692571">這項政策會強制停用指定語言的拼字檢查功能。系統會忽略該清單中無法辨識的語言。
@@ -4952,6 +4980,7 @@
 <translation id="7612157962821894603">要在 <ph name="PRODUCT_NAME" /> 啟動時套用的全系統設定</translation>
 <translation id="7613115815080726221">閒置動作執行前的緩衝時間長度 (以毫秒為單位)。如果使用者在這段時間內沒有任何動作,系統就會採取閒置動作</translation>
 <translation id="7614663184588396421">停用的通訊協定機制清單</translation>
+<translation id="7616631530432070402">傳輸層安全標準 (TLS) 中將啟用 3DES 加密套件</translation>
 <translation id="7620869951155758729">這項政策可讓你指定用來產生及驗證家長存取碼的設定。請一律使用 |current_config| 來產生存取碼,而且只有在無法透過 |future_config| 驗證存取碼時,才能使用這項設定進行驗證。
       |future_config| 是驗證存取碼時主要使用的設定。只有在 |future_config| 和 |current_config| 兩者都無法用於驗證存取碼時,才能使用 |old_configs| 進行驗證。
 
@@ -5393,6 +5422,11 @@
 <translation id="8217664958939773083">如將這項政策設為「<ph name="ENABLED" />」或不設定,系統就會允許使用無頭模式;如將這項政策設為「<ph name="DISABLED" />」,則系統會禁止使用無頭模式。</translation>
 <translation id="8220023426952118761">理想的下載速率 (kbit/秒)。</translation>
 <translation id="8220156281401380422">設定內建訊息傳遞許可清單</translation>
+<translation id="8234316309673661069">警告:我們將從 <ph name="PRODUCT_NAME" /> 第 95 版中 (約在 2021 年 10 月推出) 完全移除 3DES,屆時這項政策也會停止運作。
+      如果將這項政策設為 True,系統會啟用傳輸層安全標準 (TLS) 中的 3DES 加密套件。如果設為 False,系統將停用這些加密套件。如果不設定這項政策,3DES 加密套件目前預設為啟用,不過自 <ph name="PRODUCT_NAME" /> 第 93 版起將預設為停用。
+
+      在 <ph name="PRODUCT_NAME" /> 第 92 版中,這項政策可以用來預覽變更及測試不相容問題。自 <ph name="PRODUCT_NAME" /> 第 93 版起,這項政策可以用來暫時保持與過舊伺服器的相容性。這種方法是權宜之計,伺服器應重新設定,才是正確的做法。
+      </translation>
 <translation id="8238421250255592181">布林值標記,表示螢幕小鍵盤是否能提供自動完成功能。</translation>
 <translation id="8244171102276095471">在傳輸層安全標準 (TLS) 中啟用 RC4 加密套件</translation>
 <translation id="8244525275280476362">政策失效後的最大擷取延遲</translation>
@@ -6135,6 +6169,7 @@
       如果將這項政策設為停用,<ph name="PRODUCT_NAME" /> 會禁止安裝及更新這類擴充功能。這項政策在 <ph name="PRODUCT_NAME" /> 78 以上版本中不會有任何作用。
 
       如果不設定這項政策,<ph name="PRODUCT_NAME" /> 73 至 75 版會啟用這項政策,<ph name="PRODUCT_NAME" /> 76 和 77 版會停用這項政策。</translation>
+<translation id="93985900824506396">傳輸層安全標準 (TLS) 中將停用 3DES 加密套件</translation>
 <translation id="940706688964479124">指定下載後應自動開啟的檔案類型清單</translation>
 <translation id="943865157632139008">這項政策可讓你在安裝 <ph name="PRODUCT_FRAME_NAME" />後,設定預設的 HTML 算繪器。
       系統在預設設定下,會允許主機瀏覽器進行算繪,但是你可以覆寫預設設定,改由 <ph name="PRODUCT_FRAME_NAME" />算繪 HTML 網頁。</translation>
diff --git a/components/prefs/overlay_user_pref_store_unittest.cc b/components/prefs/overlay_user_pref_store_unittest.cc
index 1c0c855..d8be47e6 100644
--- a/components/prefs/overlay_user_pref_store_unittest.cc
+++ b/components/prefs/overlay_user_pref_store_unittest.cc
@@ -145,7 +145,7 @@
   EXPECT_TRUE(underlay_->GetMutableValue(regular_key, &original_in_underlay));
   ASSERT_TRUE(original_in_underlay);
   ASSERT_TRUE(original_in_underlay->is_dict());
-  EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
+  EXPECT_TRUE(original_in_underlay->DictEmpty());
 
   Value* modified = nullptr;
   EXPECT_TRUE(overlay_->GetMutableValue(regular_key, &modified));
diff --git a/components/search_provider_logos/google_logo_api.cc b/components/search_provider_logos/google_logo_api.cc
index f763531..84b8a8f 100644
--- a/components/search_provider_logos/google_logo_api.cc
+++ b/components/search_provider_logos/google_logo_api.cc
@@ -169,7 +169,7 @@
     return nullptr;
 
   // If there is no logo today, the "ddljson" dictionary will be empty.
-  if (ddljson->empty()) {
+  if (ddljson->DictEmpty()) {
     *parsing_failed = false;
     return nullptr;
   }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
index a61765dd..f36c1b3 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
@@ -31,10 +31,10 @@
     void attachAccountsChangeObserver(AccountsChangeObserver observer);
 
     /**
-     * Get all the accounts synchronously.
+     * Get all the accounts on device synchronously.
      */
     @WorkerThread
-    Account[] getAccountsSync() throws AccountManagerDelegateException;
+    Account[] getAccounts();
 
     /**
      * Get an auth token.
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
index 901b9f98..d24d8b8 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
@@ -279,11 +279,7 @@
     }
 
     private List<Account> getAllAccounts() {
-        try {
-            return Collections.unmodifiableList(Arrays.asList(mDelegate.getAccountsSync()));
-        } catch (AccountManagerDelegateException ex) {
-            return Collections.emptyList();
-        }
+        return Collections.unmodifiableList(Arrays.asList(mDelegate.getAccounts()));
     }
 
     private List<Account> getFilteredAccounts() {
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
index 126cbf5..f4920ca2 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeTest.java
@@ -41,14 +41,14 @@
         private final CallbackHelper mBlockGetAccounts = new CallbackHelper();
 
         @Override
-        public Account[] getAccountsSync() {
+        public Account[] getAccounts() {
             // Blocks thread that's trying to get accounts from the delegate.
             try {
                 mBlockGetAccounts.waitForFirst();
             } catch (TimeoutException e) {
                 throw new RuntimeException(e);
             }
-            return super.getAccountsSync();
+            return super.getAccounts();
         }
 
         void unblockGetAccounts() {
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/public/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
index 0a82367e..fbd55521 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -88,17 +88,23 @@
     }
 
     @Override
-    public Account[] getAccountsSync() throws AccountManagerDelegateException {
-        if (!hasGetAccountsPermission() || !isGooglePlayServicesAvailable()) {
-            // Account seeding relies on GoogleAuthUtil.getAccountId to get GAIA ids,
-            // so don't report any accounts if Google Play Services are out of date.
-            return new Account[] {};
+    public Account[] getAccounts() {
+        if (hasGetAccountsPermission() && isGooglePlayServicesAvailable()) {
+            long startTime = SystemClock.elapsedRealtime();
+            Account[] accounts =
+                    mAccountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
+            recordElapsedTimeHistogram("Signin.AndroidGetAccountsTime_AccountManager",
+                    SystemClock.elapsedRealtime() - startTime);
+            return accounts;
         }
-        long now = SystemClock.elapsedRealtime();
-        Account[] accounts = mAccountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
-        long elapsed = SystemClock.elapsedRealtime() - now;
-        recordElapsedTimeHistogram("Signin.AndroidGetAccountsTime_AccountManager", elapsed);
-        return accounts;
+        // Account seeding relies on GoogleAuthUtil.getAccountId to get GAIA ids,
+        // so don't report any accounts if Google Play Services are out of date.
+        return new Account[] {};
+    }
+
+    @Deprecated
+    protected Account[] getAccountsSync() throws AccountManagerDelegateException {
+        return getAccounts();
     }
 
     @Override
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/AccountTrackerService.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/AccountTrackerService.java
index 0802999..fe39cbbe 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/AccountTrackerService.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/AccountTrackerService.java
@@ -135,9 +135,6 @@
         ThreadUtils.assertOnUiThread();
         final AccountManagerFacade accountManagerFacade =
                 AccountManagerFacadeProvider.getInstance();
-        if (!accountManagerFacade.isGooglePlayServicesAvailable()) {
-            return;
-        }
         assert mAccountsSeedingStatus
                 != AccountsSeedingStatus.IN_PROGRESS : "There is already a seeding in progress!";
         mAccountsSeedingStatus = AccountsSeedingStatus.IN_PROGRESS;
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
index 200545e..4fa317f 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public Account[] getAccountsSync() {
+    public Account[] getAccounts() {
         ArrayList<Account> result = new ArrayList<>();
         synchronized (mLock) {
             for (AccountHolder ah : mAccounts) {
diff --git a/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java b/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
index 5138cea..c4ecac4 100644
--- a/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
+++ b/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
@@ -100,16 +100,6 @@
     }
 
     @Test
-    public void testSeedAccountsWithoutGooglePlayServices() {
-        when(mFakeAccountManagerFacade.isGooglePlayServicesAvailable()).thenReturn(false);
-
-        mService.seedAccountsIfNeeded(mRunnableMock);
-
-        verify(mFakeAccountManagerFacade, never()).tryGetGoogleAccounts(any());
-        verify(mRunnableMock, never()).run();
-    }
-
-    @Test
     public void testSeedAccountsIfNeededBeforeAccountsAreSeeded() {
         mService.seedAccountsIfNeeded(mRunnableMock);
 
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb
index 10f2bc9..d722241 100644
--- a/components/strings/components_strings_en-GB.xtb
+++ b/components/strings/components_strings_en-GB.xtb
@@ -1173,6 +1173,7 @@
 <translation id="5314967030527622926">Booklet maker</translation>
 <translation id="5316812925700871227">Rotate Anti-clockwise</translation>
 <translation id="5317780077021120954">Save</translation>
+<translation id="5321288445143113935">Maximised</translation>
 <translation id="5323105697514565458"><ph name="FRIENDLY_MATCH_TEXT" />, <ph name="MATCH_POSITION" /> of <ph name="NUM_MATCHES" /></translation>
 <translation id="5324080437450482387">Choose contact info</translation>
 <translation id="5327248766486351172">Name</translation>
@@ -1398,6 +1399,7 @@
 <translation id="6218753634732582820">Remove address from Chromium?</translation>
 <translation id="622039917539443112">Parallel fold</translation>
 <translation id="6221345481584921695">Google Safe Browsing recently <ph name="BEGIN_LINK" />detected malware<ph name="END_LINK" /> on <ph name="SITE" />. Websites that are normally safe are sometimes infected with malware. The malicious content comes from <ph name="SUBRESOURCE_HOST" />, a known malware distributor.</translation>
+<translation id="6232619828520900263">ID currently invalid</translation>
 <translation id="6234122620015464377">Trim after each document</translation>
 <translation id="6240447795304464094">Google Pay logo</translation>
 <translation id="6241121617266208201">Hide suggestions</translation>
diff --git a/components/strings/components_strings_lo.xtb b/components/strings/components_strings_lo.xtb
index d3ffe754..417f6f94 100644
--- a/components/strings/components_strings_lo.xtb
+++ b/components/strings/components_strings_lo.xtb
@@ -1174,6 +1174,7 @@
 <translation id="5314967030527622926">ເຄື່ອງສ້າງປຶ້ມນ້ອຍ</translation>
 <translation id="5316812925700871227">ໝຸນ​​ທວນ​ເຂັມ​ໂມງ</translation>
 <translation id="5317780077021120954">ບັນທຶກ</translation>
+<translation id="5321288445143113935">ຂະຫຍາຍເຕັມແລ້ວ</translation>
 <translation id="5323105697514565458"><ph name="FRIENDLY_MATCH_TEXT" />, <ph name="MATCH_POSITION" /> ໃນ <ph name="NUM_MATCHES" /></translation>
 <translation id="5324080437450482387">ເລືອກຂໍ້ມູນຕິດຕໍ່</translation>
 <translation id="5327248766486351172">ຊື່</translation>
@@ -1399,6 +1400,7 @@
 <translation id="6218753634732582820">ເອົາ​ທີ່​ຢູ່​ອອກ​​ຈາກ Chromium ບໍ?</translation>
 <translation id="622039917539443112">ພັບແບບຂະໜານ</translation>
 <translation id="6221345481584921695">ເມື່ອບໍ່ດົນມານີ້ Google Safe Browsing <ph name="BEGIN_LINK" />ໄດ້ກວດພົບມາລແວ<ph name="END_LINK" /> ຢູ່ເທິງ <ph name="SITE" />. ເວັບໄຊທ໌ທີ່ປົກກະຕິແລ້ວນັ້ນມີຄວາມປອດໄພແມ່ນບາງຄັ້ງຈະຕິດມາລແວ. ເນື້ອໃນທີ່ປອງຮ້າຍມາຈາກ <ph name="SUBRESOURCE_HOST" />, ຜູ້ຈໍາໜ່າຍມາລແວທີ່ຮູ້ຈັກ.</translation>
+<translation id="6232619828520900263">ຕອນນີ້ ID ບໍ່ຖືກຕ້ອງ</translation>
 <translation id="6234122620015464377">ຕັດອອກຫຼັງຈາກເອກະສານແຕ່ລະອັນ</translation>
 <translation id="6240447795304464094">ໂລໂກ້ Google Pay</translation>
 <translation id="6241121617266208201">ເຊື່ອງການແນະນຳ</translation>
diff --git a/components/strings/components_strings_ms.xtb b/components/strings/components_strings_ms.xtb
index f518b0b..edce1e4 100644
--- a/components/strings/components_strings_ms.xtb
+++ b/components/strings/components_strings_ms.xtb
@@ -1175,6 +1175,7 @@
 <translation id="5314967030527622926">Pembuat buku kecil</translation>
 <translation id="5316812925700871227">Putar lawan arah jam</translation>
 <translation id="5317780077021120954">Simpan</translation>
+<translation id="5321288445143113935">Dimaksimumkan</translation>
 <translation id="5323105697514565458"><ph name="FRIENDLY_MATCH_TEXT" />, <ph name="MATCH_POSITION" /> daripada <ph name="NUM_MATCHES" /></translation>
 <translation id="5324080437450482387">Pilih Maklumat Hubungan</translation>
 <translation id="5327248766486351172">Nama</translation>
@@ -1400,6 +1401,7 @@
 <translation id="6218753634732582820">Alih keluar alamat daripada Chromium?</translation>
 <translation id="622039917539443112">Lipatan selari</translation>
 <translation id="6221345481584921695">Penyemakan Selamat Google <ph name="BEGIN_LINK" />telah mengesan perisian hasad<ph name="END_LINK" /> pada <ph name="SITE" /> baru-baru ini. Tapak web yang lazimnya selamat kadangkala dijangkiti oleh perisian hasad. Kandungan berniat jahat datang dari <ph name="SUBRESOURCE_HOST" />, pengedar perisian hasad yang diketahui.</translation>
+<translation id="6232619828520900263">ID tidak sah pada masa ini</translation>
 <translation id="6234122620015464377">Pangkas selepas setiap dokumen</translation>
 <translation id="6240447795304464094">Logo Google Pay</translation>
 <translation id="6241121617266208201">Sembunyikan cadangan</translation>
diff --git a/components/strings/components_strings_si.xtb b/components/strings/components_strings_si.xtb
index 9fdfcb6..bbe0bcc 100644
--- a/components/strings/components_strings_si.xtb
+++ b/components/strings/components_strings_si.xtb
@@ -1169,6 +1169,7 @@
 <translation id="5314967030527622926">පුස්තිකා සාදන්නා</translation>
 <translation id="5316812925700871227">දක්ෂිණාවර්තව කරකවන්න</translation>
 <translation id="5317780077021120954">සුරකින්න</translation>
+<translation id="5321288445143113935">විශාල කරන ලදි</translation>
 <translation id="5323105697514565458"><ph name="FRIENDLY_MATCH_TEXT" />, <ph name="NUM_MATCHES" />න් <ph name="MATCH_POSITION" /></translation>
 <translation id="5324080437450482387">සම්බන්ධතා තතු තෝරාගන්න</translation>
 <translation id="5327248766486351172">නම</translation>
@@ -1394,6 +1395,7 @@
 <translation id="6218753634732582820">Chromium වෙතින් ලිපිනය ඉවත් කරන්නද?</translation>
 <translation id="622039917539443112">සමාන්තර නැමීම</translation>
 <translation id="6221345481584921695">Google සුරක්ෂිත පිරික්සුම විසින් මෑතකදී <ph name="BEGIN_LINK" />අනිෂ්ට මෘදුකාංග<ph name="END_LINK" /> <ph name="SITE" /> මත අනාවරණය කර ගැනිණි. සාමාන්‍යයෙන් සුරක්ෂිත වෙබ් අඩවි සමහර විට අනිෂ්ට මෘදුකාංගවලින් ආසාදනය වෙයි. දන්නා අනිෂ්ට මෘදුකාංග බෙදා හරින්නෙකු වන <ph name="SUBRESOURCE_HOST" />, වෙතින් අනිෂ්ට අන්තර්ගතය පැමිණිය හැක.</translation>
+<translation id="6232619828520900263">ID දැනට වලංගු නොවේ</translation>
 <translation id="6234122620015464377">සෑම ලේඛනයකටම පසුව කප්පාදු කරන්න</translation>
 <translation id="6240447795304464094">Google Pay ලාංඡනය</translation>
 <translation id="6241121617266208201">යෝජනා සඟවන්න</translation>
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
index f4b27e0..7b277a74 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
+++ b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
@@ -59,7 +59,7 @@
       /*poll_interval=*/base::TimeDelta::FromMinutes(30),
       /*has_remaining_local_changes=*/false);
   std::unique_ptr<base::DictionaryValue> value(snapshot.ToValue());
-  EXPECT_EQ(21u, value->size());
+  EXPECT_EQ(21u, value->DictSize());
   ExpectDictStringValue(kBirthday, *value, "birthday");
   // Base64-encoded version of |kBagOfChips|.
   ExpectDictStringValue("YmFnb2ZjaGlwcwE=", *value, "bagOfChips");
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc
index 646412e..011de8a 100644
--- a/components/sync/protocol/proto_value_conversions_unittest.cc
+++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -155,7 +155,7 @@
 
   std::unique_ptr<base::DictionaryValue> value(
       BookmarkSpecificsToValue(specifics));
-  EXPECT_FALSE(value->empty());
+  EXPECT_FALSE(value->DictEmpty());
   std::string encoded_time;
   EXPECT_TRUE(value->GetString("creation_time_us", &encoded_time));
   EXPECT_EQ(base::NumberToString(creation_time.ToInternalValue()),
@@ -234,13 +234,13 @@
 
   std::unique_ptr<base::DictionaryValue> value_with_specifics(
       ClientToServerMessageToValue(message, true /* include_specifics */));
-  EXPECT_FALSE(value_with_specifics->empty());
+  EXPECT_FALSE(value_with_specifics->DictEmpty());
   EXPECT_TRUE(
       ValueHasSpecifics(*(value_with_specifics.get()), "commit.entries"));
 
   std::unique_ptr<base::DictionaryValue> value_without_specifics(
       ClientToServerMessageToValue(message, false /* include_specifics */));
-  EXPECT_FALSE(value_without_specifics->empty());
+  EXPECT_FALSE(value_without_specifics->DictEmpty());
   EXPECT_FALSE(
       ValueHasSpecifics(*(value_without_specifics.get()), "commit.entries"));
 }
@@ -255,13 +255,13 @@
 
   std::unique_ptr<base::DictionaryValue> value_with_specifics(
       ClientToServerResponseToValue(message, true /* include_specifics */));
-  EXPECT_FALSE(value_with_specifics->empty());
+  EXPECT_FALSE(value_with_specifics->DictEmpty());
   EXPECT_TRUE(
       ValueHasSpecifics(*(value_with_specifics.get()), "get_updates.entries"));
 
   std::unique_ptr<base::DictionaryValue> value_without_specifics(
       ClientToServerResponseToValue(message, false /* include_specifics */));
-  EXPECT_FALSE(value_without_specifics->empty());
+  EXPECT_FALSE(value_without_specifics->DictEmpty());
   EXPECT_FALSE(ValueHasSpecifics(*(value_without_specifics.get()),
                                  "get_updates.entries"));
 }
diff --git a/components/sync/protocol/vault.proto b/components/sync/protocol/vault.proto
index 7ba8e41..ad27b96 100644
--- a/components/sync/protocol/vault.proto
+++ b/components/sync/protocol/vault.proto
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-syntax = "proto2";
+// Trusted vault protos to communicate with backend written in proto3 to avoid
+// subtle differences between enum fields.
+syntax = "proto3";
 
 option optimize_for = LITE_RUNTIME;
 
@@ -10,33 +12,33 @@
 package sync_pb;
 
 message SharedMemberKey {
-  optional int32 epoch = 1;
-  optional bytes wrapped_key = 2;
-  optional bytes member_proof = 3;
+  int32 epoch = 1;
+  bytes wrapped_key = 2;
+  bytes member_proof = 3;
 }
 
 message RotationProof {
-  optional int32 new_epoch = 1;
-  optional bytes rotation_proof = 2;
+  int32 new_epoch = 1;
+  bytes rotation_proof = 2;
 }
 
 message SecurityDomainDetails {
-  message SyncDetails { optional bool degraded_recoverability = 1; }
+  message SyncDetails { bool degraded_recoverability = 1; }
 
-  optional SyncDetails sync_details = 1;
+  SyncDetails sync_details = 1;
 }
 
 message SecurityDomain {
-  optional string name = 1;
-  optional SecurityDomainDetails security_domain_details = 3;
+  string name = 1;
+  SecurityDomainDetails security_domain_details = 3;
 }
 
 message SecurityDomainMember {
-  optional string name = 1;
-  optional bytes public_key = 2;
+  string name = 1;
+  bytes public_key = 2;
 
   message SecurityDomainMembership {
-    optional string security_domain = 1;
+    string security_domain = 1;
     repeated SharedMemberKey keys = 3;
     repeated RotationProof rotation_proofs = 4;
   }
@@ -48,11 +50,11 @@
     MEMBER_TYPE_PHYSICAL_DEVICE = 1;
   }
 
-  optional MemberType member_type = 4;
+  MemberType member_type = 4;
 }
 
 message JoinSecurityDomainsRequest {
-  optional SecurityDomain security_domain = 1;
-  optional SecurityDomainMember security_domain_member = 2;
-  optional SharedMemberKey shared_member_key = 3;
+  SecurityDomain security_domain = 1;
+  SecurityDomainMember security_domain_member = 2;
+  SharedMemberKey shared_member_key = 3;
 }
diff --git a/components/sync/trusted_vault/fake_security_domains_server.cc b/components/sync/trusted_vault/fake_security_domains_server.cc
index 4e7e4a26..c285eac 100644
--- a/components/sync/trusted_vault/fake_security_domains_server.cc
+++ b/components/sync/trusted_vault/fake_security_domains_server.cc
@@ -255,13 +255,13 @@
 
   const sync_pb::SharedMemberKey& shared_key =
       deserialized_content.shared_member_key();
-  if (shared_key.has_epoch() && shared_key.epoch() != state_.current_epoch) {
+  if (shared_key.epoch() != 0 && shared_key.epoch() != state_.current_epoch) {
     auto response = std::make_unique<net::test_server::BasicHttpResponse>();
     response->set_code(net::HTTP_PRECONDITION_FAILED);
     return response;
   }
 
-  if (shared_key.has_epoch()) {
+  if (shared_key.epoch() != 0) {
     // Valid joining of existing security domain.
     state_.public_key_to_shared_keys[member.public_key()] = {shared_key};
     auto response = std::make_unique<net::test_server::BasicHttpResponse>();
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
index 277eb74..801d7cc 100644
--- a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
+++ b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
@@ -262,7 +262,7 @@
 
   const sync_pb::SharedMemberKey& shared_key =
       deserialized_body.shared_member_key();
-  EXPECT_FALSE(shared_key.has_epoch());
+  EXPECT_THAT(shared_key.epoch(), Eq(0));
 
   EXPECT_THAT(DecryptTrustedVaultWrappedKey(
                   key_pair->private_key(),
diff --git a/content/browser/renderer_host/cors_rfc1918_browsertest.cc b/content/browser/renderer_host/cors_rfc1918_browsertest.cc
index b0b54f2..af588c4 100644
--- a/content/browser/renderer_host/cors_rfc1918_browsertest.cc
+++ b/content/browser/renderer_host/cors_rfc1918_browsertest.cc
@@ -7,7 +7,6 @@
 #include <string>
 #include <vector>
 
-#include "base/bind.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
 #include "base/test/scoped_feature_list.h"
@@ -20,64 +19,38 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
-#include "content/public/test/url_loader_interceptor.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
 #include "content/test/test_content_browser_client.h"
-#include "net/base/ip_address.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "services/network/public/mojom/url_loader.mojom.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
 namespace content {
 namespace {
 
-constexpr char kInsecureHost[] = "foo.test";
+// These domains are mapped to the IP addresses above using the
+// `--host-resolver-rules` command-line switch. The exact values come from the
+// embedded HTTPS server, which has certificates for these domains
+constexpr char kLocalHost[] = "a.test";
+constexpr char kPrivateHost[] = "b.test";
+constexpr char kPublicHost[] = "c.test";
 
+// Path to a default response served by all servers in this test.
 constexpr char kDefaultPath[] = "/defaultresponse";
 
+// Path to a response with the `treat-as-public-address` CSP directive.
 constexpr char kTreatAsPublicAddressPath[] =
     "/set-header?Content-Security-Policy: treat-as-public-address";
 
-GURL SecureURL(const net::EmbeddedTestServer& server, const std::string& path) {
-  // http://localhost is considered secure. Relying on this is easier than using
-  // the HTTPS test server, since that server cannot lie about its domain name,
-  // so we have to use localhost anyway.
-  return server.GetURL(path);
-}
-
-GURL InsecureURL(const net::EmbeddedTestServer& server,
-                 const std::string& path) {
-  // The mock resolver is set to resolve anything to 127.0.0.1, so we use
-  // http://foo.test as an insecure origin.
-  return server.GetURL(kInsecureHost, path);
-}
-
-GURL SecureDefaultURL(const net::EmbeddedTestServer& server) {
-  return SecureURL(server, kDefaultPath);
-}
-
-GURL InsecureDefaultURL(const net::EmbeddedTestServer& server) {
-  return InsecureURL(server, kDefaultPath);
-}
-
-GURL SecureTreatAsPublicAddressURL(const net::EmbeddedTestServer& server) {
-  return SecureURL(server, kTreatAsPublicAddressPath);
-}
-
-GURL InsecureTreatAsPublicAddressURL(const net::EmbeddedTestServer& server) {
-  return InsecureURL(server, kTreatAsPublicAddressPath);
-}
-
 // Returns a snippet of Javascript that fetch()es the given URL.
 //
 // The snippet evaluates to a boolean promise which resolves to true iff the
 // fetch was successful. The promise never rejects, as doing so makes it hard
 // to assert failure.
-std::string FetchSubresourceScript(const std::string& url_spec) {
+std::string FetchSubresourceScript(const GURL& url) {
   return JsReplace(
       R"(fetch($1).then(
            response => response.ok,
@@ -86,111 +59,7 @@
              return false;
            });
       )",
-      url_spec);
-}
-
-// Returns an IP address in the private address space.
-net::IPAddress PrivateAddress() {
-  return net::IPAddress(10, 0, 1, 2);
-}
-
-// Returns an IP address in the public address space.
-net::IPAddress PublicAddress() {
-  return net::IPAddress(40, 0, 1, 2);
-}
-
-// Minimal response headers for an intercepted response to be successful.
-constexpr base::StringPiece kMinimalResponseHeaders =  // force line break
-    R"(HTTP/1.0 200 OK
-Content-type: text/html
-
-)";
-
-// Minimal response headers for an intercepted response to be an error page.
-constexpr base::StringPiece kMinimalErrorResponseHeaders =
-    "HTTP/1.0 404 Not Found";
-
-// Minimal response body containing an HTML document.
-constexpr base::StringPiece kMinimalHtmlBody = R"(
-<html>
-<head></head>
-<body></body>
-</html>
-)";
-
-// Wraps the URLLoaderInterceptor method of the same name, asserts success.
-//
-// Note: ASSERT_* macros can only be used in functions returning void.
-void WriteResponseBody(base::StringPiece body,
-                       network::mojom::URLLoaderClient* client) {
-  ASSERT_EQ(content::URLLoaderInterceptor::WriteResponseBody(body, client),
-            MOJO_RESULT_OK);
-}
-
-// Helper for MaybeInterceptWithFakeEndPoint.
-network::mojom::URLResponseHeadPtr BuildInterceptedResponseHead(
-    const net::IPEndPoint& endpoint,
-    bool should_succeed) {
-  auto response = network::mojom::URLResponseHead::New();
-  base::StringPiece headers_string =
-      should_succeed ? kMinimalResponseHeaders : kMinimalErrorResponseHeaders;
-  response->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
-      net::HttpUtil::AssembleRawHeaders(headers_string));
-  if (should_succeed)
-    response->headers->GetMimeType(&response->mime_type);
-  response->remote_endpoint = endpoint;
-  return response;
-}
-
-// Helper for InterceptorWithFakeEndPointInternal.
-bool MaybeInterceptWithFakeEndPoint(
-    const GURL& intercepted_url,
-    const net::IPEndPoint& endpoint,
-    bool should_succeed,
-    content::URLLoaderInterceptor::RequestParams* params) {
-  const GURL& request_url = params->url_request.url;
-  if (request_url != intercepted_url) {
-    LOG(INFO) << "MaybeInterceptWithFakeEndPoint: ignoring request to "
-              << request_url;
-    return false;
-  }
-
-  LOG(INFO) << "MaybeInterceptWithFakeEndPoint: intercepting request to "
-            << request_url;
-
-  params->client->OnReceiveResponse(
-      BuildInterceptedResponseHead(endpoint, should_succeed));
-  WriteResponseBody(kMinimalHtmlBody, params->client.get());
-  return true;
-}
-
-std::unique_ptr<content::URLLoaderInterceptor>
-InterceptorWithFakeEndPointInternal(const GURL& url,
-                                    const net::IPEndPoint& endpoint,
-                                    bool should_succeed) {
-  LOG(INFO) << "Starting to intercept requests to " << url
-            << " with fake endpoint " << endpoint.ToString();
-  return std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
-      &MaybeInterceptWithFakeEndPoint, url, endpoint, should_succeed));
-}
-
-// The returned interceptor intercepts requests to |url|, fakes its network
-// endpoint to reflect the value of |endpoint|, and responds OK with a minimal
-// HTML body.
-std::unique_ptr<content::URLLoaderInterceptor> InterceptorWithFakeEndPoint(
-    const GURL& url,
-    const net::IPEndPoint& endpoint) {
-  return InterceptorWithFakeEndPointInternal(url, endpoint,
-                                             /* should_succeed=*/true);
-}
-
-// The returned interceptor intercepts requests to |url|, fakes its network
-// endpoint to reflect the value of |endpoint|, and responds with a 404 error.
-std::unique_ptr<content::URLLoaderInterceptor> FailInterceptorWithFakeEndPoint(
-    const GURL& url,
-    const net::IPEndPoint& endpoint) {
-  return InterceptorWithFakeEndPointInternal(url, endpoint,
-                                             /* should_succeed=*/false);
+      url);
 }
 
 // A |ContentBrowserClient| implementation that allows modifying the return
@@ -235,27 +104,119 @@
   ContentBrowserClient* const old_client_;
 };
 
+// A `net::EmbeddedTestServer` that only starts on demand and pretends to be
+// in a particular IP address space.
+//
+// NOTE(titouan): The IP address space overrides CLI switch is copied to utility
+// processes when said processes are started. If we start a lazy server after
+// the network process has started, any updates we make to our own CLI switches
+// will not propagate to the network process, yielding inconsistent results.
+// These tests currently do not rely on this behavior - the IP address space of
+// documents is calculated in the browser process, and all network resources
+// fetched in this test are `local`. If we want to fix this, we can get rid of
+// the fancy lazy-initialization and simply start all servers at test fixture
+// construction time, then set up the CLI switch in `SetUpCommandLine()`.
+class LazyServer {
+ public:
+  LazyServer(net::EmbeddedTestServer::Type type,
+             network::mojom::IPAddressSpace ip_address_space,
+             base::FilePath test_data_path)
+      : type_(type),
+        ip_address_space_(ip_address_space),
+        test_data_path_(std::move(test_data_path)) {}
+
+  net::EmbeddedTestServer& Get() {
+    if (!server_) {
+      Initialize();
+    }
+    return *server_;
+  }
+
+ private:
+  void Initialize() {
+    server_ = std::make_unique<net::EmbeddedTestServer>(type_);
+
+    // Use a certificate valid for multiple domains, which we can use to
+    // distinguish `local`, `private` and `public` address spaces.
+    server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+
+    server_->AddDefaultHandlers(test_data_path_);
+    EXPECT_TRUE(server_->Start());
+
+    AddCommandLineOverride();
+  }
+
+  // Sets up the command line in order for this server to be considered a part
+  // of `ip_address_space_`, irrespective of the actual IP it binds to.
+  void AddCommandLineOverride() const {
+    DCHECK(server_);
+
+    base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+    std::string switch_str = command_line.GetSwitchValueASCII(
+        network::switches::kIpAddressSpaceOverrides);
+
+    // If `switch_str` was empty, we prepend an empty value by unconditionally
+    // adding a comma before the new entry. This empty value is ignored by the
+    // switch parsing logic.
+    base::StrAppend(&switch_str,
+                    {
+                        ",",
+                        server_->host_port_pair().ToString(),
+                        "=",
+                        IPAddressSpaceToSwitchValue(ip_address_space_),
+                    });
+
+    command_line.AppendSwitchASCII(network::switches::kIpAddressSpaceOverrides,
+                                   switch_str);
+  }
+
+  static base::StringPiece IPAddressSpaceToSwitchValue(
+      network::mojom::IPAddressSpace space) {
+    switch (space) {
+      case network::mojom::IPAddressSpace::kLocal:
+        return "local";
+      case network::mojom::IPAddressSpace::kPrivate:
+        return "private";
+      case network::mojom::IPAddressSpace::kPublic:
+        return "public";
+      default:
+        ADD_FAILURE() << "Unhandled address space " << space;
+        return "";
+    }
+  }
+
+  net::EmbeddedTestServer::Type type_;
+  network::mojom::IPAddressSpace ip_address_space_;
+  base::FilePath test_data_path_;
+  std::unique_ptr<net::EmbeddedTestServer> server_;
+};
+
 }  // namespace
 
-// It is hard to test this feature fully at the integration test level. Indeed,
-// there is no good way to inject a fake endpoint value into the URLLoader code
-// that performs the CORS-RFC1918 checks. The most intrusive injection
-// primitive, URLLoaderInterceptor, cannot be made to work as it bypasses the
-// network service entirely. Intercepted subresource requests therefore do not
-// execute the code under test and are never blocked.
+// This being an integration/browser test, we concentrate on a few behaviors
+// relevant to Private Network Access:
 //
-// We are able to intercept top-level navigations, which allows us to test that
-// the correct address space is committed in the client security state for
-// local, private and public IP addresses.
+//  - testing the values of important properties on top-level documents:
+//    - address space
+//    - secure context bit
+//    - private network request policy
+//  - testing the inheritance semantics of these properties
+//  - testing the correct handling of the CSP: treat-as-public-address directive
+//  - testing that insecure private network requests are blocked when the right
+//    feature flag is enabled
+//  - and a few other odds and ends
 //
-// We further test that given a client security state with each IP address
-// space, subresource requests served by local IP addresses fail unless
-// initiated from the same address space. This provides integration testing
-// coverage for both success and failure cases of the code under test.
+// We use the `--ip-address-space-overrides` command-line switch to test against
+// `private` and `public` address spaces, even though all responses are actually
+// served from localhost. Combined with host resolver rules, this lets us define
+// three different domains that map to the different address spaces:
 //
-// Finally, we have unit tests that test all possible combinations of source and
+//  - `a.test` is `local`
+//  - `b.test` is `private`
+//  - `c.test` is `public`
+//
+// We also have unit tests that test all possible combinations of source and
 // destination IP address spaces in services/network/url_loader_unittest.cc.
-// Those cover fetches to other address spaces than local.
 class CorsRfc1918BrowserTestBase : public ContentBrowserTest {
  public:
   RenderFrameHostImpl* root_frame_host() {
@@ -266,25 +227,72 @@
  protected:
   // Allows subclasses to construct instances with different features enabled.
   explicit CorsRfc1918BrowserTestBase(
-      const std::vector<base::Feature>& enabled_features) {
+      const std::vector<base::Feature>& enabled_features)
+      : insecure_local_server_(net::EmbeddedTestServer::TYPE_HTTP,
+                               network::mojom::IPAddressSpace::kLocal,
+                               GetTestDataFilePath()),
+        insecure_private_server_(net::EmbeddedTestServer::TYPE_HTTP,
+                                 network::mojom::IPAddressSpace::kPrivate,
+                                 GetTestDataFilePath()),
+        insecure_public_server_(net::EmbeddedTestServer::TYPE_HTTP,
+                                network::mojom::IPAddressSpace::kPublic,
+                                GetTestDataFilePath()),
+        secure_local_server_(net::EmbeddedTestServer::TYPE_HTTPS,
+                             network::mojom::IPAddressSpace::kLocal,
+                             GetTestDataFilePath()),
+        secure_private_server_(net::EmbeddedTestServer::TYPE_HTTPS,
+                               network::mojom::IPAddressSpace::kPrivate,
+                               GetTestDataFilePath()),
+        secure_public_server_(net::EmbeddedTestServer::TYPE_HTTPS,
+                              network::mojom::IPAddressSpace::kPublic,
+                              GetTestDataFilePath()) {
     feature_list_.InitWithFeatures(enabled_features, {});
-
-    StartServer();
   }
 
   void SetUpOnMainThread() override {
     ContentBrowserTest::SetUpOnMainThread();
 
-    // |kInsecureHost| serves as an insecure alternative to `localhost`.
-    // This must be called on the main thread lest it segfaults.
-    host_resolver()->AddRule(kInsecureHost, "127.0.0.1");
+    // Rules must be added on the main thread, otherwise `AddRule()` segfaults.
+    host_resolver()->AddRule(kLocalHost, "127.0.0.1");
+    host_resolver()->AddRule(kPrivateHost, "127.0.0.1");
+    host_resolver()->AddRule(kPublicHost, "127.0.0.1");
+  }
+
+  GURL InsecureLocalURL(const std::string& path) {
+    return insecure_local_server_.Get().GetURL(kLocalHost, path);
+  }
+
+  GURL InsecurePrivateURL(const std::string& path) {
+    return insecure_private_server_.Get().GetURL(kPrivateHost, path);
+  }
+
+  GURL InsecurePublicURL(const std::string& path) {
+    return insecure_public_server_.Get().GetURL(kPublicHost, path);
+  }
+
+  GURL SecureLocalURL(const std::string& path) {
+    return secure_local_server_.Get().GetURL(kLocalHost, path);
+  }
+
+  GURL SecurePrivateURL(const std::string& path) {
+    return secure_private_server_.Get().GetURL(kPrivateHost, path);
+  }
+
+  GURL SecurePublicURL(const std::string& path) {
+    return secure_public_server_.Get().GetURL(kPublicHost, path);
   }
 
  private:
-  // Constructor helper. We cannot use ASSERT_* macros in constructors.
-  void StartServer() { ASSERT_TRUE(embedded_test_server()->Start()); }
-
   base::test::ScopedFeatureList feature_list_;
+
+  // All servers are started on demand. Most tests require the use of one or
+  // two servers, never six at the same time.
+  LazyServer insecure_local_server_;
+  LazyServer insecure_private_server_;
+  LazyServer insecure_public_server_;
+  LazyServer secure_local_server_;
+  LazyServer secure_private_server_;
+  LazyServer secure_public_server_;
 };
 
 // Test with insecure private network requests blocked, excluding navigations.
@@ -318,10 +326,10 @@
 // are blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTestBlockNavigations,
                        IframeFromInsecureTreatAsPublicToLocalIsBlocked) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureLocalURL(kTreatAsPublicAddressPath)));
 
-  GURL url = InsecureURL(*embedded_test_server(), "/empty.html");
+  GURL url = InsecureLocalURL("/empty.html");
 
   TestNavigationManager child_navigation_manager(shell()->web_contents(), url);
 
@@ -354,10 +362,10 @@
 // the navigation is not blocked in this case.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeFromInsecureTreatAsPublicToLocalIsNotBlocked) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureLocalURL(kTreatAsPublicAddressPath)));
 
-  GURL url = InsecureURL(*embedded_test_server(), "/empty.html");
+  GURL url = InsecureLocalURL("/empty.html");
 
   TestNavigationManager child_navigation_manager(shell()->web_contents(), url);
 
@@ -383,11 +391,11 @@
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        CspReportOnlyTreatAsPublicAddressIgnored) {
   EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureURL(*embedded_test_server(),
-                           "/set-header?Content-Security-Policy-Report-Only: "
-                           "treat-as-public-address")));
+      shell(),
+      InsecureLocalURL("/set-header?Content-Security-Policy-Report-Only: "
+                       "treat-as-public-address")));
 
-  GURL url = InsecureURL(*embedded_test_server(), "/empty.html");
+  GURL url = InsecureLocalURL("/empty.html");
 
   TestNavigationManager child_navigation_manager(shell()->web_contents(), url);
 
@@ -415,10 +423,9 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTestBlockNavigations,
     FormSubmissionFromInsecurePublictoLocalIsNotBlockedInMainFrame) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
-  GURL url = InsecureDefaultURL(*embedded_test_server());
+  GURL url = InsecureLocalURL(kDefaultPath);
   TestNavigationManager navigation_manager(shell()->web_contents(), url);
 
   base::StringPiece script_template = R"(
@@ -444,10 +451,9 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTestBlockNavigations,
     FormSubmissionFromInsecurePublictoLocalIsBlockedInChildFrame) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
-  GURL url = InsecureDefaultURL(*embedded_test_server());
+  GURL url = InsecureLocalURL(kDefaultPath);
   TestNavigationManager navigation_manager(shell()->web_contents(), url);
 
   base::StringPiece script_template = R"(
@@ -486,10 +492,9 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTestBlockNavigations,
     FormSubmissionGetFromInsecurePublictoLocalIsBlockedInChildFrame) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
-  GURL target_url = InsecureDefaultURL(*embedded_test_server());
+  GURL target_url = InsecureLocalURL(kDefaultPath);
 
   // The page navigates to `url` followed by an empty query: '?'.
   GURL expected_url = GURL(target_url.spec() + "?");
@@ -541,8 +546,12 @@
   // RenderFrame. The navigation is then cancelled by a HTTP 204 code.
   // We're left with a RenderFrameHost containing the default
   // ClientSecurityState values.
-  EXPECT_TRUE(NavigateToURLAndExpectNoCommit(
-      shell(), embedded_test_server()->GetURL("/nocontent")));
+  //
+  // Serve the response from a secure public server, to confirm that none of
+  // the connection's properties are reflected in the committed document, which
+  // is not a secure context and belongs to the `local` address space.
+  EXPECT_TRUE(
+      NavigateToURLAndExpectNoCommit(shell(), SecurePublicURL("/nocontent")));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -601,8 +610,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        ClientSecurityStateForInsecureLocalAddress) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -613,42 +621,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
-                       ClientSecurityStateForSecureLocalAddress) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
-
-  const network::mojom::ClientSecurityStatePtr security_state =
-      root_frame_host()->BuildClientSecurityState();
-  ASSERT_FALSE(security_state.is_null());
-  EXPECT_TRUE(security_state->is_web_secure_context);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
-            security_state->ip_address_space);
-}
-
-IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
-                       ClientSecurityStateForTreatAsPublicAddress) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
-
-  const network::mojom::ClientSecurityStatePtr security_state =
-      root_frame_host()->BuildClientSecurityState();
-  ASSERT_FALSE(security_state.is_null());
-  EXPECT_TRUE(security_state->is_web_secure_context);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
-            security_state->ip_address_space);
-}
-
-IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
-                       ClientSecurityStateForPrivateAddress) {
-  // Intercept the page load and pretend it came from a public IP.
-
-  const GURL url = InsecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PrivateAddress(), embedded_test_server()->port()));
-
-  EXPECT_TRUE(NavigateToURL(shell(), url));
+                       ClientSecurityStateForInsecurePrivateAddress) {
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePrivateURL(kDefaultPath)));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -659,16 +633,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
-                       ClientSecurityStateForPublicAddress) {
-  // Intercept the page load and pretend it came from a public IP.
-
-  const GURL url = InsecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PublicAddress(), embedded_test_server()->port()));
-
-  EXPECT_TRUE(NavigateToURL(shell(), url));
+                       ClientSecurityStateForInsecurePublicAddress) {
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -678,6 +644,55 @@
             security_state->ip_address_space);
 }
 
+IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
+                       ClientSecurityStateForSecureLocalAddress) {
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+  EXPECT_TRUE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
+                       ClientSecurityStateForSecurePrivateAddress) {
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePrivateURL(kDefaultPath)));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+  EXPECT_TRUE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
+                       ClientSecurityStateForSecurePublicAddress) {
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+  EXPECT_TRUE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
+                       ClientSecurityStateForTreatAsPublicAddress) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureLocalURL(kTreatAsPublicAddressPath)));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+  EXPECT_TRUE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
 // This test verifies that the chrome:// scheme is considered local for the
 // purpose of Private Network Access.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
@@ -700,14 +715,9 @@
 // end up with the response IPAddressSpace.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        ClientSecurityStateForSpecialSchemeViewSourcePublic) {
-  // Intercept the page load and pretend it came from a public IP.
-  const GURL url = SecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PublicAddress(), embedded_test_server()->port()));
-
+  const GURL url = SecurePublicURL(kDefaultPath);
   EXPECT_TRUE(NavigateToURL(shell(), GURL("view-source:" + url.spec())));
+
   EXPECT_FALSE(
       root_frame_host()->GetLastCommittedURL().SchemeIs(kViewSourceScheme));
 
@@ -722,14 +732,9 @@
 // Variation of above test with a private address.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        ClientSecurityStateForSpecialSchemeViewSourcePrivate) {
-  // Intercept the page load and pretend it came from a private IP.
-  const GURL url = SecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PrivateAddress(), embedded_test_server()->port()));
-
+  const GURL url = SecurePrivateURL(kDefaultPath);
   EXPECT_TRUE(NavigateToURL(shell(), GURL("view-source:" + url.spec())));
+
   EXPECT_FALSE(
       root_frame_host()->GetLastCommittedURL().SchemeIs(kViewSourceScheme));
 
@@ -743,17 +748,12 @@
 
 // The chrome-error:// scheme should only ever appear in origins. It shouldn't
 // affect the IPAddressSpace computation. This test verifies that we end up with
-// the response IPAddressSpace.
+// the response IPAddressSpace. Error pages should not be considered secure
+// contexts however.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        ClientSecurityStateForSpecialSchemeChromeErrorPublic) {
-  // Intercept the page load and pretend it came from a public IP.
-  const GURL url = SecureDefaultURL(*embedded_test_server());
+  EXPECT_FALSE(NavigateToURL(shell(), SecurePublicURL("/empty404.html")));
 
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = FailInterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PublicAddress(), embedded_test_server()->port()));
-
-  EXPECT_FALSE(NavigateToURL(shell(), url));
   EXPECT_FALSE(
       root_frame_host()->GetLastCommittedURL().SchemeIs(kChromeErrorScheme));
 
@@ -768,14 +768,8 @@
 // Variation of above test with a private address.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        ClientSecurityStateForSpecialSchemeChromeErrorPrivate) {
-  // Intercept the page load and pretend it came from a public IP.
-  const GURL url = SecureDefaultURL(*embedded_test_server());
+  EXPECT_FALSE(NavigateToURL(shell(), SecurePrivateURL("/empty404.html")));
 
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = FailInterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PrivateAddress(), embedded_test_server()->port()));
-
-  EXPECT_FALSE(NavigateToURL(shell(), url));
   EXPECT_FALSE(
       root_frame_host()->GetLastCommittedURL().SchemeIs(kChromeErrorScheme));
 
@@ -1074,8 +1068,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForAboutBlankFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1090,8 +1083,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForAboutBlankFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1107,8 +1099,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForAboutBlankFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromAboutBlank(root_frame_host());
@@ -1125,8 +1116,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForAboutBlankFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromAboutBlank(root_frame_host());
@@ -1145,8 +1135,7 @@
 // address space is `public`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForAboutBlankFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1164,8 +1153,7 @@
 // address space is `local`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForAboutBlankFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1185,8 +1173,7 @@
 // Compare and contrast against the above tests without "noopener".
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeNoOpenerAddressSpaceForAboutBlankIsLocal) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window =
       OpenWindowFromAboutBlankNoOpener(root_frame_host());
@@ -1202,8 +1189,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForInitialEmptyDocFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1218,8 +1204,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForInitialEmptyDocFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1235,8 +1220,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForInitialEmptyDocFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildInitialEmptyDoc(root_frame_host());
@@ -1253,8 +1237,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForInitialEmptyDocFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildInitialEmptyDoc(root_frame_host());
@@ -1273,8 +1256,7 @@
 // opener's address space is `public`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForInitialEmptyDocFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1292,8 +1274,7 @@
 // opener's address space is `local`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForInitialEmptyDocFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1313,8 +1294,7 @@
 // Compare and contrast against the above tests without "noopener".
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeNoOpenerAddressSpaceForInitialEmptyDocIsLocal) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window =
       OpenWindowInitialEmptyDocNoOpener(root_frame_host());
@@ -1330,8 +1310,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForAboutSrcdocFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1346,8 +1325,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForAboutSrcdocFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1363,8 +1341,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForAboutSrcdocFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromSrcdoc(root_frame_host());
@@ -1381,8 +1358,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForAboutSrcdocFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromSrcdoc(root_frame_host());
@@ -1398,8 +1374,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForDataURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1414,8 +1389,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForDataURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1431,8 +1405,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForDataURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromDataURL(root_frame_host());
@@ -1448,8 +1421,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        SandboxedIframeInheritsAddressSpaceForDataURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromDataURL(root_frame_host());
@@ -1465,8 +1437,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForJavascriptURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddChildFromJavascriptURL(root_frame_host());
@@ -1482,8 +1453,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForJavascriptURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddChildFromJavascriptURL(root_frame_host());
@@ -1499,8 +1469,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForJavascriptURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1515,8 +1484,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForJavascriptURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(
       root_frame_host(), "var injectedCodeWasExecuted = true");
@@ -1535,8 +1503,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeNoOpenerAddressSpaceForJavascriptURLIsLocal) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromJavascriptURLNoOpener(
       root_frame_host(), "var injectedCodeWasExecuted = true");
@@ -1557,8 +1524,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForBlobURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1573,8 +1539,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForBlobURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1590,8 +1555,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForBlobURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromBlob(root_frame_host());
@@ -1607,8 +1571,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        SandboxedIframeInheritsAddressSpaceForBlobURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromBlob(root_frame_host());
@@ -1624,8 +1587,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForBlobURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1640,8 +1602,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsAddressSpaceForBlobURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1656,8 +1617,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForFilesystemURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1672,8 +1632,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsAddressSpaceForFilesystemURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1689,8 +1648,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForFilesystemURLFromPublic) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromFilesystem(root_frame_host());
@@ -1707,8 +1665,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsAddressSpaceForFilesystemURLFromLocal) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromFilesystem(root_frame_host());
@@ -1724,8 +1681,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForAboutBlankFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1739,8 +1695,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForAboutBlankFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1755,8 +1710,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForAboutBlankFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromAboutBlank(root_frame_host());
@@ -1772,8 +1726,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForAboutBlankFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromAboutBlank(root_frame_host());
@@ -1788,8 +1741,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsSecureContextForAboutBlankFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1803,8 +1755,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsSecureContextForAboutBlankFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1819,8 +1770,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     IframeInheritsSecureContextForInitialEmptyDocFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1835,8 +1785,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     IframeInheritsSecureContextForInitialEmptyDocFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1851,8 +1800,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForInitialEmptyDocFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildInitialEmptyDoc(root_frame_host());
@@ -1868,8 +1816,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForInitialEmptyDocFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildInitialEmptyDoc(root_frame_host());
@@ -1885,8 +1832,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     OpeneeInheritsSecureContextForInitialEmptyDocFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1901,8 +1847,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     OpeneeInheritsSecureContextForInitialEmptyDocFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -1916,8 +1861,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForAboutSrcdocFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1931,8 +1875,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForAboutSrcdocFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1947,8 +1890,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForAboutSrcdocFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromSrcdoc(root_frame_host());
@@ -1964,8 +1906,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForAboutSrcdocFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromSrcdoc(root_frame_host());
@@ -1980,8 +1921,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForDataURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -1995,8 +1935,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForDataURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -2011,8 +1950,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForDataURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromDataURL(root_frame_host());
@@ -2028,8 +1966,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForDataURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromDataURL(root_frame_host());
@@ -2044,8 +1981,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForJavascriptURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddChildFromJavascriptURL(root_frame_host());
@@ -2061,8 +1997,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     IframeInheritsSecureContextForJavascriptURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddChildFromJavascriptURL(root_frame_host());
@@ -2078,8 +2013,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     OpeneeInheritsSecureContextForJavascriptURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -2093,8 +2027,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsSecureContextForJavascriptURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -2108,8 +2041,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForBlobURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -2123,8 +2055,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForBlobURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -2139,8 +2070,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForBlobURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromBlob(root_frame_host());
@@ -2156,8 +2086,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForBlobURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromBlob(root_frame_host());
@@ -2172,8 +2101,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsSecureContextForBlobURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -2187,8 +2115,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        OpeneeInheritsSecureContextForBlobURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
   ASSERT_NE(nullptr, window);
@@ -2202,8 +2129,7 @@
 
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        IframeInheritsSecureContextForFilesystemURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -2218,8 +2144,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     IframeInheritsSecureContextForFilesystemURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
@@ -2234,8 +2159,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForFilesystemURLFromSecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromFilesystem(root_frame_host());
@@ -2251,8 +2175,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     SandboxedIframeInheritsSecureContextForFilesystemURLFromInsecure) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   RenderFrameHostImpl* child_frame =
       AddSandboxedChildFromFilesystem(root_frame_host());
@@ -2271,14 +2194,11 @@
 // This is relevant to CORS-RFC1918, since `file:` URLs are considered `local`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTestNoBlocking,
                        InsecurePageCannotRequestFile) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   // Check that the page cannot load a `file:` URL.
-  EXPECT_EQ(
-      false,
-      EvalJs(root_frame_host(),
-             FetchSubresourceScript(GetTestUrl("", "empty.html").spec())));
+  EXPECT_EQ(false, EvalJs(root_frame_host(), FetchSubresourceScript(GetTestUrl(
+                                                 "", "empty.html"))));
 }
 
 // This test verifies that even with the blocking feature disabled, a secure
@@ -2287,14 +2207,11 @@
 // This is relevant to CORS-RFC1918, since `file:` URLs are considered `local`.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTestNoBlocking,
                        SecurePageCannotRequestFile) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), SecureLocalURL(kDefaultPath)));
 
   // Check that the page cannot load a `file:` URL.
-  EXPECT_EQ(
-      false,
-      EvalJs(root_frame_host(),
-             FetchSubresourceScript(GetTestUrl("", "empty.html").spec())));
+  EXPECT_EQ(false, EvalJs(root_frame_host(), FetchSubresourceScript(GetTestUrl(
+                                                 "", "empty.html"))));
 }
 
 // This test verifies that with the blocking feature disabled, the private
@@ -2302,8 +2219,7 @@
 // to warn about insecure requests.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTestNoBlocking,
                        PrivateNetworkPolicyIsWarnByDefault) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -2319,24 +2235,21 @@
 //  - from an insecure page with the "treat-as-public-address" CSP directive
 //  - to a local IP address
 // are not blocked.
-//
-// TODO(titouan): Make this pass. Request is currently blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTestNoBlocking,
                        PrivateNetworkRequestIsNotBlockedByDefault) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   // Check that the page can load a local resource.
   EXPECT_EQ(true,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that by default, the private network request policy used
 // by RenderFrameHostImpl for requests is set to block insecure requests.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        PrivateNetworkPolicyIsBlockByDefault) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
   const network::mojom::ClientSecurityStatePtr security_state =
       root_frame_host()->BuildClientSecurityState();
@@ -2355,7 +2268,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     FromInsecureTreatAsPublicToLocalWithPolicySetToAllowIsNotBlocked) {
-  GURL url = InsecureTreatAsPublicAddressURL(*embedded_test_server());
+  GURL url = InsecureLocalURL(kTreatAsPublicAddressPath);
 
   PolicyTestContentBrowserClient client;
   client.SetAllowInsecurePrivateNetworkRequestsFrom(url::Origin::Create(url));
@@ -2375,7 +2288,8 @@
 
   // Check that the page can load a local resource.
   EXPECT_EQ(true,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that child frames with distinct origins from their parent
@@ -2383,7 +2297,7 @@
 // origin of the child document instead.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        PrivateNetworkRequestPolicyCalculatedPerOrigin) {
-  GURL url = InsecureTreatAsPublicAddressURL(*embedded_test_server());
+  GURL url = InsecurePublicURL(kDefaultPath);
 
   PolicyTestContentBrowserClient client;
   client.SetAllowInsecurePrivateNetworkRequestsFrom(url::Origin::Create(url));
@@ -2392,11 +2306,10 @@
   // correct PrivateNetworkRequestPolicy.
   ContentBrowserClientRegistration registration(&client);
 
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
-  RenderFrameHostImpl* child_frame = AddChildFromURL(
-      root_frame_host(), SecureDefaultURL(*embedded_test_server()));
+  RenderFrameHostImpl* child_frame =
+      AddChildFromURL(root_frame_host(), SecureLocalURL(kDefaultPath));
 
   network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
@@ -2412,7 +2325,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     PrivateNetworkRequestPolicyInheritedWithOriginForInitialEmptyDoc) {
-  GURL url = InsecureTreatAsPublicAddressURL(*embedded_test_server());
+  GURL url = InsecurePublicURL(kDefaultPath);
 
   PolicyTestContentBrowserClient client;
   client.SetAllowInsecurePrivateNetworkRequestsFrom(url::Origin::Create(url));
@@ -2439,7 +2352,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     PrivateNetworkRequestPolicyInheritedWithOriginForAboutBlank) {
-  GURL url = InsecureTreatAsPublicAddressURL(*embedded_test_server());
+  GURL url = InsecurePublicURL(kDefaultPath);
 
   PolicyTestContentBrowserClient client;
   client.SetAllowInsecurePrivateNetworkRequestsFrom(url::Origin::Create(url));
@@ -2466,7 +2379,7 @@
 IN_PROC_BROWSER_TEST_F(
     CorsRfc1918BrowserTest,
     PrivateNetworkRequestPolicyNotInheritedWithOriginForDataURL) {
-  GURL url = InsecureTreatAsPublicAddressURL(*embedded_test_server());
+  GURL url = InsecurePublicURL(kDefaultPath);
 
   PolicyTestContentBrowserClient client;
   client.SetAllowInsecurePrivateNetworkRequestsFrom(url::Origin::Create(url));
@@ -2494,12 +2407,13 @@
 // are not blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        FromSecureTreatAsPublicToLocalIsNotBlocked) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureLocalURL(kTreatAsPublicAddressPath)));
 
-  // Check that the page can load a local resource.
-  EXPECT_EQ(true,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+  // Check that the page can load a local resource. We load it from a secure
+  // origin to avoid running afoul of mixed content restrictions.
+  EXPECT_EQ(true, EvalJs(root_frame_host(),
+                         FetchSubresourceScript(SecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that when the right feature is enabled, requests:
@@ -2508,12 +2422,13 @@
 // are blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        FromInsecureTreatAsPublicToLocalIsBlocked) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), InsecureTreatAsPublicAddressURL(*embedded_test_server())));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureLocalURL(kTreatAsPublicAddressPath)));
 
   // Check that the page cannot load a local resource.
   EXPECT_EQ(false,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that when the right feature is enabled, requests:
@@ -2522,19 +2437,12 @@
 //  are blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        FromInsecurePublicToLocalIsBlocked) {
-  // Intercept the page load and pretend it came from a public IP.
-
-  const GURL url = InsecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PublicAddress(), embedded_test_server()->port()));
-
-  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePublicURL(kDefaultPath)));
 
   // Check that the page cannot load a local resource.
   EXPECT_EQ(false,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that when the right feature is enabled, requests:
@@ -2543,19 +2451,12 @@
 //  are blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        FromInsecurePrivateToLocalIsBlocked) {
-  // Intercept the page load and pretend it came from a private IP.
-
-  const GURL url = InsecureDefaultURL(*embedded_test_server());
-
-  // Use the same port as the server, so that the fetch is not cross-origin.
-  auto interceptor = InterceptorWithFakeEndPoint(
-      url, net::IPEndPoint(PrivateAddress(), embedded_test_server()->port()));
-
-  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecurePrivateURL(kDefaultPath)));
 
   // Check that the page cannot load a local resource.
   EXPECT_EQ(false,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that when the right feature is enabled, requests:
@@ -2564,12 +2465,12 @@
 //  are not blocked.
 IN_PROC_BROWSER_TEST_F(CorsRfc1918BrowserTest,
                        FromInsecureLocalToLocalIsNotBlocked) {
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   // Check that the page can load a local resource.
   EXPECT_EQ(true,
-            EvalJs(root_frame_host(), FetchSubresourceScript("image.jpg")));
+            EvalJs(root_frame_host(),
+                   FetchSubresourceScript(InsecureLocalURL("/image.jpg"))));
 }
 
 // This test verifies that when the right feature is enabled, requests:
@@ -2581,18 +2482,16 @@
     CorsRfc1918BrowserTest,
     FromSecurePublicEmbeddedInInsecureLocalToLocalIsBlocked) {
   // First navigate to an insecure page served by a local IP address.
-  EXPECT_TRUE(
-      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+  EXPECT_TRUE(NavigateToURL(shell(), InsecureLocalURL(kDefaultPath)));
 
   // Then embed a secure public iframe.
-  GURL iframe_url = SecureTreatAsPublicAddressURL(*embedded_test_server());
-  std::string script = base::ReplaceStringPlaceholders(
+  std::string script = JsReplace(
       R"(
         const iframe = document.createElement("iframe");
-        iframe.src = "$1";
+        iframe.src = $1;
         document.body.appendChild(iframe);
       )",
-      {iframe_url.spec()}, nullptr);
+      SecurePublicURL(kDefaultPath));
   EXPECT_TRUE(ExecJs(root_frame_host(), script));
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
@@ -2614,7 +2513,8 @@
             security_state->ip_address_space);
 
   // Check that the iframe cannot load a local resource.
-  EXPECT_EQ(false, EvalJs(child_frame, FetchSubresourceScript("image.jpg")));
+  EXPECT_EQ(false, EvalJs(child_frame, FetchSubresourceScript(
+                                           InsecureLocalURL("/image.jpg"))));
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 3b397c7..719f86e 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1758,8 +1758,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!include_speculative &&
-      lifecycle_state() == LifecycleStateImpl::kSpeculative)
+      (lifecycle_state() == LifecycleStateImpl::kSpeculative ||
+       lifecycle_state() == LifecycleStateImpl::kPendingCommit)) {
     return;
+  }
 
   // Since |this| may not be current in its FrameTree, we can't begin iterating
   // from |frame_tree_node()|, so we special case the first invocation for
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index e4406170..a7fb9bec 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -21,11 +21,11 @@
 #include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/common/fetch/fetch_request_type_converters.h"
-#include "content/common/service_worker/service_worker_loader_helpers.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
+#include "third_party/blink/public/common/service_worker/service_worker_loader_helpers.h"
 
 namespace content {
 
@@ -339,7 +339,8 @@
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   DCHECK_EQ(status_, Status::kStarted);
 
-  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, response_head_.get());
+  blink::ServiceWorkerLoaderHelpers::SaveResponseInfo(*response,
+                                                      response_head_.get());
 
   response_head_->did_service_worker_navigation_preload =
       did_navigation_preload_;
@@ -363,8 +364,8 @@
   // Handle a redirect response. ComputeRedirectInfo returns non-null redirect
   // info if the given response is a redirect.
   base::Optional<net::RedirectInfo> redirect_info =
-      ServiceWorkerLoaderHelpers::ComputeRedirectInfo(resource_request_,
-                                                      *response_head_);
+      blink::ServiceWorkerLoaderHelpers::ComputeRedirectInfo(resource_request_,
+                                                             *response_head_);
   if (redirect_info) {
     TRACE_EVENT_WITH_FLOW2(
         "ServiceWorker", "ServiceWorkerMainResourceLoader::StartResponse", this,
@@ -401,7 +402,7 @@
     DCHECK(response->blob->blob.is_valid());
     body_as_blob_.Bind(std::move(response->blob->blob));
     mojo::ScopedDataPipeConsumerHandle data_pipe;
-    int error = ServiceWorkerLoaderHelpers::ReadBlobResponseBody(
+    int error = blink::ServiceWorkerLoaderHelpers::ReadBlobResponseBody(
         &body_as_blob_, response->blob->size,
         base::BindOnce(&ServiceWorkerMainResourceLoader::OnBlobReadingComplete,
                        weak_factory_.GetWeakPtr()),
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 29c63700..948bd4a 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -303,6 +303,7 @@
       sandbox::policy::switches::kAddXrAppContainerCaps,
 #endif
       network::switches::kUseFirstPartySet,
+      network::switches::kIpAddressSpaceOverrides,
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
       switches::kSchedulerBoostUrgent,
 #endif
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index d009abe..248a3cc 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -135,8 +135,6 @@
     "process_type.cc",
     "process_visibility_tracker.cc",
     "process_visibility_tracker.h",
-    "service_worker/service_worker_loader_helpers.cc",
-    "service_worker/service_worker_loader_helpers.h",
     "service_worker/service_worker_utils.cc",
     "service_worker/service_worker_utils.h",
     "set_process_title.cc",
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
index 73367178..a3a7542 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
@@ -107,9 +107,8 @@
     private Rect fullscreenButtonBounds(Rect videoRect) {
         Rect panel = buttonPanelBounds(videoRect);
 
-        // In these tests, we have no overflow items, so the fullscreen button is the rightmost
-        // button in the panel.
-        int right = panel.right;
+        // The fullscreen button is the second rightmost button in the panel.
+        int right = panel.right - BUTTON_WIDTH;
         int left = right - BUTTON_WIDTH;
         return new Rect(left, panel.top, right, panel.bottom);
     }
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index d065f2d..71d22ea 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -14,7 +14,6 @@
 #include "base/strings/strcat.h"
 #include "base/trace_event/trace_event.h"
 #include "content/common/fetch/fetch_request_type_converters.h"
-#include "content/common/service_worker/service_worker_loader_helpers.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
@@ -25,6 +24,7 @@
 #include "net/url_request/url_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
+#include "third_party/blink/public/common/service_worker/service_worker_loader_helpers.h"
 #include "third_party/blink/public/common/service_worker/service_worker_type_converters.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom.h"
@@ -494,7 +494,8 @@
     return;
   }
 
-  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, response_head_.get());
+  blink::ServiceWorkerLoaderHelpers::SaveResponseInfo(*response,
+                                                      response_head_.get());
   response_head_->response_start = base::TimeTicks::Now();
   response_head_->load_timing.receive_headers_start = base::TimeTicks::Now();
   response_head_->load_timing.receive_headers_end =
@@ -503,7 +504,7 @@
 
   // Handle a redirect response. ComputeRedirectInfo returns non-null redirect
   // info if the given response is a redirect.
-  redirect_info_ = ServiceWorkerLoaderHelpers::ComputeRedirectInfo(
+  redirect_info_ = blink::ServiceWorkerLoaderHelpers::ComputeRedirectInfo(
       resource_request_, *response_head_);
   if (redirect_info_) {
     if (redirect_limit_-- == 0) {
@@ -771,7 +772,7 @@
   DCHECK(body_pipe);
   DCHECK(!body_reading_complete_);
 
-  return ServiceWorkerLoaderHelpers::ReadBlobResponseBody(
+  return blink::ServiceWorkerLoaderHelpers::ReadBlobResponseBody(
       &body_as_blob_, body_as_blob_size_,
       base::BindOnce(&ServiceWorkerSubresourceLoader::OnBodyReadingComplete,
                      weak_factory_.GetWeakPtr()),
diff --git a/content/services/auction_worklet/auction_runner.cc b/content/services/auction_worklet/auction_runner.cc
index 632e4a9..675ab44f9 100644
--- a/content/services/auction_worklet/auction_runner.cc
+++ b/content/services/auction_worklet/auction_runner.cc
@@ -139,10 +139,10 @@
       base::BindOnce(&AuctionRunner::OnBidScored, base::Unretained(this)));
 }
 
-void AuctionRunner::OnBidScored(SellerWorklet::ScoreResult score_result) {
-  bid_states_[seller_considering_].score_result = score_result;
-  if (score_result.error_msg.has_value())
-    errors_.push_back(std::move(score_result.error_msg).value());
+void AuctionRunner::OnBidScored(double score,
+                                const std::vector<std::string>& errors) {
+  bid_states_[seller_considering_].seller_score = score;
+  errors_.insert(errors_.end(), errors.begin(), errors.end());
   ++seller_considering_;
   ScoreOne();
 }
@@ -171,8 +171,8 @@
   const BidState* best_bid = nullptr;
   // TODO(morlovich): What if there is a tie?
   for (const BidState& bid_state : bid_states_) {
-    if (bid_state.score_result.score > best_bid_score) {
-      best_bid_score = bid_state.score_result.score;
+    if (bid_state.seller_score > best_bid_score) {
+      best_bid_score = bid_state.seller_score;
       best_bid = &bid_state;
     }
   }
@@ -187,11 +187,12 @@
 
 void AuctionRunner::ReportSellerResult(const BidState* best_bid) {
   DCHECK(best_bid->bid_result);
+  DCHECK_GT(best_bid->seller_score, 0);
   seller_worklet_->ReportResult(
       *auction_config_, browser_signals_->top_frame_origin.host(),
       best_bid->bidder->group->owner, best_bid->bid_result->render_url,
       AdRenderFingerprint(best_bid), best_bid->bid_result->bid,
-      best_bid->score_result.score,
+      best_bid->seller_score,
       base::BindOnce(&AuctionRunner::OnReportSellerResultComplete,
                      base::Unretained(this), best_bid));
 }
diff --git a/content/services/auction_worklet/auction_runner.h b/content/services/auction_worklet/auction_runner.h
index 9020dbf..0983766 100644
--- a/content/services/auction_worklet/auction_runner.h
+++ b/content/services/auction_worklet/auction_runner.h
@@ -61,7 +61,7 @@
 
     std::unique_ptr<BidderWorklet> bidder_worklet;
     base::Optional<BidderWorklet::Bid> bid_result;
-    SellerWorklet::ScoreResult score_result;
+    double seller_score = 0;
   };
 
   AuctionRunner(
@@ -91,7 +91,7 @@
   void ScoreOne();
   void ScoreBid(const BidState* state);
   // Callback from ScoreBid().
-  void OnBidScored(SellerWorklet::ScoreResult score_result);
+  void OnBidScored(double score, const std::vector<std::string>& errors);
 
   std::string AdRenderFingerprint(const BidState* state);
   base::Optional<std::string> PerBuyerSignals(const BidState* state);
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index ec3c1f81..facd3f9 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -111,11 +111,11 @@
 //
 // TODO(mmenke): Remove once this class switches over to using Mojo.
 
-void InvokeScoreAdCallbackAsync(
-    base::OnceCallback<void(SellerWorklet::ScoreResult)> callback,
-    SellerWorklet::ScoreResult score_result) {
+void InvokeScoreAdCallbackAsync(SellerWorklet::ScoreAdCallback callback,
+                                double score,
+                                const std::vector<std::string>& errors) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), std::move(score_result)));
+      FROM_HERE, base::BindOnce(std::move(callback), score, errors));
 }
 
 void InvokeReportResultCallbackAsync(
@@ -127,24 +127,6 @@
 
 }  // namespace
 
-SellerWorklet::ScoreResult::ScoreResult() = default;
-
-SellerWorklet::ScoreResult::ScoreResult(double score)
-    : success(true), score(score) {
-  DCHECK_GT(score, 0);
-}
-
-SellerWorklet::ScoreResult::ScoreResult(base::Optional<std::string> error_msg)
-    : error_msg(std::move(error_msg)) {}
-
-SellerWorklet::ScoreResult::ScoreResult(const ScoreResult& other) = default;
-SellerWorklet::ScoreResult::ScoreResult(ScoreResult&& other) = default;
-SellerWorklet::ScoreResult::~ScoreResult() = default;
-SellerWorklet::ScoreResult& SellerWorklet::ScoreResult::operator=(
-    const ScoreResult&) = default;
-SellerWorklet::ScoreResult& SellerWorklet::ScoreResult::operator=(
-    ScoreResult&&) = default;
-
 SellerWorklet::Report::Report() = default;
 
 SellerWorklet::Report::Report(std::string signals_for_winner, GURL report_url)
@@ -185,7 +167,7 @@
     const url::Origin& browser_signal_interest_group_owner,
     const std::string& browser_signal_ad_render_fingerprint,
     base::TimeDelta browser_signal_bidding_duration,
-    base::OnceCallback<void(ScoreResult)> callback) {
+    ScoreAdCallback callback) {
   callback = base::BindOnce(&InvokeScoreAdCallbackAsync, std::move(callback));
 
   AuctionV8Helper::FullIsolateScope isolate_scope(v8_helper_);
@@ -197,14 +179,16 @@
 
   std::vector<v8::Local<v8::Value>> args;
   if (!v8_helper_->AppendJsonValue(context, ad_metadata_json, &args)) {
-    std::move(callback).Run(ScoreResult());
+    std::move(callback).Run(0 /* score */,
+                            std::vector<std::string>() /* errors */);
     return;
   }
 
   args.push_back(gin::ConvertToV8(isolate, bid));
 
   if (!AppendAuctionConfig(v8_helper_, context, auction_config, &args)) {
-    std::move(callback).Run(ScoreResult());
+    std::move(callback).Run(0 /* score */,
+                            std::vector<std::string>() /* errors */);
     return;
   }
 
@@ -223,7 +207,8 @@
       !browser_signals_dict.Set(
           "biddingDurationMsec",
           browser_signal_bidding_duration.InMilliseconds())) {
-    std::move(callback).Run(ScoreResult());
+    std::move(callback).Run(0 /* score */,
+                            std::vector<std::string>() /* errors */);
     return;
   }
   args.push_back(browser_signals);
@@ -235,24 +220,29 @@
            ->RunScript(context, worklet_script_->Get(isolate), "scoreAd", args,
                        error_msg_out)
            .ToLocal(&score_ad_result)) {
-    std::move(callback).Run(ScoreResult(std::move(error_msg_out)));
+    std::vector<std::string> errors;
+    if (error_msg_out)
+      errors.emplace_back(std::move(error_msg_out).value());
+    std::move(callback).Run(0 /* score */, errors);
     return;
   }
 
   if (!gin::ConvertFromV8(isolate, score_ad_result, &score) ||
       std::isnan(score) || !std::isfinite(score)) {
-    std::move(callback).Run(ScoreResult(
-        base::StrCat({script_source_url_.spec(),
-                      " scoreAd() did not return a valid number."})));
+    std::move(callback).Run(
+        0 /* score */, std::vector<std::string>{base::StrCat(
+                           {script_source_url_.spec(),
+                            " scoreAd() did not return a valid number."})});
     return;
   }
 
   if (score <= 0) {
-    std::move(callback).Run(ScoreResult());
+    std::move(callback).Run(0 /* score */,
+                            std::vector<std::string>() /* errors */);
     return;
   }
 
-  std::move(callback).Run(ScoreResult(score));
+  std::move(callback).Run(score, std::vector<std::string>() /* errors */);
 }
 
 void SellerWorklet::ReportResult(
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index d623eb6..85076cc 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -28,38 +28,6 @@
 // seller worklet's Javascript.
 class SellerWorklet {
  public:
-  // The result of invoking scoreAd().
-  struct ScoreResult {
-    // Creates a ScoreResult for a failure or rejected bid.
-    ScoreResult();
-
-    // Creates a ScoreResult for a successfully scored ad. `score` will be > 0.
-    explicit ScoreResult(double score);
-
-    // Creates a ScoreResult representing a fatal error, potentially with a
-    // helpful diagnostic message in `error_msg`.
-    explicit ScoreResult(base::Optional<std::string> error_msg);
-
-    ScoreResult(const ScoreResult& other);
-    ScoreResult(ScoreResult&& other);
-
-    ~ScoreResult();
-
-    ScoreResult& operator=(const ScoreResult&);
-    ScoreResult& operator=(ScoreResult&&);
-
-    // `success` will be false on any type of failure, and score will be 0.
-    bool success = false;
-
-    // Score. 0 if no bid is offered (even if underlying script returned a
-    // negative value).
-    double score = 0;
-
-    // Error message for debugging. This is not guaranteed to be present on
-    // failure.
-    base::Optional<std::string> error_msg;
-  };
-
   // The result of invoking reportResult().
   struct Report {
     // Creates a Report for a failure.
@@ -101,6 +69,13 @@
       base::OnceCallback<void(bool success,
                               base::Optional<std::string> error_msg)>;
 
+  // Callback for ScoreAd(). On success, `score` is the positive score returned
+  // by the script. On failure, it's 0. `errors` is a vector of any errors that
+  // occurred while running the script.
+  using ScoreAdCallback =
+      base::OnceCallback<void(double score,
+                              const std::vector<std::string>& errors)>;
+
   // Starts loading the worklet script on construction. Callback will be invoked
   // asynchronously once the data has been fetched or an error has occurred.
   // Must be destroyed before `v8_helper`.
@@ -123,7 +98,7 @@
                const url::Origin& browser_signal_interest_group_owner,
                const std::string& browser_signal_ad_render_fingerprint,
                base::TimeDelta browser_signal_bidding_duration,
-               base::OnceCallback<void(ScoreResult)> callback);
+               ScoreAdCallback callback);
 
   // Calls reportResult(), and invokes passed in callback asynchronously with
   // the reporting information. May only be called once the worklet has
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index a667e16..8fabeec 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -90,10 +90,10 @@
   void RunScoreAdWithReturnValueExpectingResult(
       const std::string& raw_return_value,
       double expected_score,
-      base::Optional<std::string> expected_error_msg = base::nullopt) {
+      const std::vector<std::string>& expected_errors =
+          std::vector<std::string>()) {
     RunScoreAdWithJavascriptExpectingResult(
-        CreateScoreAdScript(raw_return_value), expected_score,
-        std::move(expected_error_msg));
+        CreateScoreAdScript(raw_return_value), expected_score, expected_errors);
   }
 
   // Configures `url_loader_factory_` to return the provided script, and then
@@ -102,38 +102,35 @@
   void RunScoreAdWithJavascriptExpectingResult(
       const std::string& javascript,
       double expected_score,
-      base::Optional<std::string> expected_error_msg = base::nullopt) {
+      const std::vector<std::string>& expected_errors =
+          std::vector<std::string>()) {
     SCOPED_TRACE(javascript);
     AddJavascriptResponse(&url_loader_factory_, url_, javascript);
-    RunScoreAdExpectingResult(expected_score, std::move(expected_error_msg));
+    RunScoreAdExpectingResult(expected_score, expected_errors);
   }
 
   // Loads and runs a scode_ad() script, expecting the supplied result.
   void RunScoreAdExpectingResult(
       double expected_score,
-      base::Optional<std::string> expected_error_msg = base::nullopt) {
+      const std::vector<std::string>& expected_errors =
+          std::vector<std::string>()) {
     auto seller_worket = CreateWorklet();
     ASSERT_TRUE(seller_worket);
 
     base::RunLoop run_loop;
-    SellerWorklet::ScoreResult actual_result;
     seller_worket->ScoreAd(
         ad_metadata_, bid_, *auction_config_,
         browser_signal_top_window_hostname_,
         browser_signal_interest_group_owner_,
         browser_signal_ad_render_fingerprint_, browser_signal_bidding_duration_,
         base::BindLambdaForTesting(
-            [&run_loop, &actual_result](SellerWorklet::ScoreResult result) {
-              actual_result = result;
+            [&run_loop, &expected_score, expected_errors](
+                double score, const std::vector<std::string>& errors) {
+              EXPECT_EQ(expected_score, score);
+              EXPECT_EQ(expected_errors, errors);
               run_loop.Quit();
             }));
     run_loop.Run();
-    EXPECT_EQ(expected_score > 0, actual_result.success);
-    EXPECT_EQ(expected_score, actual_result.score);
-    EXPECT_EQ(expected_error_msg.has_value(),
-              actual_result.error_msg.has_value());
-    EXPECT_EQ(expected_error_msg.value_or("Not an error"),
-              actual_result.error_msg.value_or("Not an error"));
   }
 
   // Configures `url_loader_factory_` to return a report_result() script created
@@ -274,30 +271,33 @@
 
   // No return value.
   RunScoreAdWithReturnValueExpectingResult(
-      "", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "", 0, {"https://url.test/ scoreAd() did not return a valid number."});
 
   // Wrong return type / invalid values.
   RunScoreAdWithReturnValueExpectingResult(
-      "[15]", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "[15]", 0,
+      {"https://url.test/ scoreAd() did not return a valid number."});
   RunScoreAdWithReturnValueExpectingResult(
-      "1/0", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "1/0", 0, {"https://url.test/ scoreAd() did not return a valid number."});
   RunScoreAdWithReturnValueExpectingResult(
-      "0/0", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "0/0", 0, {"https://url.test/ scoreAd() did not return a valid number."});
   RunScoreAdWithReturnValueExpectingResult(
-      "-1/0", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "-1/0", 0,
+      {"https://url.test/ scoreAd() did not return a valid number."});
   RunScoreAdWithReturnValueExpectingResult(
-      "true", 0, "https://url.test/ scoreAd() did not return a valid number.");
+      "true", 0,
+      {"https://url.test/ scoreAd() did not return a valid number."});
 
   // Throw exception.
   RunScoreAdWithReturnValueExpectingResult(
       "shrimp", 0,
-      "https://url.test/:4 Uncaught ReferenceError: shrimp is not defined.");
+      {"https://url.test/:4 Uncaught ReferenceError: shrimp is not defined."});
 }
 
 TEST_F(SellerWorkletTest, ScoreAdDateNotAvailable) {
   RunScoreAdWithReturnValueExpectingResult(
       "Date.parse(Date().toString())", 0,
-      "https://url.test/:4 Uncaught ReferenceError: Date is not defined.");
+      {"https://url.test/:4 Uncaught ReferenceError: Date is not defined."});
 }
 
 // Checks that input parameters are correctly passed in.
@@ -650,7 +650,6 @@
     // function is run sequentially, and when one function is run after the
     // other.
     for (int j = 0; j < 2; ++j) {
-      SellerWorklet::ScoreResult score_result;
       base::RunLoop run_loop;
       seller_worket->ScoreAd(
           ad_metadata_, bid_, *auction_config_,
@@ -659,13 +658,13 @@
           browser_signal_ad_render_fingerprint_,
           browser_signal_bidding_duration_,
           base::BindLambdaForTesting(
-              [&run_loop, &score_result](SellerWorklet::ScoreResult result) {
-                score_result = result;
+              [&run_loop](double score,
+                          const std::vector<std::string>& errors) {
+                EXPECT_EQ(2, score);
+                EXPECT_TRUE(errors.empty());
                 run_loop.Quit();
               }));
       run_loop.Run();
-      EXPECT_TRUE(score_result.success);
-      EXPECT_EQ(2, score_result.score);
     }
 
     for (int j = 0; j < 2; ++j) {
diff --git a/content/test/data/devtools/navigation.html b/content/test/data/devtools/navigation.html
index 90e246f0..48e5f42 100644
--- a/content/test/data/devtools/navigation.html
+++ b/content/test/data/devtools/navigation.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <html>
 <body>
 Dummy page.
diff --git a/content/test/data/devtools/page-with-oopif.html b/content/test/data/devtools/page-with-oopif.html
index 35590fed..f7eaad2b 100644
--- a/content/test/data/devtools/page-with-oopif.html
+++ b/content/test/data/devtools/page-with-oopif.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <html>
   <body>
   <h1>Top frame</h1>
diff --git a/device/bluetooth/device.cc b/device/bluetooth/device.cc
index aee2806..c2d5734 100644
--- a/device/bluetooth/device.cc
+++ b/device/bluetooth/device.cc
@@ -45,6 +45,9 @@
     device_info->rssi->value = device->GetInquiryRSSI().value();
   }
 
+  for (auto const& it : device->GetManufacturerData())
+    device_info->manufacturer_data_map.insert_or_assign(it.first, it.second);
+
   for (auto const& it : device->GetServiceData())
     device_info->service_data_map.insert_or_assign(it.first, it.second);
 
diff --git a/device/bluetooth/public/mojom/device.mojom b/device/bluetooth/public/mojom/device.mojom
index dcf5b3a..5fea8b1c 100644
--- a/device/bluetooth/public/mojom/device.mojom
+++ b/device/bluetooth/public/mojom/device.mojom
@@ -68,6 +68,10 @@
   bool is_gatt_connected;
   RSSIWrapper? rssi;
 
+  // Important: the blobs associated with each key are arbitrary and untrusted.
+  // Please refer to the note on "The Rule of 2" at the top of this file.
+  map<uint16, array<uint8>> manufacturer_data_map;
+
   // Important: the blobs associated with each UUID are arbitrary and untrusted.
   // Please refer to the note on "The Rule of 2" at the top of this file.
   map<UUID, array<uint8>> service_data_map;
diff --git a/docs/README.md b/docs/README.md
index 72b2af24..68e2f0ad 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -157,6 +157,9 @@
     you are interested in.
 *   [Shutdown](shutdown.md) - Explains the steps of Chrome shutdown, to make it
     easier to determine where to add a new shutdown operation.
+*   [API Keys](api_keys.md) - When you need access to Google APIs for a custom
+    build, fork, integration of stock Chromium, or are building ChromiumOS (for
+    login).
 
 ### Testing
 *   [Running and Debugging Web Tests](testing/web_tests.md)
diff --git a/docs/api_keys.md b/docs/api_keys.md
new file mode 100644
index 0000000..6ed917f
--- /dev/null
+++ b/docs/api_keys.md
@@ -0,0 +1,164 @@
+# API Keys
+
+When using a custom build, fork, or integration of Chromium, or if you're
+building ChromiumOS, you will need access to Google API for key functionality.
+
+[TOC]
+
+*** note
+**Note:** Software distribution with keys acquired for yourself is allowed, but
+the keys themselves cannot be shared with parties outside the legal entity that
+accepted the API ToS.  Keep in mind that a number of the APIs will have no or
+very limited quota and not all of the APIs have additional quota available for
+purchase.
+***
+
+**Googlers only:**
+
+*   For a simpler approach to API keys, see https://go/chrome-api-key-setup
+*   If you need a new API enabled in Chrome, use https://b/new?component=165132
+
+**How-to:**
+First, acquire API keys. Then, specify the API keys to use either when you build
+Chromium, or at runtime using environment variables.
+
+## Acquiring Keys
+
+1.  Make sure you are a member of chromium-dev@chromium.org (you can choose
+    not to receive mail).
+    *** note
+    **Note:** the APIs below are only visible to people subscribed to that group.
+    ***
+1.  Make sure you are logged in with the Google account associated with the email
+    address that you used to subscribe to chromium-dev.
+1.  Go to https://cloud.google.com/console
+1.  _optional_  You may add other members of your organization or team on the Team
+    tab.
+1.  Open the **APIs and Services > Library** from the hamburger menu, search for
+    all of the following APIs. For each of these APIs:
+    1.  Click on it
+    1.  Click `Enable API` button at the top
+    1.  Read and agree to the Terms of Service
+    1.  Check the `I have read and agree to the <API name> Terms of Service`
+        checkbox
+    1.  Click Accept.
+
+    **List of APIs** (if any are not shown, recheck step 1 above):
+
+    *   Cloud Search API
+    *   Geolocation API (requires [enabling
+        billing](https://developers.google.com/console/help/#EnableBilling) but
+        is free to use; you can skip this one, in which case geolocation features
+        of Chrome will not work)
+    *   Google Drive API (enable this for Files.app on Chrome OS and
+        SyncFileSystem API)
+    *   Safe Browsing API
+    *   Time Zone API
+    *   Optional
+        *   Admin SDK
+        *   Cloud Translation API
+        *   Geocoding API
+        *   Google Assistant API
+        *   Google Calendar API
+        *   Nearby Messages API
+
+1.  Go to the **Credentials** sub tab under the **API & Services** section in the
+    hamburger menu.
+1.  Click the `Create credentials` button then click on the **OAuth client
+    ID** item in the drop-down list.
+    *   Click on the `Configure consent screen` button. Fill in the "product
+        name" (anything you choose) and other details, then click on `Save`.
+    *   Return to the Credentials tab and click the `Add credentials` button
+        again, then select "OAuth 2.0 client ID" from the drop-down list.
+    *   In the "Application type" section check the **Other** option and give it a
+        name in the "Name" text box, then click `Create`.
+1.  In the pop-up window that appears, you'll see a **client ID** and a **Client
+    secret** string. Copy and paste those in a text file on your dev box then
+    click `OK` to dismiss. A new item should now appear in the **OAuth 2.0 client
+    IDs** list. You can click on the name of your client ID to retrieve the ID and
+    secret at any time. In the next few sections, these values will be referred
+    to as the **Client ID** and **Client secret** fields.
+1.  Click the `Create credentials` button _again_ on the same page.
+    *   In the pop-over window that shows up, click the `API key` button.
+    *   A pop-over should show up giving you the API key. Copy/paste in to a text
+        file to save, although you will be able to access this as well.
+    *   Click `OK` to dismiss.
+
+You should now have an API key and an OAuth 2.0 client ID in the **Credentials**
+tab. The next sections will refer to the value as the "API key".
+
+*** note
+**Note:** Your keys are not for distribution, and should not be shared with
+others.
+***
+
+## Providing Keys at Build time
+
+If you are building Chromium yourself, you can provide keys as part of your
+build configuration, that way they are always baked into your binary.
+
+Specify three variables in your `args.gn` file (edit by running `gn args
+out/your_out_dir_here`)
+
+```bash
+google_api_key = "your_api_key"
+google_default_client_id = "your_client_id"
+google_default_client_secret = "your_client_secret"
+```
+
+## Providing Keys at Runtime
+
+If you prefer, you can build a Chromium binary (or use a pre-built Chromium
+binary) without API keys baked in, and instead provide them at runtime. To do
+so, set the environment variables `GOOGLE_API_KEY`, `GOOGLE_DEFAULT_CLIENT_ID`
+and `GOOGLE_DEFAULT_CLIENT_SECRET` to your "API key", "Client ID" and "Client
+secret" values respectively.
+
+On Chromium OS to specify the keys as environment variables append them to the
+end of `/etc/chrome_dev.conf`:
+
+```bash
+GOOGLE_API_KEY=your_api_key
+GOOGLE_DEFAULT_CLIENT_ID=your_client_id
+GOOGLE_DEFAULT_CLIENT_SECRET=your_client_secret
+```
+
+## Signing in to Chromium is restricted
+
+Signing in to Chromium requires an OAuth 2.0 token for authentication. As this
+OAuth 2.0 token gives access to various Google services that handle user data
+(e.g. Chrome sync), for security and privacy reasons the generation of this
+OAuth 2.0 token is restricted. This means that signing in to Chromium is
+restricted (as the OAuth 2.0 token cannot be generated). In order to sign in to
+Chromium builds, please add your test account to
+google-browser-signin-testaccounts@chromium.org (accounts in this group are
+allowed to get access tokens bypassing the restriction above).
+
+*** note
+**Note:** Starting with Chromium M69, when the browser is set up with an OAuth
+2.0 client ID and client secret, signing in with your Google Account to any
+Google web property will also attempt to sign you in to Chromium (which will
+fail as explained above). To avoid such errors, remove your OAuth 2.0 client
+ID and client secret from your build to stop generating tokens when users sign
+in to Google web properties (remove `google_default_client_id`,
+`google_default_client_secret` from gn args and `GOOGLE_DEFAULT_CLIENT_ID`
+and `GOOGLE_DEFAULT_CLIENT_SECRET` from your environment settings).
+***
+
+## Getting Keys for Your Chromium Derivative
+
+Many of the Google APIs used by Chrome are specific to Google and not intended
+for use in derived products. In the [API Console](http://developers.google.com/console)
+you may be able to purchase additional quota for some of the APIs listed above.
+**For APIs that do not have a "Pricing" link, additional quota is not available
+for purchase.**
+
+## Polyfilling chrome.identity API in Your Chromium Derivative
+
+The default Chromium `chrome.identity.getAuthToken` API that extensions may
+call to obtain auth tokens will fail outside of Google Chrome as the
+implementation uses restricted APIs.
+
+A prototype CL for Chromium embedders might use to replace the implementation
+with one not dependent upon private APIs can be found attached to
+[this post](https://groups.google.com/a/chromium.org/g/embedder-dev/c/tGCJ3QNVzYE).
diff --git a/extensions/renderer/native_renderer_messaging_service.cc b/extensions/renderer/native_renderer_messaging_service.cc
index 166da49..1718f8c3 100644
--- a/extensions/renderer/native_renderer_messaging_service.cc
+++ b/extensions/renderer/native_renderer_messaging_service.cc
@@ -402,7 +402,7 @@
 
   const Extension* extension = script_context->extension();
   if (extension) {
-    if (!source->tab.empty() && !extension->is_platform_app()) {
+    if (!source->tab.DictEmpty() && !extension->is_platform_app()) {
       sender_builder.Set("tab", content::V8ValueConverter::Create()->ToV8Value(
                                     &source->tab, v8_context));
     }
diff --git a/fuchsia/runners/common/web_component.cc b/fuchsia/runners/common/web_component.cc
index aca830e..fe1ffad 100644
--- a/fuchsia/runners/common/web_component.cc
+++ b/fuchsia/runners/common/web_component.cc
@@ -32,15 +32,18 @@
       module_context_(
           startup_context()->svc()->Connect<fuchsia::modular::ModuleContext>()),
       navigation_listener_binding_(this) {
+  DCHECK(!debug_name_.empty());
   DCHECK(runner);
 
+  LOG(INFO) << "Creating component " << debug_name_;
+
   // If the ComponentController request is valid then bind it, and configure it
   // to destroy this component on error.
   if (controller_request.is_valid()) {
     controller_binding_.Bind(std::move(controller_request));
     controller_binding_.set_error_handler([this](zx_status_t status) {
       ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
-          << " ComponentController disconnected";
+          << " ComponentController disconnected for component " << debug_name_;
       // Teardown the component with dummy values, since ComponentController
       // channel isn't there to receive them.
       DestroyComponent(0, fuchsia::sys::TerminationReason::UNKNOWN);
@@ -82,8 +85,10 @@
   // ZX_ERR_PEER_CLOSED will usually indicate a crash, reported elsewhere.
   // Therefore only log other, more unusual, |status| codes.
   frame_.set_error_handler([this](zx_status_t status) {
-    if (status != ZX_OK && status != ZX_ERR_PEER_CLOSED)
-      ZX_LOG(ERROR, status) << " Frame disconnected";
+    if (status != ZX_OK && status != ZX_ERR_PEER_CLOSED) {
+      ZX_LOG(ERROR, status)
+          << " component " << debug_name_ << ": Frame disconnected";
+    }
     DestroyComponent(status, fuchsia::sys::TerminationReason::EXITED);
   });
 
@@ -109,6 +114,7 @@
     const GURL& url,
     std::vector<fuchsia::net::http::Header> extra_headers) {
   DCHECK(url.is_valid());
+
   fuchsia::web::NavigationControllerPtr navigation_controller;
   frame()->GetNavigationController(navigation_controller.NewRequest());
 
@@ -184,6 +190,10 @@
 
 void WebComponent::DestroyComponent(int64_t exit_code,
                                     fuchsia::sys::TerminationReason reason) {
+  LOG(INFO) << "Component " << debug_name_
+            << " is shutting down. reason=" << static_cast<int>(reason)
+            << " exit_code=" << exit_code;
+
   termination_reason_ = reason;
   termination_exit_code_ = exit_code;
   runner_->DestroyComponent(this);
diff --git a/fuchsia/runners/common/web_content_runner.cc b/fuchsia/runners/common/web_content_runner.cc
index ccf16c73..d0f80851 100644
--- a/fuchsia/runners/common/web_content_runner.cc
+++ b/fuchsia/runners/common/web_content_runner.cc
@@ -18,6 +18,7 @@
 #include "base/fuchsia/scoped_service_binding.h"
 #include "base/fuchsia/startup_context.h"
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "fuchsia/runners/buildflags.h"
 #include "fuchsia/runners/common/web_component.h"
 #include "url/gurl.h"
@@ -42,6 +43,11 @@
   return status == ZX_OK;
 }
 
+std::string CreateUniqueComponentName() {
+  static int last_component_id_ = 0;
+  return base::StringPrintf("web-component:%d", ++last_component_id_);
+}
+
 }  // namespace
 
 WebContentRunner::WebContentRunner(
@@ -90,7 +96,7 @@
   }
 
   std::unique_ptr<WebComponent> component = std::make_unique<WebComponent>(
-      std::string(), this,
+      CreateUniqueComponentName(), this,
       std::make_unique<base::StartupContext>(std::move(startup_info)),
       std::move(controller_request));
 #if BUILDFLAG(WEB_RUNNER_REMOTE_DEBUGGING_PORT) != 0
diff --git a/google_apis/test/embedded_setup_chromeos.html b/google_apis/test/embedded_setup_chromeos.html
index 5d8c2cc8..89f036e 100644
--- a/google_apis/test/embedded_setup_chromeos.html
+++ b/google_apis/test/embedded_setup_chromeos.html
@@ -9,6 +9,7 @@
 gaia.chromeOSLogin.parent_webview_ = undefined;
 gaia.chromeOSLogin.parent_webview_url_ = undefined;
 gaia.chromeOSLogin.initialized_ = false;
+gaia.chromeOSLogin.sendImplicitServices = true;
 
 const urlParams = new URLSearchParams(window.location.search);
 const syncTrustedVaultKeysRequestedByClient = !!urlParams.get('szkr');
@@ -77,6 +78,14 @@
       gaia.chromeOSLogin.parent_webview_url_);
 };
 
+gaia.chromeOSLogin.sendCloseView = function() {
+  msg = {
+    'method': 'closeView',
+  };
+  gaia.chromeOSLogin.parent_webview_.postMessage(msg,
+      gaia.chromeOSLogin.parent_webview_url_);
+};
+
 gaia.chromeOSLogin.backButton = function(show) {
   var msg = {
     'method': 'backButton',
@@ -130,6 +139,8 @@
       services = [];
     } else {
       console.warn("Services are not set for testing.");
+      if (gaia.chromeOSLogin.sendImplicitServices)
+        services = []
     }
 
     request = new XMLHttpRequest();
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_dxgi.cc b/gpu/ipc/common/gpu_memory_buffer_impl_dxgi.cc
index 532bc38..f720d09 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_dxgi.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_dxgi.cc
@@ -103,8 +103,8 @@
   }
 
   DCHECK(!shared_memory_handle_);
-  DCHECK(gpu_memory_buffer_manager_);
-  DCHECK(shared_memory_pool_);
+  CHECK(gpu_memory_buffer_manager_);
+  CHECK(shared_memory_pool_);
 
   shared_memory_handle_ = shared_memory_pool_->MaybeAllocateBuffer(
       gfx::BufferSizeForBufferFormat(size_, format_));
diff --git a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
index 4689dff..af2ef0fb 100644
--- a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
@@ -33,6 +33,7 @@
 <translation id="122699739164161391">Close All Tabs</translation>
 <translation id="1229222343402087523">Search ${searchPhrase} in Chrome</translation>
 <translation id="1231733316453485619">Turn on sync?</translation>
+<translation id="1242044645101871359">Sign in again</translation>
 <translation id="1254117744268754948">Choose folder</translation>
 <translation id="1265739287306757398">Learn How</translation>
 <translation id="1272079795634619415">Stop</translation>
@@ -97,6 +98,7 @@
 <translation id="1820259098641718022">Added to Reading List</translation>
 <translation id="1870148520156231997">Reveal password</translation>
 <translation id="1872096359983322073">Torch</translation>
+<translation id="1894205589103145703">Something went wrong during sign-in.</translation>
 <translation id="1911619930368729126">Upload to Google Drive</translation>
 <translation id="1923342640370224680">Last Hour</translation>
 <translation id="1941314575388338491">Double tap to copy.</translation>
@@ -110,6 +112,7 @@
 <translation id="2073572773299281212">Active <ph name="DAYS" /> days ago</translation>
 <translation id="2074131957428911366">You can always choose what to sync in <ph name="BEGIN_LINK" />settings<ph name="END_LINK" />.</translation>
 <translation id="2079545284768500474">Undo</translation>
+<translation id="2086623437239112659">Your stored sign-in info might be out of date.</translation>
 <translation id="209018056901015185">Request desktop site</translation>
 <translation id="2103075008456228677">Open history.google.com</translation>
 <translation id="2116625576999540962"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> items moved</translation>
@@ -400,6 +403,7 @@
 <translation id="5132942445612118989">Sync your passwords, history and more on all devices</translation>
 <translation id="5140288047769711648">Chrome will remember this password for you. You don't have to remember it.</translation>
 <translation id="5150492518600715772">Send to your device</translation>
+<translation id="5168414296986405587">Built for iPadOS</translation>
 <translation id="5181140330217080051">Downloading</translation>
 <translation id="5186185447130319458">Private</translation>
 <translation id="5188482106078495165">Your cookies setting applies to all tabs. To apply a new setting to an open tab, reload the tab.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_lo.xtb b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
index 1274b8e9..b335a79 100644
--- a/ios/chrome/app/strings/resources/ios_strings_lo.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
@@ -33,6 +33,7 @@
 <translation id="122699739164161391">ປິດແຖບທັງໝົດ</translation>
 <translation id="1229222343402087523">ຊອກຫາ ${searchPhrase} ໃນ Chrome</translation>
 <translation id="1231733316453485619">ເປີດການຊິ້ງຂໍ້ມູນບໍ?</translation>
+<translation id="1242044645101871359">ເຂົ້າສູ່ລະບົບອີກເທື່ອໜຶ່ງ</translation>
 <translation id="1254117744268754948">ເລືອກ​ໂຟລເດີ</translation>
 <translation id="1265739287306757398">ສຶກສາວິທີການ</translation>
 <translation id="1272079795634619415">ຢຸດ</translation>
@@ -97,6 +98,7 @@
 <translation id="1820259098641718022">ເພີ່ມໃສ່ລາຍການທີ່ຈະອ່ານ</translation>
 <translation id="1870148520156231997">ເປີດເຜີຍລະຫັດຜ່ານ</translation>
 <translation id="1872096359983322073">ໄຟສາຍ</translation>
+<translation id="1894205589103145703">ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນໃນລະຫວ່າງການເຂົ້າສູ່ລະບົບ.</translation>
 <translation id="1911619930368729126">ອັບ​ໂຫຼດ​ໃສ່ Google Drive</translation>
 <translation id="1923342640370224680">ຊົ່ວ​ໂມງ​ສຸດທ້າຍ</translation>
 <translation id="1941314575388338491">ແຕະສອງຄັ້ງເພື່ອສຳເນົາ</translation>
@@ -110,6 +112,7 @@
 <translation id="2073572773299281212">ນຳໃຊ້ເມື່ອ <ph name="DAYS" /> ກ່ອນ</translation>
 <translation id="2074131957428911366">ທ່ານສາມາດເລືອກສິ່ງທີ່ຈະຊິ້ງຂໍ້ມູນໄດ້ໃນ <ph name="BEGIN_LINK" />ການຕັ້ງຄ່າ<ph name="END_LINK" />.</translation>
 <translation id="2079545284768500474">ບໍ່ເຮັດ</translation>
+<translation id="2086623437239112659">ຂໍ້ມູນການເຂົ້າສູ່ລະບົບທີ່ທ່ານບັນທຶກໄວ້ອາດເກົ່າແລ້ວ.</translation>
 <translation id="209018056901015185">ຂໍ​ເວັບ​ໄຊ​ທ໌​ເດັ​ສ​ທັອບ</translation>
 <translation id="2103075008456228677">ເປີດ history.google.com</translation>
 <translation id="2116625576999540962"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ລາຍ​ການ​ຖືກ​ຍ້າຍ​ໄປ​ແລ້ວ</translation>
@@ -400,6 +403,7 @@
 <translation id="5132942445612118989">ຊິ້ງຂໍ້ມູນລະຫັດຜ່ານ, ປະຫວັດຂອງທ່ານ ແລະ ອື່ນໆອີກຢູ່ໃນທຸກອຸປະກອນ</translation>
 <translation id="5140288047769711648">Chrome ຈະຈື່ລະຫັດຜ່ານນີ້ສຳລັບທ່ານ. ທ່ານບໍ່ຈໍາເປັນຕ້ອງຈື່ມັນ.</translation>
 <translation id="5150492518600715772">ສົ່ງຫາອຸປະກອນຂອງທ່ານ</translation>
+<translation id="5168414296986405587">ສ້າງມາສຳລັບ iPadOS</translation>
 <translation id="5181140330217080051">ກໍາລັງດາວ​ໂຫຼດ</translation>
 <translation id="5186185447130319458">ສ່ວນຕົວ</translation>
 <translation id="5188482106078495165">ການຕັ້ງຄ່າຄຸກກີ້ຂອງທ່ານນຳໃຊ້ກັບແຖບທັງໝົດ. ເພື່ອນຳໃຊ້ການຕັ້ງຄ່າໃໝ່ກັບແຖບເປີດ, ກະລຸນາໂຫຼດແຖບ.</translation>
@@ -429,6 +433,7 @@
 <translation id="5508435575041083207">ອອກຈາກລະບົບ ແລະ ລຶບລ້າງຂໍ້ມູນອອກຈາກອຸປະກອນນີ້</translation>
 <translation id="5513681519188741830"><ph name="TIME" /> ຊມ ກ່ອນ</translation>
 <translation id="5525269841082836315">ສ້າງວະ​ລີ​ຜ່ານ</translation>
+<translation id="5532698011560297095">ບໍ່ສາມາດເຂົ້າສູ່ລະບົບໄດ້</translation>
 <translation id="5548760955356983418">Handoff ໃຫ້​ທ່ານ​ເລີ່ມ​ທ່ອງ​ເວັບ​ໄຊ​ທ໌​ຢູ່​ໃນ​ອຸ​ປະ​ກອນ​ນີ້ ແລະ​ຈາກ​ນັ້ນ​ສືບ​ຕໍ່​ຢູ່​ໃນ Mac ຂອງ​ທ່ານ​ໄດ້​ຢ່າງ​ງ່າຍ​ດາຍ. ເວັບ​ໄຊ​ທ໌​ເປີດ​ປະ​ຈຸ​ບັນ​ຈະ​ປະ​ກົດ​ຂຶ້ນ​ຢູ່​ໃນ Dock ຂອງ Mac ຂອງ​ທ່ານ.
 
 Handoff ຍັງ​ຕ້ອງ​ໄດ້​ເປີດ​ໃຊ້​ງານ​ຢູ່​ໃນ​ພາກ​ທົ່ວ​ໄປ​ຂອງ​ການ​ຕັ້ງ​ຄ່າ​ນຳ​ອີກ, ແລະ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຕ້ອງ​ໃຊ້​ບັນ​ຊີ iCloud ດຽວ​ກັນ​ນຳ.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ms.xtb b/ios/chrome/app/strings/resources/ios_strings_ms.xtb
index 5efe4d9..9b5a39e 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ms.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ms.xtb
@@ -33,6 +33,7 @@
 <translation id="122699739164161391">Tutup Semua Tab</translation>
 <translation id="1229222343402087523">Cari ${searchPhrase} dalam Chrome</translation>
 <translation id="1231733316453485619">Hidupkan penyegerakan?</translation>
+<translation id="1242044645101871359">Log Masuk Semula</translation>
 <translation id="1254117744268754948">Pilih Folder</translation>
 <translation id="1265739287306757398">Ketahui Caranya</translation>
 <translation id="1272079795634619415">Berhenti</translation>
@@ -97,6 +98,7 @@
 <translation id="1820259098641718022">Ditambahkan pada Senarai Bacaan</translation>
 <translation id="1870148520156231997">Dedahkan Kata Laluan</translation>
 <translation id="1872096359983322073">Lampu suluh</translation>
+<translation id="1894205589103145703">Kesilapan telah berlaku semasa log masuk.</translation>
 <translation id="1911619930368729126">Muat naik ke Google Drive</translation>
 <translation id="1923342640370224680">Jam Terakhir</translation>
 <translation id="1941314575388338491">Ketik dua kali untuk menyalin.</translation>
@@ -110,6 +112,7 @@
 <translation id="2073572773299281212">Aktif <ph name="DAYS" /> Hari Yang Lalu</translation>
 <translation id="2074131957428911366">Anda boleh memilih item yang hendak disegerakkan dalam <ph name="BEGIN_LINK" />tetapan<ph name="END_LINK" /> pada bila-bila masa.</translation>
 <translation id="2079545284768500474">Buat asal</translation>
+<translation id="2086623437239112659">Maklumat log masuk anda yang disimpan mungkin sudah lapuk.</translation>
 <translation id="209018056901015185">Minta Tapak Desktop</translation>
 <translation id="2103075008456228677">Buka history.google.com</translation>
 <translation id="2116625576999540962"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> item dialihkan</translation>
@@ -400,6 +403,7 @@
 <translation id="5132942445612118989">Segerakkan kata laluan, sejarah &amp; pelbagai lagi pada semua peranti</translation>
 <translation id="5140288047769711648">Chrome akan mengingati kata laluan ini untuk anda. Anda tidak perlu mengingatnya.</translation>
 <translation id="5150492518600715772">Hantar Ke Peranti Anda</translation>
+<translation id="5168414296986405587">Dibina untuk iPadOS</translation>
 <translation id="5181140330217080051">Memuat turun</translation>
 <translation id="5186185447130319458">Peribadi</translation>
 <translation id="5188482106078495165">Tetapan kuki anda digunakan pada semua tab. Untuk menggunakan tetapan baharu pada tab yang terbuka, muat semula tab itu.</translation>
@@ -429,6 +433,7 @@
 <translation id="5508435575041083207">Log Keluar dan Kosongkan Data daripada Peranti ini</translation>
 <translation id="5513681519188741830"><ph name="TIME" /> j yang lalu</translation>
 <translation id="5525269841082836315">Buat Frasa Laluan</translation>
+<translation id="5532698011560297095">Tidak Dapat Log Masuk</translation>
 <translation id="5548760955356983418">Ciri Serah membolehkan anda mula menyemak imbas tapak web pada peranti ini, kemudian meneruskannya pada Mac anda dengan mudah. Tapak web yang dibuka pada masa ini akan muncul dalam Dock Mac anda.
 
 Serah mestilah turut didayakan dalam bahagian Umum pada Tetapan dan peranti anda mestilah menggunakan akaun iCloud yang sama.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_si.xtb b/ios/chrome/app/strings/resources/ios_strings_si.xtb
index 0e4460db..b7ab694 100644
--- a/ios/chrome/app/strings/resources/ios_strings_si.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_si.xtb
@@ -33,6 +33,7 @@
 <translation id="122699739164161391">සියලු පටිති වසන්න</translation>
 <translation id="1229222343402087523">Chrome තුළ ${searchPhrase} සොයන්න</translation>
 <translation id="1231733316453485619">සමමුහුව ක්‍රියාත්මක කරන්න ද?</translation>
+<translation id="1242044645101871359">නැවත පුරන්න</translation>
 <translation id="1254117744268754948">ෆෝල්ඩරය තෝරන්න</translation>
 <translation id="1265739287306757398">කෙසේදැයි දැන ගන්න</translation>
 <translation id="1272079795634619415">නවතන්න</translation>
@@ -97,6 +98,7 @@
 <translation id="1820259098641718022">කියවීම් ලැයිස්තුවට එක් කරන ලදී</translation>
 <translation id="1870148520156231997">මුරපදය අනාවරණ කරන්න</translation>
 <translation id="1872096359983322073">පන්දම</translation>
+<translation id="1894205589103145703">පිරීම අතරතුර යම් දෙයක් වැරදිණි.</translation>
 <translation id="1911619930368729126">Google Drive වෙත උඩුගත කරන්න</translation>
 <translation id="1923342640370224680">අවසන් පැයේ</translation>
 <translation id="1941314575388338491">පිටපත් කිරීමට දෙවරක් තට්ටු කරන්න.</translation>
@@ -110,6 +112,7 @@
 <translation id="2073572773299281212">දින <ph name="DAYS" /> කට පෙර ක්‍රියාත්මකයි</translation>
 <translation id="2074131957428911366">ඔබට සැමවිටම <ph name="BEGIN_LINK" />සැකසීම්<ph name="END_LINK" /> තුළ සමමුහු කළ යුතු දෙය තෝරා ගත හැක.</translation>
 <translation id="2079545284768500474">පසුගමනය</translation>
+<translation id="2086623437239112659">ඔබගේ ගබඩා කළ පිරීමේ තතු කල් ඉකුත්ව තිබිය හැකිය.</translation>
 <translation id="209018056901015185">ඩෙක්ස්ටොප් අඩවිය ඉල්ලන්න</translation>
 <translation id="2103075008456228677">history.google.com විවෘත කරන්න</translation>
 <translation id="2116625576999540962">අයිතම <ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ක් ගෙන යන ලදි</translation>
@@ -400,6 +403,7 @@
 <translation id="5132942445612118989">ඔබේ මුරපද, ඉතිහාසය සහ තවත් දෑ සියලුම උපාංගවල සමමුහු කරන්න</translation>
 <translation id="5140288047769711648">Chrome ඔබ වෙනුවෙන් මෙම මුරපදය මතක තබා ගනියි. ඔබට එය මතක තබා ගැනීමට අවශ්‍ය නැත.</translation>
 <translation id="5150492518600715772">ඔබේ උපාංගය වෙත යවන්න</translation>
+<translation id="5168414296986405587">iPadOS සඳහා තනා ඇත</translation>
 <translation id="5181140330217080051">බාගනිමින්</translation>
 <translation id="5186185447130319458">රහසිගත</translation>
 <translation id="5188482106078495165">ඔබේ කුකි සැකසීම සියලු ටැබවලට යෙදේ. නව සැකසීමක් විවෘත ටැබයකට යෙදීමට, ටැබය නැවත පූරණය කරන්න.</translation>
@@ -429,6 +433,7 @@
 <translation id="5508435575041083207">වරනය වී මෙම උපාංගයෙන් දත්ත හිස් කරන්න</translation>
 <translation id="5513681519188741830">පැ <ph name="TIME" />කට පෙර</translation>
 <translation id="5525269841082836315">මුර-වැකිකඩ සාදන්න</translation>
+<translation id="5532698011560297095">පිරීමට නොහැකිය</translation>
 <translation id="5548760955356983418">Handoff ඔබට මෙම උපාංගය මත වෙබ් අඩවියක් බ්‍රවුස් කිරීම ඇරඹීමට ඉඩ දෙන අතර අනතුරුව ඔබේ Mac එකේ දිගටම කරගෙන යාමට ඉඩ දෙයි. වත්මන් විවෘත යෙදුම ඔබේ Mac හි ඩොක් තුළ දිස් වනු ඇත.
 
 සැකසුම්වල පොදු අංශය තුළද Handoff සබල කළ යුතු අතර ඔබේ උපාංග එකම iCloud ගිණුම භාවිත කළ යුතුය.</translation>
diff --git a/ios/chrome/browser/discover_feed/discover_feed_service.h b/ios/chrome/browser/discover_feed/discover_feed_service.h
index bedd3ac..f8ad395 100644
--- a/ios/chrome/browser/discover_feed/discover_feed_service.h
+++ b/ios/chrome/browser/discover_feed/discover_feed_service.h
@@ -9,8 +9,9 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 
-class ChromeBrowserState;
+class AuthenticationService;
 @class DiscoverFeedMetricsRecorder;
+class PrefService;
 
 // A browser-context keyed service that is used to keep the Discover Feed data
 // up to date.
@@ -18,7 +19,9 @@
                             public signin::IdentityManager::Observer {
  public:
   // Initializes the service.
-  explicit DiscoverFeedService(ChromeBrowserState* browser_state);
+  DiscoverFeedService(PrefService* pref_service,
+                      AuthenticationService* authentication_service,
+                      signin::IdentityManager* identity_manager);
   ~DiscoverFeedService() override;
 
   // Returns the FeedMetricsRecorder to be used by the Feed, a single instance
diff --git a/ios/chrome/browser/discover_feed/discover_feed_service.mm b/ios/chrome/browser/discover_feed/discover_feed_service.mm
index 80a5c93..e5f1f6ac 100644
--- a/ios/chrome/browser/discover_feed/discover_feed_service.mm
+++ b/ios/chrome/browser/discover_feed/discover_feed_service.mm
@@ -5,8 +5,6 @@
 #include "ios/chrome/browser/discover_feed/discover_feed_service.h"
 
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/signin/authentication_service_factory.h"
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
 #import "ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/discover_feed/discover_feed_configuration.h"
@@ -16,9 +14,10 @@
 #error "This file requires ARC support."
 #endif
 
-DiscoverFeedService::DiscoverFeedService(ChromeBrowserState* browser_state) {
-  signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForBrowserState(browser_state);
+DiscoverFeedService::DiscoverFeedService(
+    PrefService* pref_service,
+    AuthenticationService* authentication_service,
+    signin::IdentityManager* identity_manager) {
   if (identity_manager)
     identity_manager_observation_.Observe(identity_manager);
 
@@ -26,10 +25,8 @@
 
   DiscoverFeedConfiguration* discover_config =
       [[DiscoverFeedConfiguration alloc] init];
-  discover_config.browserState = browser_state;
-  discover_config.authService =
-      AuthenticationServiceFactory::GetForBrowserState(browser_state);
-  discover_config.prefService = browser_state->GetPrefs();
+  discover_config.authService = authentication_service;
+  discover_config.prefService = pref_service;
   discover_config.metricsRecorder = discover_feed_metrics_recorder_;
   ios::GetChromeBrowserProvider()->GetDiscoverFeedProvider()->StartFeed(
       discover_config);
diff --git a/ios/chrome/browser/discover_feed/discover_feed_service_factory.mm b/ios/chrome/browser/discover_feed/discover_feed_service_factory.mm
index e8f96e14..e51f03e 100644
--- a/ios/chrome/browser/discover_feed/discover_feed_service_factory.mm
+++ b/ios/chrome/browser/discover_feed/discover_feed_service_factory.mm
@@ -42,5 +42,8 @@
     web::BrowserState* context) const {
   ChromeBrowserState* browser_state =
       ChromeBrowserState::FromBrowserState(context);
-  return std::make_unique<DiscoverFeedService>(browser_state);
+  return std::make_unique<DiscoverFeedService>(
+      browser_state->GetPrefs(),
+      AuthenticationServiceFactory::GetForBrowserState(browser_state),
+      IdentityManagerFactory::GetForBrowserState(browser_state));
 }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h
index bd83364b..aa8663a 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h
@@ -20,6 +20,7 @@
   MockAutofillSaveUpdateAddressProfileDelegateIOS(
       const autofill::AutofillProfile& profile,
       const autofill::AutofillProfile* original_profile,
+      const std::string& locale,
       autofill::AutofillClient::AddressProfileSavePromptCallback callback);
   ~MockAutofillSaveUpdateAddressProfileDelegateIOS() override;
 
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm
index bd76acc..d7cad4e 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm
@@ -16,9 +16,11 @@
     MockAutofillSaveUpdateAddressProfileDelegateIOS(
         const autofill::AutofillProfile& profile,
         const autofill::AutofillProfile* original_profile,
+        const std::string& locale,
         autofill::AutofillClient::AddressProfileSavePromptCallback callback)
     : AutofillSaveUpdateAddressProfileDelegateIOS(profile,
                                                   original_profile,
+                                                  locale,
                                                   std::move(callback)) {}
 
 MockAutofillSaveUpdateAddressProfileDelegateIOS::
@@ -38,6 +40,6 @@
     CreateMockAutofillSaveUpdateAddressProfileDelegateIOSFactory(
         autofill::AutofillProfile profile) {
   return std::make_unique<MockAutofillSaveUpdateAddressProfileDelegateIOS>(
-      profile, /*original_profile=*/nullptr,
+      profile, /*original_profile=*/nullptr, /*locale=*/"en-US",
       autofill::AutofillClient::AddressProfileSavePromptCallback());
 }
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
index 354572ff..cd66a60 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
@@ -29,8 +29,8 @@
   // The button label text.
   std::u16string button_label_text() const { return button_label_text_; }
 
-  // The message sub text.
-  std::u16string message_sub_text() const { return message_sub_text_; }
+  // The description.
+  std::u16string description() const { return description_; }
 
   // The name of the icon image.
   NSString* icon_image_name() const { return icon_image_name_; }
@@ -50,7 +50,7 @@
   // Configuration data extracted from |infobar_|'s save address profile
   // delegate.
   std::u16string message_text_;
-  std::u16string message_sub_text_;
+  std::u16string description_;
   std::u16string button_label_text_;
   NSString* icon_image_name_ = nil;
 
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm
index 0614e89..83d50b8 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm
+++ b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm
@@ -29,7 +29,7 @@
           FromInfobarDelegate(infobar_->delegate());
   message_text_ = delegate->GetMessageText();
   button_label_text_ = delegate->GetMessageActionText();
-  message_sub_text_ = delegate->GetMessageDescriptionText();
+  description_ = delegate->GetDescription();
   is_update_banner_ = delegate->GetOriginalProfile() ? true : false;
 }
 
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm
index 68f0c3d..5474b1f7 100644
--- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm
+++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm
@@ -7,7 +7,6 @@
 #include "base/check.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h"
-#include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/infobars/infobar_ios.h"
 #import "ios/chrome/browser/overlays/public/common/infobars/infobar_overlay_request_config.h"
 
@@ -27,8 +26,7 @@
       static_cast<autofill::AutofillSaveUpdateAddressProfileDelegateIOS*>(
           infobar_->delegate());
 
-  address_ = delegate->GetEnvelopeStyleAddress(
-      GetApplicationContext()->GetApplicationLocale());
+  address_ = delegate->GetEnvelopeStyleAddress();
   emailAddress_ = delegate->GetEmailAddress();
   phoneNumber_ = delegate->GetPhoneNumber();
   current_address_profile_saved_ = infobar->accepted();
diff --git a/ios/chrome/browser/ui/authentication/signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
index 353d890..06cfae7 100644
--- a/ios/chrome/browser/ui/authentication/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
@@ -47,7 +47,6 @@
     "//components/policy/core/common:common_constants",
     "//components/prefs",
     "//components/signin/ios/browser",
-    "//components/version_info",
     "//ios/chrome/app:tests_hook",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/policy:policy_util",
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/BUILD.gn
index 7613c8ff..be3accf 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/BUILD.gn
@@ -24,6 +24,7 @@
   deps = [
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/authentication",
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
index 6ee73802..6dca731 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
@@ -5,6 +5,8 @@
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.h"
 
 #import "base/strings/sys_string_conversions.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_table_view_controller_action_delegate.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_view_controller.h"
@@ -33,7 +35,9 @@
 - (void)startWithSelectedIdentity:(ChromeIdentity*)selectedIdentity {
   [super start];
   self.mediator = [[ConsistencyAccountChooserMediator alloc]
-      initWithSelectedIdentity:selectedIdentity];
+      initWithSelectedIdentity:selectedIdentity
+                   prefService:self.browser->GetBrowserState()->GetPrefs()];
+
   self.accountChooserViewController =
       [[ConsistencyAccountChooserViewController alloc] init];
   self.accountChooserViewController.modelDelegate = self.mediator;
@@ -42,6 +46,11 @@
   [self.accountChooserViewController view];
 }
 
+- (void)stop {
+  [super stop];
+  [self.mediator disconnect];
+}
+
 #pragma mark - Properties
 
 - (UIViewController*)viewController {
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.h b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.h
index f13041b1..8381391 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.h
@@ -12,6 +12,7 @@
 @class ChromeIdentity;
 @protocol ConsistencyAccountChooserConsumer;
 @class ConsistencyAccountChooserMediator;
+class PrefService;
 
 // Mediator for ConsistencyAccountChooserCoordinator.
 @interface ConsistencyAccountChooserMediator
@@ -24,8 +25,12 @@
 - (instancetype)init NS_UNAVAILABLE;
 
 - (instancetype)initWithSelectedIdentity:(ChromeIdentity*)selectedIdentity
+                             prefService:(PrefService*)prefService
     NS_DESIGNATED_INITIALIZER;
 
+// Disconnect the mediator.
+- (void)disconnect;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONSISTENCY_PROMO_SIGNIN_CONSISTENCY_ACCOUNT_CHOOSER_CONSISTENCY_ACCOUNT_CHOOSER_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.mm
index 0458586..85d4f05b7 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_mediator.mm
@@ -28,13 +28,17 @@
 @property(nonatomic, strong) NSArray* sortedIdentityItemConfigurators;
 @property(nonatomic, assign, readonly)
     ios::ChromeIdentityService* chromeIdentityService;
+// Pref service to retrieve preference values.
+@property(nonatomic, assign) PrefService* prefService;
 
 @end
 
 @implementation ConsistencyAccountChooserMediator
 
-- (instancetype)initWithSelectedIdentity:(ChromeIdentity*)selectedIdentity {
+- (instancetype)initWithSelectedIdentity:(ChromeIdentity*)selectedIdentity
+                             prefService:(PrefService*)prefService {
   if (self = [super init]) {
+    _prefService = prefService;
     _identityServiceObserver =
         std::make_unique<ChromeIdentityServiceObserverBridge>(self);
     _browserProviderObserver =
@@ -46,6 +50,14 @@
   return self;
 }
 
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
+- (void)disconnect {
+  self.prefService = nullptr;
+}
+
 #pragma mark - Properties
 
 - (ios::ChromeIdentityService*)chromeIdentityService {
@@ -67,9 +79,14 @@
 
 // Updates |self.sortedIdentityItemConfigurators| based on ChromeIdentity list.
 - (void)loadIdentityItemConfigurators {
+  if (!self.prefService) {
+    return;
+  }
+
   NSMutableArray* configurators = [NSMutableArray array];
   NSArray* identities =
-      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay();
+      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay(
+          self.prefService);
   BOOL hasSelectedIdentity = NO;
   for (ChromeIdentity* identity in identities) {
     IdentityItemConfigurator* configurator =
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/BUILD.gn
index 866ecbf2..4a2de09 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/BUILD.gn
@@ -16,8 +16,10 @@
     "consistency_default_account_view_controller.mm",
   ]
   deps = [
+    "//components/prefs",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/authentication:authentication",
     "//ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet",
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm
index c7295b3..1a95b5a 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.h"
 
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -28,7 +30,8 @@
 @implementation ConsistencyDefaultAccountCoordinator
 
 - (void)start {
-  self.mediator = [[ConsistencyDefaultAccountMediator alloc] init];
+  self.mediator = [[ConsistencyDefaultAccountMediator alloc]
+      initWithPrefService:self.browser->GetBrowserState()->GetPrefs()];
   self.mediator.delegate = self;
   self.defaultAccountViewController =
       [[ConsistencyDefaultAccountViewController alloc] init];
@@ -45,6 +48,11 @@
   [self.defaultAccountViewController stopSpinner];
 }
 
+- (void)stop {
+  [self.mediator disconnect];
+  self.mediator = nil;
+}
+
 #pragma mark - Properties
 
 - (UIViewController*)viewController {
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h
index c1f37697..1da807fa 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h
@@ -10,6 +10,7 @@
 @class ChromeIdentity;
 @class ConsistencyDefaultAccountMediator;
 @protocol ConsistencyDefaultAccountConsumer;
+class PrefService;
 
 // Delegate for ConsistencyDefaultAccountMediator.
 @protocol ConsistencyDefaultAccountMediatorDelegate <NSObject>
@@ -23,12 +24,21 @@
 // Mediator for ConsistencyDefaultAccountCoordinator.
 @interface ConsistencyDefaultAccountMediator : NSObject
 
+// The designated initializer.
+- (instancetype)initWithPrefService:(PrefService*)prefService
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
 @property(nonatomic, weak) id<ConsistencyDefaultAccountMediatorDelegate>
     delegate;
 @property(nonatomic, strong) id<ConsistencyDefaultAccountConsumer> consumer;
 // Identity presented to the user.
 @property(nonatomic, strong) ChromeIdentity* selectedIdentity;
 
+// Disconnect the mediator.
+- (void)disconnect;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONSISTENCY_PROMO_SIGNIN_CONSISTENCY_DEFAULT_ACCOUNT_CONSISTENCY_DEFAULT_ACCOUNT_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
index 8cd03b8..7f2353bf 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.h"
 
+#include "components/prefs/pref_service.h"
 #import "ios/chrome/browser/chrome_browser_provider_observer_bridge.h"
 #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
 #import "ios/chrome/browser/ui/authentication/resized_avatar_cache.h"
@@ -24,13 +25,15 @@
 
 @property(nonatomic, strong) UIImage* avatar;
 @property(nonatomic, strong) ResizedAvatarCache* avatarCache;
+@property(nonatomic, assign) PrefService* prefService;
 
 @end
 
 @implementation ConsistencyDefaultAccountMediator
 
-- (instancetype)init {
+- (instancetype)initWithPrefService:(PrefService*)prefService {
   if (self = [super init]) {
+    _prefService = prefService;
     _identityServiceObserver =
         std::make_unique<ChromeIdentityServiceObserverBridge>(self);
     _browserProviderObserver =
@@ -40,6 +43,14 @@
   return self;
 }
 
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
+- (void)disconnect {
+  self.prefService = nullptr;
+}
+
 #pragma mark - Properties
 
 - (void)setConsumer:(id<ConsistencyDefaultAccountConsumer>)consumer {
@@ -60,9 +71,15 @@
 
 // Updates the default identity.
 - (void)selectSelectedIdentity {
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
+  if (!self.prefService) {
+    return;
+  }
+
+  NSArray* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(self.prefService);
+
   if (identities.count == 0) {
     [self.delegate consistencyDefaultAccountMediatorNoIdentities:self];
     return;
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
index 1a698c5..d5f92d4b 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
@@ -114,6 +114,12 @@
                                       completion:nil];
 }
 
+- (void)stop {
+  [super stop];
+  [self.defaultAccountCoordinator stop];
+  self.defaultAccountCoordinator = nil;
+}
+
 #pragma mark - Properties
 
 - (ChromeIdentity*)selectedIdentity {
@@ -267,6 +273,7 @@
     (ConsistencyAccountChooserCoordinator*)coordinator {
   self.defaultAccountCoordinator.selectedIdentity =
       self.accountChooserCoordinator.selectedIdentity;
+  [self.accountChooserCoordinator stop];
   self.accountChooserCoordinator = nil;
   [self.navigationController popViewControllerAnimated:YES];
 }
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
index 46bdafdf..194b972 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
@@ -5,6 +5,8 @@
 #import "ios/chrome/browser/ui/authentication/signin/signin_coordinator.h"
 
 #include "base/notreached.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.h"
@@ -30,9 +32,10 @@
                                        identity:(ChromeIdentity*)identity
                                     accessPoint:(AccessPoint)accessPoint
                                     promoAction:(PromoAction)promoAction {
-  UserSigninLogger* logger =
-      [[UserSigninLogger alloc] initWithAccessPoint:accessPoint
-                                        promoAction:promoAction];
+  UserSigninLogger* logger = [[UserSigninLogger alloc]
+      initWithAccessPoint:accessPoint
+              promoAction:promoAction
+              prefService:browser->GetBrowserState()->GetPrefs()];
   return [[UserSigninCoordinator alloc]
       initWithBaseViewController:viewController
                          browser:browser
@@ -47,7 +50,8 @@
                                                             (Browser*)browser {
   UserSigninLogger* logger = [[FirstRunSigninLogger alloc]
       initWithAccessPoint:AccessPoint::ACCESS_POINT_START_PAGE
-              promoAction:PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO];
+              promoAction:PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO
+              prefService:browser->GetBrowserState()->GetPrefs()];
   return [[UserSigninCoordinator alloc]
       initWithBaseNavigationController:navigationController
                                browser:browser
@@ -61,7 +65,8 @@
                                                 browser:(Browser*)browser {
   UserSigninLogger* logger = [[UpgradeSigninLogger alloc]
       initWithAccessPoint:AccessPoint::ACCESS_POINT_SIGNIN_PROMO
-              promoAction:PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO];
+              promoAction:PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO
+              prefService:browser->GetBrowserState()->GetPrefs()];
   return [[UserSigninCoordinator alloc]
       initWithBaseViewController:viewController
                          browser:browser
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_utils.h b/ios/chrome/browser/ui/authentication/signin/signin_utils.h
index 1ff77033..7e7a130 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils.h
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils.h
@@ -17,17 +17,16 @@
 namespace signin {
 
 // Returns true if this user sign-in upgrade should be shown for |browserState|.
-bool ShouldPresentUserSigninUpgrade(ChromeBrowserState* browserState);
+bool ShouldPresentUserSigninUpgrade(ChromeBrowserState* browser_state,
+                                    const base::Version& current_version);
 
 // Records in user defaults:
 //   + the Chromium current version.
 //   + increases the sign-in promo display count.
 //   + Gaia ids list.
 // Separated out into a discrete function to allow overriding when testing.
-void RecordVersionSeen();
-
-// Set the Chromium current version for sign-in. Used for tests only.
-void SetCurrentVersionForTesting(base::Version* version);
+void RecordVersionSeen(PrefService* pref_service,
+                       const base::Version& current_version);
 
 // Returns a boolean indicating whether browser sign-in is allowed across the
 // app.
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_utils.mm b/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
index 3de0b433..c404c038 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
@@ -11,7 +11,6 @@
 #import "components/prefs/pref_service.h"
 #import "components/signin/ios/browser/features.h"
 #import "components/signin/public/base/signin_pref_names.h"
-#import "components/version_info/version_info.h"
 #import "ios/chrome/app/tests_hook.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
@@ -28,39 +27,52 @@
 #error "This file requires ARC support."
 #endif
 
-using base::SysNSStringToUTF8;
-using base::Version;
-
 namespace {
-Version* g_current_version_for_test = nullptr;
 
-Version CurrentVersion() {
-  if (g_current_version_for_test) {
-    return *g_current_version_for_test;
-  }
-  Version currentVersion = version_info::GetVersion();
-  DCHECK(currentVersion.IsValid());
-  return currentVersion;
-}
-
-NSSet* GaiaIdSetWithIdentities(NSArray* identities) {
-  NSMutableSet* gaiaIdSet = [NSMutableSet set];
+// Converts an array of identities to a set of gaia ids.
+NSSet<NSString*>* GaiaIdSetWithIdentities(
+    NSArray<ChromeIdentity*>* identities) {
+  NSMutableSet* gaia_id_set = [NSMutableSet set];
   for (ChromeIdentity* identity in identities) {
-    [gaiaIdSet addObject:identity.gaiaID];
+    [gaia_id_set addObject:identity.gaiaID];
   }
-  return [gaiaIdSet copy];
+  return [gaia_id_set copy];
 }
+
+// Returns whether the gaia ids |recorded_gaia_ids| is a strict subset of the
+// current |identities| (i.e. all the gaia ids are in identities but there is
+// at least one new identity).
+bool IsStrictSubset(NSArray<NSString*>* recorded_gaia_ids,
+                    NSArray<ChromeIdentity*>* identities) {
+  // Optimisation for the case of a nil or empty |recorded_gaia_ids|.
+  // This allow not special casing the construction of the NSSet (as
+  // -[NSSet setWithArray:] does not support nil for the array).
+  if (recorded_gaia_ids.count == 0)
+    return identities.count > 0;
+
+  NSSet<NSString*>* recorded_gaia_ids_set =
+      [NSSet setWithArray:recorded_gaia_ids];
+  NSSet<NSString*>* identities_gaia_ids_set =
+      GaiaIdSetWithIdentities(identities);
+  return [recorded_gaia_ids_set isSubsetOfSet:identities_gaia_ids_set] &&
+         ![recorded_gaia_ids_set isEqualToSet:identities_gaia_ids_set];
+}
+
 }  // namespace
 
 #pragma mark - Public
 
 namespace signin {
 
-bool ShouldPresentUserSigninUpgrade(ChromeBrowserState* browserState) {
+bool ShouldPresentUserSigninUpgrade(ChromeBrowserState* browser_state,
+                                    const base::Version& current_version) {
+  DCHECK(browser_state);
+  DCHECK(current_version.IsValid());
+
   if (tests_hook::DisableSigninRecallPromo())
     return false;
 
-  if (browserState->IsOffTheRecord())
+  if (browser_state->IsOffTheRecord())
     return false;
 
   // There will be an error shown if the user chooses to sign in or select
@@ -69,70 +81,70 @@
     return false;
 
   // Sign-in can be disabled by policy.
-  if (!signin::IsSigninAllowed(browserState->GetPrefs()))
+  if (!signin::IsSigninAllowed(browser_state->GetPrefs()))
     return false;
 
-  AuthenticationService* authService =
-      AuthenticationServiceFactory::GetForBrowserState(browserState);
+  AuthenticationService* auth_service =
+      AuthenticationServiceFactory::GetForBrowserState(browser_state);
   // Do not show the SSO promo if the user is already logged in.
-  if (authService->IsAuthenticated())
+  if (auth_service->IsAuthenticated())
     return false;
 
   if (signin::ForceStartupSigninPromo())
     return true;
 
   // Show the promo at most every two major versions.
-  NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults];
-  NSString* versionShown =
-      [standardDefaults stringForKey:kDisplayedSSORecallForMajorVersionKey];
-  if (versionShown) {
-    Version seenVersion(SysNSStringToUTF8(versionShown));
-    Version currentVersion = CurrentVersion();
-    if (currentVersion.components()[0] - seenVersion.components()[0] < 2)
-      return false;
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSString* version_string =
+      [defaults stringForKey:kDisplayedSSORecallForMajorVersionKey];
+
+  if (version_string) {
+    const base::Version version_shown(base::SysNSStringToUTF8(version_string));
+    if (version_shown.IsValid()) {
+      if (current_version.components()[0] - version_shown.components()[0] < 2)
+        return false;
+    }
   }
-  // Don't show the promo if there is no identities.
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
-  if ([identities count] == 0)
+
+  // Don't show the promo if there are no identities.
+  NSArray* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(browser_state->GetPrefs());
+  if (identities.count == 0)
     return false;
+
   // The sign-in promo should be shown twice, even if no account has been added.
-  NSInteger displayCount =
-      [standardDefaults integerForKey:kSigninPromoViewDisplayCountKey];
-  if (displayCount <= 1)
+  NSInteger display_count =
+      [defaults integerForKey:kSigninPromoViewDisplayCountKey];
+  if (display_count <= 1)
     return true;
+
   // Otherwise, it can be shown only if a new account has been added.
-  NSArray* lastKnownGaiaIdList =
-      [standardDefaults arrayForKey:kLastShownAccountGaiaIdVersionKey];
-  NSSet* lastKnownGaiaIdSet = lastKnownGaiaIdList
-                                  ? [NSSet setWithArray:lastKnownGaiaIdList]
-                                  : [NSSet set];
-  NSSet* currentGaiaIdSet = GaiaIdSetWithIdentities(identities);
-  return [lastKnownGaiaIdSet isSubsetOfSet:currentGaiaIdSet] &&
-         ![lastKnownGaiaIdSet isEqualToSet:currentGaiaIdSet];
+  NSArray<NSString*>* last_known_gaia_id_list =
+      [defaults arrayForKey:kLastShownAccountGaiaIdVersionKey];
+  return IsStrictSubset(last_known_gaia_id_list, identities);
 }
 
-void RecordVersionSeen() {
-  NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults];
-  [standardDefaults
-      setObject:base::SysUTF8ToNSString(CurrentVersion().GetString())
-         forKey:kDisplayedSSORecallForMajorVersionKey];
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
-  NSArray* gaiaIdList = GaiaIdSetWithIdentities(identities).allObjects;
-  [standardDefaults setObject:gaiaIdList
-                       forKey:kLastShownAccountGaiaIdVersionKey];
-  NSInteger displayCount =
-      [standardDefaults integerForKey:kSigninPromoViewDisplayCountKey];
-  ++displayCount;
-  [standardDefaults setInteger:displayCount
-                        forKey:kSigninPromoViewDisplayCountKey];
-}
+void RecordVersionSeen(PrefService* pref_service,
+                       const base::Version& current_version) {
+  DCHECK(pref_service);
+  DCHECK(current_version.IsValid());
 
-void SetCurrentVersionForTesting(Version* version) {
-  g_current_version_for_test = version;
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:base::SysUTF8ToNSString(current_version.GetString())
+               forKey:kDisplayedSSORecallForMajorVersionKey];
+  NSArray<ChromeIdentity*>* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(pref_service);
+  NSSet<NSString*>* gaia_id_set = GaiaIdSetWithIdentities(identities);
+  [defaults setObject:gaia_id_set.allObjects
+               forKey:kLastShownAccountGaiaIdVersionKey];
+  NSInteger display_count =
+      [defaults integerForKey:kSigninPromoViewDisplayCountKey];
+  ++display_count;
+  [defaults setInteger:display_count forKey:kSigninPromoViewDisplayCountKey];
 }
 
 bool IsSigninAllowed(const PrefService* prefs) {
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 220416c..603874a 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
@@ -8,45 +8,33 @@
 
 #include <memory>
 
-#import "base/bind.h"
 #import "base/version.h"
 #import "components/pref_registry/pref_registry_syncable.h"
 #import "components/signin/public/base/signin_pref_names.h"
 #import "components/sync_preferences/pref_service_mock_factory.h"
 #import "components/sync_preferences/pref_service_syncable.h"
 #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#import "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/prefs/browser_prefs.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
 #import "ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_constants.h"
-#import "ios/chrome/test/block_cleanup_test.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-using base::Version;
-using sync_preferences::PrefServiceMockFactory;
-using sync_preferences::PrefServiceSyncable;
-using user_prefs::PrefRegistrySyncable;
-using web::WebTaskEnvironment;
-
 namespace {
 
-class SigninUtilsTest : public BlockCleanupTest {
+class SigninUtilsTest : public PlatformTest {
  public:
-  SigninUtilsTest() : version_("1.0") {
-    signin::SetCurrentVersionForTesting(&version_);
-  }
-
-  ~SigninUtilsTest() override { signin::SetCurrentVersionForTesting(nullptr); }
+  SigninUtilsTest() = default;
 
   void SetUp() override {
-    BlockCleanupTest::SetUp();
+    PlatformTest::SetUp();
     TestChromeBrowserState::Builder builder;
     builder.SetPrefService(CreatePrefService());
     builder.AddTestingFactory(
@@ -56,9 +44,6 @@
     chrome_browser_state_ = builder.Build();
     ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
         ->AddIdentities(@[ @"foo", @"bar" ]);
-    WebStateList* web_state_list = nullptr;
-    browser_ = std::make_unique<TestBrowser>(chrome_browser_state_.get(),
-                                             web_state_list);
   }
 
   void TearDown() override {
@@ -67,76 +52,73 @@
     [standardDefaults removeObjectForKey:kLastShownAccountGaiaIdVersionKey];
     [standardDefaults removeObjectForKey:kSigninPromoViewDisplayCountKey];
     [standardDefaults synchronize];
-    BlockCleanupTest::TearDown();
+    PlatformTest::TearDown();
   }
 
-  std::unique_ptr<PrefServiceSyncable> CreatePrefService() {
-    PrefServiceMockFactory factory;
-    scoped_refptr<PrefRegistrySyncable> registry(new PrefRegistrySyncable);
-    std::unique_ptr<PrefServiceSyncable> prefs =
+  std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService() {
+    sync_preferences::PrefServiceMockFactory factory;
+    scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
+        new user_prefs::PrefRegistrySyncable);
+    std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs =
         factory.CreateSyncable(registry.get());
     RegisterBrowserStatePrefs(registry.get());
     return prefs;
   }
 
  protected:
-  WebTaskEnvironment task_environment_;
+  web::WebTaskEnvironment task_environment_;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<Browser> browser_;
-  base::Version version_;
 };
 
 // Should show the sign-in upgrade for the first time.
 TEST_F(SigninUtilsTest, TestWillDisplay) {
-  EXPECT_TRUE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_1_0));
 }
 
 // Should not show the sign-in upgrade twice on the same version.
 TEST_F(SigninUtilsTest, TestWillNotDisplaySameVersion) {
-  signin::RecordVersionSeen();
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_1_0));
 }
 
 // Should not show the sign-in upgrade twice until two major version after.
 TEST_F(SigninUtilsTest, TestWillNotDisplayOneMinorVersion) {
-  signin::RecordVersionSeen();
-  // Set the future version to be one minor release ahead.
-  Version version_1_1("1.1");
-  signin::SetCurrentVersionForTesting(&version_1_1);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  const base::Version version_1_1("1.1");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_1_1));
 }
 
 // Should not show the sign-in upgrade twice until two major version after.
 TEST_F(SigninUtilsTest, TestWillNotDisplayTwoMinorVersions) {
-  signin::RecordVersionSeen();
-  // Set the future version to be two minor releases ahead.
-  Version version_1_2("1.2");
-  signin::SetCurrentVersionForTesting(&version_1_2);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  const base::Version version_1_2("1.2");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_1_2));
 }
 
 // Should not show the sign-in upgrade twice until two major version after.
 TEST_F(SigninUtilsTest, TestWillNotDisplayOneMajorVersion) {
-  signin::RecordVersionSeen();
-  // Set the future version to be one major release ahead.
-  Version version_2_0("2.0");
-  signin::SetCurrentVersionForTesting(&version_2_0);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  const base::Version version_2_0("2.0");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_2_0));
 }
 
 // Should show the sign-in upgrade a second time, 2 version after.
 TEST_F(SigninUtilsTest, TestWillDisplayTwoMajorVersions) {
-  signin::RecordVersionSeen();
-  // Set the future version to be two major releases ahead.
-  Version version_3_0("3.0");
-  signin::SetCurrentVersionForTesting(&version_3_0);
-  EXPECT_TRUE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  const base::Version version_1_0("1.0");
+  const base::Version version_3_0("3.0");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_3_0));
 }
 
 // Show the sign-in upgrade on version 1.0.
@@ -144,14 +126,13 @@
 // Move to version 5.0.
 // Expected: should not show the sign-in upgrade.
 TEST_F(SigninUtilsTest, TestWillShowTwoTimesOnly) {
-  signin::RecordVersionSeen();
-  Version version_3_0("3.0");
-  signin::SetCurrentVersionForTesting(&version_3_0);
-  signin::RecordVersionSeen();
-  Version version_5_0("5.0");
-  signin::SetCurrentVersionForTesting(&version_5_0);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  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(chrome_browser_state_->GetPrefs(), version_1_0);
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_3_0);
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_5_0));
 }
 
 // Show the sign-in upgrade on version 1.0.
@@ -160,16 +141,15 @@
 // Add new account.
 // Expected: should show the sign-in upgrade.
 TEST_F(SigninUtilsTest, TestWillShowForNewAccountAdded) {
-  signin::RecordVersionSeen();
-  Version version_3_0("3.0");
-  signin::SetCurrentVersionForTesting(&version_3_0);
-  signin::RecordVersionSeen();
-  Version version_5_0("5.0");
-  signin::SetCurrentVersionForTesting(&version_5_0);
+  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(chrome_browser_state_->GetPrefs(), version_1_0);
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_3_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
-  EXPECT_TRUE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_5_0));
 }
 
 // Add new account.
@@ -179,15 +159,14 @@
 // Remove previous account.
 // Expected: should not show the sign-in upgrade.
 TEST_F(SigninUtilsTest, TestWillNotShowWithAccountRemoved) {
+  const base::Version version_1_0("1.0");
+  const base::Version version_3_0("3.0");
+  const base::Version version_5_0("5.0");
   NSString* newAccountGaiaId = @"foo1";
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ newAccountGaiaId ]);
-  signin::RecordVersionSeen();
-  Version version_3_0("3.0");
-  signin::SetCurrentVersionForTesting(&version_3_0);
-  signin::RecordVersionSeen();
-  Version version_5_0("5.0");
-  signin::SetCurrentVersionForTesting(&version_5_0);
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_3_0);
   NSArray* allIdentities =
       ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
           ->GetAllIdentities(nullptr);
@@ -201,8 +180,8 @@
   ASSERT_NE(nil, foo1Identity);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->ForgetIdentity(foo1Identity, nil);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_5_0));
 }
 
 // Show the sign-in upgrade on version 1.0.
@@ -211,16 +190,15 @@
 // Add an account.
 // Expected: should not show the sign-in upgrade.
 TEST_F(SigninUtilsTest, TestWillNotShowNewAccountUntilTwoVersion) {
-  signin::RecordVersionSeen();
-  Version version_3_0("3.0");
-  signin::SetCurrentVersionForTesting(&version_3_0);
-  signin::RecordVersionSeen();
+  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(chrome_browser_state_->GetPrefs(), version_1_0);
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_3_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
-  Version version_4_0("4.0");
-  signin::SetCurrentVersionForTesting(&version_4_0);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_4_0));
 }
 
 // Show the sign-in upgrade on version 1.0.
@@ -229,23 +207,24 @@
 // Expected: should not show the sign-in upgrade (only display every 2
 // versions).
 TEST_F(SigninUtilsTest, TestWillNotShowNewAccountUntilTwoVersionBis) {
-  signin::RecordVersionSeen();
-  Version version_2_0("2.0");
-  signin::SetCurrentVersionForTesting(&version_2_0);
+  const base::Version version_1_0("1.0");
+  const base::Version version_2_0("2.0");
+  signin::RecordVersionSeen(chrome_browser_state_->GetPrefs(), version_1_0);
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_2_0));
 }
 
 // Should not show the sign-in upgrade if sign-in is disabled by policy.
 TEST_F(SigninUtilsTest, TestWillNotShowIfDisabledByPolicy) {
+  const base::Version version_1_0("1.0");
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo1" ]);
   chrome_browser_state_->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false);
 
-  EXPECT_FALSE(
-      signin::ShouldPresentUserSigninUpgrade(chrome_browser_state_.get()));
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
+      chrome_browser_state_.get(), version_1_0));
 }
 
 // signin::IsSigninAllowed should respect the kSigninAllowed pref.
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/BUILD.gn
index dc847f8..875713f 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/BUILD.gn
@@ -15,7 +15,9 @@
     "user_signin_logger.mm",
   ]
   deps = [
+    "//components/prefs",
     "//components/signin/public/base",
+    "//components/version_info",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/signin",
   ]
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/first_run_signin_logger.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/first_run_signin_logger.mm
index cf29a1b..2568de8 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/first_run_signin_logger.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/first_run_signin_logger.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/authentication/signin/user_signin/logging/first_run_signin_logger.h"
 
 #import "base/metrics/user_metrics.h"
+#include "components/version_info/version_info.h"
 #import "ios/chrome/browser/ui/authentication/signin/signin_utils.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,7 +34,8 @@
     LogSigninAccessPointStarted(self.accessPoint, self.promoAction);
     RecordSigninUserActionForAccessPoint(self.accessPoint, self.promoAction);
   }
-  signin::RecordVersionSeen();
+  if (self.prefService)
+    signin::RecordVersionSeen(self.prefService, version_info::GetVersion());
 }
 
 @end
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/upgrade_signin_logger.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/upgrade_signin_logger.mm
index b750ad3..4dc5d99 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/upgrade_signin_logger.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/upgrade_signin_logger.mm
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "components/signin/public/base/signin_metrics.h"
+#include "components/version_info/version_info.h"
 #import "ios/chrome/browser/ui/authentication/signin/signin_utils.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
@@ -49,11 +50,15 @@
 
 - (void)logSigninStarted {
   [super logSigninStarted];
+  if (!self.prefService) {
+    return;
+  }
+
   RecordSigninUserActionForAccessPoint(self.accessPoint, self.promoAction);
 
   // Records in user defaults that the promo has been shown as well as the
   // number of times it's been displayed.
-  signin::RecordVersionSeen();
+  signin::RecordVersionSeen(self.prefService, version_info::GetVersion());
   NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults];
   int promoSeenCount =
       [standardDefaults integerForKey:kDisplayedSSORecallPromoCountKey];
@@ -61,9 +66,10 @@
   [standardDefaults setInteger:promoSeenCount
                         forKey:kDisplayedSSORecallPromoCountKey];
 
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
+  NSArray* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(self.prefService);
   UMA_HISTOGRAM_COUNTS_100(kUMASSORecallAccountsAvailable, [identities count]);
   UMA_HISTOGRAM_COUNTS_100(kUMASSORecallPromoSeenCount, promoSeenCount);
 }
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.h b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.h
index face613..8a01332 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.h
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.h
@@ -5,6 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_USER_SIGNIN_LOGGING_USER_SIGNIN_LOGGER_H_
 #define IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_USER_SIGNIN_LOGGING_USER_SIGNIN_LOGGER_H_
 
+#include "components/prefs/pref_service.h"
 #import "components/signin/public/base/signin_metrics.h"
 #import "ios/chrome/browser/ui/authentication/signin/signin_constants.h"
 
@@ -12,8 +13,10 @@
 @interface UserSigninLogger : NSObject
 
 - (instancetype)init NS_UNAVAILABLE;
+// The designated initializer.
 - (instancetype)initWithAccessPoint:(signin_metrics::AccessPoint)accessPoint
                         promoAction:(signin_metrics::PromoAction)promoAction
+                        prefService:(PrefService*)prefService
     NS_DESIGNATED_INITIALIZER;
 
 // View where the sign-in button was displayed.
@@ -22,6 +25,12 @@
 // Promo button used to trigger the sign-in.
 @property(nonatomic, assign, readonly) signin_metrics::PromoAction promoAction;
 
+// Pref service to retrieve preference values.
+@property(nonatomic, assign) PrefService* prefService;
+
+// Disconnect this object.
+- (void)disconnect;
+
 // Logs sign-in started when the user consent screen is first displayed.
 - (void)logSigninStarted;
 
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.mm
index 459f84e..8df4ae2 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/logging/user_signin_logger.mm
@@ -22,15 +22,25 @@
 #pragma mark - Public
 
 - (instancetype)initWithAccessPoint:(AccessPoint)accessPoint
-                        promoAction:(PromoAction)promoAction {
+                        promoAction:(PromoAction)promoAction
+                        prefService:(PrefService*)prefService {
   self = [super init];
   if (self) {
     _accessPoint = accessPoint;
     _promoAction = promoAction;
+    _prefService = prefService;
   }
   return self;
 }
 
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
+- (void)disconnect {
+  self.prefService = nullptr;
+}
+
 - (void)logSigninStarted {
   LogSigninAccessPointStarted(self.accessPoint, self.promoAction);
 }
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
index 1ea3f93..6ce0937 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
@@ -178,6 +178,7 @@
   DCHECK(!self.addAccountSigninCoordinator);
   DCHECK(!self.advancedSettingsSigninCoordinator);
   [super stop];
+  [self.logger disconnect];
 }
 
 #pragma mark - UnifiedConsentCoordinatorDelegate
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index 6b0309b..bdf91134 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -415,9 +415,10 @@
     _accessPoint = accessPoint;
     _browserState = browserState;
     _presenter = presenter;
-    NSArray* identities = ios::GetChromeBrowserProvider()
-                              ->GetChromeIdentityService()
-                              ->GetAllIdentitiesSortedForDisplay();
+    NSArray* identities =
+        ios::GetChromeBrowserProvider()
+            ->GetChromeIdentityService()
+            ->GetAllIdentitiesSortedForDisplay(browserState->GetPrefs());
     if (identities.count != 0) {
       [self selectIdentity:identities[0]];
     }
@@ -619,9 +620,10 @@
 
 - (void)identityListChanged {
   ChromeIdentity* newIdentity = nil;
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
+  NSArray* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(self.browserState->GetPrefs());
   if (identities.count != 0) {
     newIdentity = identities[0];
   }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
index 473bef7..dca48bc 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
@@ -16,6 +16,7 @@
     ":unified_consent_ui",
     "//base",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/authentication/unified_consent/identity_chooser",
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn
index dd622ea..44016e23 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn
@@ -16,7 +16,10 @@
   deps = [
     ":identity_chooser_ui",
     "//base",
+    "//components/prefs",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/authentication/cells",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.mm
index 42532d2..77669de2 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.mm
@@ -8,6 +8,8 @@
 
 #include "base/check_op.h"
 #include "base/notreached.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_transition_delegate.h"
@@ -78,7 +80,9 @@
       UIModalPresentationCustom;
 
   // Creates the mediator.
-  self.identityChooserMediator = [[IdentityChooserMediator alloc] init];
+  self.identityChooserMediator = [[IdentityChooserMediator alloc]
+      initWithPrefService:self.browser->GetBrowserState()->GetPrefs()];
+
   self.identityChooserMediator.consumer = self.identityChooserViewController;
   // Setups.
   self.identityChooserViewController.presentationDelegate = self;
@@ -90,6 +94,12 @@
                  completion:nil];
 }
 
+- (void)stop {
+  [super stop];
+  [self.identityChooserMediator disconnect];
+  self.identityChooserMediator = nil;
+}
+
 #pragma mark - Setters/Getters
 
 - (void)setSelectedIdentity:(ChromeIdentity*)selectedIdentity {
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_unittest.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_unittest.mm
index 57f82dd..c1242e6 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_unittest.mm
@@ -83,6 +83,7 @@
       identityChooserViewController:presented_view_controller
         didSelectIdentityWithGaiaID:@"1"];
   EXPECT_NSEQ(identity, coordinator_.selectedIdentity);
+  [coordinator_ stop];
 }
 
 TEST_F(IdentityChooserCoordinatorTest, testIdentityInvalidatedDuringSelection) {
@@ -98,4 +99,5 @@
       identityChooserViewController:presented_view_controller
         didSelectIdentityWithGaiaID:@"1"];
   EXPECT_NSEQ(nil, coordinator_.selectedIdentity);
+  [coordinator_ stop];
 }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h
index 5b53a52..1abc0b970 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h
@@ -9,11 +9,18 @@
 
 @class ChromeIdentity;
 @protocol IdentityChooserConsumer;
+class PrefService;
 
 // A mediator object that monitors updates of chrome identities, and updates the
 // IdentityChooserViewController.
 @interface IdentityChooserMediator : NSObject
 
+// The designated initializer.
+- (instancetype)initWithPrefService:(PrefService*)prefService
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
 // Selected Chrome identity.
 @property(nonatomic, strong) ChromeIdentity* selectedIdentity;
 // View controller.
@@ -22,6 +29,9 @@
 // Starts this mediator.
 - (void)start;
 
+// Disconnect the mediator.
+- (void)disconnect;
+
 // Selects an identity with a Gaia ID.
 - (void)selectIdentityWithGaiaID:(NSString*)gaiaID;
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.mm
index e5ad9d63..aeee387 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_mediator.h"
 
 #include "base/strings/sys_string_conversions.h"
+#include "components/prefs/pref_service.h"
 #include "ios/chrome/browser/chrome_browser_provider_observer_bridge.h"
 #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_identity_item.h"
@@ -26,6 +27,9 @@
 @property(nonatomic, assign, readonly)
     ios::ChromeIdentityService* chromeIdentityService;
 
+// Pref service to retrieve preference values.
+@property(nonatomic, assign) PrefService* prefService;
+
 @end
 
 @implementation IdentityChooserMediator
@@ -33,6 +37,17 @@
 @synthesize consumer = _consumer;
 @synthesize selectedIdentity = _selectedIdentity;
 
+- (instancetype)initWithPrefService:(PrefService*)prefService {
+  if (self = [super init]) {
+    _prefService = prefService;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
 - (void)start {
   _identityServiceObserver =
       std::make_unique<ChromeIdentityServiceObserverBridge>(self);
@@ -41,6 +56,10 @@
   [self loadIdentitySection];
 }
 
+- (void)disconnect {
+  self.prefService = nullptr;
+}
+
 - (void)setSelectedIdentity:(ChromeIdentity*)selectedIdentity {
   if ([_selectedIdentity isEqual:selectedIdentity])
     return;
@@ -71,9 +90,14 @@
 // Creates the identity section with its header item, and all the identity items
 // based on the ChromeIdentity.
 - (void)loadIdentitySection {
+  if (!self.prefService) {
+    return;
+  }
+
   // Create all the identity items.
   NSArray<ChromeIdentity*>* identities =
-      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay();
+      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay(
+          self.prefService);
   NSMutableArray<TableViewIdentityItem*>* items = [NSMutableArray array];
   for (ChromeIdentity* identity in identities) {
     TableViewIdentityItem* item =
@@ -109,10 +133,15 @@
 #pragma mark - ChromeIdentityServiceObserver
 
 - (void)identityListChanged {
+  if (!self.prefService) {
+    return;
+  }
+
   [self loadIdentitySection];
   // Updates the selection.
   NSArray* allIdentities =
-      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay();
+      self.chromeIdentityService->GetAllIdentitiesSortedForDisplay(
+          self.prefService);
   if (![allIdentities containsObject:self.selectedIdentity]) {
     if (allIdentities.count) {
       self.selectedIdentity = allIdentities[0];
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
index d099fd4c..c0fb3f9 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
@@ -46,7 +46,7 @@
 
 @property(nonatomic, weak) id<UnifiedConsentCoordinatorDelegate> delegate;
 // Identity selected by the user to sign-in. By default, the first identity from
-// GetAllIdentitiesSortedForDisplay() is used.
+// |GetAllIdentitiesSortedForDisplay(PrefService) is used.
 // Must be non-nil if at least one identity exists.
 @property(nonatomic, strong) ChromeIdentity* selectedIdentity;
 // Informs the coordinator whether the identity picker should automatically be
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
index 2d8a7841..f58c22d 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -5,6 +5,7 @@
 #include "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h"
 
 #include "base/check_op.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_coordinator_delegate.h"
@@ -42,7 +43,9 @@
     _unifiedConsentViewController = [[UnifiedConsentViewController alloc] init];
     _unifiedConsentViewController.delegate = self;
     _unifiedConsentMediator = [[UnifiedConsentMediator alloc]
-        initWithUnifiedConsentViewController:_unifiedConsentViewController];
+        initWithUnifiedConsentViewController:_unifiedConsentViewController
+                                 prefService:browser->GetBrowserState()
+                                                 ->GetPrefs()];
     _unifiedConsentMediator.delegate = self;
   }
   return self;
@@ -52,6 +55,12 @@
   [self.unifiedConsentMediator start];
 }
 
+- (void)stop {
+  [self.identityChooserCoordinator stop];
+  [self.unifiedConsentMediator disconnect];
+  self.unifiedConsentMediator = nil;
+}
+
 - (void)scrollToBottom {
   [self.unifiedConsentViewController scrollToBottom];
 }
@@ -155,6 +164,7 @@
 - (void)identityChooserCoordinatorDidClose:
     (IdentityChooserCoordinator*)coordinator {
   CHECK_EQ(self.identityChooserCoordinator, coordinator);
+  [self.identityChooserCoordinator stop];
   self.identityChooserCoordinator.delegate = nil;
   self.identityChooserCoordinator = nil;
 }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.h b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.h
index 8db26d7d..d56466a6 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.h
@@ -8,6 +8,7 @@
 #import <Foundation/Foundation.h>
 
 @class ChromeIdentity;
+class PrefService;
 @class UnifiedConsentMediator;
 @class UnifiedConsentViewController;
 
@@ -27,20 +28,25 @@
 @interface UnifiedConsentMediator : NSObject
 
 // Identity selected by the user to sign-in. By default, the first identity from
-// GetAllIdentitiesSortedForDisplay() is used. If there is no identity in the
-// list, the identity picker will be hidden. Nil is not accepted if at least one
-// identity exists.
+// |GetAllIdentitiesSortedForDisplay(PrefService) is used. If there is no
+// identity in the list, the identity picker will be hidden. Nil is not accepted
+// if at least one identity exists.
 @property(nonatomic, strong) ChromeIdentity* selectedIdentity;
 // Instance delegate.
 @property(nonatomic, weak) id<UnifiedConsentMediatorDelegate> delegate;
 
 - (instancetype)initWithUnifiedConsentViewController:
-    (UnifiedConsentViewController*)viewController NS_DESIGNATED_INITIALIZER;
+                    (UnifiedConsentViewController*)viewController
+                                         prefService:(PrefService*)prefService
+    NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
 // Starts this mediator.
 - (void)start;
 
+// Disconnect the mediator.
+- (void)disconnect;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_UNIFIED_CONSENT_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.mm
index aeaa11a4..99b435c9 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_mediator.mm
@@ -27,6 +27,8 @@
 @property(nonatomic, strong) UIImage* selectedIdentityAvatar;
 // NO until the mediator is started.
 @property(nonatomic, assign) BOOL started;
+// Pref service to retrieve preference values.
+@property(nonatomic, assign) PrefService* prefService;
 
 @end
 
@@ -38,9 +40,11 @@
 @synthesize started = _started;
 
 - (instancetype)initWithUnifiedConsentViewController:
-    (UnifiedConsentViewController*)viewController {
+                    (UnifiedConsentViewController*)viewController
+                                         prefService:(PrefService*)prefService {
   self = [super init];
   if (self) {
+    _prefService = prefService;
     _unifiedConsentViewController = viewController;
     _identityServiceObserver =
         std::make_unique<ChromeIdentityServiceObserverBridge>(self);
@@ -50,6 +54,32 @@
   return self;
 }
 
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
+- (void)start {
+  DCHECK(self.prefService);
+
+  NSArray* identities =
+      ios::GetChromeBrowserProvider()
+          ->GetChromeIdentityService()
+          ->GetAllIdentitiesSortedForDisplay(self.prefService);
+  if (identities.count != 0) {
+    self.selectedIdentity = identities[0];
+  }
+  // Make sure the view is loaded so the mediator can set it up.
+  [self.unifiedConsentViewController loadViewIfNeeded];
+  self.started = YES;
+  [self updateViewController];
+}
+
+- (void)disconnect {
+  self.prefService = nullptr;
+}
+
+#pragma mark - Properties
+
 - (void)setSelectedIdentity:(ChromeIdentity*)selectedIdentity {
   if ([self.selectedIdentity isEqual:selectedIdentity]) {
     return;
@@ -63,19 +93,6 @@
   [self updateViewController];
 }
 
-- (void)start {
-  NSArray* identities = ios::GetChromeBrowserProvider()
-                            ->GetChromeIdentityService()
-                            ->GetAllIdentitiesSortedForDisplay();
-  if (identities.count != 0) {
-    self.selectedIdentity = identities[0];
-  }
-  // Make sure the view is loaded so the mediator can set it up.
-  [self.unifiedConsentViewController loadViewIfNeeded];
-  self.started = YES;
-  [self updateViewController];
-}
-
 #pragma mark - Private
 
 // Updates the view if the mediator has been started.
@@ -128,12 +145,17 @@
 #pragma mark - ChromeIdentityServiceObserver
 
 - (void)identityListChanged {
+  if (!self.prefService) {
+    return;
+  }
+
   if (!self.selectedIdentity || !ios::GetChromeBrowserProvider()
                                      ->GetChromeIdentityService()
                                      ->IsValidIdentity(self.selectedIdentity)) {
-    NSArray* identities = ios::GetChromeBrowserProvider()
-                              ->GetChromeIdentityService()
-                              ->GetAllIdentitiesSortedForDisplay();
+    NSArray* identities =
+        ios::GetChromeBrowserProvider()
+            ->GetChromeIdentityService()
+            ->GetAllIdentitiesSortedForDisplay(self.prefService);
     ChromeIdentity* newIdentity = nil;
     if (identities.count != 0) {
       newIdentity = identities[0];
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
index 6c1d880b..228c8a8 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -332,7 +332,9 @@
     // TODO(crbug.com/1167062): Respect SaveAddressProfilePromptOptions.
     auto delegate =
         std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>(
-            profile, original_profile, std::move(callback));
+            profile, original_profile,
+            GetApplicationContext()->GetApplicationLocale(),
+            std::move(callback));
     infobar_manager_->AddInfoBar(std::make_unique<InfoBarIOS>(
         InfobarType::kInfobarTypeSaveAutofillAddressProfile,
         std::move(delegate)));
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 1ac7c92..7d164c2 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -4684,11 +4684,6 @@
     [iterator->second stop];
     _ntpCoordinatorsForWebStates.erase(iterator);
   }
-
-  // Ignore changes while the tab grid is visible (or while suspended).
-  // The display will be refreshed when this view becomes active again.
-  if (!self.visible || !self.webUsageEnabled)
-    return;
 }
 
 - (void)webStateList:(WebStateList*)webStateList
diff --git a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
index b2b4ea5..a18a5117 100644
--- a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
@@ -10,14 +10,11 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// Screen array.
-FirstRunScreenType screens[] = {};
-}
-
 @interface FirstRunScreenProvider ()
 
-@property(nonatomic) int index;
+@property(nonatomic, assign) NSInteger index;
+
+@property(nonatomic, strong) NSArray* screens;
 
 @end
 
@@ -26,26 +23,28 @@
 - (instancetype)init {
   self = [super init];
   if (self) {
-    SetupScreens();
+    [self setupScreens];
     _index = -1;
   }
   return self;
 }
 
 - (FirstRunScreenType)nextScreenType {
-  DCHECK(screens);
-  DCHECK(self.index == -1 || screens[self.index] != kFirstRunCompleted);
-  return screens[++self.index];
+  DCHECK(self.screens);
+  DCHECK(self.index == -1 ||
+         ![self.screens[self.index] isEqual:@(kFirstRunCompleted)]);
+  return static_cast<FirstRunScreenType>(
+      [self.screens[++self.index] integerValue]);
 }
 
 #pragma mark - Private
-void SetupScreens() {
+
+// Sets the screens up.
+- (void)setupScreens {
   // TODO(crbug.com/1195198): Add logic to generate a custimizeed screen
   // order.
-  screens[0] = kWelcomeAndConsent;
-  screens[1] = kSignIn;
-  screens[2] = kSync;
-  screens[3] = kFirstRunCompleted;
+  _screens =
+      @[ @(kWelcomeAndConsent), @(kSignIn), @(kSync), @(kFirstRunCompleted) ];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/first_run/signin/BUILD.gn b/ios/chrome/browser/ui/first_run/signin/BUILD.gn
index 145eb124..2a07c64 100644
--- a/ios/chrome/browser/ui/first_run/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/signin/BUILD.gn
@@ -58,6 +58,7 @@
     ":signin_ui",
     "//base",
     "//base/test:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/main:test_support",
     "//ios/chrome/browser/ui/authentication",
     "//ios/public/provider/chrome/browser:test_support",
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm
index 6a5971c..86d1fd4 100644
--- a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm
+++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm
@@ -82,7 +82,8 @@
                                     ->HasIdentities();
   self.viewController = [[SigninScreenViewController alloc] init];
   self.viewController.delegate = self;
-  self.mediator = [[SigninScreenMediator alloc] init];
+  self.mediator = [[SigninScreenMediator alloc]
+      initWithPrefService:self.browser->GetBrowserState()->GetPrefs()];
   NSArray* identities = ios::GetChromeBrowserProvider()
                             ->GetChromeIdentityService()
                             ->GetAllIdentitiesSortedForDisplay(
@@ -102,6 +103,7 @@
 - (void)stop {
   self.delegate = nil;
   self.viewController = nil;
+  [self.mediator disconnect];
   self.mediator = nil;
   [self.identityChooserCoordinator stop];
   self.identityChooserCoordinator = nil;
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.h b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.h
index 5c60e8f..16e38c0 100644
--- a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.h
+++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.h
@@ -9,13 +9,18 @@
 
 @class AuthenticationFlow;
 @class ChromeIdentity;
+class PrefService;
 @protocol SigninScreenConsumer;
 @protocol SigninScreenMediatorDelegate;
 
 // Mediator that handles the sign-in operation.
 @interface SigninScreenMediator : NSObject
 
-- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// The designated initializer.
+- (instancetype)initWithPrefService:(PrefService*)prefService
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
 
 // Consumer for this mediator.
 @property(nonatomic, weak) id<SigninScreenConsumer> consumer;
@@ -29,6 +34,9 @@
 // Whether an account has been added. Must be set externally.
 @property(nonatomic, assign) BOOL addedAccount;
 
+// Disconnect the mediator.
+- (void)disconnect;
+
 // Starts the sign in process, using |authenticationFlow|.
 - (void)startSignInWithAuthenticationFlow:
     (AuthenticationFlow*)authenticationFlow;
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm
index b470e410..8b8c08d 100644
--- a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm
+++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator.mm
@@ -30,16 +30,17 @@
 @property(nonatomic, strong) AuthenticationFlow* authenticationFlow;
 // Logger used to record sign in metrics.
 @property(nonatomic, strong) UserSigninLogger* logger;
+// Pref service to retrieve preference values.
+@property(nonatomic, assign) PrefService* prefService;
 
 @end
 
 @implementation SigninScreenMediator
 
-#pragma mark - Public
-
-- (instancetype)init {
+- (instancetype)initWithPrefService:(PrefService*)prefService {
   self = [super init];
   if (self) {
+    _prefService = prefService;
     _browserProviderObserver =
         std::make_unique<ChromeBrowserProviderObserverBridge>(self);
     _identityServiceObserver =
@@ -48,11 +49,21 @@
     _logger = [[FirstRunSigninLogger alloc]
         initWithAccessPoint:signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE
                 promoAction:signin_metrics::PromoAction::
-                                PROMO_ACTION_NO_SIGNIN_PROMO];
+                                PROMO_ACTION_NO_SIGNIN_PROMO
+                prefService:prefService];
   }
   return self;
 }
 
+- (void)dealloc {
+  DCHECK(!self.prefService);
+}
+
+- (void)disconnect {
+  [self.logger disconnect];
+  self.prefService = nullptr;
+}
+
 - (void)startSignInWithAuthenticationFlow:
     (AuthenticationFlow*)authenticationFlow {
   DCHECK(!self.authenticationFlow);
@@ -105,10 +116,15 @@
 #pragma mark - ChromeIdentityServiceObserver
 
 - (void)identityListChanged {
+  if (!self.prefService) {
+    return;
+  }
+
   if (!self.selectedIdentity ||
       !self.identityService->IsValidIdentity(self.selectedIdentity)) {
     NSArray* identities =
-        self.identityService->GetAllIdentitiesSortedForDisplay();
+        self.identityService->GetAllIdentitiesSortedForDisplay(
+            self.prefService);
     ChromeIdentity* newIdentity = nil;
     if (identities.count != 0) {
       newIdentity = identities[0];
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator_unittest.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator_unittest.mm
index 3ee6e81..6d5c833 100644
--- a/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_mediator_unittest.mm
@@ -6,6 +6,7 @@
 
 #import "base/test/ios/wait_util.h"
 #import "base/test/task_environment.h"
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/ui/authentication/authentication_flow.h"
 #import "ios/chrome/browser/ui/first_run/signin/signin_screen_consumer.h"
@@ -56,10 +57,13 @@
 class SigninScreenMediatorTest : public PlatformTest {
  protected:
   void SetUp() override {
+    PlatformTest::SetUp();
     browser_provider_ = ios::TestChromeBrowserProvider::GetTestProvider();
     identity_service_ =
         ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-    mediator_ = [[SigninScreenMediator alloc] init];
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+    mediator_ = [[SigninScreenMediator alloc]
+        initWithPrefService:browser_state_->GetPrefs()];
     consumer_ = [[FakeSigninScreenConsumer alloc] init];
     identity_ = [FakeChromeIdentity identityWithEmail:@"test@email.com"
                                                gaiaID:@"gaiaID"
@@ -67,6 +71,9 @@
   }
 
   void TearDown() override {
+    PlatformTest::TearDown();
+    [mediator_ disconnect];
+    browser_state_.reset();
     identity_service_->WaitForServiceCallbacksToComplete();
   }
 
@@ -83,6 +90,7 @@
   base::test::TaskEnvironment task_enviroment_;
   SigninScreenMediator* mediator_;
   ios::TestChromeBrowserProvider* browser_provider_;
+  std::unique_ptr<ChromeBrowserState> browser_state_;
   ios::FakeChromeIdentityService* identity_service_;
   FakeSigninScreenConsumer* consumer_;
   FakeChromeIdentity* identity_;
diff --git a/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm
index e5fabbc6..87f1a82 100644
--- a/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm
+++ b/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm
@@ -50,15 +50,14 @@
 }
 
 - (void)start {
-  // TODO(crbug.com/1189840): Check if sync screen need to be shown.
-  // if not:
-  // [self.delegate willFinishPresenting]
-  // if yes:
-  // DCHECK if an user identity is existed.
   ChromeBrowserState* browserState = self.browser->GetBrowserState();
   AuthenticationService* authenticationService =
       AuthenticationServiceFactory::GetForBrowserState(browserState);
-  DCHECK(authenticationService->GetAuthenticatedIdentity());
+
+  if (!authenticationService->GetAuthenticatedIdentity()) {
+    // Don't show sync screen if no logged-in user account.
+    return [self.delegate willFinishPresenting];
+  }
 
   self.viewController = [[SyncScreenViewController alloc] init];
   self.viewController.delegate = self;
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_consumer.h b/ios/chrome/browser/ui/infobars/banners/infobar_banner_consumer.h
index 8056306..657792a 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_consumer.h
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_consumer.h
@@ -33,6 +33,10 @@
 // The subtitle displayed by this InfobarBanner.
 - (void)setSubtitleText:(NSString*)subtitleText;
 
+// If YES, restricts the number of lines in subtitle to 1.
+- (void)setRestrictSubtitleTextToSingleLine:
+    (BOOL)restrictSubtitleTextToSingleLine;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_BANNERS_INFOBAR_BANNER_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
index 9b73c67..cc6da79 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -66,6 +66,7 @@
 @property(nonatomic, copy) NSString* titleText;
 @property(nonatomic, copy) NSString* subtitleText;
 @property(nonatomic, assign) BOOL useIconBackgroundTint;
+@property(nonatomic, assign) BOOL restrictSubtitleTextToSingleLine;
 
 // The original position of this InfobarVC view in the parent's view coordinate
 // system.
@@ -113,6 +114,7 @@
         [[InfobarMetricsRecorder alloc] initWithType:infobarType];
     _presentsModal = presentsModal;
     _useIconBackgroundTint = YES;
+    _restrictSubtitleTextToSingleLine = NO;
   }
   return self;
 }
@@ -205,7 +207,11 @@
       [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
   self.subTitleLabel.adjustsFontForContentSizeCategory = YES;
   self.subTitleLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
-  self.subTitleLabel.numberOfLines = 0;
+  if (_restrictSubtitleTextToSingleLine) {
+    self.subTitleLabel.numberOfLines = 1;
+  } else {
+    self.subTitleLabel.numberOfLines = 0;
+  }
   // If |self.subTitleText| hasn't been set or is empty, hide the label to keep
   // the title label centered in the Y axis.
   self.subTitleLabel.hidden = !self.subtitleText.length;
@@ -437,6 +443,11 @@
   _useIconBackgroundTint = useIconBackgroundTint;
 }
 
+- (void)setRestrictSubtitleTextToSingleLine:
+    (BOOL)restrictSubtitleTextToSingleLine {
+  _restrictSubtitleTextToSingleLine = restrictSubtitleTextToSingleLine;
+}
+
 #pragma mark - Private Methods
 
 - (void)bannerInfobarButtonWasPressed:(UIButton*)sender {
diff --git a/ios/chrome/browser/ui/infobars/banners/test/fake_infobar_banner_consumer.h b/ios/chrome/browser/ui/infobars/banners/test/fake_infobar_banner_consumer.h
index 05d4c1ac..39ddfa0b 100644
--- a/ios/chrome/browser/ui/infobars/banners/test/fake_infobar_banner_consumer.h
+++ b/ios/chrome/browser/ui/infobars/banners/test/fake_infobar_banner_consumer.h
@@ -17,6 +17,7 @@
 @property(nonatomic, copy) NSString* titleText;
 @property(nonatomic, copy) NSString* subtitleText;
 @property(nonatomic, assign) BOOL useIconBackgroundTint;
+@property(nonatomic, assign) BOOL restrictSubtitleTextToSingleLine;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_BANNERS_TEST_FAKE_INFOBAR_BANNER_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index 0538d60..4297627 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -108,6 +108,7 @@
     "//components/previous_session_info",
     "//components/signin/public/identity_manager",
     "//components/url_formatter",
+    "//components/version_info",
     "//components/web_resource",
     "//ios/chrome/app:app",
     "//ios/chrome/app:blocking_scene_commands",
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 2be2153..01ac1db 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -25,6 +25,7 @@
 #include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/url_formatter/url_formatter.h"
+#include "components/version_info/version_info.h"
 #include "components/web_resource/web_resource_pref_names.h"
 #import "ios/chrome/app/application_delegate/app_state.h"
 #import "ios/chrome/app/application_delegate/startup_information.h"
@@ -1246,8 +1247,10 @@
 // Returns YES if the promo is shown.
 - (BOOL)presentSigninUpgradePromoIfPossible {
   if (!signin::ShouldPresentUserSigninUpgrade(
-          self.sceneState.appState.mainBrowserState))
+          self.sceneState.appState.mainBrowserState,
+          version_info::GetVersion())) {
     return NO;
+  }
   // Don't show promos if first run is shown in any scene.  (Note:  This flag
   // is only YES while the first run UI is visible.  However, as this function
   // is called immediately after the UI is shown, it's a safe check.)
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm
index 9c79a3c..edebec5 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm
@@ -55,8 +55,9 @@
       setButtonText:base::SysUTF16ToNSString(self.config->button_label_text())];
   [self.consumer
       setTitleText:base::SysUTF16ToNSString(self.config->message_text())];
-  [self.consumer setSubtitleText:base::SysUTF16ToNSString(
-                                     self.config->message_sub_text())];
+  [self.consumer
+      setSubtitleText:base::SysUTF16ToNSString(self.config->description())];
+  [self.consumer setRestrictSubtitleTextToSingleLine:YES];
 
   if (!self.config->is_update_banner()) {
     // TODO(crbug.com/1167062): Implement update address modal.
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm
index 98a4bcf5..39989d1 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm
@@ -37,7 +37,7 @@
   std::unique_ptr<autofill::AutofillSaveUpdateAddressProfileDelegateIOS>
       passed_delegate = std::make_unique<
           autofill::AutofillSaveUpdateAddressProfileDelegateIOS>(
-          profile, /*original_profile=*/nullptr,
+          profile, /*original_profile=*/nullptr, /*locale=*/"en-US",
           base::BindOnce(
               ^(autofill::AutofillClient::SaveAddressProfileOfferUserDecision
                     user_decision,
@@ -64,6 +64,6 @@
               consumer.titleText);
   EXPECT_NSEQ(base::SysUTF16ToNSString(delegate->GetMessageActionText()),
               consumer.buttonText);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(delegate->GetMessageDescriptionText()),
+  EXPECT_NSEQ(base::SysUTF16ToNSString(delegate->GetDescription()),
               consumer.subtitleText);
 }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index e89e8cf9..b69aed8d7 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-35d7ae19040e80213bb06980fc3eedce4c9d0bce
\ No newline at end of file
+2ada7fe086f904100a88e696cffeb45bab79ec3b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index b14017ed6..c9433e0 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-59ca4ceb38baff1c9e2eeeb502556b641aba3f38
\ No newline at end of file
+eae9a2a50ade8cfb80950bc8d1f88ad8af93f94f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index eb4921e1..3f9526b 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-01aa7452836219f25c06154691cfa80c5be4eb29
\ No newline at end of file
+a64ce99c50e024731b8107b1d786ec86d5a40d1e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index bd897c7..6474952 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-444aca6a525e0c7d9819294fece138b14968d378
\ No newline at end of file
+ffbcb955b784f2d1299c028cc154e115adc00be0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index d4b75f00..02dcd76 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-92538aa587ca462479e95d44fef04387d29cb7ab
\ No newline at end of file
+d263236002e5cd16fda82c1327959e3f665ff3f5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index c2d44cc..396a8bd4 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-5893af5486cdc1d6ab608d5e05b05799e60b8be5
\ No newline at end of file
+a4bf70260afcb4623561b2d6d8b27153e6f6de15
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index d08c962..d79414e 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-d45355c9f46f8f579890e0f1b2bd4418b92dfd58
\ No newline at end of file
+c4efdff2a5f772d3a550df270607b3b2bc88d2b3
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index b3ab907..6484e87 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-28619a92d294036dbd5f57f63542c8e1637095f9
\ No newline at end of file
+0ae95d57ef1f8352cca72a5e86de0a9ab28ded05
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index a7378f38..383232b 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-f7e79edf5b139e3e8e0f1ed00279b9b1c9475239
\ No newline at end of file
+6a7d557416f5f60616b6e02a885a44f47ba94fb5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index d9e42da..718cd44 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-398b440d6bf365bd5ffd0853c978a75480d7315b
\ No newline at end of file
+b796c0a4c9efd6b3b6603a496eba16d612676382
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/discover_feed/discover_feed_configuration.h b/ios/public/provider/chrome/browser/discover_feed/discover_feed_configuration.h
index 0f54ab4..9c5f24f2 100644
--- a/ios/public/provider/chrome/browser/discover_feed/discover_feed_configuration.h
+++ b/ios/public/provider/chrome/browser/discover_feed/discover_feed_configuration.h
@@ -8,16 +8,12 @@
 #import <Foundation/Foundation.h>
 
 class AuthenticationService;
-class ChromeBrowserState;
 @class DiscoverFeedMetricsRecorder;
 class PrefService;
 
 // Configuration object used by the DiscoverFeedProvider.
 @interface DiscoverFeedConfiguration : NSObject
 
-// BrowserState used by DiscoverFeedProvider. DEPRECATED.
-@property(nonatomic, assign) ChromeBrowserState* browserState;
-
 // AuthenticationService used by DiscoverFeedProvider.
 @property(nonatomic, assign) AuthenticationService* authService;
 
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
index 52691bb..7ea8b0d4 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -175,12 +175,6 @@
 
   // Returns all ChromeIdentity objects sorted by the ordering used in the
   // account manager, which is typically based on the keychain ordering of
-  // accounts.
-  // Deprecated. See GetAllIdentitiesSortedForDisplay(prefService).
-  virtual NSArray* GetAllIdentitiesSortedForDisplay();
-
-  // Returns all ChromeIdentity objects sorted by the ordering used in the
-  // account manager, which is typically based on the keychain ordering of
   // accounts.It uses PrefService to filter ChromeIdentities according to
   // enterprise policies.
   virtual NSArray* GetAllIdentitiesSortedForDisplay(PrefService* pref_service);
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index 193c21c..c44ccd81 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -81,10 +81,6 @@
   return nil;
 }
 
-NSArray* ChromeIdentityService::GetAllIdentitiesSortedForDisplay() {
-  return GetAllIdentitiesSortedForDisplay(nullptr);
-}
-
 NSArray* ChromeIdentityService::GetAllIdentitiesSortedForDisplay(
     PrefService* pref_service) {
   return nil;
diff --git a/ios/web/favicon/favicon_util.mm b/ios/web/favicon/favicon_util.mm
index 0cae02e0..7bcb35c9 100644
--- a/ios/web/favicon/favicon_util.mm
+++ b/ios/web/favicon/favicon_util.mm
@@ -23,7 +23,7 @@
                        const GURL& page_origin,
                        std::vector<web::FaviconURL>* urls) {
   BOOL has_favicon = NO;
-  for (const base::Value& favicon : *favicons) {
+  for (const base::Value& favicon : favicons->GetList()) {
     if (!favicon.is_dict())
       return false;
 
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc
index cf23b2a..18f4af4 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.cc
+++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -247,8 +247,15 @@
     SetCaptureIntentCallback callback) {
   DCHECK(mojo_task_runner_->BelongsToCurrentThread());
 
-  base::AutoLock lock(capture_intent_lock_);
-  capture_intent_ = capture_intent;
+  {
+    base::AutoLock lock(capture_intent_lock_);
+    capture_intent_ = capture_intent;
+  }
+  // Reset fps range for VCD to determine it if not explicitly set by app.
+  {
+    base::AutoLock lock(fps_ranges_lock_);
+    specified_fps_range_ = {};
+  }
   std::move(callback).Run();
 }
 
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 2f8bf06..23f25f2 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -307,8 +307,11 @@
   device_context_ = device_context;
   device_context_->SetState(CameraDeviceContext::State::kStarting);
 
-  if (camera_app_device_) {
-    camera_app_device_->SetCameraDeviceContext(device_context_);
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_descriptor_.device_id);
+  if (camera_app_device) {
+    camera_app_device->SetCameraDeviceContext(device_context_);
   }
 
   auto camera_info = camera_hal_delegate_->GetCameraInfoFromDeviceId(
@@ -370,8 +373,11 @@
   // CameraDeviceContext::State::kStopping.
   DCHECK_NE(device_context_->GetState(), CameraDeviceContext::State::kStopping);
 
-  if (camera_app_device_) {
-    camera_app_device_->SetCameraDeviceContext(nullptr);
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_descriptor_.device_id);
+  if (camera_app_device) {
+    camera_app_device->SetCameraDeviceContext(nullptr);
   }
 
   device_close_callback_ = std::move(device_close_callback);
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h
index e774718f..e798baa 100644
--- a/media/capture/video/chromeos/camera_device_delegate.h
+++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -26,7 +26,6 @@
 namespace media {
 
 class Camera3AController;
-class CameraAppDeviceImpl;
 class CameraHalDelegate;
 class RequestManager;
 
@@ -270,8 +269,6 @@
 
   std::queue<base::OnceClosure> on_reconfigured_callbacks_;
 
-  base::WeakPtr<CameraAppDeviceImpl> camera_app_device_;
-
   uint32_t device_api_version_;
 
   // States of SetPhotoOptions
diff --git a/remoting/base/chromoting_event.cc b/remoting/base/chromoting_event.cc
index 6d162ae..98caa0e 100644
--- a/remoting/base/chromoting_event.cc
+++ b/remoting/base/chromoting_event.cc
@@ -224,129 +224,129 @@
 // everything in a DictionaryValue that needs to be converted.
 apis::v1::ChromotingEvent ChromotingEvent::CreateProto() const {
   apis::v1::ChromotingEvent event_proto;
-  if (values_map_->HasKey(kAuthMethodKey)) {
+  if (values_map_->FindKey(kAuthMethodKey)) {
     event_proto.set_auth_method(
         static_cast<apis::v1::ChromotingEvent_AuthMethod>(
             values_map_->FindKey(kAuthMethodKey)->GetInt()));
   }
-  if (values_map_->HasKey(kCaptureLatencyKey)) {
+  if (values_map_->FindKey(kCaptureLatencyKey)) {
     event_proto.set_capture_latency(
         values_map_->FindKey(kCaptureLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kConnectionErrorKey)) {
+  if (values_map_->FindKey(kConnectionErrorKey)) {
     event_proto.set_connection_error(
         static_cast<apis::v1::ChromotingEvent_ConnectionError>(
             values_map_->FindKey(kConnectionErrorKey)->GetInt()));
   }
-  if (values_map_->HasKey(kConnectionTypeKey)) {
+  if (values_map_->FindKey(kConnectionTypeKey)) {
     event_proto.set_connection_type(
         static_cast<apis::v1::ChromotingEvent_ConnectionType>(
             values_map_->FindKey(kConnectionTypeKey)->GetInt()));
   }
-  if (values_map_->HasKey(kCpuKey)) {
+  if (values_map_->FindKey(kCpuKey)) {
     event_proto.set_cpu(values_map_->FindKey(kCpuKey)->GetString());
   }
-  if (values_map_->HasKey(kDecodeLatencyKey)) {
+  if (values_map_->FindKey(kDecodeLatencyKey)) {
     event_proto.set_decode_latency(
         values_map_->FindKey(kDecodeLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kEncodeLatencyKey)) {
+  if (values_map_->FindKey(kEncodeLatencyKey)) {
     event_proto.set_encode_latency(
         values_map_->FindKey(kEncodeLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kHostOsKey)) {
+  if (values_map_->FindKey(kHostOsKey)) {
     event_proto.set_host_os(static_cast<apis::v1::ChromotingEvent_Os>(
         values_map_->FindKey(kHostOsKey)->GetInt()));
   }
-  if (values_map_->HasKey(kHostOsVersionKey)) {
+  if (values_map_->FindKey(kHostOsVersionKey)) {
     event_proto.set_host_os_version(
         values_map_->FindKey(kHostOsVersionKey)->GetString());
   }
-  if (values_map_->HasKey(kHostVersionKey)) {
+  if (values_map_->FindKey(kHostVersionKey)) {
     event_proto.set_host_version(
         values_map_->FindKey(kHostVersionKey)->GetString());
   }
-  if (values_map_->HasKey(kMaxCaptureLatencyKey)) {
+  if (values_map_->FindKey(kMaxCaptureLatencyKey)) {
     event_proto.set_max_capture_latency(
         values_map_->FindKey(kMaxCaptureLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kMaxDecodeLatencyKey)) {
+  if (values_map_->FindKey(kMaxDecodeLatencyKey)) {
     event_proto.set_max_decode_latency(
         values_map_->FindKey(kMaxDecodeLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kMaxEncodeLatencyKey)) {
+  if (values_map_->FindKey(kMaxEncodeLatencyKey)) {
     event_proto.set_max_encode_latency(
         values_map_->FindKey(kMaxEncodeLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kMaxRenderLatencyKey)) {
+  if (values_map_->FindKey(kMaxRenderLatencyKey)) {
     event_proto.set_max_render_latency(
         values_map_->FindKey(kMaxRenderLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kMaxRoundtripLatencyKey)) {
+  if (values_map_->FindKey(kMaxRoundtripLatencyKey)) {
     event_proto.set_max_roundtrip_latency(
         values_map_->FindKey(kMaxRoundtripLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kModeKey)) {
+  if (values_map_->FindKey(kModeKey)) {
     event_proto.set_mode(static_cast<apis::v1::ChromotingEvent_Mode>(
         values_map_->FindKey(kModeKey)->GetInt()));
   }
-  if (values_map_->HasKey(kOsKey)) {
+  if (values_map_->FindKey(kOsKey)) {
     event_proto.set_os(static_cast<apis::v1::ChromotingEvent_Os>(
         values_map_->FindKey(kOsKey)->GetInt()));
   }
-  if (values_map_->HasKey(kOsVersionKey)) {
+  if (values_map_->FindKey(kOsVersionKey)) {
     event_proto.set_os_version(
         values_map_->FindKey(kOsVersionKey)->GetString());
   }
-  if (values_map_->HasKey(kPreviousSessionStateKey)) {
+  if (values_map_->FindKey(kPreviousSessionStateKey)) {
     event_proto.set_previous_session_state(
         static_cast<apis::v1::ChromotingEvent_SessionState>(
             values_map_->FindKey(kPreviousSessionStateKey)->GetInt()));
   }
-  if (values_map_->HasKey(kRenderLatencyKey)) {
+  if (values_map_->FindKey(kRenderLatencyKey)) {
     event_proto.set_render_latency(
         values_map_->FindKey(kRenderLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kRoleKey)) {
+  if (values_map_->FindKey(kRoleKey)) {
     event_proto.set_role(static_cast<apis::v1::ChromotingEvent_Role>(
         values_map_->FindKey(kRoleKey)->GetInt()));
   }
-  if (values_map_->HasKey(kRoundtripLatencyKey)) {
+  if (values_map_->FindKey(kRoundtripLatencyKey)) {
     event_proto.set_roundtrip_latency(
         values_map_->FindKey(kRoundtripLatencyKey)->GetDouble());
   }
-  if (values_map_->HasKey(kSessionDurationKey)) {
+  if (values_map_->FindKey(kSessionDurationKey)) {
     event_proto.set_session_duration(
         values_map_->FindKey(kSessionDurationKey)->GetDouble());
   }
-  if (values_map_->HasKey(kSessionEntryPointKey)) {
+  if (values_map_->FindKey(kSessionEntryPointKey)) {
     event_proto.set_session_entry_point(
         static_cast<apis::v1::ChromotingEvent_SessionEntryPoint>(
             values_map_->FindKey(kSessionEntryPointKey)->GetInt()));
   }
-  if (values_map_->HasKey(kSessionIdKey)) {
+  if (values_map_->FindKey(kSessionIdKey)) {
     event_proto.set_session_id(
         values_map_->FindKey(kSessionIdKey)->GetString());
   }
-  if (values_map_->HasKey(kSessionStateKey)) {
+  if (values_map_->FindKey(kSessionStateKey)) {
     event_proto.set_session_state(
         static_cast<apis::v1::ChromotingEvent_SessionState>(
             values_map_->FindKey(kSessionStateKey)->GetInt()));
   }
-  if (values_map_->HasKey(kSignalStrategyTypeKey)) {
+  if (values_map_->FindKey(kSignalStrategyTypeKey)) {
     event_proto.set_signal_strategy_type(
         static_cast<apis::v1::ChromotingEvent_SignalStrategyType>(
             values_map_->FindKey(kSignalStrategyTypeKey)->GetInt()));
   }
-  if (values_map_->HasKey(kTypeKey)) {
+  if (values_map_->FindKey(kTypeKey)) {
     event_proto.set_type(static_cast<apis::v1::ChromotingEvent_Type>(
         values_map_->FindKey(kTypeKey)->GetInt()));
   }
-  if (values_map_->HasKey(kVideoBandwidthKey)) {
+  if (values_map_->FindKey(kVideoBandwidthKey)) {
     event_proto.set_video_bandwidth(
         values_map_->FindKey(kVideoBandwidthKey)->GetDouble());
   }
-  if (values_map_->HasKey(kWebAppVersionKey)) {
+  if (values_map_->FindKey(kWebAppVersionKey)) {
     event_proto.set_webapp_version(
         values_map_->FindKey(kWebAppVersionKey)->GetString());
   }
diff --git a/remoting/resources/remoting_strings_mn.xtb b/remoting/resources/remoting_strings_mn.xtb
index afacd592..6b1399c 100644
--- a/remoting/resources/remoting_strings_mn.xtb
+++ b/remoting/resources/remoting_strings_mn.xtb
@@ -82,7 +82,7 @@
 <translation id="4784508858340177375">X сервер гэмтсэн эсвэл эхэлж чадсангүй.</translation>
 <translation id="4798680868612952294">Хулганы сонголт</translation>
 <translation id="4804818685124855865">Таслах</translation>
-<translation id="4808503597364150972">Та <ph name="HOSTNAME" />-ныхаа PIN кодоо оруулна уу</translation>
+<translation id="4808503597364150972">Та <ph name="HOSTNAME" />-ныхаа ПИН кодоо оруулна уу</translation>
 <translation id="4812684235631257312">Host</translation>
 <translation id="4867841927763172006">Илгээх PrtScn</translation>
 <translation id="4974476491460646149"><ph name="HOSTNAME" />-н холболт хаагдсан</translation>
@@ -99,7 +99,7 @@
 <translation id="5397086374758643919">Chrome Remote Desktop Host-ийг устгагч</translation>
 <translation id="5419418238395129586">Сүүлд онлайн байсан: <ph name="DATE" /></translation>
 <translation id="544077782045763683">Хост унтарсан байна.</translation>
-<translation id="5601503069213153581">PIN</translation>
+<translation id="5601503069213153581">ПИН</translation>
 <translation id="5690427481109656848">Google ХХК</translation>
 <translation id="5708869785009007625">Одоогоор таны десктопыг <ph name="USER" />-тай хуваалцсан байна.</translation>
 <translation id="5750083143895808682"><ph name="EMAIL_ADDRESS" />-р нэвтэрсэн байна.</translation>
@@ -144,7 +144,7 @@
 <translation id="7678209621226490279">Зүүн холбогч</translation>
 <translation id="7693372326588366043">Хостуудын жагсаалтыг дахин сэргээх</translation>
 <translation id="7714222945760997814">Үүнийг мэдэгдэх</translation>
-<translation id="7868137160098754906">Компьютерийн алсын удирдлагад нэвтрэх PIN кодоо оруулна уу.</translation>
+<translation id="7868137160098754906">Компьютерийн алсын удирдлагад нэвтрэх ПИН кодоо оруулна уу.</translation>
 <translation id="7895403300744144251">Алсын компьютерийн аюулгүй байдлын бодлогын дагуу таны бүртгэлээс холболт зөвшөөрдөггүй.</translation>
 <translation id="7936528439960309876">Баруун холбогч</translation>
 <translation id="7970576581263377361">Таниулах үйлдэл амжилтгүй боллоо. Chromium руу дахин нэвтэрч орно уу.</translation>
diff --git a/services/network/public/cpp/ip_address_space_util.cc b/services/network/public/cpp/ip_address_space_util.cc
index 88738d4..220192a 100644
--- a/services/network/public/cpp/ip_address_space_util.cc
+++ b/services/network/public/cpp/ip_address_space_util.cc
@@ -9,10 +9,13 @@
 
 #include "base/command_line.h"
 #include "base/no_destructor.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
 #include "services/network/public/cpp/network_switches.h"
 
 namespace network {
@@ -20,34 +23,47 @@
 
 using mojom::IPAddressSpace;
 using net::IPAddress;
+using net::IPEndPoint;
 
-// Represents a single override of the form: subnet -> address space.
-//
-// We could name this `Override`, but `override` is a reserved keyword so that
-// makes for awkward variable naming. Since the subnet is parsed from a CIDR
-// block, `OverrideBlock` works well too.
-class OverrideBlock {
- public:
-  OverrideBlock(IPAddress prefix, size_t prefix_length, IPAddressSpace space)
-      : prefix_(std::move(prefix)),
-        prefix_length_(prefix_length),
-        space_(space) {}
+// Parses a string of the form "<URL-safe IP address>:<port>".
+base::Optional<IPEndPoint> ParseEndpoint(base::StringPiece str) {
+  // Find the last colon character in `str`. We do not use
+  // `base::SplitStringPiece()` because IPv6 address literals may contain colon
+  // characters too.
+  const auto pos = str.rfind(':');
+  if (pos == str.npos) {
+    return base::nullopt;
+  }
 
-  // Parses an override block from `str`, of the form "<CIDR block>=<space>".
-  static base::Optional<OverrideBlock> Parse(base::StringPiece str);
+  base::StringPiece address_str = str.substr(0, pos);
 
-  // Returns this block's address space if `address` belongs to this instance's
-  // subnet. Returns nullopt otherwise.
-  base::Optional<IPAddressSpace> Apply(const IPAddress& address) const;
+  // Skip the colon. Note that this is safe because if `pos` is not `npos`, it
+  // is guaranteed to be < `str.size()`, and `substr()` accepts arguments that
+  // are <= `str.size()`. In other words, if the colon character is the last in
+  // `str`, then `port_str` is assigned "".
+  base::StringPiece port_str = str.substr(pos + 1);
 
- private:
-  // Use `Parse()` instead.
-  OverrideBlock() = default;
+  IPAddress address;
+  if (!net::ParseURLHostnameToAddress(address_str, &address)) {
+    return base::nullopt;
+  }
 
-  IPAddress prefix_;
-  size_t prefix_length_ = 0;
-  IPAddressSpace space_ = IPAddressSpace::kUnknown;
-};
+  // Parse to a `unsigned int`, which is guaranteed to be at least 16 bits wide.
+  // See https://en.cppreference.com/w/cpp/language/types.
+  unsigned port_unsigned = 0;
+  if (!base::StringToUint(port_str, &port_unsigned)) {
+    return base::nullopt;
+  }
+
+  if (!base::IsValueInRangeForNumericType<uint16_t>(port_unsigned)) {
+    return base::nullopt;
+  }
+
+  // Use `checked_cast()` for extra safety, though this should never `CHECK()`
+  // thanks to the previous call to `IsValueInRangeForNumericType()`.
+  uint16_t port = base::checked_cast<uint16_t>(port_unsigned);
+  return IPEndPoint(address, port);
+}
 
 base::Optional<IPAddressSpace> ParseIPAddressSpace(base::StringPiece str) {
   if (str == "public") {
@@ -65,21 +81,30 @@
   return base::nullopt;
 }
 
-// static
-base::Optional<OverrideBlock> OverrideBlock::Parse(base::StringPiece str) {
+// Represents a single command-line-specified endpoint override.
+struct EndpointOverride {
+  // The IP endpoint to override the address space for.
+  IPEndPoint endpoint;
+
+  // The IP address space to which `endpoint` should be mapped.
+  IPAddressSpace space;
+};
+
+// Parses an override from `str`, of the form "<endpoint>=<space>".
+base::Optional<EndpointOverride> ParseEndpointOverride(base::StringPiece str) {
   std::vector<base::StringPiece> tokens = base::SplitStringPiece(
       str, "=", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
-  // There should be 2 parts: the CIDR block and the address space.
+  // There should be 2 parts: the endpoint and the address space.
   if (tokens.size() != 2) {
     return base::nullopt;
   }
 
-  base::StringPiece cidr = tokens[0];
+  base::StringPiece endpoint = tokens[0];
   base::StringPiece address_space = tokens[1];
 
-  OverrideBlock block;
-  if (!net::ParseCIDRBlock(cidr, &block.prefix_, &block.prefix_length_)) {
+  base::Optional<IPEndPoint> parsed_endpoint = ParseEndpoint(endpoint);
+  if (!parsed_endpoint.has_value()) {
     return base::nullopt;
   }
 
@@ -89,11 +114,75 @@
     return base::nullopt;
   }
 
-  block.space_ = *parsed_address_space;
-  return block;
+  EndpointOverride result;
+  result.endpoint = std::move(*parsed_endpoint);
+  result.space = *parsed_address_space;
+  return result;
 }
 
-base::Optional<IPAddressSpace> OverrideBlock::Apply(
+// Parses a comma-separated list of overrides. Ignores invalid entries.
+std::vector<EndpointOverride> ParseEndpointOverrideList(
+    base::StringPiece list) {
+  // Since we skip invalid entries anyway, we can skip empty entries.
+  std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+      list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+  std::vector<EndpointOverride> endpoint_overrides;
+  for (base::StringPiece token : tokens) {
+    base::Optional<EndpointOverride> parsed = ParseEndpointOverride(token);
+    if (parsed.has_value()) {
+      endpoint_overrides.push_back(*std::move(parsed));
+    }
+  }
+
+  return endpoint_overrides;
+}
+
+// Applies overrides specified on the command-line to `endpoint`.
+// Returns nullopt if no override matches `endpoint`.
+base::Optional<IPAddressSpace> ApplyCommandLineOverrides(
+    const IPEndPoint& endpoint) {
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  if (!command_line.HasSwitch(switches::kIpAddressSpaceOverrides)) {
+    return base::nullopt;
+  }
+
+  std::string switch_str =
+      command_line.GetSwitchValueASCII(switches::kIpAddressSpaceOverrides);
+  std::vector<EndpointOverride> endpoint_overrides =
+      ParseEndpointOverrideList(switch_str);
+
+  for (const auto& endpoint_override : endpoint_overrides) {
+    if (endpoint_override.endpoint == endpoint) {
+      return endpoint_override.space;
+    }
+  }
+
+  return base::nullopt;
+}
+
+// Represents a single entry of the form: subnet -> address space.
+class AddressSpaceMapEntry {
+ public:
+  AddressSpaceMapEntry(IPAddress prefix,
+                       size_t prefix_length,
+                       IPAddressSpace space)
+      : prefix_(std::move(prefix)),
+        prefix_length_(prefix_length),
+        space_(space) {}
+
+  // Returns the assigned address space if `address` belongs to this instance's
+  // subnet. Returns nullopt otherwise.
+  base::Optional<IPAddressSpace> Apply(const IPAddress& address) const;
+
+ private:
+  IPAddress prefix_;
+  size_t prefix_length_ = 0;
+  IPAddressSpace space_ = IPAddressSpace::kUnknown;
+};
+
+base::Optional<IPAddressSpace> AddressSpaceMapEntry::Apply(
     const IPAddress& address) const {
   if (net::IPAddressMatchesPrefix(address, prefix_, prefix_length_)) {
     return space_;
@@ -102,47 +191,27 @@
   return base::nullopt;
 }
 
-// Represents a sequential list of `OverrideBlock` instances.
-class OverrideBlockList {
+// Maps IP addresses to IP address spaces.
+class AddressSpaceMap {
  public:
-  explicit OverrideBlockList(std::vector<OverrideBlock> blocks)
-      : blocks_(std::move(blocks)) {}
+  explicit AddressSpaceMap(std::vector<AddressSpaceMapEntry> entries)
+      : entries_(std::move(entries)) {}
 
-  // Parses a comma-separated list of override blocks. Ignores invalid blocks.
-  static OverrideBlockList Parse(base::StringPiece str);
-
-  // Applies blocks in this list to `address`, in sequential order. Returns the
-  // address space of the first matching override block. Returns nullopt if no
-  // match is found.
+  // Applies entries in this map to `address`, in sequential order.
+  // Returns the address space of the first matching entry.
+  // Returns nullopt if no match is found.
   base::Optional<IPAddressSpace> Apply(const IPAddress& address) const;
 
  private:
-  std::vector<OverrideBlock> blocks_;
+  std::vector<AddressSpaceMapEntry> entries_;
 };
 
-// static
-OverrideBlockList OverrideBlockList::Parse(base::StringPiece list) {
-  // Since we skip invalid entries anyway, we can skip empty entries.
-  std::vector<base::StringPiece> tokens = base::SplitStringPiece(
-      list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-  std::vector<OverrideBlock> blocks;
-  for (base::StringPiece token : tokens) {
-    base::Optional<OverrideBlock> block = OverrideBlock::Parse(token);
-    if (block.has_value()) {
-      blocks.push_back(*std::move(block));
-    }
-  }
-
-  return OverrideBlockList(std::move(blocks));
-}
-
-base::Optional<IPAddressSpace> OverrideBlockList::Apply(
+base::Optional<IPAddressSpace> AddressSpaceMap::Apply(
     const IPAddress& address) const {
   base::Optional<IPAddressSpace> space;
 
-  for (const OverrideBlock& block : blocks_) {
-    space = block.Apply(address);
+  for (const AddressSpaceMapEntry& entry : entries_) {
+    space = entry.Apply(address);
     if (space.has_value()) {
       break;
     }
@@ -152,61 +221,49 @@
   return space;
 }
 
-// Applies override blocks specified on the command-line to `address`.
-// Returns nullopt if no override block matches `address`.
-base::Optional<IPAddressSpace> ApplyCommandLineOverrides(
-    const IPAddress& address) {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (!command_line.HasSwitch(switches::kIpAddressSpaceOverrides)) {
-    return base::nullopt;
-  }
+// Returns a map containing all default-non-public subnets.
+const AddressSpaceMap& NonPublicAddressSpaceMap() {
+  // For brevity below, otherwise entries do not fit on single lines.
+  using Entry = AddressSpaceMapEntry;
 
-  std::string switch_str =
-      command_line.GetSwitchValueASCII(switches::kIpAddressSpaceOverrides);
-  return OverrideBlockList::Parse(switch_str).Apply(address);
-}
-
-// Returns a block list containing all default-non-public subnets.
-const OverrideBlockList& NonPublicBlockList() {
-  // Have to repeat `OverrideBlockList` because perfect forwarding does not deal
+  // Have to repeat `AddressSpaceMap` because perfect forwarding does not deal
   // well with initializer lists.
-  static const base::NoDestructor<OverrideBlockList> kBlocks(OverrideBlockList({
+  static const base::NoDestructor<AddressSpaceMap> kMap(AddressSpaceMap({
       // IPv6 Loopback (RFC 4291): ::1/128
-      OverrideBlock(IPAddress::IPv6Localhost(), 128, IPAddressSpace::kLocal),
+      Entry(IPAddress::IPv6Localhost(), 128, IPAddressSpace::kLocal),
       // IPv6 Unique-local (RFC 4193, RFC 8190): fc00::/7
-      OverrideBlock(
-          IPAddress(0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 7,
-          IPAddressSpace::kPrivate),
+      Entry(IPAddress(0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 7,
+            IPAddressSpace::kPrivate),
       // IPv6 Link-local unicast (RFC 4291): fe80::/10
-      OverrideBlock(
-          IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 10,
-          IPAddressSpace::kPrivate),
+      Entry(IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 10,
+            IPAddressSpace::kPrivate),
       // IPv4 Loopback (RFC 1122): 127.0.0.0/8
-      OverrideBlock(IPAddress(127, 0, 0, 0), 8, IPAddressSpace::kLocal),
+      Entry(IPAddress(127, 0, 0, 0), 8, IPAddressSpace::kLocal),
       // IPv4 Private use (RFC 1918): 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
-      OverrideBlock(IPAddress(10, 0, 0, 0), 8, IPAddressSpace::kPrivate),
-      OverrideBlock(IPAddress(172, 16, 0, 0), 12, IPAddressSpace::kPrivate),
-      OverrideBlock(IPAddress(192, 168, 0, 0), 16, IPAddressSpace::kPrivate),
+      Entry(IPAddress(10, 0, 0, 0), 8, IPAddressSpace::kPrivate),
+      Entry(IPAddress(172, 16, 0, 0), 12, IPAddressSpace::kPrivate),
+      Entry(IPAddress(192, 168, 0, 0), 16, IPAddressSpace::kPrivate),
       // IPv4 Link-local (RFC 3927): 169.254.0.0/16
-      OverrideBlock(IPAddress(169, 254, 0, 0), 16, IPAddressSpace::kPrivate),
+      Entry(IPAddress(169, 254, 0, 0), 16, IPAddressSpace::kPrivate),
   }));
-  return *kBlocks;
+  return *kMap;
 }
 
 }  // namespace
 
-IPAddressSpace IPAddressToIPAddressSpace(const IPAddress& address) {
-  if (!address.IsValid()) {
+IPAddressSpace IPEndPointToIPAddressSpace(const IPEndPoint& endpoint) {
+  if (!endpoint.address().IsValid()) {
     return IPAddressSpace::kUnknown;
   }
 
-  base::Optional<IPAddressSpace> space = ApplyCommandLineOverrides(address);
+  base::Optional<IPAddressSpace> space = ApplyCommandLineOverrides(endpoint);
   if (space.has_value()) {
     return *space;
   }
 
-  return NonPublicBlockList().Apply(address).value_or(IPAddressSpace::kPublic);
+  return NonPublicAddressSpaceMap()
+      .Apply(endpoint.address())
+      .value_or(IPAddressSpace::kPublic);
 }
 
 namespace {
diff --git a/services/network/public/cpp/ip_address_space_util.h b/services/network/public/cpp/ip_address_space_util.h
index 1843047..0f3092d 100644
--- a/services/network/public/cpp/ip_address_space_util.h
+++ b/services/network/public/cpp/ip_address_space_util.h
@@ -9,22 +9,26 @@
 
 namespace net {
 
-class IPAddress;
+class IPEndPoint;
 
 }  // namespace net
 
 namespace network {
 
-// Returns the IPAddressSpace to which `address` belongs.
+// Returns the IPAddressSpace to which `endpoint` belongs.
 //
-// Returns `kUnknown` for invalid addresses. Otherwise, takes into account the
-// `--ip-address-space-overrides` command-line switch.
+// Returns `kUnknown` for invalid IP addresses. Otherwise, takes into account
+// the `--ip-address-space-overrides` command-line switch.
+//
+// `endpoint`'s port is only used for matching to command-line overrides. It is
+// ignored otherwise. In particular, if no overrides are specified on the
+// command-line, then this function ignores the port entirely.
 //
 // WARNING: This can only be used as-is for subresource requests loaded over the
 // network. Special URL schemes and resource headers must also be taken into
 // account at higher layers.
 mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP)
-    IPAddressToIPAddressSpace(const net::IPAddress& address);
+    IPEndPointToIPAddressSpace(const net::IPEndPoint& endpoint);
 
 // Returns whether `lhs` is less public than `rhs`.
 //
diff --git a/services/network/public/cpp/ip_address_space_util_unittest.cc b/services/network/public/cpp/ip_address_space_util_unittest.cc
index d3c5c32..9176076a 100644
--- a/services/network/public/cpp/ip_address_space_util_unittest.cc
+++ b/services/network/public/cpp/ip_address_space_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -15,6 +16,7 @@
 using mojom::IPAddressSpace;
 using net::IPAddress;
 using net::IPAddressBytes;
+using net::IPEndPoint;
 
 IPAddress PublicIPv4Address() {
   return IPAddress(64, 233, 160, 0);
@@ -24,20 +26,25 @@
   return IPAddress(192, 168, 1, 1);
 }
 
+// Helper for tests that do not care about command-line overrides.
+IPAddressSpace IPAddressToIPAddressSpace(const IPAddress& address) {
+  return IPEndPointToIPAddressSpace(IPEndPoint(address, 80));
+}
+
 // Verifies that the address space of an invalid IP address is `unknown`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceInvalid) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceInvalid) {
   EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress()), IPAddressSpace::kUnknown);
 }
 
 // Verifies that the address space of a regular IP address is `public`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV4Public) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV4Public) {
   EXPECT_EQ(IPAddressToIPAddressSpace(PublicIPv4Address()),
             IPAddressSpace::kPublic);
 }
 
 // Verifies that the address space of IP addresses belonging to any of the
 // three "Private Use" address blocks defined in RFC 1918 is `private`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV4PrivateUse) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV4PrivateUse) {
   EXPECT_EQ(IPAddressToIPAddressSpace(PrivateIPv4Address()),
             IPAddressSpace::kPrivate);
 
@@ -92,7 +99,7 @@
 
 // Verifies that the address space of IP addresses belonging to the "Link-local"
 // 169.254.0.0/16 block are `private`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV4LinkLocal) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV4LinkLocal) {
   // Lower bound (exclusive).
   EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(169, 253, 255, 255)),
             IPAddressSpace::kPublic);
@@ -110,7 +117,7 @@
 
 // Verifies that the address space of IPv4 localhost and the rest of the
 // 127.0.0.0/8 block is `local`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV4Localhost) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV4Localhost) {
   EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress::IPv4Localhost()),
             IPAddressSpace::kLocal);
 
@@ -137,14 +144,14 @@
 }
 
 // Verifies that the address space of a regular IPv6 address is `public`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV6Public) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV6Public) {
   EXPECT_EQ(IPAddressToIPAddressSpace(ParseIPAddress("42::")),
             IPAddressSpace::kPublic);
 }
 
 // Verifies that the address space of IPv6 addresses in the "Unique-local"
 // (fc00::/7) address block is `private`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV6UniqueLocal) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV6UniqueLocal) {
   // Lower bound (exclusive).
   EXPECT_EQ(IPAddressToIPAddressSpace(
                 ParseIPAddress("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")),
@@ -164,7 +171,7 @@
 
 // Verifies that the address space of IPv6 addresses in the "Link-local unicast"
 // (fe80::/10) address block is `private`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV6LinkLocalUnicast) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV6LinkLocalUnicast) {
   // Lower bound (exclusive).
   EXPECT_EQ(IPAddressToIPAddressSpace(
                 ParseIPAddress("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff")),
@@ -183,7 +190,7 @@
 }
 
 // Verifies that the address space of IPv6 localhost (::1/128) is `local`.
-TEST(IPAddressSpaceTest, IPAddressToIPAddressSpaceV6Localhost) {
+TEST(IPAddressSpaceTest, IPEndPointToIPAddressSpaceV6Localhost) {
   EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress::IPv6Localhost()),
             IPAddressSpace::kLocal);
 
@@ -198,7 +205,7 @@
 
 // Verifies that IPv4-mapped IPv6 addresses belong to the address space of the
 // mapped IPv4 address.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceIPv4MappedIPv6) {
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceIPv4MappedIPv6) {
   EXPECT_EQ(IPAddressToIPAddressSpace(
                 net::ConvertIPv4ToIPv4MappedIPv6(PublicIPv4Address())),
             IPAddressSpace::kPublic);
@@ -214,7 +221,7 @@
 
 // Verifies that the `ip-address-space-overrides` switch can be present and
 // empty, in which case it is ignored.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideEmpty) {
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideEmpty) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides, "");
 
@@ -223,184 +230,135 @@
             IPAddressSpace::kLocal);
 }
 
-// Verifies that a single IPv4 address space can be overridden.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideSingle) {
+// Verifies that a single IPv4 endpoints can be overridden.
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideSingle) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "127.1.0.1/24=public");
+                                 "127.0.0.1:80=public");
 
-  // 1 bit lower than the lower bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 0, 255, 255)),
+  // Wrong IP address.
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(127, 0, 0, 0), 80)),
             IPAddressSpace::kLocal);
 
-  // Lower and upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 0)),
-            IPAddressSpace::kPublic);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 255)),
-            IPAddressSpace::kPublic);
-
-  // 1 bit higher than the upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 1, 0)),
+  // Wrong port.
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(127, 0, 0, 1), 81)),
             IPAddressSpace::kLocal);
+
+  // Exact match.
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(127, 0, 0, 1), 80)),
+            IPAddressSpace::kPublic);
 }
 
-// Verifies that multiple IPv4 address spaces can be overridden.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideMultiple) {
+// Verifies that multiple IPv4 endpoints can be overridden.
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideMultiple) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "127.1.0.1/16=public,127.2.0.1/16=private");
+                                 "10.2.3.4:80=public,8.8.8.8:8888=private");
 
-  // First override block.
-
-  // 1 bit lower than the lower bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 0, 255, 255)),
-            IPAddressSpace::kLocal);
-
-  // Lower and upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 0)),
-            IPAddressSpace::kPublic);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 255, 255)),
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(10, 2, 3, 4), 80)),
             IPAddressSpace::kPublic);
 
-  // Second override block (contiguous with first block).
-
-  // Lower and upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 2, 0, 0)),
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(8, 8, 8, 8), 8888)),
             IPAddressSpace::kPrivate);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 2, 255, 255)),
-            IPAddressSpace::kPrivate);
-
-  // 1 bit higher than the upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 3, 0, 0)),
-            IPAddressSpace::kLocal);
 }
 
 // Verifies that invalid entries in the command-line switch comma-separated list
 // are simply ignored, and that subsequent entries are still applied.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideInvalid) {
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideInvalid) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
-  command_line.AppendSwitchASCII(
-      switches::kIpAddressSpaceOverrides,
-      "127.1.0.1/16=public,potato,,127.2.0.1/16=private");
+  command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
+                                 ","                       // Empty.
+                                 "1.2.3.4:80foo=public,"   // Invalid port.
+                                 "1.2.3.4:65536=private,"  // Port out of range.
+                                 "1:80=public,"            // Invalid address.
+                                 "1.2.3.4:80=potato,"  // Invalid address space.
+                                 "1.2.3.4:=public,"    // Missing port.
+                                 "1.2.3.4=public,"     // Missing colon, port.
+                                 "1.2.3.4:80=,"        // Missing address space.
+                                 "1.2.3.4:80,"  // Missing equal, address space.
+                                 "1.2.3.4:80=private");
 
-  // First valid override block applies.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 0)),
-            IPAddressSpace::kPublic);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 255, 255)),
-            IPAddressSpace::kPublic);
-
-  // Second valid override block applies, despite preceding garbage.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 2, 0, 0)),
-            IPAddressSpace::kPrivate);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 2, 255, 255)),
+  // Valid override applies, despite preceding garbage.
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(1, 2, 3, 4), 80)),
             IPAddressSpace::kPrivate);
 }
 
 // Verifies that command-line overrides that overlap with previously-given
 // overrides are ignored. In other words, the first matching override is
 // applied.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideOverlap) {
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideOverlap) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "127.1.0.1/24=public,127.1.0.1/16=private");
+                                 "8.8.8.8:80=local,8.8.8.8:80=private");
 
-  // The first matching override block applies.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 0)),
-            IPAddressSpace::kPublic);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 0, 255)),
-            IPAddressSpace::kPublic);
-
-  // Same here, but the first block no longer matches.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 1, 0)),
-            IPAddressSpace::kPrivate);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(127, 1, 255, 255)),
-            IPAddressSpace::kPrivate);
+  // The first matching override applies.
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(8, 8, 8, 8), 80)),
+            IPAddressSpace::kLocal);
 }
 
 // Verifies that invalid IP addresses are not subject to overrides.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideInvalidAddress) {
-  // 0.0.0.0/0 is not a valid CIDR block apparently. We cover the entirety of
-  // IPv4 addresses using two /1 blocks instead.
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideInvalidAddress) {
+  // 0.0.0.0:80 should not really match the invalid IP address, but it is still
+  // the most likely to match.
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "0.0.0.0/1=local,128.0.0.0/1=local");
+                                 "0.0.0.0:80=local");
 
   // Check that the override *does not apply* to an invalid IP address.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress()), IPAddressSpace::kUnknown);
-
-  // Check that the override applies to all valid IPv4 addresses.
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(0, 0, 0, 0)),
-            IPAddressSpace::kLocal);
-  EXPECT_EQ(IPAddressToIPAddressSpace(PublicIPv4Address()),
-            IPAddressSpace::kLocal);
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(255, 255, 255, 255)),
-            IPAddressSpace::kLocal);
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(IPAddress(), 80)),
+            IPAddressSpace::kUnknown);
 }
 
-// Verifies that command-line overrides can specify IPv6 subnets.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideV6) {
+// Verifies that command-line overrides can specify IPv6 addresses.
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideV6) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "2001::/16=local,2020::/24=private");
+                                 "[2001::]:2001=local,[2020::1]:1234=private");
 
-  // First override block.
+  // First override.
 
-  // 1 bit lower than lower bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                ParseIPAddress("2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff")),
-            IPAddressSpace::kPublic);
+  // Wrong address.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2001::1"), 2001)),
+      IPAddressSpace::kPublic);
 
-  // Lower and upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(ParseIPAddress("2001::")),
-            IPAddressSpace::kLocal);
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                ParseIPAddress("2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff")),
-            IPAddressSpace::kLocal);
+  // Wrong port.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2001::"), 2000)),
+      IPAddressSpace::kPublic);
 
-  // 1 bit higher than upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(ParseIPAddress("2002::")),
-            IPAddressSpace::kPublic);
+  // Exact match.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2001::"), 2001)),
+      IPAddressSpace::kLocal);
 
   // Second override block.
 
-  // 1 bit lower than lower bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                ParseIPAddress("2019:ffff:ffff:ffff:ffff:ffff:ffff:ffff")),
-            IPAddressSpace::kPublic);
+  // Wrong address.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2020::"), 1234)),
+      IPAddressSpace::kPublic);
 
-  // Lower and upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(ParseIPAddress("2020::")),
-            IPAddressSpace::kPrivate);
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                ParseIPAddress("2020:00ff:ffff:ffff:ffff:ffff:ffff:ffff")),
-            IPAddressSpace::kPrivate);
+  // Wrong port.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2020::1"), 1235)),
+      IPAddressSpace::kPublic);
 
-  // 1 bit higher than upper bound.
-  EXPECT_EQ(IPAddressToIPAddressSpace(ParseIPAddress("2020:100::")),
-            IPAddressSpace::kPublic);
-
-  // IPv4 addresses are unaffected.
-  EXPECT_EQ(IPAddressToIPAddressSpace(PrivateIPv4Address()),
-            IPAddressSpace::kPrivate);
-  EXPECT_EQ(IPAddressToIPAddressSpace(PublicIPv4Address()),
-            IPAddressSpace::kPublic);
+  // Exact match.
+  EXPECT_EQ(
+      IPEndPointToIPAddressSpace(IPEndPoint(ParseIPAddress("2020::1"), 1234)),
+      IPAddressSpace::kPrivate);
 }
 
-// Verifies that IPv4-mapped IPv6 addresses are overridden as though they were
-// the mapped IPv4 address instead. This is a quirk of the implementation that
-// we test for completeness - it is not particularly useful.
-TEST(IPAddressSpaceTest, IPAddressToAddressSpaceOverrideIPv4MappedIPv6) {
+// Verifies that IPv4-mapped IPv6 addresses are not overridden as though they
+// were the mapped IPv4 address instead.
+TEST(IPAddressSpaceTest, IPEndPointToAddressSpaceOverrideIPv4MappedIPv6) {
   auto& command_line = *base::CommandLine::ForCurrentProcess();
   command_line.AppendSwitchASCII(switches::kIpAddressSpaceOverrides,
-                                 "127.1.0.0/16=public");
+                                 "127.0.0.1:80=public");
 
-  // Check that the override applies to all valid IPv4 addresses.
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                net::ConvertIPv4ToIPv4MappedIPv6(IPAddress(127, 1, 0, 0))),
-            IPAddressSpace::kPublic);
-
-  EXPECT_EQ(IPAddressToIPAddressSpace(
-                net::ConvertIPv4ToIPv4MappedIPv6(IPAddress(127, 2, 0, 0))),
+  EXPECT_EQ(IPEndPointToIPAddressSpace(IPEndPoint(
+                net::ConvertIPv4ToIPv4MappedIPv6(IPAddress(127, 0, 0, 1)), 80)),
             IPAddressSpace::kLocal);
 }
 
diff --git a/services/network/public/cpp/link_header_parser.cc b/services/network/public/cpp/link_header_parser.cc
index 916cdd7..d5248b3 100644
--- a/services/network/public/cpp/link_header_parser.cc
+++ b/services/network/public/cpp/link_header_parser.cc
@@ -38,6 +38,8 @@
   std::string value = base::ToLowerASCII(attr.value());
   if (value == "preload")
     return mojom::LinkRelAttribute::kPreload;
+  else if (value == "modulepreload")
+    return mojom::LinkRelAttribute::kModulePreload;
   return base::nullopt;
 }
 
diff --git a/services/network/public/cpp/link_header_parser_unittest.cc b/services/network/public/cpp/link_header_parser_unittest.cc
index 9291ef27..cecac41 100644
--- a/services/network/public/cpp/link_header_parser_unittest.cc
+++ b/services/network/public/cpp/link_header_parser_unittest.cc
@@ -95,6 +95,16 @@
   // reasonable.
 }
 
+TEST(LinkHeaderParserTest, RelAttributeModulePreload) {
+  auto headers =
+      base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK\n");
+  headers->AddHeader("link", "</foo.mjs>; rel=modulepreload");
+  std::vector<mojom::LinkHeaderPtr> parsed_headers =
+      ParseLinkHeaders(*headers, kBaseUrl);
+  ASSERT_EQ(parsed_headers.size(), 1UL);
+  EXPECT_EQ(parsed_headers[0]->rel, mojom::LinkRelAttribute::kModulePreload);
+}
+
 TEST(LinkHeaderParserTest, LinkAsAttribute) {
   auto headers =
       base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/2 200 OK\n");
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc
index f5845e2..8346e390 100644
--- a/services/network/public/cpp/network_switches.cc
+++ b/services/network/public/cpp/network_switches.cc
@@ -88,18 +88,20 @@
 // set.
 const char kUseFirstPartySet[] = "use-first-party-set";
 
-// Specifies manual overrides to the IP address -> IP address space mapping.
+// Specifies manual overrides to the IP endpoint -> IP address space mapping.
 // This allows running local tests against "public" and "private" IP addresses.
 //
 // This switch is specified as a comma-separated list of overrides. Each
-// override is given as a colon-separated "<subnet>:<address space>" pair.
+// override is given as a colon-separated "<endpoint>:<address space>" pair.
 // Grammar, in pseudo-BNF format:
 //
 //   switch := override-list
 //   override-list := override “,” override-list | <nil>
-//   override := cidr-block “=” address-space
+//   override := ip-endpoint “=” address-space
 //   address-space := “public” | “private” | “local”
-//   cidr-block := see `net::ParseCIDRBlock()` for details
+//   ip-endpoint := ip-address ":" port
+//   ip-address := see `net::ParseURLHostnameToAddress()` for details
+//   port := integer in the [0-65535] range
 //
 // Any invalid entries in the comma-separated list are ignored.
 //
diff --git a/services/network/public/mojom/link_header.mojom b/services/network/public/mojom/link_header.mojom
index 2c226dc..a476bab 100644
--- a/services/network/public/mojom/link_header.mojom
+++ b/services/network/public/mojom/link_header.mojom
@@ -10,6 +10,8 @@
 enum LinkRelAttribute {
   // https://w3c.github.io/preload/
   kPreload,
+  // https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload
+  kModulePreload,
 };
 
 // Represents subset of possible values for `as` attribute of the Link header.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index ac7b971b6..b56d2e4 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1140,7 +1140,7 @@
   // Now that the request endpoint's address has been resolved, check if
   // this request should be blocked by CORS-RFC1918 rules.
   mojom::IPAddressSpace resource_address_space =
-      IPAddressToIPAddressSpace(info.endpoint.address());
+      IPEndPointToIPAddressSpace(info.endpoint);
   if (!CanConnectToAddressSpace(resource_address_space)) {
     // Remember the CORS error so we can annotate the URLLoaderCompletionStatus
     // with it later, then fail the request with the same net error code as
@@ -2202,7 +2202,7 @@
     devtools_observer->OnRawResponse(
         devtools_request_id().value(), url_request_->maybe_stored_cookies(),
         std::move(header_array), raw_response_headers,
-        IPAddressToIPAddressSpace(response_info.remote_endpoint.address()));
+        IPEndPointToIPAddressSpace(response_info.remote_endpoint));
   }
 
   if (auto* cookie_observer = GetCookieAccessObserver()) {
diff --git a/services/preferences/tracked/pref_hash_filter.cc b/services/preferences/tracked/pref_hash_filter.cc
index 763aac94..65136fa 100644
--- a/services/preferences/tracked/pref_hash_filter.cc
+++ b/services/preferences/tracked/pref_hash_filter.cc
@@ -274,7 +274,7 @@
 void PrefHashFilter::ClearFromExternalStore(
     HashStoreContents* external_validation_hash_store_contents,
     const base::DictionaryValue* changed_paths_and_macs) {
-  DCHECK(!changed_paths_and_macs->empty());
+  DCHECK(!changed_paths_and_macs->DictEmpty());
 
   for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
        !it.IsAtEnd(); it.Advance()) {
@@ -287,7 +287,7 @@
     std::unique_ptr<HashStoreContents> external_validation_hash_store_contents,
     std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
     bool write_success) {
-  DCHECK(!changed_paths_and_macs->empty());
+  DCHECK(!changed_paths_and_macs->DictEmpty());
   DCHECK(external_validation_hash_store_contents);
   if (!write_success)
     return;
diff --git a/services/preferences/tracked/pref_hash_store_impl.cc b/services/preferences/tracked/pref_hash_store_impl.cc
index 923dded..095016ee 100644
--- a/services/preferences/tracked/pref_hash_store_impl.cc
+++ b/services/preferences/tracked/pref_hash_store_impl.cc
@@ -207,7 +207,7 @@
   // Treat NULL and empty the same; otherwise we would need to store a hash for
   // the entire dictionary (or some other special beacon) to differentiate these
   // two cases which are really the same for dictionaries.
-  if (!initial_split_value || initial_split_value->empty())
+  if (!initial_split_value || initial_split_value->DictEmpty())
     return has_hashes ? ValueState::CLEARED : ValueState::UNCHANGED;
 
   if (!has_hashes)
diff --git a/services/preferences/tracked/pref_hash_store_impl_unittest.cc b/services/preferences/tracked/pref_hash_store_impl_unittest.cc
index 20664d4..a2e9e05 100644
--- a/services/preferences/tracked/pref_hash_store_impl_unittest.cc
+++ b/services/preferences/tracked/pref_hash_store_impl_unittest.cc
@@ -83,7 +83,7 @@
       pref_hash_store.ComputeSplitMacs("foo.bar", nullptr);
 
   ASSERT_TRUE(computed_macs);
-  EXPECT_TRUE(computed_macs->empty());
+  EXPECT_TRUE(computed_macs->DictEmpty());
 }
 
 TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
diff --git a/services/video_capture/device_media_to_mojo_adapter.cc b/services/video_capture/device_media_to_mojo_adapter.cc
index 1ffa4a045..b59c655 100644
--- a/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_media_to_mojo_adapter.cc
@@ -199,6 +199,16 @@
           switches::kVideoCaptureUseGpuMemoryBuffer)) {
     kMaxBufferCount = 30;
   }
+#elif defined(OS_WIN)
+  // On Windows, for GMB backed zero-copy more buffers are needed because it's
+  // routinely observed that it runs out of default buffer count when just
+  // displaying 60 FPS media in a video element
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableVideoCaptureUseGpuMemoryBuffer) &&
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kVideoCaptureUseGpuMemoryBuffer)) {
+    kMaxBufferCount = 30;
+  }
 #endif
 
   return kMaxBufferCount;
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 0ab8e8a..cca9997 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -1603,7 +1603,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-16.04"
+              "os": "Ubuntu-18.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -1636,7 +1636,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-16.04"
+              "os": "Ubuntu-18.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 92fbbaa..83109d4 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -6373,7 +6373,7 @@
       },
       'V8 Blink Linux Debug': {
         'mixins': [
-          'linux-xenial',
+          'linux-bionic',
         ],
         'additional_compile_targets': ['blink_tests'],
         'test_suites': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b4ceaab..d38997f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2292,6 +2292,21 @@
             ]
         }
     ],
+    "CredentialEditAndroid": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "EditPasswordsInSettings"
+                    ]
+                }
+            ]
+        }
+    ],
     "CriticalPersistedTabData_V2": [
         {
             "platforms": [
@@ -4207,6 +4222,8 @@
                 "android",
                 "android_webview",
                 "chromeos",
+                "chromeos_lacros",
+                "ios",
                 "linux",
                 "mac",
                 "windows"
@@ -5298,25 +5315,6 @@
             ]
         }
     ],
-    "OmniboxButtonRowPedalsDesktop": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "ButtonRowWithPedalsAndKeywordButton",
-                    "enable_features": [
-                        "OmniboxKeywordSearchButton"
-                    ]
-                }
-            ]
-        }
-    ],
     "OmniboxDNSInterceptionChecksPolicyRollout": [
         {
             "platforms": [
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index 39141348..03bcd09 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -174,6 +174,7 @@
     "renderer_preferences/renderer_preferences.cc",
     "renderer_preferences/renderer_preferences_mojom_traits.cc",
     "scheduler/web_scheduler_tracked_feature.cc",
+    "service_worker/service_worker_loader_helpers.cc",
     "service_worker/service_worker_scope_match.cc",
     "service_worker/service_worker_status_code.cc",
     "service_worker/service_worker_type_converters.cc",
diff --git a/third_party/blink/common/DEPS b/third_party/blink/common/DEPS
index 406eb2f..fbedc36 100644
--- a/third_party/blink/common/DEPS
+++ b/third_party/blink/common/DEPS
@@ -17,6 +17,7 @@
     "+services/metrics/public/mojom/ukm_interface.mojom.h",
     "+services/network/public/cpp",
     "+services/network/public/mojom/content_security_policy.mojom.h",
+    "+services/network/public/mojom/fetch_api.mojom-shared.h",
     "+services/network/public/mojom/parsed_headers.mojom.h",
     "+services/network/public/mojom/referrer_policy.mojom.h",
     "+services/network/public/mojom/web_sandbox_flags.mojom-shared.h",
@@ -32,6 +33,7 @@
     "+third_party/blink/public/common",
     "+third_party/blink/public/mojom",
     "+third_party/icu/source/common/unicode/unistr.h",
+    "+ui/base/page_transition_types.h",
     "+ui/base/ui_base_switches_util.h",
     "+ui/base/dragdrop/mojom",
     "+ui/display",
diff --git a/third_party/blink/common/net/ip_address_space_util.cc b/third_party/blink/common/net/ip_address_space_util.cc
index bb2fd68..156b845 100644
--- a/third_party/blink/common/net/ip_address_space_util.cc
+++ b/third_party/blink/common/net/ip_address_space_util.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/public/common/net/ip_address_space_util.h"
 
 #include "base/logging.h"
+#include "net/base/ip_endpoint.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
 #include "services/network/public/cpp/ip_address_space_util.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
@@ -57,18 +58,17 @@
   }
 
   // Otherwise, calculate the address space via the provided IP address.
-  return network::IPAddressToIPAddressSpace(
-      response_head->remote_endpoint.address());
+  return network::IPEndPointToIPAddressSpace(response_head->remote_endpoint);
 }
 
 IPAddressSpace CalculateResourceAddressSpace(const GURL& url,
-                                             const net::IPAddress& address) {
+                                             const net::IPEndPoint& endpoint) {
   if (url.SchemeIsFile()) {
     // See: https://wicg.github.io/cors-rfc1918/#file-url.
     return IPAddressSpace::kLocal;
   }
 
-  return network::IPAddressToIPAddressSpace(address);
+  return network::IPEndPointToIPAddressSpace(endpoint);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/common/net/ip_address_space_util_unittest.cc b/third_party/blink/common/net/ip_address_space_util_unittest.cc
index eb6b574..30120d4 100644
--- a/third_party/blink/common/net/ip_address_space_util_unittest.cc
+++ b/third_party/blink/common/net/ip_address_space_util_unittest.cc
@@ -6,8 +6,10 @@
 
 #include <utility>
 
+#include "base/command_line.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "services/network/public/mojom/parsed_headers.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
@@ -109,24 +111,60 @@
       CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
 }
 
+TEST(IPAddressSpaceTest, CalculateClientAddressSpaceOverride) {
+  auto& command_line = *base::CommandLine::ForCurrentProcess();
+  command_line.AppendSwitchASCII(network::switches::kIpAddressSpaceOverrides,
+                                 "10.2.3.4:80=public,8.8.8.8:8888=private");
+
+  URLResponseHead response_head;
+  response_head.remote_endpoint = IPEndPoint(IPAddress(10, 2, 3, 4), 80);
+  response_head.parsed_headers = ParsedHeaders::New();
+
+  EXPECT_EQ(
+      IPAddressSpace::kPublic,
+      CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
+
+  response_head.remote_endpoint = IPEndPoint(IPAddress(8, 8, 8, 8), 8888);
+
+  EXPECT_EQ(
+      IPAddressSpace::kPrivate,
+      CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
+}
+
 TEST(IPAddressSpaceTest, CalculateResourceAddressSpaceFileURL) {
   EXPECT_EQ(IPAddressSpace::kLocal,
-            CalculateResourceAddressSpace(GURL("file:///foo"), IPAddress()));
+            CalculateResourceAddressSpace(GURL("file:///foo"), IPEndPoint()));
 }
 
 TEST(IPAddressSpaceTest, CalculateResourceAddressSpaceIPAddress) {
-  EXPECT_EQ(IPAddressSpace::kLocal,
-            CalculateResourceAddressSpace(GURL("http:///foo.test"),
-                                          IPAddress::IPv4Localhost()));
+  EXPECT_EQ(
+      IPAddressSpace::kLocal,
+      CalculateResourceAddressSpace(
+          GURL("http://foo.test"), IPEndPoint(IPAddress::IPv4Localhost(), 80)));
   EXPECT_EQ(IPAddressSpace::kPrivate,
-            CalculateResourceAddressSpace(GURL("http:///foo.test"),
-                                          PrivateIPv4Address()));
+            CalculateResourceAddressSpace(
+                GURL("http://foo.test"), IPEndPoint(PrivateIPv4Address(), 80)));
   EXPECT_EQ(IPAddressSpace::kPublic,
-            CalculateResourceAddressSpace(GURL("http:///foo.test"),
-                                          PublicIPv4Address()));
+            CalculateResourceAddressSpace(GURL("http://foo.test"),
+                                          IPEndPoint(PublicIPv4Address(), 80)));
   EXPECT_EQ(
       IPAddressSpace::kUnknown,
-      CalculateResourceAddressSpace(GURL("http:///foo.test"), IPAddress()));
+      CalculateResourceAddressSpace(GURL("http://foo.test"), IPEndPoint()));
+}
+
+TEST(IPAddressSpaceTest, CalculateResourceAddressSpaceOverride) {
+  auto& command_line = *base::CommandLine::ForCurrentProcess();
+  command_line.AppendSwitchASCII(network::switches::kIpAddressSpaceOverrides,
+                                 "10.2.3.4:80=public,8.8.8.8:8888=private");
+
+  EXPECT_EQ(
+      IPAddressSpace::kPublic,
+      CalculateResourceAddressSpace(GURL("http://foo.test"),
+                                    IPEndPoint(IPAddress(10, 2, 3, 4), 80)));
+  EXPECT_EQ(
+      IPAddressSpace::kPrivate,
+      CalculateResourceAddressSpace(GURL("http://foo.test"),
+                                    IPEndPoint(IPAddress(8, 8, 8, 8), 8888)));
 }
 
 }  // namespace
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/third_party/blink/common/service_worker/service_worker_loader_helpers.cc
similarity index 97%
rename from content/common/service_worker/service_worker_loader_helpers.cc
rename to third_party/blink/common/service_worker/service_worker_loader_helpers.cc
index 2d789de1..39cb0f45 100644
--- a/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/third_party/blink/common/service_worker/service_worker_loader_helpers.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/common/service_worker/service_worker_loader_helpers.h"
+#include "third_party/blink/public/common/service_worker/service_worker_loader_helpers.h"
 
 #include <limits>
 #include <memory>
@@ -22,7 +22,7 @@
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "ui/base/page_transition_types.h"
 
-namespace content {
+namespace blink {
 namespace {
 
 // Calls |callback| when Blob reading is complete.
@@ -171,4 +171,4 @@
   return net::OK;
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index f3d26cdc..30bea4c 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -195,6 +195,7 @@
     "security/protocol_handler_security_level.h",
     "security/security_style.h",
     "security_context/insecure_request_policy.h",
+    "service_worker/service_worker_loader_helpers.h",
     "service_worker/service_worker_scope_match.h",
     "service_worker/service_worker_status_code.h",
     "service_worker/service_worker_type_converters.h",
diff --git a/third_party/blink/public/common/net/ip_address_space_util.h b/third_party/blink/public/common/net/ip_address_space_util.h
index 0e21e6c..8521f73 100644
--- a/third_party/blink/public/common/net/ip_address_space_util.h
+++ b/third_party/blink/public/common/net/ip_address_space_util.h
@@ -13,7 +13,7 @@
 
 namespace net {
 
-class IPAddress;
+class IPEndPoint;
 
 }  // namespace net
 
@@ -43,7 +43,7 @@
     const GURL& url,
     const network::mojom::URLResponseHead* response_head);
 
-// Given a response URL and the IP address the requested resource was fetched
+// Given a response URL and the IP endpoint the requested resource was fetched
 // from, this function calculates the IPAddressSpace of the requested resource.
 //
 // As opposed to CalculateClientAddressSpace(), this function is used to
@@ -52,7 +52,7 @@
 //
 // See: https://wicg.github.io/cors-rfc1918/#integration-fetch
 network::mojom::IPAddressSpace BLINK_COMMON_EXPORT
-CalculateResourceAddressSpace(const GURL& url, const net::IPAddress& address);
+CalculateResourceAddressSpace(const GURL& url, const net::IPEndPoint& endpoint);
 
 }  // namespace blink
 
diff --git a/content/common/service_worker/service_worker_loader_helpers.h b/third_party/blink/public/common/service_worker/service_worker_loader_helpers.h
similarity index 80%
rename from content/common/service_worker/service_worker_loader_helpers.h
rename to third_party/blink/public/common/service_worker/service_worker_loader_helpers.h
index 5181455..4dbcd421 100644
--- a/content/common/service_worker/service_worker_loader_helpers.h
+++ b/third_party/blink/public/common/service_worker/service_worker_loader_helpers.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
-#define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
 
 #include "base/containers/flat_map.h"
 #include "base/optional.h"
@@ -11,6 +11,7 @@
 #include "net/http/http_request_headers.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/mojom/url_response_head.mojom-forward.h"
+#include "third_party/blink/public/common/common_export.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
 
@@ -18,11 +19,11 @@
 struct ResourceRequest;
 }
 
-namespace content {
+namespace blink {
 
 // Helper functions for service worker classes that use URLLoader
 //(e.g., ServiceWorkerMainResourceLoader and ServiceWorkerSubresourceLoader).
-class ServiceWorkerLoaderHelpers {
+class BLINK_COMMON_EXPORT ServiceWorkerLoaderHelpers {
  public:
   // Populates |out_head| with given |response|.
   static void SaveResponseInfo(const blink::mojom::FetchAPIResponse& response,
@@ -45,6 +46,6 @@
       mojo::ScopedDataPipeConsumerHandle* handle_out);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index d14942a8..5499345 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6495,6 +6495,58 @@
       boolean allowed
       optional PermissionsPolicyBlockLocator locator
 
+  # Origin Trial(https://www.chromium.org/blink/origin-trials) support.
+  # Status for an Origin Trial token.
+  experimental type OriginTrialTokenStatus extends string
+    enum
+      Success
+      NotSupported
+      Insecure
+      Expired
+      WrongOrigin
+      InvalidSignature
+      Malformed
+      WrongVersion
+      FeatureDisabled
+      TokenDisabled
+      FeatureDisabledForUser
+
+  # Status for an Origin Trial.
+  experimental type OriginTrialStatus extends string
+    enum
+      Enabled
+      ValidTokenNotProvided
+      OSNotSupported
+      TrialNotAllowed
+
+  experimental type OriginTrialUsageRestriction extends string
+    enum
+      None
+      Subset
+
+  experimental type OriginTrialToken extends object
+    properties
+      string origin
+      boolean matchSubDomains
+      string trialName
+      Network.TimeSinceEpoch expiryTime
+      boolean isThirdParty
+      OriginTrialUsageRestriction usageRestriction
+
+  experimental type OriginTrialTokenWithStatus extends object
+    properties
+      string rawTokenText
+      # `parsedToken` is present only when the token is extractable and
+      # parsable.
+      optional OriginTrialToken parsedToken
+      OriginTrialTokenStatus status
+
+  experimental type OriginTrial extends object
+    properties
+      string trialName
+      OriginTrialStatus status
+      array of OriginTrialTokenWithStatus tokensWithStatus
+
   # Information about the Frame on the page.
   type Frame extends object
     properties
@@ -6529,6 +6581,8 @@
       experimental CrossOriginIsolatedContextType crossOriginIsolatedContextType
       # Indicated which gated APIs / features are available.
       experimental array of GatedAPIFeatures gatedAPIFeatures
+      # Frame document's origin trials with at least one token present.
+      experimental optional array of OriginTrial originTrials
 
   # Information about the Resource on the page.
   experimental type FrameResource extends object
diff --git a/third_party/blink/public/strings/blink_strings.grd b/third_party/blink/public/strings/blink_strings.grd
index d2391ec..460fcf2 100644
--- a/third_party/blink/public/strings/blink_strings.grd
+++ b/third_party/blink/public/strings/blink_strings.grd
@@ -975,6 +975,14 @@
         hide closed captions menu
       </message>
 
+      <message name="IDS_AX_MEDIA_SHOW_PLAYBACK_SPEED_MENU_BUTTON" desc="Accessibility label for show playback speed menu button">
+        show playback speed menu
+      </message>
+
+      <message name="IDS_AX_MEDIA_HIDE_PLAYBACK_SPEED_MENU_BUTTON" desc="Accessibility label for hide playback speed menu button">
+        hide playback speed menu
+      </message>
+
       <message name="IDS_AX_MEDIA_CAST_OFF_BUTTON" desc="Accessibility label for remote playback button">
         play on remote device
       </message>
@@ -1211,6 +1219,36 @@
       <message name="IDS_MEDIA_OVERFLOW_MENU_CLOSED_CAPTIONS_SUBMENU_TITLE" desc="Media controls overflow menu title for the closed captions submenu. The text for this overflow menu should be short.">
         Options
       </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED" desc="Media controls overflow menu item label for a playback speed button. The text for this overflow menu should be short.">
+        Playback speed
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE" desc="Media controls overflow menu title for the playback speed submenu. The text for this overflow menu should be short.">
+        Options
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_25X_TITLE" desc="Media controls overflow menu title for the 0.25x playback speed. The text for this overflow menu should be short.">
+        0.25
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_5X_TITLE" desc="Media controls overflow menu title for the 0.5x playback speed. The text for this overflow menu should be short.">
+        0.5
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_75X_TITLE" desc="Media controls overflow menu title for the 0.75x playback speed. The text for this overflow menu should be short.">
+        0.75
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_NORMAL_TITLE" desc="Media controls overflow menu title for the normal playback speed. The text for this overflow menu should be short.">
+        Normal
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_25X_TITLE" desc="Media controls overflow menu title for the 1.25x playback speed. The text for this overflow menu should be short.">
+        1.25
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_5X_TITLE" desc="Media controls overflow menu title for the 1.5x playback speed. The text for this overflow menu should be short.">
+        1.5
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_75X_TITLE" desc="Media controls overflow menu title for the 1.75x playback speed. The text for this overflow menu should be short.">
+        1.75
+      </message>
+      <message name="IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_2X_TITLE" desc="Media controls overflow menu title for the double playback speed. The text for this overflow menu should be short.">
+        2
+      </message>
       <message name="IDS_MEDIA_OVERFLOW_MENU_CAST" desc="Media controls overflow menu item label for a cast button.">
         Cast
       </message>
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_HIDE_PLAYBACK_SPEED_MENU_BUTTON.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_HIDE_PLAYBACK_SPEED_MENU_BUTTON.png.sha1
new file mode 100644
index 0000000..65ae908
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_HIDE_PLAYBACK_SPEED_MENU_BUTTON.png.sha1
@@ -0,0 +1 @@
+2e1eda9c8ec6c243e7a2121fbdabf00e14b04843
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_SHOW_PLAYBACK_SPEED_MENU_BUTTON.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_SHOW_PLAYBACK_SPEED_MENU_BUTTON.png.sha1
new file mode 100644
index 0000000..7358c19
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_AX_MEDIA_SHOW_PLAYBACK_SPEED_MENU_BUTTON.png.sha1
@@ -0,0 +1 @@
+c546cf664019753eed458678855e490c04a6ecf8
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED.png.sha1
new file mode 100644
index 0000000..7358c19
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED.png.sha1
@@ -0,0 +1 @@
+c546cf664019753eed458678855e490c04a6ecf8
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_25X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_25X_TITLE.png.sha1
new file mode 100644
index 0000000..b0dd11c
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_25X_TITLE.png.sha1
@@ -0,0 +1 @@
+89a35e664259deef546fbd84263e293ac052f6fc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_5X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_5X_TITLE.png.sha1
new file mode 100644
index 0000000..b0dd11c
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_5X_TITLE.png.sha1
@@ -0,0 +1 @@
+89a35e664259deef546fbd84263e293ac052f6fc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_75X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_75X_TITLE.png.sha1
new file mode 100644
index 0000000..b0dd11c
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_75X_TITLE.png.sha1
@@ -0,0 +1 @@
+89a35e664259deef546fbd84263e293ac052f6fc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_25X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_25X_TITLE.png.sha1
new file mode 100644
index 0000000..bc0c13a6
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_25X_TITLE.png.sha1
@@ -0,0 +1 @@
+d9110ec468f6a639023d5dea606dd2b9e85f84bc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_5X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_5X_TITLE.png.sha1
new file mode 100644
index 0000000..bc0c13a6
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_5X_TITLE.png.sha1
@@ -0,0 +1 @@
+d9110ec468f6a639023d5dea606dd2b9e85f84bc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_75X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_75X_TITLE.png.sha1
new file mode 100644
index 0000000..bc0c13a6
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_75X_TITLE.png.sha1
@@ -0,0 +1 @@
+d9110ec468f6a639023d5dea606dd2b9e85f84bc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_2X_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_2X_TITLE.png.sha1
new file mode 100644
index 0000000..bc0c13a6
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_2X_TITLE.png.sha1
@@ -0,0 +1 @@
+d9110ec468f6a639023d5dea606dd2b9e85f84bc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_NORMAL_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_NORMAL_TITLE.png.sha1
new file mode 100644
index 0000000..b0dd11c
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_NORMAL_TITLE.png.sha1
@@ -0,0 +1 @@
+89a35e664259deef546fbd84263e293ac052f6fc
\ No newline at end of file
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE.png.sha1
new file mode 100644
index 0000000..65ae908
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE.png.sha1
@@ -0,0 +1 @@
+2e1eda9c8ec6c243e7a2121fbdabf00e14b04843
\ No newline at end of file
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
index b8a4c8c2..a2265de 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -1628,6 +1628,22 @@
 In case of `func2(...)` which adds `[DefaultValue=Undefined]`, if JavaScript calls `func2(100, 200)`, then it behaves as if JavaScript called `func2(100, 200, undefined)`. Consequently, `HTMLFoo::func2(int a, int b, int c)` is called in Blink. 100 is passed to `a`, 200 is passed to `b`, and 0 is passed to `c`. (A JavaScript `undefined` is converted to 0, following the value conversion rule in the Web IDL spec; if it were a DOMString parameter, it would end up as the string `"undefined"`.) In this way, Blink needs to just implement `func2(int a, int b, int c)` and needs not to implement both `func2(int a, int b)` and `func2(int a, int b, int c)`.
 
 
+### [DirectSocketEnabled] _(a, i, m)_
+
+Summary: Interfaces and interface members with a `DirectSocketEnabled` extended attribute are exposed only inside contexts whose [cross-origin isolated capability](https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-cross-origin-isolated-capability) is enabled, and when the [kDirectSocket](https://source.chromium.org/chromium/chromium/src/+/main:content/public/common/content_features.cc;drc=25b97f298830b78a443fd7cdfd0b3e190817d1dd;l=556) feature flag is enabled.
+
+Note that it's likely for these requirements to shift over time: <https://crbug.com/1206150>.
+
+Usage: The `[DirectSocketEnabled]` extended attribute may be specified on interfaces, attributes, and operations:
+
+```webidl
+[DirectSocketEnabled]
+interface TCPSocket {
+  ...
+};
+```
+
+
 ### [NoAllocDirectCall]
 
 Summary: `[NoAllocDirectCall]` marks a given method as being usable with the fast API calls implemented in V8. They get their value conversions inlined in TurboFan, leading to overall better performance.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 593e2e1..70f33a2 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3973,14 +3973,32 @@
 
   if (GetDocument().FocusedElement() == this &&
       GetDocument().GetFrame()->HasStickyUserActivation()) {
+    ChromeClient& chrome_client = GetDocument().GetPage()->GetChromeClient();
     // Bring up the keyboard in the context of anything triggered by a user
     // gesture. Since tracking that across arbitrary boundaries (eg.
     // animations) is difficult, for now we match IE's heuristic and bring
     // up the keyboard if there's been any gesture since load.
-    GetDocument()
-        .GetPage()
-        ->GetChromeClient()
-        .ShowVirtualKeyboardOnElementFocus(*GetDocument().GetFrame());
+    chrome_client.ShowVirtualKeyboardOnElementFocus(*GetDocument().GetFrame());
+
+    // Trigger a tooltip to show for the newly focused element only when the
+    // focus was set resulting from a keyboard action.
+    //
+    // TODO(bebeaudr): To also trigger a tooltip when the |params.type| is
+    // kSpatialNavigation, we'll first have to ensure that the fake mouse move
+    // event fired by `SpatialNavigationController::DispatchMouseMoveEvent` does
+    // not lead to a cursor triggered tooltip update. The only tooltip update
+    // that there should be in that case is the one triggered from the spatial
+    // navigation keypress. This issue is tracked in https://crbug.com/1206446.
+    switch (params.type) {
+      case mojom::blink::FocusType::kForward:
+      case mojom::blink::FocusType::kBackward:
+      case mojom::blink::FocusType::kAccessKey:
+        chrome_client.ElementFocusedFromKeypress(*GetDocument().GetFrame(),
+                                                 this);
+        break;
+      default:
+        break;
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc
index a189baf..1b8749a 100644
--- a/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -1056,13 +1056,30 @@
   TooltipCapturingChromeClient() = default;
 
   void SetToolTip(LocalFrame&, const String& str, TextDirection) override {
-    last_tool_tip_ = str;
+    last_tooltip_text_ = str;
+    // Always reset the bounds to zero as this function doesn't set bounds.
+    last_tooltip_bounds_ = gfx::Rect();
   }
 
-  String& LastToolTip() { return last_tool_tip_; }
+  void UpdateTooltipFromKeyboard(LocalFrame&,
+                                 const String& str,
+                                 TextDirection,
+                                 const gfx::Rect& bounds) override {
+    last_tooltip_text_ = str;
+    last_tooltip_bounds_ = bounds;
+  }
+
+  void ResetTooltip() {
+    last_tooltip_text_ = "";
+    last_tooltip_bounds_ = gfx::Rect();
+  }
+
+  const String& LastToolTipText() { return last_tooltip_text_; }
+  const gfx::Rect& LastToolTipBounds() { return last_tooltip_bounds_; }
 
  private:
-  String last_tool_tip_;
+  String last_tooltip_text_;
+  gfx::Rect last_tooltip_bounds_;
 };
 
 class EventHandlerTooltipTest : public EventHandlerTest {
@@ -1074,7 +1091,11 @@
     SetupPageWithClients(chrome_client_);
   }
 
-  String& LastToolTip() { return chrome_client_->LastToolTip(); }
+  const String& LastToolTipText() { return chrome_client_->LastToolTipText(); }
+  const gfx::Rect& LastToolTipBounds() {
+    return chrome_client_->LastToolTipBounds();
+  }
+  void ResetTooltip() { chrome_client_->ResetTooltip(); }
 
  private:
   Persistent<TooltipCapturingChromeClient> chrome_client_;
@@ -1086,7 +1107,7 @@
       "<style>.box { width: 100%; height: 100%; }</style>"
       "<img src='image.png' class='box' title='tooltip'>link</img>");
 
-  EXPECT_EQ(WTF::String(), LastToolTip());
+  EXPECT_EQ(WTF::String(), LastToolTipText());
 
   WebMouseEvent mouse_move_event(
       WebInputEvent::Type::kMouseMove, gfx::PointF(51, 50), gfx::PointF(51, 50),
@@ -1096,7 +1117,7 @@
   GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
       mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
 
-  EXPECT_EQ("tooltip", LastToolTip());
+  EXPECT_EQ("tooltip", LastToolTipText());
 
   WebMouseEvent mouse_leave_event(
       WebInputEvent::Type::kMouseLeave, gfx::PointF(0, 0), gfx::PointF(0, 0),
@@ -1106,7 +1127,94 @@
   GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent(
       mouse_leave_event);
 
-  EXPECT_EQ(WTF::String(), LastToolTip());
+  EXPECT_EQ(WTF::String(), LastToolTipText());
+}
+
+// macOS doesn't have keyboard-triggered tooltips.
+#if defined(OS_MAC)
+#define MAYBE_FocusSetFromKeyboardUpdatesTooltip \
+  DISABLED_FocusSetFromKeyboardUpdatesTooltip
+#else
+#define MAYBE_FocusSetFromKeyboardUpdatesTooltip \
+  FocusSetFromKeyboardUpdatesTooltip
+#endif
+TEST_F(EventHandlerTooltipTest, MAYBE_FocusSetFromKeyboardUpdatesTooltip) {
+  SetHtmlInnerHTML(
+      "<button id='b1' title='my tooltip 1'>button 1</button><button id='b2' "
+      "title='my tooltip 2' accessKey='a'>button 2</button>");
+
+  EXPECT_EQ(WTF::String(), LastToolTipText());
+  EXPECT_EQ(gfx::Rect(), LastToolTipBounds());
+
+  // 1. Moving the focus with the tab key should trigger a tooltip update.
+  {
+    WebKeyboardEvent e{WebInputEvent::Type::kRawKeyDown,
+                       WebInputEvent::kNoModifiers,
+                       WebInputEvent::GetStaticTimeStampForTests()};
+    e.dom_code = static_cast<int>(ui::DomCode::TAB);
+    e.dom_key = ui::DomKey::TAB;
+    GetDocument().GetFrame()->GetEventHandler().KeyEvent(e);
+
+    Element* element = GetDocument().getElementById("b1");
+    EXPECT_EQ("my tooltip 1", LastToolTipText());
+    EXPECT_EQ(element->BoundsInViewport(), LastToolTipBounds());
+  }
+
+  ResetTooltip();
+
+  // 2. Moving the focus by pressing the access key on button should trigger a
+  // tooltip update.
+  {
+    WebKeyboardEvent e{WebInputEvent::Type::kRawKeyDown, WebInputEvent::kAltKey,
+                       WebInputEvent::GetStaticTimeStampForTests()};
+    e.unmodified_text[0] = 'a';
+    GetDocument().GetFrame()->GetEventHandler().HandleAccessKey(e);
+
+    Element* element = GetDocument().getElementById("b2");
+    EXPECT_EQ("my tooltip 2", LastToolTipText());
+    EXPECT_EQ(element->BoundsInViewport(), LastToolTipBounds());
+  }
+
+  ResetTooltip();
+
+  // 3. Moving the focus by pressing a directional arrow while spatial
+  // navigation is enabled should trigger a tooltip update.
+  {
+    // TODO(bebeaudr): Implement this once we support updating a tooltip with
+    // spatial navigation.
+  }
+
+  ResetTooltip();
+
+  // 4. Moving the focus to an element with a mouse action shouldn't update the
+  // tooltip.
+  {
+    Element* element = GetDocument().getElementById("b1");
+    gfx::PointF mouse_press_point =
+        gfx::PointF(element->BoundsInViewport().Center());
+    WebMouseEvent mouse_press_event(
+        WebInputEvent::Type::kMouseDown, mouse_press_point, mouse_press_point,
+        WebPointerProperties::Button::kLeft, 1,
+        WebInputEvent::Modifiers::kLeftButtonDown, base::TimeTicks::Now());
+    mouse_press_event.SetFrameScale(1);
+    GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
+        mouse_press_event);
+
+    EXPECT_EQ("", LastToolTipText());
+    EXPECT_EQ(gfx::Rect(), LastToolTipBounds());
+  }
+
+  ResetTooltip();
+
+  // 5. Setting the focus to an element with a script action (FocusType::kNone
+  // means that the focus was set from a script) shouldn't update the tooltip.
+  {
+    Element* element = GetDocument().getElementById("b2");
+    element->focus();
+
+    EXPECT_EQ("", LastToolTipText());
+    EXPECT_EQ(gfx::Rect(), LastToolTipBounds());
+  }
 }
 
 class UnbufferedInputEventsTrackingChromeClient : public EmptyChromeClient {
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index b3146dc..569747cd 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -35,6 +35,7 @@
 
 #include "base/containers/span.h"
 #include "build/build_config.h"
+#include "third_party/blink/public/common/origin_trials/trial_token.h"
 #include "third_party/blink/public/common/widget/screen_info.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
@@ -68,6 +69,7 @@
 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
 #include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/script_resource.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.h"
@@ -1211,6 +1213,120 @@
   return features;
 }
 
+protocol::Page::OriginTrialTokenStatus CreateOriginTrialTokenStatus(
+    blink::OriginTrialTokenStatus status) {
+  switch (status) {
+    case blink::OriginTrialTokenStatus::kSuccess:
+      return protocol::Page::OriginTrialTokenStatusEnum::Success;
+    case blink::OriginTrialTokenStatus::kNotSupported:
+      return protocol::Page::OriginTrialTokenStatusEnum::NotSupported;
+    case blink::OriginTrialTokenStatus::kInsecure:
+      return protocol::Page::OriginTrialTokenStatusEnum::Insecure;
+    case blink::OriginTrialTokenStatus::kExpired:
+      return protocol::Page::OriginTrialTokenStatusEnum::Expired;
+    case blink::OriginTrialTokenStatus::kWrongOrigin:
+      return protocol::Page::OriginTrialTokenStatusEnum::WrongOrigin;
+    case blink::OriginTrialTokenStatus::kInvalidSignature:
+      return protocol::Page::OriginTrialTokenStatusEnum::InvalidSignature;
+    case blink::OriginTrialTokenStatus::kMalformed:
+      return protocol::Page::OriginTrialTokenStatusEnum::Malformed;
+    case blink::OriginTrialTokenStatus::kWrongVersion:
+      return protocol::Page::OriginTrialTokenStatusEnum::WrongVersion;
+    case blink::OriginTrialTokenStatus::kFeatureDisabled:
+      return protocol::Page::OriginTrialTokenStatusEnum::FeatureDisabled;
+    case blink::OriginTrialTokenStatus::kTokenDisabled:
+      return protocol::Page::OriginTrialTokenStatusEnum::TokenDisabled;
+    case blink::OriginTrialTokenStatus::kFeatureDisabledForUser:
+      return protocol::Page::OriginTrialTokenStatusEnum::FeatureDisabledForUser;
+  }
+}
+
+protocol::Page::OriginTrialStatus CreateOriginTrialStatus(
+    blink::OriginTrialStatus status) {
+  switch (status) {
+    case blink::OriginTrialStatus::kEnabled:
+      return protocol::Page::OriginTrialStatusEnum::Enabled;
+    case blink::OriginTrialStatus::kValidTokenNotProvided:
+      return protocol::Page::OriginTrialStatusEnum::ValidTokenNotProvided;
+    case blink::OriginTrialStatus::kOSNotSupported:
+      return protocol::Page::OriginTrialStatusEnum::OSNotSupported;
+    case blink::OriginTrialStatus::kTrialNotAllowed:
+      return protocol::Page::OriginTrialStatusEnum::TrialNotAllowed;
+  }
+}
+
+protocol::Page::OriginTrialUsageRestriction CreateOriginTrialUsageRestriction(
+    blink::TrialToken::UsageRestriction blink_restriction) {
+  switch (blink_restriction) {
+    case blink::TrialToken::UsageRestriction::kNone:
+      return protocol::Page::OriginTrialUsageRestrictionEnum::None;
+    case blink::TrialToken::UsageRestriction::kSubset:
+      return protocol::Page::OriginTrialUsageRestrictionEnum::Subset;
+  }
+}
+
+std::unique_ptr<protocol::Page::OriginTrialToken> CreateOriginTrialToken(
+    const blink::TrialToken& blink_trial_token) {
+  return protocol::Page::OriginTrialToken::create()
+      .setOrigin(SecurityOrigin::CreateFromUrlOrigin(blink_trial_token.origin())
+                     ->ToRawString())
+      .setIsThirdParty(blink_trial_token.is_third_party())
+      .setMatchSubDomains(blink_trial_token.match_subdomains())
+      .setExpiryTime(blink_trial_token.expiry_time().ToDoubleT())
+      .setTrialName(blink_trial_token.feature_name().c_str())
+      .setUsageRestriction(CreateOriginTrialUsageRestriction(
+          blink_trial_token.usage_restriction()))
+      .build();
+}
+
+std::unique_ptr<protocol::Page::OriginTrialTokenWithStatus>
+CreateOriginTrialTokenWithStatus(
+    const blink::OriginTrialTokenResult& blink_token_result) {
+  auto result =
+      protocol::Page::OriginTrialTokenWithStatus::create()
+          .setRawTokenText(blink_token_result.raw_token)
+          .setStatus(CreateOriginTrialTokenStatus(blink_token_result.status))
+          .build();
+
+  if (blink_token_result.parsed_token.has_value()) {
+    result->setParsedToken(
+        CreateOriginTrialToken(*blink_token_result.parsed_token));
+  }
+  return result;
+}
+
+std::unique_ptr<protocol::Page::OriginTrial> CreateOriginTrial(
+    const blink::OriginTrialResult& blink_trial_result) {
+  auto tokens_with_status = std::make_unique<
+      protocol::Array<protocol::Page::OriginTrialTokenWithStatus>>();
+
+  for (const auto& blink_token_result : blink_trial_result.token_results) {
+    tokens_with_status->push_back(
+        CreateOriginTrialTokenWithStatus(blink_token_result));
+  }
+
+  return protocol::Page::OriginTrial::create()
+      .setTrialName(blink_trial_result.trial_name)
+      .setStatus(CreateOriginTrialStatus(blink_trial_result.status))
+      .setTokensWithStatus(std::move(tokens_with_status))
+      .build();
+}
+
+std::unique_ptr<protocol::Array<protocol::Page::OriginTrial>>
+CreateOriginTrials(LocalDOMWindow* window) {
+  auto trials =
+      std::make_unique<protocol::Array<protocol::Page::OriginTrial>>();
+  // Note: `blink::OriginTrialContext` is initialized when
+  // `blink::ExecutionContext` is created. `GetOriginTrialContext()` should
+  // not return nullptr.
+  const blink::OriginTrialContext* context = window->GetOriginTrialContext();
+  DCHECK(context);
+  for (const auto& entry : context->GetOriginTrialResultsForDevtools()) {
+    trials->push_back(CreateOriginTrial(entry.value));
+  }
+  return trials;
+}
+
 }  // namespace
 
 std::unique_ptr<protocol::Page::Frame> InspectorPageAgent::BuildObjectForFrame(
@@ -1257,6 +1373,9 @@
   } else {
     frame_object->setAdFrameType(protocol::Page::AdFrameTypeEnum::None);
   }
+  auto origin_trials = CreateOriginTrials(frame->DomWindow());
+  if (!origin_trials->empty())
+    frame_object->setOriginTrials(std::move(origin_trials));
   return frame_object;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 30cc03d..baff7c4 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -225,10 +225,16 @@
       // will be re-inserted after us.
       if (LayoutBlock* cb = ContainingBlock()) {
         cb->RemovePositionedObjects(this, kNewContainingBlock);
-        if (IsOutOfFlowPositioned()) {
+        if (IsOutOfFlowPositioned() && !cb->IsLayoutNGObject()) {
           // Insert this object into containing block's positioned descendants
           // list in case the parent won't layout. This is needed especially
           // there are descendants scheduled for overflow recalc.
+          //
+          // Only do this if the containing block is a legacy object, to let
+          // LayoutNG decide when to insert positioned objects. In particular,
+          // we don't want that if the OOF participates in block fragmentation,
+          // since an OOF will then be laid out as a child of a fragmentainer,
+          // rather than its actual containing block.
           cb->InsertPositionedObject(this);
         }
       }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index f2e16a77..6c28ca1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -2170,14 +2170,13 @@
 
 void NGBlockLayoutAlgorithm::FinalizeForTableCell(
     LayoutUnit unconstrained_intrinsic_block_size) {
-  const bool has_inflow_children = !container_builder_.Children().IsEmpty();
-
   // Hide table-cells if:
   //  - They are within a collapsed column(s).
   //  - They have "empty-cells: hide", non-collapsed borders, and no children.
   container_builder_.SetIsHiddenForPaint(
       ConstraintSpace().IsTableCellHiddenForPaint() ||
-      (ConstraintSpace().HideTableCellIfEmpty() && !has_inflow_children));
+      (ConstraintSpace().HideTableCellIfEmpty() &&
+       container_builder_.Children().IsEmpty()));
 
   container_builder_.SetHasCollapsedBorders(
       ConstraintSpace().IsTableCellWithCollapsedBorders());
@@ -2213,14 +2212,10 @@
                                        BorderScrollbarPadding().block_end);
       }
 
-      // Only adjust if we have *inflow* children. If we only have
-      // OOF-positioned children don't align them to the alignment baseline.
-      if (has_inflow_children) {
-        if (auto alignment_baseline =
-                ConstraintSpace().TableCellAlignmentBaseline()) {
-          container_builder_.MoveChildrenInBlockDirection(
-              *alignment_baseline - *container_builder_.Baseline());
-        }
+      if (auto alignment_baseline =
+              ConstraintSpace().TableCellAlignmentBaseline()) {
+        container_builder_.MoveChildrenInBlockDirection(
+            *alignment_baseline - *container_builder_.Baseline());
       }
       break;
     case EVerticalAlign::kMiddle:
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index e20a85d..280993b 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -186,6 +186,10 @@
   void ContentsSizeChanged(LocalFrame*, const IntSize&) const override {}
   void ShowMouseOverURL(const HitTestResult&) override {}
   void SetToolTip(LocalFrame&, const String&, TextDirection) override {}
+  void UpdateTooltipFromKeyboard(LocalFrame&,
+                                 const String&,
+                                 TextDirection,
+                                 const gfx::Rect&) override {}
   void PrintDelegate(LocalFrame*) override {}
   ColorChooser* OpenColorChooser(LocalFrame*,
                                  ColorChooserClient*,
diff --git a/third_party/blink/renderer/core/page/chrome_client.cc b/third_party/blink/renderer/core/page/chrome_client.cc
index a4ee25fc..acd7505 100644
--- a/third_party/blink/renderer/core/page/chrome_client.cc
+++ b/third_party/blink/renderer/core/page/chrome_client.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/page/frame_tree.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
@@ -285,6 +286,20 @@
   SetToolTip(frame, tool_tip, tool_tip_direction);
 }
 
+void ChromeClient::ElementFocusedFromKeypress(LocalFrame& frame,
+                                              const Element* element) {
+  String tooltip_text = element->title();
+  if (tooltip_text.IsNull())
+    tooltip_text = element->DefaultToolTip();
+
+  LayoutObject* layout_object = element->GetLayoutObject();
+  if (!tooltip_text.IsNull() && layout_object) {
+    TextDirection tooltip_direction = layout_object->StyleRef().Direction();
+    UpdateTooltipFromKeyboard(frame, tooltip_text, tooltip_direction,
+                              element->BoundsInViewport());
+  }
+}
+
 void ChromeClient::ClearToolTip(LocalFrame& frame) {
   current_tool_tip_text_for_test_ = String();
   // Do not check last_tool_tip_* and do not update them intentionally.
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h
index c441be81..899bf76 100644
--- a/third_party/blink/renderer/core/page/chrome_client.h
+++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -342,6 +342,16 @@
                                const HitTestLocation&,
                                const HitTestResult&);
   virtual void SetToolTip(LocalFrame&, const String&, TextDirection) = 0;
+  void ElementFocusedFromKeypress(LocalFrame&, const Element*);
+  // This function allows us to trigger a tooltip to show from a keypress. The
+  // tooltip will be positioned in the gfx::Rect passed by parameter. That rect
+  // corresponds to the focused element's bounds, which are in viewport
+  // coordinates at this point. They will be converted to enclosed DIPS before
+  // being passed to the browser process.
+  virtual void UpdateTooltipFromKeyboard(LocalFrame&,
+                                         const String&,
+                                         TextDirection,
+                                         const gfx::Rect&) = 0;
   void ClearToolTip(LocalFrame&);
   String GetLastToolTipTextForTesting() {
     return current_tool_tip_text_for_test_;
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index 8c725af..b576c6d8 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -559,6 +559,16 @@
   }
 }
 
+void ChromeClientImpl::UpdateTooltipFromKeyboard(LocalFrame& frame,
+                                                 const String& tooltip_text,
+                                                 TextDirection dir,
+                                                 const gfx::Rect& bounds) {
+  if (!RuntimeEnabledFeatures::KeyboardAccessibleTooltipEnabled())
+    return;
+
+  // TODO(bebeaudr): Add WidgetHost function and call it here.
+}
+
 void ChromeClientImpl::DispatchViewportPropertiesDidChange(
     const ViewportDescription& description) const {
   web_view_->UpdatePageDefinedViewportConstraints(description);
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h
index bf2c4a2..b6d23d6 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -152,6 +152,10 @@
   void MainFrameLayoutUpdated() const override;
   void ShowMouseOverURL(const HitTestResult&) override;
   void SetToolTip(LocalFrame&, const String&, TextDirection) override;
+  void UpdateTooltipFromKeyboard(LocalFrame&,
+                                 const String&,
+                                 TextDirection,
+                                 const gfx::Rect&) override;
   void DispatchViewportPropertiesDidChange(
       const ViewportDescription&) const override;
   void PrintDelegate(LocalFrame*) override;
diff --git a/third_party/blink/renderer/modules/media_controls/BUILD.gn b/third_party/blink/renderer/modules/media_controls/BUILD.gn
index d3045881..54bed7a 100644
--- a/third_party/blink/renderer/modules/media_controls/BUILD.gn
+++ b/third_party/blink/renderer/modules/media_controls/BUILD.gn
@@ -57,6 +57,10 @@
     "elements/media_control_picture_in_picture_button_element.h",
     "elements/media_control_play_button_element.cc",
     "elements/media_control_play_button_element.h",
+    "elements/media_control_playback_speed_button_element.cc",
+    "elements/media_control_playback_speed_button_element.h",
+    "elements/media_control_playback_speed_list_element.cc",
+    "elements/media_control_playback_speed_list_element.h",
     "elements/media_control_popup_menu_element.cc",
     "elements/media_control_popup_menu_element.h",
     "elements/media_control_remaining_time_display_element.cc",
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
index 93e60ae..28194b7 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
@@ -42,10 +42,12 @@
 void MediaControlOverflowMenuListElement::SetIsWanted(bool wanted) {
   MediaControlPopupMenuElement::SetIsWanted(wanted);
 
-  if (wanted)
+  if (wanted) {
     OpenOverflowMenu();
-  else if (!GetMediaControls().TextTrackListIsWanted())
+  } else if (!GetMediaControls().TextTrackListIsWanted() &&
+             !GetMediaControls().PlaybackSpeedListIsWanted()) {
     CloseOverflowMenu();
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.cc
new file mode 100644
index 0000000..a726773
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.cc
@@ -0,0 +1,54 @@
+// 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 "third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.h"
+
+#include "third_party/blink/public/strings/grit/blink_strings.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
+#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+#include "third_party/blink/renderer/platform/language.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
+
+namespace blink {
+
+MediaControlPlaybackSpeedButtonElement::MediaControlPlaybackSpeedButtonElement(
+    MediaControlsImpl& media_controls)
+    : MediaControlInputElement(media_controls) {
+  setAttribute(html_names::kAriaLabelAttr,
+               WTF::AtomicString(GetLocale().QueryString(
+                   IDS_AX_MEDIA_SHOW_PLAYBACK_SPEED_MENU_BUTTON)));
+  setType(input_type_names::kButton);
+  SetShadowPseudoId(
+      AtomicString("-internal-media-controls-playback-speed-button"));
+}
+
+bool MediaControlPlaybackSpeedButtonElement::WillRespondToMouseClickEvents() {
+  return true;
+}
+
+int MediaControlPlaybackSpeedButtonElement::GetOverflowStringId() const {
+  return IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED;
+}
+
+bool MediaControlPlaybackSpeedButtonElement::HasOverflowButton() const {
+  return true;
+}
+
+const char* MediaControlPlaybackSpeedButtonElement::GetNameForHistograms()
+    const {
+  return IsOverflowElement() ? "PlaybackSpeedOverflowButton"
+                             : "PlaybackSpeedButton";
+}
+
+void MediaControlPlaybackSpeedButtonElement::DefaultEventHandler(Event& event) {
+  if (event.type() == event_type_names::kClick ||
+      event.type() == event_type_names::kGesturetap) {
+    GetMediaControls().TogglePlaybackSpeedList();
+  }
+  MediaControlInputElement::DefaultEventHandler(event);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.h
new file mode 100644
index 0000000..69a92212
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.h
@@ -0,0 +1,35 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_BUTTON_ELEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_BUTTON_ELEMENT_H_
+
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class Event;
+class MediaControlsImpl;
+
+class MODULES_EXPORT MediaControlPlaybackSpeedButtonElement final
+    : public MediaControlInputElement {
+ public:
+  explicit MediaControlPlaybackSpeedButtonElement(MediaControlsImpl&);
+
+  // MediaControlInputElement overrides.
+  bool WillRespondToMouseClickEvents() override;
+  int GetOverflowStringId() const override;
+  bool HasOverflowButton() const override;
+
+ protected:
+  const char* GetNameForHistograms() const override;
+
+ private:
+  void DefaultEventHandler(Event&) override;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_BUTTON_ELEMENT_H_
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc
new file mode 100644
index 0000000..435855b
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc
@@ -0,0 +1,173 @@
+// 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 "third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h"
+
+#include "third_party/blink/public/strings/grit/blink_strings.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
+#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
+#include "third_party/blink/renderer/core/html/html_span_element.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
+#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
+
+namespace blink {
+
+namespace {
+
+struct PlaybackSpeed {
+  const int display_name;
+  const double playback_rate;
+};
+
+static const PlaybackSpeed kPlaybackSpeeds[] = {
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_25X_TITLE, 0.25},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_5X_TITLE, 0.5},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_0_75X_TITLE, 0.75},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_NORMAL_TITLE, 1.0},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_25X_TITLE, 1.25},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_5X_TITLE, 1.5},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_1_75X_TITLE, 1.75},
+    {IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_2X_TITLE, 2.0}};
+
+const QualifiedName& PlaybackRateAttrName() {
+  // Save the playback rate in an attribute.
+  DEFINE_STATIC_LOCAL(QualifiedName, playback_rate_attr,
+                      (g_null_atom, "data-playback-rate", g_null_atom));
+  return playback_rate_attr;
+}
+
+}  // anonymous namespace
+
+MediaControlPlaybackSpeedListElement::MediaControlPlaybackSpeedListElement(
+    MediaControlsImpl& media_controls)
+    : MediaControlPopupMenuElement(media_controls) {
+  setAttribute(html_names::kRoleAttr, "menu");
+  setAttribute(html_names::kAriaLabelAttr,
+               WTF::AtomicString(GetLocale().QueryString(
+                   IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE)));
+  SetShadowPseudoId(
+      AtomicString("-internal-media-controls-playback-speed-list"));
+}
+
+bool MediaControlPlaybackSpeedListElement::WillRespondToMouseClickEvents() {
+  return true;
+}
+
+void MediaControlPlaybackSpeedListElement::SetIsWanted(bool wanted) {
+  if (wanted)
+    RefreshPlaybackSpeedListMenu();
+
+  if (!wanted && !GetMediaControls().OverflowMenuIsWanted())
+    GetMediaControls().CloseOverflowMenu();
+
+  MediaControlPopupMenuElement::SetIsWanted(wanted);
+}
+
+void MediaControlPlaybackSpeedListElement::DefaultEventHandler(Event& event) {
+  if (event.type() == event_type_names::kClick) {
+    // This handles the back button click. Clicking on a menu item triggers the
+    // change event instead.
+    GetMediaControls().ToggleOverflowMenu();
+    event.SetDefaultHandled();
+  } else if (event.type() == event_type_names::kChange) {
+    // Identify which input element was selected and update playback speed
+    Node* target = event.target()->ToNode();
+    if (!target || !target->IsElementNode())
+      return;
+
+    double playback_rate =
+        To<Element>(target)->GetFloatingPointAttribute(PlaybackRateAttrName());
+    MediaElement().setPlaybackRate(playback_rate);
+
+    // Close the playback speed list.
+    SetIsWanted(false);
+    event.SetDefaultHandled();
+  }
+  MediaControlPopupMenuElement::DefaultEventHandler(event);
+}
+
+Element* MediaControlPlaybackSpeedListElement::CreatePlaybackSpeedListItem(
+    const int display_name,
+    const double playback_rate) {
+  auto* playback_speed_item =
+      MakeGarbageCollected<HTMLLabelElement>(GetDocument());
+  playback_speed_item->SetShadowPseudoId(
+      AtomicString("-internal-media-controls-playback-speed-list-item"));
+  auto* playback_speed_item_input = MakeGarbageCollected<HTMLInputElement>(
+      GetDocument(), CreateElementFlags());
+  playback_speed_item_input->SetShadowPseudoId(
+      AtomicString("-internal-media-controls-playback-speed-list-item-input"));
+  playback_speed_item_input->setAttribute(html_names::kAriaHiddenAttr, "true");
+  playback_speed_item_input->setType(input_type_names::kCheckbox);
+  playback_speed_item_input->SetFloatingPointAttribute(PlaybackRateAttrName(),
+                                                       playback_rate);
+  if (playback_rate == MediaElement().playbackRate()) {
+    playback_speed_item_input->setChecked(true);
+    playback_speed_item->setAttribute(html_names::kAriaCheckedAttr, "true");
+  }
+  // Allows to focus the list entry instead of the button.
+  playback_speed_item->setTabIndex(0);
+  playback_speed_item_input->setTabIndex(-1);
+
+  // Set playback speed label into an aria-hidden span so that aria will not
+  // repeat the contents twice.
+  auto playback_speed_label = GetLocale().QueryString(display_name);
+  auto* playback_speed_label_span =
+      MakeGarbageCollected<HTMLSpanElement>(GetDocument());
+  playback_speed_label_span->setInnerText(playback_speed_label,
+                                          ASSERT_NO_EXCEPTION);
+  playback_speed_label_span->setAttribute(html_names::kAriaHiddenAttr, "true");
+  playback_speed_item->setAttribute(html_names::kAriaLabelAttr,
+                                    WTF::AtomicString(playback_speed_label));
+  playback_speed_item->ParserAppendChild(playback_speed_label_span);
+  playback_speed_item->ParserAppendChild(playback_speed_item_input);
+
+  return playback_speed_item;
+}
+
+Element* MediaControlPlaybackSpeedListElement::CreatePlaybackSpeedHeaderItem() {
+  auto* header_item = MakeGarbageCollected<HTMLLabelElement>(GetDocument());
+  header_item->SetShadowPseudoId(
+      "-internal-media-controls-playback-speed-list-header");
+  header_item->ParserAppendChild(
+      Text::Create(GetDocument(),
+                   GetLocale().QueryString(
+                       IDS_MEDIA_OVERFLOW_MENU_PLAYBACK_SPEED_SUBMENU_TITLE)));
+  header_item->setAttribute(html_names::kRoleAttr, "button");
+  header_item->setAttribute(html_names::kAriaLabelAttr,
+                            AtomicString(GetLocale().QueryString(
+                                IDS_AX_MEDIA_HIDE_PLAYBACK_SPEED_MENU_BUTTON)));
+  header_item->setTabIndex(0);
+  return header_item;
+}
+
+void MediaControlPlaybackSpeedListElement::RefreshPlaybackSpeedListMenu() {
+  EventDispatchForbiddenScope::AllowUserAgentEvents allow_events;
+  RemoveChildren(kOmitSubtreeModifiedEvent);
+
+  ParserAppendChild(CreatePlaybackSpeedHeaderItem());
+
+  // Construct a menu for playback speeds.
+  for (unsigned i = 0; i < base::size(kPlaybackSpeeds); i++) {
+    auto& playback_speed = kPlaybackSpeeds[i];
+    auto* playback_speed_item = CreatePlaybackSpeedListItem(
+        playback_speed.display_name, playback_speed.playback_rate);
+    playback_speed_item->setAttribute(
+        html_names::kAriaSetsizeAttr,
+        WTF::AtomicString::Number(base::size(kPlaybackSpeeds) + 1));
+    playback_speed_item->setAttribute(html_names::kAriaPosinsetAttr,
+                                      WTF::AtomicString::Number(i + 1));
+    playback_speed_item->setAttribute(html_names::kRoleAttr,
+                                      "menuitemcheckbox");
+    ParserAppendChild(playback_speed_item);
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h
new file mode 100644
index 0000000..ff76bcf
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h
@@ -0,0 +1,40 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_LIST_ELEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_LIST_ELEMENT_H_
+
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h"
+
+namespace blink {
+
+class Event;
+class MediaControlsImpl;
+
+class MediaControlPlaybackSpeedListElement final
+    : public MediaControlPopupMenuElement {
+ public:
+  explicit MediaControlPlaybackSpeedListElement(MediaControlsImpl&);
+
+  // Node interface.
+  bool WillRespondToMouseClickEvents() override;
+
+  void SetIsWanted(bool) final;
+
+ private:
+  void DefaultEventHandler(Event&) override;
+
+  void RefreshPlaybackSpeedListMenu();
+
+  // Creates the playback speed element in the list.
+  Element* CreatePlaybackSpeedListItem(const int display_name,
+                                       const double playback_rate);
+
+  // Creates the header element of the playback speed list.
+  Element* CreatePlaybackSpeedHeaderItem();
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PLAYBACK_SPEED_LIST_ELEMENT_H_
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 071e0572..858a14e9 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -74,6 +74,8 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_panel_enclosure_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_picture_in_picture_button_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_button_element.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_scrubbing_message_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.h"
@@ -332,6 +334,8 @@
       volume_control_container_(nullptr),
       toggle_closed_captions_button_(nullptr),
       text_track_list_(nullptr),
+      playback_speed_button_(nullptr),
+      playback_speed_list_(nullptr),
       overflow_list_(nullptr),
       media_button_panel_(nullptr),
       loading_panel_(nullptr),
@@ -557,6 +561,8 @@
   toggle_closed_captions_button_ =
       MakeGarbageCollected<MediaControlToggleClosedCaptionsButtonElement>(
           *this);
+  playback_speed_button_ =
+      MakeGarbageCollected<MediaControlPlaybackSpeedButtonElement>(*this);
   overflow_menu_ =
       MakeGarbageCollected<MediaControlOverflowMenuButtonElement>(*this);
 
@@ -569,6 +575,10 @@
       MakeGarbageCollected<MediaControlTextTrackListElement>(*this);
   ParserAppendChild(text_track_list_);
 
+  playback_speed_list_ =
+      MakeGarbageCollected<MediaControlPlaybackSpeedListElement>(*this);
+  ParserAppendChild(playback_speed_list_);
+
   overflow_list_ =
       MakeGarbageCollected<MediaControlOverflowMenuListElement>(*this);
   ParserAppendChild(overflow_list_);
@@ -591,6 +601,9 @@
       toggle_closed_captions_button_->CreateOverflowElement(
           MakeGarbageCollected<MediaControlToggleClosedCaptionsButtonElement>(
               *this)));
+  overflow_list_->ParserAppendChild(
+      playback_speed_button_->CreateOverflowElement(
+          MakeGarbageCollected<MediaControlPlaybackSpeedButtonElement>(*this)));
   if (picture_in_picture_button_) {
     overflow_list_->ParserAppendChild(
         picture_in_picture_button_->CreateOverflowElement(
@@ -1049,7 +1062,8 @@
   }
 
   // Don't hide the media controls when a panel is showing.
-  if (text_track_list_->IsWanted() || overflow_list_->IsWanted())
+  if (text_track_list_->IsWanted() || playback_speed_list_->IsWanted() ||
+      overflow_list_->IsWanted())
     return false;
 
   // Don't hide if we have accessiblity focus.
@@ -1135,6 +1149,14 @@
   return text_track_list_->IsWanted();
 }
 
+void MediaControlsImpl::TogglePlaybackSpeedList() {
+  playback_speed_list_->SetIsWanted(!playback_speed_list_->IsWanted());
+}
+
+bool MediaControlsImpl::PlaybackSpeedListIsWanted() {
+  return playback_speed_list_->IsWanted();
+}
+
 MediaControlsTextTrackManager& MediaControlsImpl::GetTextTrackManager() {
   return *text_track_manager_;
 }
@@ -1220,6 +1242,7 @@
       std::make_pair(cast_button_.Get(), false),
       std::make_pair(download_button_.Get(), false),
       std::make_pair(toggle_closed_captions_button_.Get(), false),
+      std::make_pair(playback_speed_button_.Get(), false),
   };
 
   // These are the elements in order of priority that take up vertical room.
@@ -1948,6 +1971,7 @@
       mute_button_.Get(),
       volume_slider_.Get(),
       toggle_closed_captions_button_.Get(),
+      playback_speed_button_.Get(),
       picture_in_picture_button_.Get(),
       cast_button_.Get(),
       current_time_display_.Get(),
@@ -2061,6 +2085,9 @@
 
   if (TextTrackListIsWanted())
     ToggleTextTrackList();
+
+  if (PlaybackSpeedListIsWanted())
+    TogglePlaybackSpeedList();
 }
 
 void MediaControlsImpl::VolumeSliderWantedTimerFired(TimerBase*) {
@@ -2147,11 +2174,13 @@
   visitor->Trace(picture_in_picture_button_);
   visitor->Trace(animated_arrow_container_element_);
   visitor->Trace(toggle_closed_captions_button_);
+  visitor->Trace(playback_speed_button_);
   visitor->Trace(fullscreen_button_);
   visitor->Trace(download_button_);
   visitor->Trace(duration_display_);
   visitor->Trace(enclosure_);
   visitor->Trace(text_track_list_);
+  visitor->Trace(playback_speed_list_);
   visitor->Trace(overflow_menu_);
   visitor->Trace(overflow_list_);
   visitor->Trace(cast_button_);
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
index 40bb414..e64e1ec5e 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -59,6 +59,8 @@
 class MediaControlPanelElement;
 class MediaControlPanelEnclosureElement;
 class MediaControlPictureInPictureButtonElement;
+class MediaControlPlaybackSpeedButtonElement;
+class MediaControlPlaybackSpeedListElement;
 class MediaControlPlayButtonElement;
 class MediaControlRemainingTimeDisplayElement;
 class MediaControlScrubbingMessageElement;
@@ -128,6 +130,10 @@
   bool TextTrackListIsWanted();
   MediaControlsTextTrackManager& GetTextTrackManager();
 
+  // Methods related to the playback speed menu.
+  void TogglePlaybackSpeedList();
+  bool PlaybackSpeedListIsWanted();
+
   // Methods related to the overflow menu.
   void OpenOverflowMenu();
   void CloseOverflowMenu();
@@ -367,6 +373,8 @@
   Member<MediaControlToggleClosedCaptionsButtonElement>
       toggle_closed_captions_button_;
   Member<MediaControlTextTrackListElement> text_track_list_;
+  Member<MediaControlPlaybackSpeedButtonElement> playback_speed_button_;
+  Member<MediaControlPlaybackSpeedListElement> playback_speed_list_;
   Member<MediaControlOverflowMenuButtonElement> overflow_menu_;
   Member<MediaControlOverflowMenuListElement> overflow_list_;
   Member<MediaControlButtonPanelElement> media_button_panel_;
diff --git a/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed.svg b/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed.svg
new file mode 100644
index 0000000..20014ca2
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M13.05 9.79L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zm0 0L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zm0 0L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zM11 4.07V2.05c-2.01.2-3.84 1-5.32 2.21L7.1 5.69A7.941 7.941 0 0111 4.07zM5.69 7.1L4.26 5.68A9.949 9.949 0 002.05 11h2.02c.18-1.46.76-2.79 1.62-3.9zM4.07 13H2.05c.2 2.01 1 3.84 2.21 5.32l1.43-1.43A7.868 7.868 0 014.07 13zm1.61 6.74A9.981 9.981 0 0011 21.95v-2.02a7.941 7.941 0 01-3.9-1.62l-1.42 1.43zM22 12c0 5.16-3.92 9.42-8.95 9.95v-2.02C16.97 19.41 20 16.05 20 12s-3.03-7.41-6.95-7.93V2.05C18.08 2.58 22 6.84 22 12z"/>
+</svg>
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed_white.svg b/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed_white.svg
new file mode 100644
index 0000000..8120128
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/resources/ic_playback_speed_white.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" fill="#FFF">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M13.05 9.79L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zm0 0L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zm0 0L10 7.5v9l3.05-2.29L16 12l-2.95-2.21zM11 4.07V2.05c-2.01.2-3.84 1-5.32 2.21L7.1 5.69A7.941 7.941 0 0111 4.07zM5.69 7.1L4.26 5.68A9.949 9.949 0 002.05 11h2.02c.18-1.46.76-2.79 1.62-3.9zM4.07 13H2.05c.2 2.01 1 3.84 2.21 5.32l1.43-1.43A7.868 7.868 0 014.07 13zm1.61 6.74A9.981 9.981 0 0011 21.95v-2.02a7.941 7.941 0 01-3.9-1.62l-1.42 1.43zM22 12c0 5.16-3.92 9.42-8.95 9.95v-2.02C16.97 19.41 20 16.05 20 12s-3.03-7.41-6.95-7.93V2.05C18.08 2.58 22 6.84 22 12z"/>
+</svg>
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
index 3a9717d..e0782ff 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -171,6 +171,8 @@
 video::-webkit-media-controls-toggle-closed-captions-button,
 audio::-internal-media-controls-download-button,
 video::-internal-media-controls-download-button,
+audio::-internal-media-controls-playback-speed-button,
+video::-internal-media-controls-playback-speed-button,
 video::-internal-media-controls-picture-in-picture-button {
   -webkit-appearance: -internal-media-control;
   background-size: 20px;
@@ -403,6 +405,11 @@
   background-image: -internal-light-dark(-webkit-image-set(url(ic_download.svg) 1x), -webkit-image-set(url(ic_download_white.svg) 1x));
 }
 
+video::-internal-media-controls-playback-speed-button,
+audio::-internal-media-controls-playback-speed-button {
+  background-image: -internal-light-dark(-webkit-image-set(url(ic_playback_speed.svg) 1x), -webkit-image-set(url(ic_playback_speed_white.svg) 1x));
+}
+
 video::-internal-media-controls-overflow-button,
 audio::-internal-media-controls-overflow-button {
   background-image: -internal-light-dark(-webkit-image-set(url(ic_menu.svg) 1x), -webkit-image-set(url(ic_menu_white.svg) 1x));
@@ -850,6 +857,8 @@
 
 audio::-internal-media-controls-text-track-list,
 video::-internal-media-controls-text-track-list,
+audio::-internal-media-controls-playback-speed-list,
+video::-internal-media-controls-playback-speed-list,
 audio::-internal-media-controls-overflow-menu-list,
 video::-internal-media-controls-overflow-menu-list {
   position: fixed;
@@ -880,8 +889,12 @@
 
 audio::-internal-media-controls-text-track-list-header,
 video::-internal-media-controls-text-track-list-header,
+audio::-internal-media-controls-playback-speed-list-header,
+video::-internal-media-controls-playback-speed-list-header,
 audio::-internal-media-controls-text-track-list-item,
 video::-internal-media-controls-text-track-list-item,
+audio::-internal-media-controls-playback-speed-list-item,
+video::-internal-media-controls-playback-speed-list-item,
 audio::-internal-media-controls-overflow-menu-list-item,
 video::-internal-media-controls-overflow-menu-list-item {
   display: flex;
@@ -941,13 +954,14 @@
   text-overflow: ellipsis;
 }
 
-label[pseudo="-internal-media-controls-text-track-list-item"] span {
+label[pseudo="-internal-media-controls-text-track-list-item"] span,
+label[pseudo="-internal-media-controls-playback-speed-list-item"] span {
   line-height: normal;
   overflow: hidden;
   text-overflow: ellipsis;
   /*
    * We need to make sure the blue tick has enough space to render. The blue tick needs at least 18px
-   * so the max width the span can go is 200(text-track-list) - 58(left-padding of list-item)
+   * so the max width the span can go is 200(list) - 58(left-padding of list-item)
    * - 16(right-padding of list-item) -30(left and right margin of the checkbox) - 18(blue tick) = 78px
    */
   max-width: 78px;
@@ -1008,10 +1022,14 @@
 
 audio::-internal-media-controls-text-track-list-header:focus,
 video::-internal-media-controls-text-track-list-header:focus,
-audio::-internal-media-controls-overflow-menu-list-item:focus,
-video::-internal-media-controls-overflow-menu-list-item:focus,
+audio::-internal-media-controls-playback-speed-list-header:focus,
+video::-internal-media-controls-playback-speed-list-header:focus,
 audio::-internal-media-controls-text-track-list-item:focus,
-video::-internal-media-controls-text-track-list-item:focus {
+video::-internal-media-controls-text-track-list-item:focus,
+audio::-internal-media-controls-playback-speed-list-item:focus,
+video::-internal-media-controls-playback-speed-list-item:focus,
+audio::-internal-media-controls-overflow-menu-list-item:focus,
+video::-internal-media-controls-overflow-menu-list-item:focus {
   background-color: -internal-light-dark(#e0e0e0, #545454);
   color: -internal-light-dark(rgba(0,0,0,0.87), rgba(255,255,255,0.87));
   outline: none;
@@ -1024,25 +1042,33 @@
 
 audio::-internal-media-controls-text-track-list-header,
 video::-internal-media-controls-text-track-list-header,
+audio::-internal-media-controls-playback-speed-list-header,
+video::-internal-media-controls-playback-speed-list-header,
 audio::-internal-media-controls-text-track-list-item,
-video::-internal-media-controls-text-track-list-item {
+video::-internal-media-controls-text-track-list-item,
+audio::-internal-media-controls-playback-speed-list-item,
+video::-internal-media-controls-playback-speed-list-item {
   padding-left: 58px;
   justify-content: space-between;
 }
 
 audio::-internal-media-controls-text-track-list-header,
-video::-internal-media-controls-text-track-list-header {
+video::-internal-media-controls-text-track-list-header,
+audio::-internal-media-controls-playback-speed-list-header,
+video::-internal-media-controls-playback-speed-list-header {
   background-size: 18px;
   background-position: 20px center;
   background-repeat: no-repeat;
   background-image: -internal-light-dark(-webkit-image-set(url(ic_arrow_back.svg) 1x), -webkit-image-set(url(ic_arrow_back_white.svg) 1x));
 }
 
-label[pseudo="-internal-media-controls-text-track-list-item"] * {
+label[pseudo="-internal-media-controls-text-track-list-item"] *,
+label[pseudo="-internal-media-controls-playback-speed-list-item"] * {
   pointer-events: none;
 }
 
-label[pseudo="-internal-media-controls-text-track-list-item"] input {
+label[pseudo="-internal-media-controls-text-track-list-item"] input,
+label[pseudo="-internal-media-controls-playback-speed-list-item"] input {
   -webkit-appearance: none;
   width: 18px;
   height: 18px;
@@ -1050,7 +1076,8 @@
   float: right;
 }
 
-label[pseudo="-internal-media-controls-text-track-list-item"] input:checked {
+label[pseudo="-internal-media-controls-text-track-list-item"] input:checked,
+label[pseudo="-internal-media-controls-playback-speed-list-item"] input:checked {
   background: -webkit-image-set(url(ic_check_blue.svg) 1x) no-repeat center center;
 }
 
@@ -1568,6 +1595,8 @@
   /* Overflow menu */
   audio::-internal-media-controls-text-track-list,
   video::-internal-media-controls-text-track-list,
+  audio::-internal-media-controls-playback-speed-list,
+  video::-internal-media-controls-playback-speed-list,
   audio::-internal-media-controls-overflow-menu-list,
   video::-internal-media-controls-overflow-menu-list {
     background: Window;
@@ -1577,8 +1606,12 @@
   }
   audio::-internal-media-controls-text-track-list-header,
   video::-internal-media-controls-text-track-list-header,
+  audio::-internal-media-controls-playback-speed-list-header,
+  video::-internal-media-controls-playback-speed-list-header,
   audio::-internal-media-controls-text-track-list-item,
   video::-internal-media-controls-text-track-list-item,
+  audio::-internal-media-controls-playback-speed-list-item,
+  video::-internal-media-controls-playback-speed-list-item,
   audio::-internal-media-controls-overflow-menu-list-item,
   video::-internal-media-controls-overflow-menu-list-item {
     background-color: Window;
diff --git a/third_party/blink/renderer/platform/bindings/union_base.h b/third_party/blink/renderer/platform/bindings/union_base.h
index f0ef5df..d0a9590 100644
--- a/third_party/blink/renderer/platform/bindings/union_base.h
+++ b/third_party/blink/renderer/platform/bindings/union_base.h
@@ -5,10 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
 
-#include "base/containers/span.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
index 5f51fd9c..3b4c45d8 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
@@ -830,7 +830,7 @@
   //
   // Implements: https://wicg.github.io/cors-rfc1918/#integration-html
   response->SetAddressSpace(CalculateResourceAddressSpace(
-      KURL(response->ResponseUrl()), head.remote_endpoint.address()));
+      KURL(response->ResponseUrl()), head.remote_endpoint));
 
   WebVector<WebString> cors_exposed_header_names(
       head.cors_exposed_header_names.size());
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
index a160585..54fe7561 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -393,7 +393,8 @@
                   buffer_context_->GetGpuMemoryBuffer()->GetSize(),
                   buffer_context_->GetGpuMemoryBuffer()->GetFormat(),
                   gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing(),
-                  video_capture_impl_.gpu_factories_->GpuMemoryBufferManager());
+                  video_capture_impl_.gpu_factories_->GpuMemoryBufferManager(),
+                  video_capture_impl_.pool_);
     }
   }
   // After initializing, either |frame_| or |gpu_memory_buffer_| has been set.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index fb22c2f..9b48545 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -61,6 +61,8 @@
 # Tests are flaky after a WPT import
 crbug.com/1204961 [ Mac ] external/wpt/websockets/stream/tentative/abort.any.html?wpt_flags=h2 [ Pass Failure ]
 crbug.com/1204961 [ Mac ] external/wpt/websockets/stream/tentative/constructor.any.sharedworker.html?wpt_flags=h2 [ Pass Failure ]
+# Flaking on WebKit Linux MSAN
+crbug.com/1207373 [ Linux ] external/wpt/uievents/order-of-events/mouse-events/mousemove-across.html [ Pass Failure ]
 
 # WPT Test harness doesn't deal with finding an about:blank ref test
 crbug.com/1066130 external/wpt/infrastructure/assumptions/blank.html [ Failure ]
@@ -1090,15 +1092,13 @@
 
 ### Tests failing with LayoutNGBlockFragmentation enabled:
 crbug.com/1146973 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-009.html [ Failure ]
-crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/change-out-of-flow-type-and-remove-inner-multicol-crash.html [ Crash Failure ]
-crbug.com/996655 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/going-out-of-flow-after-spanner.html [ Crash Failure Pass ]
+crbug.com/1206618 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/going-out-of-flow-after-spanner.html [ Failure ]
 crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure Crash ]
 crbug.com/1130451 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-list-item-001.html [ Failure ]
 crbug.com/1130451 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-list-item-002.html [ Failure ]
-crbug.com/1058792 virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column.html [ Failure ]
 crbug.com/1151880 virtual/layout_ng_block_frag/fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
 crbug.com/1151880 virtual/layout_ng_block_frag/fast/multicol/dynamic/remove-column-content-next-to-abspos-between-spanners.html [ Failure ]
-crbug.com/1079031 virtual/layout_ng_block_frag/fast/multicol/dynamic/static-becomes-relpos-has-abspos.html [ Failure ]
+crbug.com/1206618 virtual/layout_ng_block_frag/fast/multicol/dynamic/static-becomes-relpos-has-abspos.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-margin-at-row-boundary.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-margin-at-row-boundary-fixed-multicol-height.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/forced-break-in-nested-columns.html [ Failure ]
@@ -5847,7 +5847,6 @@
 crbug.com/476553 virtual/scroll-unification/plugins/mouse-click-iframe-to-plugin.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification/plugins/transformed-events.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification/scrollbars/listbox-scrollbar-combinations.html [ Pass Failure Timeout Crash ]
-crbug.com/476553 virtual/scroll-unification/scrollbars/scrollbar-added-during-drag.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-layout_ng_block_frag/fast/forms/fieldset/fieldset-legend-change.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-overlay-scrollbar/plugin-overlay-scrollbar-mouse-capture.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-deleted-scrollbar.html [ Pass Failure Timeout Crash ]
@@ -5858,7 +5857,6 @@
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/hidden-scrollbars-invisible.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/overlay-scrollbars-within-overflow-scroll.html [ Pass Failure Timeout Crash ]
-crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/scrollbar-added-during-drag.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/scrollbar-buttons.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/scrollbar-corner-colors.html [ Pass Failure Timeout Crash ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/scrollbar-orientation.html [ Pass Failure Timeout Crash ]
@@ -6823,6 +6821,10 @@
 crbug.com/1093041 virtual/oopr-canvas2d/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html [ Pass Failure Timeout ]
 crbug.com/1146560 virtual/oopr-canvas2d/fast/canvas/color-space/canvas-createImageBitmap-e_srgb.html [ Pass Failure Timeout ]
 
+# Sheriff 2021-05-10
+crbug.com/1207319 external/wpt/html/cross-origin-embedder-policy/credentialless/cache-storage.tentative.https.html [ Pass Timeout ]
+crbug.com/1207337 virtual/scroll-unification/fast/scroll-snap/animate-fling-to-snap-points-2.html [ Pass Failure ]
+
 # Sheriff 2021-05-04
 crbug.com/1205659 [ Mac ] external/wpt/IndexedDB/key-generators/reading-autoincrement-indexes.any.worker.html [ Pass Timeout ]
 crbug.com/1205659 [ Mac ] storage/indexeddb/empty-blob-file.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-baseline-static-position.html b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-baseline-static-position.html
deleted file mode 100644
index e3f5236..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-baseline-static-position.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<link rel="help" href="https://crbug.com/1206654" />
-<link rel="match" href="../reference/ref-filled-green-100px-square-only.html" />
-<style>
-table {
-  width: 100px;
-  height: 100px;
-  position: relative;
-  line-height: 0;
-  border-spacing: 0;
-}
-td {
-  vertical-align: baseline;
-  width: 50px;
-  padding: 0;
-}
-div {
-  width: 50px;
-  height: 100px;
-  background: green;
-}
-</style>
-<p>Test passes if there is a filled green square.</p>
-<table>
-  <td>
-    <div style="display: inline-block;"></div> <!-- Creates a baseline at 100px. -->
-  </td>
-  <td>
-    <div style="position: absolute;"></div> <!-- Static-position shouldn't shift to the baseline. -->
-  </td>
-</table>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
index 3ebbd7d..122983e 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/credentialless/resources/dispatcher.js
@@ -20,15 +20,23 @@
   };
 }
 
-// Wait for a random amount of time in the range [50ms,150ms].
+// Wait for a random amount of time in the range [10ms,100ms].
 const randomDelay = () => {
-  return new Promise(resolve => setTimeout(resolve, 50 + 100*Math.random()));
+  return new Promise(resolve => setTimeout(resolve, 10 + 90*Math.random()));
 }
 
-// The official web-platform-test runner sometimes drops requests when too many
-// are requested in parallel. Limiting this document to send/receive only one at
-// a time fixes the issue.
-const limiter = concurrencyLimiter(1);
+// Sending too many requests in parallel causes congestion. Limiting it improves
+// throughput.
+//
+// Note: The following table has been determined on the test:
+// ../cache-storage.tentative.https.html
+// using Chrome with a 64 core CPU / 64GB ram, in release mode:
+// ┌───────────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬────┐
+// │concurrency│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 10│ 15│ 20│ 30│ 50│ 100│
+// ├───────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼────┤
+// │time (s)   │ 54│ 38│ 31│ 29│ 26│ 24│ 22│ 22│ 22│ 22│ 34│ 36 │
+// └───────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴────┘
+const limiter = concurrencyLimiter(6);
 
 const send = async function(uuid, message) {
   await limiter(async () => {
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
index b0e7cc1..2e95b215 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
@@ -14,13 +14,13 @@
   entry => {
     assert_true(entry.name.includes('#hash=1'),
       "There should be a hash in the resource name");
-    invariants.assert_http_resource(entry);
+    invariants.assert_tao_pass_no_redirect(entry);
   },
   "Image resources should generate conformant entries");
 
 attribute_test(
   load.font, "/fonts/Ahem.ttf",
-  invariants.assert_http_resource,
+  invariants.assert_tao_pass_no_redirect,
   "Font resources should generate conformant entries");
 
 attribute_test(
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resource-TAO-match-origin.html b/third_party/blink/web_tests/external/wpt/resource-timing/resource-TAO-match-origin.html
new file mode 100644
index 0000000..7e738f9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resource-TAO-match-origin.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing TAO tests</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#timing-allow-origin"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/entry-invariants.js"></script>
+<script src="resources/resource-loaders.js"></script>
+<script>
+const {REMOTE_ORIGIN} = get_host_info();
+const path = REMOTE_ORIGIN + '/resource-timing/resources/TAOResponse.py?tao=match_origin';
+attribute_test(load.xhr_sync, path,
+  invariants.assert_tao_pass_no_redirect,
+'The timing allow check algorithm will pass when the Timing-Allow-Origin header value list contains a case-sensitive match.');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resource_TAO_match_origin.html b/third_party/blink/web_tests/external/wpt/resource-timing/resource_TAO_match_origin.html
deleted file mode 100644
index 4793dbf..0000000
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resource_TAO_match_origin.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<title>Resource Timing TAO tests</title>
-<link rel="author" title="Google" href="http://www.google.com/" />
-<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#timing-allow-origin"/>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/webperftestharness.js"></script>
-<script src="resources/webperftestharnessextension.js"></script>
-<script>
-setup({explicit_done: true});
-
-// explicitly test the namespace before we start testing
-test_namespace("getEntriesByType");
-
-var d;
-var iframe;
-var iframeBody;
-var image;
-var random = Math.random();
-
-function setup_iframe() {
-    iframe = document.getElementById('frameContext');
-    d = iframe.contentWindow.document;
-    iframeBody = d.body;
-    iframe.addEventListener('load', onload_test, false);
-}
-function onload_test() {
-    if (window.performance.getEntriesByType === undefined) {
-      done();
-      return;
-    }
-    var context = new PerformanceContext(iframe.contentWindow.performance);
-    var entries = context.getEntriesByType('resource');
-
-    assert_greater_than(entries.length, 0, "The iframe should have at least one resource timing entry.");
-    if(entries.length > 0) {
-        entry = entries[0];
-
-        test_not_equals((entry.redirectStart + entry.redirectEnd + entry.domainLookupStart + entry.domainLookupEnd + entry.connectStart + entry.connectEnd + entry.secureConnectionStart + entry.requestStart + entry.responseStart), 0, 'redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should NOT be all returned as 0 when the Timing-Allow-Origin header value list contains a case-sensitive match for the value of the origin of the current document and TAO algorithm passes');
-    }
-
-    done();
-}
-window.setup_iframe = setup_iframe;
-</script>
-</head>
-<body>
-<h1>Description</h1>
-<p>This test validates that for a cross origin resource, the timing allow check algorithm will pass when the Timing-Allow-Origin header value list contains a case-sensitive match for the value of the origin of the current document.</p>
-<div id="log"></div>
-<iframe id="frameContext" src="resources/iframe_TAO_match_origin.html"></iframe>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
index c25ccc0..163f8ca 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
@@ -49,3 +49,6 @@
         response.headers.set(b'Timing-Allow-Origin', origin.upper())
     else:
         pass
+    response.status = 200
+    response.headers.set(b"Content-Type", b"text/plain")
+    response.content = "TEST"
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/entry-invariants.js b/third_party/blink/web_tests/external/wpt/resource-timing/resources/entry-invariants.js
index eb885e6..93bc993 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/entry-invariants.js
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/entry-invariants.js
@@ -37,8 +37,9 @@
 
 const invariants = {
   // Asserts that attributes of the given PerformanceResourceTiming entry match
-  // what the spec dictates for any resource fetched over HTTP.
-  assert_http_resource: entry => {
+  // what the spec dictates for any resource fetched without redirects but
+  // passing the Timing-Allow-Origin checks.
+  assert_tao_pass_no_redirect: entry => {
     assert_ordered_(entry, [
       "fetchStart",
       "domainLookupStart",
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
new file mode 100644
index 0000000..02b2f1f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-insecure-main-frame.js b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-insecure-main-frame.js
index 158f3e6..c192cf4 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-insecure-main-frame.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-insecure-main-frame.js
@@ -10,7 +10,7 @@
   await page.navigate('http://devtools.test:8000/inspector-protocol/resources/empty.html');
 
   const issuePromise = dp.Audits.onceIssueAdded();
-  await page.loadHTML(`<img src="https://devtools.test:8443/inspector-protocol/conversion/resources/conversion-redirect.php"></img>`);
+  await page.loadHTML(`<!DOCTYPE html><img src="https://devtools.test:8443/inspector-protocol/conversion/resources/conversion-redirect.php"></img>`);
   const issue = await issuePromise;
   testRunner.log(issue.params.issue, "Issue reported: ", ['frame', 'requestId']);
   testRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-invalid-data.js b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-invalid-data.js
index 643237fe..b010d20 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-invalid-data.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/attribution-invalid-data.js
@@ -11,6 +11,7 @@
 
   const issuePromises = [dp.Audits.onceIssueAdded(), dp.Audits.onceIssueAdded()];
   await page.loadHTML(`
+    <!DOCTYPE html>
     <img src="https://devtools.test:8443/inspector-protocol/conversion/resources/conversion-redirect-invalid-data.php"></img>
     <img src="https://devtools.test:8443/inspector-protocol/conversion/resources/conversion-redirect-missing-data.php"></img>`);
   const issues = await Promise.all(issuePromises);
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/conversion-disabled-permission-policy-issue.js b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/conversion-disabled-permission-policy-issue.js
index e9aa0b69..2bfb8e83 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/conversion-disabled-permission-policy-issue.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/conversion/conversion-disabled-permission-policy-issue.js
@@ -12,6 +12,7 @@
 
   const eventPromises = [dp.Network.onceRequestWillBeSent(), dp.Audits.onceIssueAdded()];
   await page.loadHTML(`
+    <!DOCTYPE html>
     <img src="https://devtools.test:8443/inspector-protocol/conversion/resources/conversion-redirect.php"></img>`);
 
   const [requestWillBeSent, issue] = await Promise.all(eventPromises);
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/hello-world.html b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/hello-world.html
index 14046a9b..8510a98 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/hello-world.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/resources/hello-world.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <body>
   <h1>hello world</h1>
 </body>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/active-mixed-content-iframe.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/active-mixed-content-iframe.html
index 091b81ea..36ef95dd 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/active-mixed-content-iframe.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/active-mixed-content-iframe.html
@@ -1 +1,2 @@
+<!DOCTYPE html>
 <script src="http://example.test:8000/inspector-protocol/resources/blank.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/empty.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/empty.html
index e69de29..0e76edd6 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/empty.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-page.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-page.html
index 90531a4b..bd54434 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-page.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-page.html
@@ -1,2 +1,3 @@
+<!DOCTYPE html>
 <html>
 </html>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-css.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-css.html
index a3468bb..89bd93b 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-css.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-css.html
@@ -1 +1,2 @@
+<!DOCTYPE html>
 <link rel="stylesheet" href="http://devtools.test:8000/inspector-protocol/resources/styles.css" />
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-iframe.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-iframe.html
index acd40fa..558444a 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-iframe.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-iframe.html
@@ -1 +1,2 @@
+<!DOCTYPE html>
 <iframe src='http://devtools.test:8000/inspector-protocol/resources/iframe.html'></iframe>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-within-iframe.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-within-iframe.html
index f0cb84a..be5b8c7 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-within-iframe.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/mixed-content-within-iframe.html
@@ -1 +1,2 @@
+<!DOCTYPE html>
 <iframe src='https://devtools.test:8443/inspector-protocol/resources/active-mixed-content-iframe.html'></iframe>
diff --git a/third_party/blink/web_tests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html b/third_party/blink/web_tests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
index f4326c95..b3c796f 100644
--- a/third_party/blink/web_tests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
+++ b/third_party/blink/web_tests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
@@ -25,7 +25,7 @@
 
     // The overflow menu should always have the same number of elements.
     // Their visibility will change over time based on the size of the video.
-    assert_equals(children.length, 7);
+    assert_equals(children.length, 8);
 
     // Ensure that all of the buttons are visible in the right order
     for (var i = 0; i < children.length; i++) {
diff --git a/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial-expected.txt b/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial-expected.txt
new file mode 100644
index 0000000..2b73f3a
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial-expected.txt
@@ -0,0 +1,22 @@
+Verifies that we can successfully retrieve origin trial in frame tree.
+[
+    [0] : {
+        status : ValidTokenNotProvided
+        tokensWithStatus : [
+            [0] : {
+                parsedToken : {
+                    expiryTime : 1761176198
+                    isThirdParty : false
+                    matchSubDomains : false
+                    origin : http://127.0.0.1:8000
+                    trialName : AppCache
+                    usageRestriction : None
+                }
+                rawTokenText : AnwB3aSh6U8pmYtO/AzzxELSwk8BRJoj77nUnCq6u3N8LMJKlX/ImydQmXn3SgE0a+8RyowLbV835tXQHJMHuAEAAABQeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQXBwQ2FjaGUiLCAiZXhwaXJ5IjogMTc2MTE3NjE5OH0=
+                status : WrongOrigin
+            }
+        ]
+        trialName : AppCache
+    }
+]
+
diff --git a/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial.js b/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial.js
new file mode 100644
index 0000000..a17280b8
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/origin-trial/origin-trial.js
@@ -0,0 +1,12 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startHTML(`
+  <meta http-equiv="origin-trial"
+        content="AnwB3aSh6U8pmYtO/AzzxELSwk8BRJoj77nUnCq6u3N8LMJKlX/ImydQmXn3SgE0a+8RyowLbV835tXQHJMHuAEAAABQeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQXBwQ2FjaGUiLCAiZXhwaXJ5IjogMTc2MTE3NjE5OH0="
+  />
+  `, 'Verifies that we can successfully retrieve origin trial in frame tree.');
+
+  await dp.Page.enable();
+  testRunner.log(
+    (await dp.Page.getResourceTree()).result.frameTree.frame.originTrials);
+  testRunner.completeTest();
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/media/controls/accessibility-playback-speed-button.html b/third_party/blink/web_tests/media/controls/accessibility-playback-speed-button.html
new file mode 100644
index 0000000..c11368f
--- /dev/null
+++ b/third_party/blink/web_tests/media/controls/accessibility-playback-speed-button.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>Media Controls: playback speed button accessibility tests</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<video controls></video>
+<script>
+async_test(t => {
+  var video = document.querySelector('video');
+  enableTestMode(video);
+  video.src = '../content/test.ogv';
+
+video.onloadeddata = t.step_func(_ => {
+    assert_true(isPlaybackSpeedButtonEnabled(video));
+
+    var playback_speed_button = playbackSpeedButton(video);
+    var playback_speed_overflow_item = playbackSpeedOverflowItem(video);
+    assert_not_equals(playback_speed_button, null);
+    assert_not_equals(playback_speed_overflow_item, null);
+
+    assert_equals(playback_speed_button.getAttribute('aria-label'),
+                  'show playback speed menu');
+
+    assert_equals(playback_speed_overflow_item.getAttribute('aria-label'),
+                  'show playback speed menu');
+
+    clickPlaybackSpeedButton(video, t.step_func_done(function() {
+      // Get the menu that displays the list of playback speeds.
+      var playbackSpeedsList = playbackSpeedMenu(video);
+      assert_equals(playbackSpeedsList.getAttribute('aria-label'), 'Options');
+      var listHeader = playbackSpeedListHeader(video);
+      assert_equals(listHeader.getAttribute('aria-label'), 'hide playback speed menu');
+
+      const playbackSpeeds = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2];
+      playbackSpeeds.forEach(function(playbackSpeed, index) {
+        var playbackSpeedListItem = playbackSpeedListItemAtPlaybackRate(video, playbackSpeed);
+        assert_equals(playbackSpeedListItem.innerText, playbackSpeed == 1.0 ? 'Normal' : `${playbackSpeed}`);
+        assert_equals(playbackSpeedListItem.getAttribute('role'), 'menuitemcheckbox');
+        assert_equals(playbackSpeedListItem.getAttribute('aria-setsize'), '9');
+        assert_equals(playbackSpeedListItem.getAttribute('aria-posinset'), `${index + 1}`);
+      });
+    }));
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/media/controls/click-and-drag-on-overflow-menu-doesnt-close.html b/third_party/blink/web_tests/media/controls/click-and-drag-on-overflow-menu-doesnt-close.html
index 7553e521..a85a508 100644
--- a/third_party/blink/web_tests/media/controls/click-and-drag-on-overflow-menu-doesnt-close.html
+++ b/third_party/blink/web_tests/media/controls/click-and-drag-on-overflow-menu-doesnt-close.html
@@ -12,6 +12,7 @@
   const overflowBtn = overflowButton(video);
   const downloadBtn = downloadsOverflowItem(video);
   const captionsBtn = captionsOverflowItem(video);
+  const playbackSpeedBtn = playbackSpeedOverflowItem(video);
 
   // Add text tracks so that the captions option appears.
   [ '../track/captions-webvtt/captions-fast.vtt',
@@ -32,22 +33,27 @@
   // Neither the downloads button nor the captions button should receive a click during the click and drag.
   downloadBtn.addEventListener('click', t.unreached_func('Downloads received a click'));
   captionsBtn.addEventListener('click', t.unreached_func('Captions received a click'));
+  playbackSpeedBtn.addEventListener('click', t.unreached_func('Playback speed received a click'));
 
   function clickAndDrag() {
     assert_true(isControlVisible(menu), 'Overflow menu should be visible before we start click-and-drag');
     assert_true(isControlVisible(downloadBtn), 'Download button should be visible');
     assert_true(isControlVisible(captionsBtn), 'Captions button should be visible');
+    assert_true(isControlVisible(playbackSpeedBtn), 'Playback speed button should be visible');
 
     const downloadPosition = elementCoordinates(downloadBtn);
     const captionsPosition = elementCoordinates(captionsBtn);
+    const playbackSpeedPosition = elementCoordinates(playbackSpeedBtn);
 
-    // Click down on downloads but drag and release over captions.
+    // Click down on downloads but drag and release over captions and playback speed.
     chrome.gpuBenchmarking.pointerActionSequence([{
       source: 'mouse',
       actions: [
         { name: 'pointerDown', x: downloadPosition[0], y: downloadPosition[1] },
         { name: 'pointerMove', x: captionsPosition[0], y: captionsPosition[1] },
         { name: 'pointerUp', x: captionsPosition[0], y: captionsPosition[1] },
+        { name: 'pointerMove', x: playbackSpeedPosition[0], y: playbackSpeedPosition[1] },
+        { name: 'pointerUp', x: playbackSpeedPosition[0], y: playbackSpeedPosition[1] },
       ]
     }], t.step_func_done(() => {
       assert_true(isControlVisible(menu), 'Overflow menu should still be visible after click-and-drag');
diff --git a/third_party/blink/web_tests/media/controls/overflow-button-disabled-no-source.html b/third_party/blink/web_tests/media/controls/overflow-button-disabled-no-source.html
index 1755c0d0..75d3b0f 100644
--- a/third_party/blink/web_tests/media/controls/overflow-button-disabled-no-source.html
+++ b/third_party/blink/web_tests/media/controls/overflow-button-disabled-no-source.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <html>
-<title>Test that the overflow menu is shown but disabled with no source.</title>
+<title>Test that the overflow menu is disabled with no source.</title>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../media-controls.js"></script>
@@ -9,16 +9,16 @@
 async_test(t => {
   const video = document.querySelector('video');
 
-  // Make sure the button is visible and disabled.
+  // Make sure the button is disabled.
   assert_true(overflowButton(video).disabled);
   assert_equals(overflowButton(video).style.display, '');
 
   // Set the source and start playing.
   video.src = '../content/60_sec_video.webm';
   video.play().then(t.step_func_done(() => {
-    // Make sure the button has been hidden and is no longer disabled.
+    // Make sure the button is no longer disabled.
     assert_false(overflowButton(video).disabled);
-    assert_equals(overflowButton(video).style.display, 'none');
+    assert_equals(overflowButton(video).style.display, '');
   }), t.unreached_func());
 });
 </script>
diff --git a/third_party/blink/web_tests/media/controls/overflow-menu-hide-on-click-item.html b/third_party/blink/web_tests/media/controls/overflow-menu-hide-on-click-item.html
index 504e069f..c30dc6c9 100644
--- a/third_party/blink/web_tests/media/controls/overflow-menu-hide-on-click-item.html
+++ b/third_party/blink/web_tests/media/controls/overflow-menu-hide-on-click-item.html
@@ -38,8 +38,16 @@
         singleTapOnControl(overflowButton(video), t.step_func(() => {
           assert_not_equals(getComputedStyle(menu).display, 'none');
 
-          singleTapOnControl(captionsOverflowItem(video), t.step_func_done(() => {
+          singleTapOnControl(captionsOverflowItem(video), t.step_func(() => {
             assert_equals(getComputedStyle(menu).display, 'none');
+
+            singleTapOnControl(overflowButton(video), t.step_func(() => {
+              assert_not_equals(getComputedStyle(menu).display, 'none');
+
+              singleTapOnControl(playbackSpeedOverflowItem(video), t.step_func_done(() => {
+                assert_equals(getComputedStyle(menu).display, 'none');
+              }));
+            }));
           }));
         }));
       }));
diff --git a/third_party/blink/web_tests/media/controls/overflow-menu-keyboard-navigation.html b/third_party/blink/web_tests/media/controls/overflow-menu-keyboard-navigation.html
index 500040a..e45a731 100644
--- a/third_party/blink/web_tests/media/controls/overflow-menu-keyboard-navigation.html
+++ b/third_party/blink/web_tests/media/controls/overflow-menu-keyboard-navigation.html
@@ -75,10 +75,11 @@
                     menu.lastElementChild);
 
       const elements = [ menu.lastElementChild,
-                         menu.lastElementChild.previousSibling ];
+                         menu.lastElementChild.previousSibling,
+                         menu.lastElementChild.previousSibling.previousSibling ];
 
       if (document.pictureInPictureEnabled)
-        elements.push(menu.lastElementChild.previousSibling.previousSibling);
+        elements.push(menu.lastElementChild.previousSibling.previousSibling.previousSibling);
 
       testNavigation(internals.shadowRoot(video), elements,
                      () => { eventSender.keyDown('ArrowUp'); },
diff --git a/third_party/blink/web_tests/media/controls/playback-speed-button.html b/third_party/blink/web_tests/media/controls/playback-speed-button.html
new file mode 100644
index 0000000..b504320
--- /dev/null
+++ b/third_party/blink/web_tests/media/controls/playback-speed-button.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Clicking on the overflow playback speed button shows the playback speed menu.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../overflow-menu.js"></script>
+
+<!--Padding ensures the overflow menu is visible for the tests. -->
+<body style="padding-top: 200px; padding-left: 100px">
+<video controls></video>
+<script>
+async_test(function(t) {
+  // Set up video.
+  var video = document.querySelector("video");
+  video.src = "../content/test.ogv";
+  video.setAttribute("width", "60");
+  video.setAttribute("height", "100");
+
+  enableTestMode(video);
+
+  video.onloadeddata = t.step_func_done(function() {
+    var overflowList = getOverflowList(video);
+    var overflowMenu = getOverflowMenuButton(video);
+
+    // Get the menu that displays the list of playback speeds.
+   var playbackSpeedsList = mediaControlsElement(internals.shadowRoot(video).firstChild, "-internal-media-controls-playback-speed-list");
+
+    // Initially the list should not be visible.
+    assert_equals(getComputedStyle(playbackSpeedsList).display, "none");
+
+    // Click on the overflow menu button.
+    var coords = elementCoordinates(overflowMenu);
+    clickAtCoordinates(coords[0], coords[1]);
+
+    // Click on the playback speed button.
+    var coords = elementCoordinates(overflowList.children[OverflowMenuButtons.PLAYBACK_SPEED]);
+    clickAtCoordinates(coords[0], coords[1]);
+    assert_not_equals(getComputedStyle(playbackSpeedsList).display, "none");
+  });
+});
+</script>
+</body>
diff --git a/third_party/blink/web_tests/media/controls/playback-speed-list-hide-on-click-outside.html b/third_party/blink/web_tests/media/controls/playback-speed-list-hide-on-click-outside.html
new file mode 100644
index 0000000..d242a36
--- /dev/null
+++ b/third_party/blink/web_tests/media/controls/playback-speed-list-hide-on-click-outside.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>Clicking on the overflow playback speed button shows the playback speeds list menu.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../overflow-menu.js"></script>
+
+<!--Padding ensures the overflow menu is visible for the tests. -->
+<body style="padding-top: 200px; padding-left: 100px">
+<video controls></video>
+<script>
+async_test(function(t) {
+  // Set up video
+  var video = document.querySelector("video");
+  video.src = "../content/test.ogv";
+  video.setAttribute("width", "60");
+  video.setAttribute("height", "100");
+
+  video.onloadeddata = t.step_func_done(function() {
+    var overflowList = getOverflowList(video);
+    var overflowMenu = getOverflowMenuButton(video);
+
+    // Get the menu that displays the list of playback speeds
+    var playbackSpeedsList = mediaControlsElement(internals.shadowRoot(video).firstChild, "-internal-media-controls-playback-speed-list");
+
+    // Initially the list should not be visible
+    assert_equals(getComputedStyle(playbackSpeedsList).display, "none");
+
+    // Click on the overflow menu button
+    var coords = elementCoordinates(overflowMenu);
+    clickAtCoordinates(coords[0], coords[1]);
+
+    // Click on the playback speed button
+    var coords = elementCoordinates(overflowList.children[OverflowMenuButtons.PLAYBACK_SPEED]);
+    clickAtCoordinates(coords[0], coords[1]);
+
+    // Click on anywhere outside the playback speeds list will close the list
+    var coords = coordinatesOutsideElement(playbackSpeedsList);
+    clickAtCoordinates(coords[0], coords[1]);
+    assert_equals(getComputedStyle(playbackSpeedsList).display, "none");
+  });
+});
+</script>
+</body>
diff --git a/third_party/blink/web_tests/media/controls/playback-speed-menu.html b/third_party/blink/web_tests/media/controls/playback-speed-menu.html
new file mode 100644
index 0000000..db2ba35
--- /dev/null
+++ b/third_party/blink/web_tests/media/controls/playback-speed-menu.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<title>Test that we can display a playback speeds list menu and set playback rate from the list.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<!-- Width should be large enough to display playback speed button. -->
+<video controls style="width: 500px"></video>
+<script>
+async_test(function(t) {
+  var video = document.querySelector("video");
+  video.src = "../content/test.ogv";
+
+  enableTestMode(video);
+
+  video.onloadeddata = t.step_func(function() {
+    assert_true(isPlaybackSpeedButtonEnabled(video));
+    assert_equals(video.playbackRate, 1);
+
+    clickPlaybackSpeedAtPlaybackRate(video, 0.25, t.step_func(function() {
+      assert_equals(video.playbackRate, 0.25);
+
+      clickPlaybackSpeedAtPlaybackRate(video, 0.5, t.step_func(function() {
+        assert_equals(video.playbackRate, 0.5);
+
+        clickPlaybackSpeedAtPlaybackRate(video, 0.75, t.step_func(function() {
+          assert_equals(video.playbackRate, 0.75);
+
+          clickPlaybackSpeedAtPlaybackRate(video, 1, t.step_func(function() {
+            assert_equals(video.playbackRate, 1);
+
+            clickPlaybackSpeedAtPlaybackRate(video, 1.25, t.step_func(function() {
+              assert_equals(video.playbackRate, 1.25);
+
+              clickPlaybackSpeedAtPlaybackRate(video, 1.5, t.step_func(function() {
+                assert_equals(video.playbackRate, 1.5);
+
+                clickPlaybackSpeedAtPlaybackRate(video, 1.75, t.step_func(function() {
+                  assert_equals(video.playbackRate, 1.75);
+
+                  clickPlaybackSpeedAtPlaybackRate(video, 2, t.step_func_done(function() {
+                    assert_equals(video.playbackRate, 2);
+                  }));
+                }));
+              }));
+            }));
+          }));
+        }));
+      }));
+    }));
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/media/media-controls.js b/third_party/blink/web_tests/media/media-controls.js
index 01ceaea..1e1865f0 100644
--- a/third_party/blink/web_tests/media/media-controls.js
+++ b/third_party/blink/web_tests/media/media-controls.js
@@ -138,6 +138,23 @@
   return element;
 }
 
+function playbackSpeedMenu(video)
+{
+  var controlID = '-internal-media-controls-playback-speed-list';
+  var element = mediaControlsElement(internals.shadowRoot(video).firstChild, controlID);
+  if (!element)
+    throw 'Failed to find the playback speed menu';
+  return element;
+}
+
+function playbackSpeedListHeader(video)
+{
+  var element = playbackSpeedMenu(video).childNodes[0];
+  if (!element)
+    throw 'Failed to find the playback speed header'
+  return element;
+}
+
 function overflowMenu(video)
 {
   var controlID = '-internal-media-controls-overflow-menu-list';
@@ -166,6 +183,10 @@
   return overflowItem(video, '-webkit-media-controls-toggle-closed-captions-button');
 }
 
+function playbackSpeedOverflowItem(video) {
+  return overflowItem(video, '-internal-media-controls-playback-speed-button');
+}
+
 function castOverflowItem(video) {
   return overflowItem(video, '-internal-media-controls-cast-button');
 }
@@ -289,6 +310,11 @@
   return !button.disabled && button.style.display != "none";
 }
 
+function isPlaybackSpeedButtonEnabled(video) {
+  var button = playbackSpeedOverflowItem(video);
+  return !button.disabled && button.style.display != "none";
+}
+
 function isDownloadsButtonEnabled(video) {
   var button = downloadsOverflowItem(video);
   return !button.disabled && button.style.display != "none";
@@ -319,6 +345,14 @@
     return mediaControlsButton(videoElement, 'toggle-closed-captions-button');
 }
 
+function playbackSpeedButton(videoElement) {
+  var controlID = '-internal-media-controls-playback-speed-button';
+  var button = mediaControlsElement(internals.shadowRoot(videoElement).firstChild, controlID);
+  if (!button)
+    throw 'Failed to find playback speed button';
+  return button;
+}
+
 function playButton(videoElement) {
     return mediaControlsButton(videoElement, 'play-button');
 }
@@ -446,6 +480,37 @@
     assert_equals(textTrackDisplayElement(video), null);
 }
 
+function playbackSpeedListItemAtPlaybackRate(video, playbackRate) {
+  var playbackSpeedItems = playbackSpeedMenu(video).childNodes;
+  for (var i = 0; i < playbackSpeedItems.length; i++) {
+      var playbackSpeedItem = playbackSpeedItems[i];
+      var innerCheckbox = playbackSpeedListItemInnerCheckbox(playbackSpeedItem);
+      if (innerCheckbox && innerCheckbox.getAttribute("data-playback-rate") == playbackRate)
+          return playbackSpeedItem;
+  }
+}
+function clickPlaybackSpeedButton(video, callback) {
+  openOverflowAndClickButton(video, playbackSpeedOverflowItem(video), callback);
+}
+
+function clickPlaybackSpeedAtPlaybackRate(video, playbackRate, callback) {
+  clickPlaybackSpeedButton(video, function () {
+    var playbackSpeed = playbackSpeedListItemAtPlaybackRate(video, playbackRate);
+    playbackSpeed.scrollIntoView();
+    singleTapOnControl(playbackSpeed, callback);
+  });
+}
+
+function playbackSpeedListItemInnerCheckbox(playbackSpeedListItem) {
+  const children = playbackSpeedListItem.children;
+  for (var i = 0; i < children.length; i++) {
+    const child = children[i];
+    if (internals.shadowPseudoId(child) == "-internal-media-controls-playback-speed-list-item-input")
+      return child;
+  }
+  return null;
+}
+
 function runAfterHideMediaControlsTimerFired(func, mediaElement)
 {
     if (mediaElement.paused)
diff --git a/third_party/blink/web_tests/media/overflow-menu.js b/third_party/blink/web_tests/media/overflow-menu.js
index b135997..c165a0d4 100644
--- a/third_party/blink/web_tests/media/overflow-menu.js
+++ b/third_party/blink/web_tests/media/overflow-menu.js
@@ -6,6 +6,7 @@
     "-webkit-media-controls-mute-button",
     "-internal-media-controls-cast-button",
     "-webkit-media-controls-toggle-closed-captions-button",
+    "-internal-media-controls-playback-speed-button",
     "-internal-media-controls-picture-in-picture-button",
 ];
 //  PseudoID for the overflow button
@@ -31,10 +32,11 @@
   MUTE: 3,
   CAST: 4,
   CLOSED_CAPTIONS: 5,
+  PLAYBACK_SPEED: 6,
 };
 
 // Default text within the overflow menu
-var overflowMenuText = ["Play", "Fullscreen", "Download", "Mute", "Cast", "CaptionsOff"];
+var overflowMenuText = ["Play", "Fullscreen", "Download", "Mute", "Cast", "CaptionsOff", "Playback speed"];
 
 if (document.pictureInPictureEnabled)
   overflowMenuText.push('Picture in Picture');
diff --git a/third_party/blink/web_tests/media/track/cue-style-invalidation.html b/third_party/blink/web_tests/media/track/cue-style-invalidation.html
index 6a7f839..5dc9ea9 100644
--- a/third_party/blink/web_tests/media/track/cue-style-invalidation.html
+++ b/third_party/blink/web_tests/media/track/cue-style-invalidation.html
@@ -36,7 +36,7 @@
         ascendant.offsetTop;
         ascendant.classList.add("cue");
         if (window.internals)
-            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 11);
+            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 12);
         assert_equals(getComputedStyle(cueNode).backgroundColor, green);
 
         assert_equals(getComputedStyle(cNode).backgroundColor, red);
diff --git a/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html b/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html
index 47e3be2c..9b624fb 100644
--- a/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html
+++ b/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html
@@ -8,7 +8,7 @@
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
-<video controls disablePictureInPicture></video>
+<video controls></video>
 <script>
 async_test(function(t) {
   // Set up video
@@ -31,12 +31,8 @@
     var coords = elementCoordinates(overflowList.children[OverflowMenuButtons.FULLSCREEN]);
     clickAtCoordinates(coords[0], coords[1]);
 
-    document.onwebkitfullscreenchange = t.step_func(() => {
+    document.onwebkitfullscreenchange = t.step_func_done(() => {
       assert_equals(document.fullscreenElement, video);
-      // Hiding the overflow menu is triggered by layout.
-      runAfterLayoutAndPaint(t.step_func_done(() => {
-        assert_equals(getComputedStyle(overflowMenu).display, "none");
-      }));
     });
   }));
 });
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 4d38cbc..92c6523 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/vertical-align-baseline-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/vertical-align-baseline-expected.png
index c841e1b..3eeb70d 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/vertical-align-baseline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/vertical-align-baseline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
index 9de967c2..a11bb1a 100644
--- a/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
index 03f1da5..445c640 100644
--- a/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
index e5e8d6de..62a11ed 100644
--- a/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
index 9c530f5..4ec84cb7 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
index 9572b808..d2f8471 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
index fd66e00f..70b8bec8 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index abfacee..9a4378da 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index a2eeeb28f..fa00af5 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 4d647566..70629127 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index b534b5f..3a5a617 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
new file mode 100644
index 0000000..e2668b9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..a11bb1a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-repaint-expected.png
new file mode 100644
index 0000000..445c640
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
new file mode 100644
index 0000000..62a11ed
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
new file mode 100644
index 0000000..4ec84cb7
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
new file mode 100644
index 0000000..d2f8471
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..70b8bec8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
new file mode 100644
index 0000000..87905c9b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..a2ac778
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-repaint-expected.png
new file mode 100644
index 0000000..a69f030
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
new file mode 100644
index 0000000..60453695
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
new file mode 100644
index 0000000..1c293bd8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
new file mode 100644
index 0000000..d1a0d145
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..e2b423b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 76fb5ec..235214a9 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
index 660f1fc0..3afadb40 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-repaint-expected.png
index a185ca7..fd0f3d4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
index f805da63..df5b495 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-clone-expected.png
index 5a7ab65..81e3ff6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png
index e6e87e6..2d74c5f 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
index 413020d..a85217a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 81ac686..64421fff 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 30048ad..89ef2a3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 2ff66126..4237dea2 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 7bded8c..581c7f8 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..3afadb40
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-repaint-expected.png
new file mode 100644
index 0000000..fd0f3d4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
new file mode 100644
index 0000000..df5b495
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
new file mode 100644
index 0000000..81e3ff6
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
new file mode 100644
index 0000000..2d74c5f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..a85217a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
index 2f2e5c6..4fcf781 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
index d490dd2..72cb126 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
index 9d3c8f2..369cb14 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
index c326a6d..1b2cd88a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
index f894dea..421f698 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
deleted file mode 100644
index 37ddf2d..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index f17f9518..bb1ee73 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 3fc2944..35aeb67e2 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..4fcf781
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
new file mode 100644
index 0000000..72cb126
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
new file mode 100644
index 0000000..369cb14
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
new file mode 100644
index 0000000..1b2cd88a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..421f698
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index bf6353f..13d43660 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
index 029faa5..7f4d45d2 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
index 4c440d524..9219f13 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
index 37a5e6ee..65a83152 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
index 53d53b64..6149fae 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
index a005a14c..88420f90 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
index 0d087479..e525e33 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 37ddf2d..442db2f 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index fded683c..b1668679 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 990eeddc..0c704c7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 86c678bf..af71867 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..7f4d45d2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-repaint-expected.png
new file mode 100644
index 0000000..9219f13
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
new file mode 100644
index 0000000..65a83152
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
new file mode 100644
index 0000000..6149fae
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
new file mode 100644
index 0000000..88420f90
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..e525e33
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/synchronous_html_parser/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 9e516ce..134e041 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/vertical-align-baseline-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/vertical-align-baseline-expected.png
index 049a378f..12bf965 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/vertical-align-baseline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/vertical-align-baseline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
index b1729c1..e89c20c1 100644
--- a/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
index a75c4d49..a601fb67 100644
--- a/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
index 531e2cb..bf0589e 100644
--- a/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
index ab4d9b7..d814f1e2 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
index e13a47a..abe0a29 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
index 0222d0db..3231d6e8 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index b614cdef..0344095 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 2ceb5867..2893d72e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index b8bb5cb..5da3c2f 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 81f0416c5..299cb82 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
new file mode 100644
index 0000000..7a25866
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 2272219..2f385a5 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/vertical-align-baseline-expected.png b/third_party/blink/web_tests/platform/win/fast/table/vertical-align-baseline-expected.png
index 8c4d1f3b..0be278bd 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/vertical-align-baseline-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/vertical-align-baseline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
index 95c461c..844fb6a 100644
--- a/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
index e56c329..7f48a38 100644
--- a/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
index ec7b2a2..80939478 100644
--- a/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
index 366c068..c68c75c 100644
--- a/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
index cb26ec4..8d613450 100644
--- a/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
index 20f5e52..ce5124d 100644
--- a/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 66c9e33..458abc1 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 6884ba7..a0feae6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index f3d44bc..3191694 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 6193acc..c0cea46 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
new file mode 100644
index 0000000..3141639
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
deleted file mode 100644
index 66c9e33..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/scrollbars/scrollbar-added-during-drag.html b/third_party/blink/web_tests/scrollbars/scrollbar-added-during-drag.html
index e4a4ba2..2782f5a 100644
--- a/third_party/blink/web_tests/scrollbars/scrollbar-added-during-drag.html
+++ b/third_party/blink/web_tests/scrollbars/scrollbar-added-during-drag.html
@@ -35,6 +35,7 @@
 </head>
 <body>
 <iframe id="f"></iframe>
+<script src="../resources/gesture-util.js"></script>
 <script>
 
 var frame = document.getElementById("f").contentWindow;
@@ -48,9 +49,11 @@
         frameBody.style.width = "600px";
 });
 
-function runTest() {
+async function runTest() {
     testRunner.waitUntilDone();
 
+    await waitForCompositorCommit();
+
     // Tell eventSender not to batch mouse move events.
     eventSender.dragMode = false;
 
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 477ba43..28465116 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-4-242-g2f62d8e07
-Revision: 2f62d8e075656e6b5fb597e681ba4b2b8296900c
+Version: VER-2-10-4-243-g967a34eee
+Revision: 967a34eee3fd34f496366ed1283ab5268d23690a
 CPEPrefix: cpe:/a:freetype:freetype:2.10.4
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 06c1ac1..8dfcc66 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -198,6 +198,8 @@
       "src/src/hb-ot-var-mvar-table.hh",
       "src/src/hb-ot-var.cc",
       "src/src/hb-pool.hh",
+      "src/src/hb-priority-queue.hh",
+      "src/src/hb-repacker.hh",
       "src/src/hb-sanitize.hh",
       "src/src/hb-serialize.hh",
       "src/src/hb-set-digest.hh",
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 129a13b..e9a630f 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,10 +1,10 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.7.4-246
+Version: 2.8.1-0
 CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:2.6.4
-Date: 20210316
-Revision: 4c34478b28497acfce02b8a544fed4ae20526336
+Date: 20210505
+Revision: b37f03f16b39d397a626f097858e9ae550234ca0
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/third_party/usrsctp/README.chromium b/third_party/usrsctp/README.chromium
index bd87e34..b4ca43c 100644
--- a/third_party/usrsctp/README.chromium
+++ b/third_party/usrsctp/README.chromium
@@ -2,8 +2,8 @@
 URL: http://github.com/sctplab/usrsctp
 Version: 0
 CPEPrefix: cpe:/a:usrsctp_project:usrsctp:2019-12-20
-Date: May 3, 2021
-Revision: 0bd8b8110bc1a388649e504de1e673114e91013f
+Date: May 10, 2021
+Revision: acfce46e428cc084b4bd0164e1b019261a8dbeda
 License: New BSD
 License File: LICENSE
 Security Critical: yes
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index de4c8e0..cdecce44 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -46874,6 +46874,8 @@
   <int value="50643563" label="MBIMode:enabled"/>
   <int value="51793504" label="protect-sync-credential-on-reauth:disabled"/>
   <int value="52150780" label="OsSettingsPolymer3:disabled"/>
+  <int value="52186948"
+      label="AllowDefaultWebAppMigrationForChromeOsManagedUsers:enabled"/>
   <int value="52368742" label="enable-pixel-canvas-recording:disabled"/>
   <int value="54258707" label="NewTabstripAnimation:enabled"/>
   <int value="54571864" label="EnableDisplayZoomSetting:enabled"/>
@@ -48843,6 +48845,8 @@
       label="AssistantEnableMediaSessionIntegration:disabled"/>
   <int value="1789517771" label="MacV2Sandbox:enabled"/>
   <int value="1789793147" label="HTTPSServerPreviewsUsingURLLoader:disabled"/>
+  <int value="1789795039"
+      label="AllowDefaultWebAppMigrationForChromeOsManagedUsers:disabled"/>
   <int value="1792609232" label="NTPShortcuts:enabled"/>
   <int value="1793023585"
       label="ClickToCallContextMenuForSelectedText:disabled"/>
@@ -64767,6 +64771,7 @@
   <int value="13" label="kChromeViewsDelegate"/>
   <int value="14" label="kDevToolsWindow"/>
   <int value="15" label="kWebAppPermissionDialogWindow"/>
+  <int value="16" label="kSessionDataDeleter"/>
 </enum>
 
 <enum name="ProfileMenuActionableItem">
@@ -71028,6 +71033,15 @@
   <int value="8" label="The Startup pages button was clicked."/>
 </enum>
 
+<enum name="SessionDataStatus">
+  <int value="0" label="kUninitialized"/>
+  <int value="1" label="kInitialized"/>
+  <int value="2" label="kDeletionStarted"/>
+  <int value="3" label="kDeletionFinished"/>
+  <int value="4" label="kNoDeletionDueToForceKeepSessionData"/>
+  <int value="5" label="kNoDeletionDueToShutdown"/>
+</enum>
+
 <enum name="SessionRestoreActions">
   <int value="0" label="A session restore was started"/>
   <int value="1" label="A session restore deferred one or more tabs"/>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
index ac46323..cd8de83c 100644
--- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -127,7 +127,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Canvas.GetImageDataScaledDuration"
-    units="microseconds * 10/sqrt(pixels)" expires_after="2021-01-31">
+    units="microseconds * 10/sqrt(pixels)" expires_after="2022-05-10">
   <owner>fserb@chromium.org</owner>
   <owner>aaronhk@chromium.org</owner>
   <summary>
@@ -144,6 +144,9 @@
     will cause this metric to have an abnormal distribution. When considering
     revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
     solution.
+
+    Warning: this histogram was expired from 2021-01-31 to 2021-05-10; data may
+    be missing.
   </summary>
 </histogram>
 
@@ -216,7 +219,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Canvas.PutImageDataScaledDuration"
-    units="microseconds * 10/sqrt(pixels)" expires_after="2021-01-31">
+    units="microseconds * 10/sqrt(pixels)" expires_after="2022-05-10">
   <owner>fserb@chromium.org</owner>
   <owner>aaronhk@chromium.org</owner>
   <summary>
@@ -233,6 +236,9 @@
     will cause this metric to have an abnormal distribution. When considering
     revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
     solution.
+
+    Warning: this histogram was expired from 2021-01-31 to 2021-05-10; data may
+    be missing.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index d01a6cd3..d973b55 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -579,6 +579,25 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.Gaia.Message.{GaiaAuthFlow}.{MessageName}"
+    enum="BooleanReceived" expires_after="2022-01-01">
+  <owner>rsorokin@chromium.org</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    Records whether or not {MessageName} was received during the {GaiaAuthFlow}
+    authentication on the login screen. Recorded on the successful online
+    authentication only.
+  </summary>
+  <token key="GaiaAuthFlow">
+    <variant name="Gaia"/>
+    <variant name="Saml"/>
+  </token>
+  <token key="MessageName">
+    <variant name="CloseView"/>
+    <variant name="UserInfo"/>
+  </token>
+</histogram>
+
 <histogram name="ChromeOS.Gaia.PasswordFlow" enum="BooleanStartedCompleted"
     expires_after="2022-01-01">
   <owner>rsorokin@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
index b3ed4855..e8f8065 100644
--- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -448,6 +448,16 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Discardable.FreelistSize.Dirty" units="KiB"
+    expires_after="2021-12-04">
+  <owner>thiabaud@google.com</owner>
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    Amount of resident memory that was in use but has now been moved to the
+    freelist. Recorded during |OnMemoryDump|.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Discardable.FreelistSize.Foreground" units="KiB"
     expires_after="2021-10-04">
   <owner>thiabaud@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index 786a5337..9f41edb5 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -945,6 +945,22 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.PakIntegrity.{PakFile}" enum="BooleanSuccess"
+    expires_after="2022-05-01">
+  <owner>rsesek@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Reports whether the {PakFile} file's SHA-256 hash matches the digest
+    produced at build-time. This detects on-disk corruption of the .pak file.
+    Recorded at startup on ChromeOS, Linux, Mac, and Windows.
+  </summary>
+  <token key="PakFile">
+    <variant name="Chrome100" summary="chrome_100_percent.pak"/>
+    <variant name="Chrome200" summary="chrome_200_percent.pak"/>
+    <variant name="Resources" summary="resources.pak"/>
+  </token>
+</histogram>
+
 <histogram name="SafeBrowsing.Policy.AllowlistDomainsTotalSize" units="bytes"
     expires_after="2022-02-26">
   <owner>xinghuilu@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/session/histograms.xml b/tools/metrics/histograms/histograms_xml/session/histograms.xml
index 3cb930f2..5ed0f68 100644
--- a/tools/metrics/histograms/histograms_xml/session/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/session/histograms.xml
@@ -73,6 +73,27 @@
   </summary>
 </histogram>
 
+<histogram name="Session.SessionData.CleanupTime" units="ms"
+    expires_after="M95">
+  <owner>dullweber@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <summary>
+    Records the duration of a session-only cookies and site data deletion when
+    the deletion is finished. Only recorded for users with Clear on Exit
+    settings.
+  </summary>
+</histogram>
+
+<histogram name="Session.SessionData.StatusFromLastSession"
+    enum="SessionDataStatus" expires_after="M95">
+  <owner>dullweber@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <summary>
+    Records whether cookie deletion on previous session exit succeeded. Only
+    recorded on startup for users with Clear on Exit settings.
+  </summary>
+</histogram>
+
 <histogram name="Session.TimeSpentInFocusMode" units="s" expires_after="M80">
   <owner>yiningwang@google.com</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 8155b6c..574f83f 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -2,7 +2,7 @@
     "trace_processor_shell": {
         "win": {
             "hash": "23cff3007ff25abed77bdaa20c104a0cfdb12219",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/5dfd4bdd5b10dc62ae2c6d021573bb889efaf056/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/5d9269eb9603b51fb1e830da1fe617400824da92/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "72fc3915dddc48d4d1a256acf8eada25c740eb9e",
@@ -10,7 +10,7 @@
         },
         "linux": {
             "hash": "b95b2b75294ef7c5ed96e53582c5d8f0d4e575bd",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/5dfd4bdd5b10dc62ae2c6d021573bb889efaf056/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/97ab54da511763dfeebe6d03279e7b1f75c12b11/trace_processor_shell"
         }
     },
     "power_profile.sql": {