diff --git a/DEPS b/DEPS
index ceedad8..2de60bc 100644
--- a/DEPS
+++ b/DEPS
@@ -304,15 +304,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '3b247bf59924dfb2400747e84b52a917138df3c9',
+  'skia_revision': '32f4cfc2460b48e00f05c73ef41cdf2852617f0b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6dc0c82ab7af4149c751ab44d8da5d127c7dc5b3',
+  'v8_revision': 'ab2b75dcf8729614806334150606d018bc092f7d',
   # 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': 'b0f9c01ec3033452d75be3c0307febadfdc0ddae',
+  'angle_revision': '1b8d11a580fbe5f0c7024ee7912f2d4361e11c18',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -467,7 +467,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '85832f6a6d8760e1f9d8c5e771c149f33d0b13f3',
+  'cros_components_revision': '247f84f08e5ce752f40cd2a74693ec0b8dc7bb7b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -515,7 +515,7 @@
 allowed_hosts = [
   'android.googlesource.com',
   'aomedia.googlesource.com',
-  'beto-rust.googlesource.com',
+  'beto-core.googlesource.com',
   'boringssl.googlesource.com',
   'chrome-infra-packages.appspot.com',
   'chrome-internal.googlesource.com',
@@ -796,7 +796,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '533eac35d9da5308947f27a382fb6ae641f6895e',
+    '2206d93464819bdca32639e3fd89f746fe59ebc0',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -985,7 +985,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'qy3eWpNl1aAOhF7X_alJ2QNxLt9wLfAbACD0c4hAN0sC',
+          'version': 'QNAxUuOTpBt1SYYwm3OThELbjhGSxagL_Wf49uXtSS4C',
       },
     ],
     'condition': 'checkout_android',
@@ -1693,7 +1693,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '0b3824020e3b444cb05de5020ded5102fc259507',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6c650e1ad49593538b1bff04070cce56b8f036f9',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1838,7 +1838,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@d36b7c91621ac101d0bdcda19aee6362190dca50',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@da6d09fb0492cfeecc2a254152a07de5c3e0b11c',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1878,7 +1878,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e8dbfc3f48b4605bd0eb5bfb7c361434480b55fd',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '6456952c9477be87b31ede36c9a78f470467a933',
+    Var('webrtc_git') + '/src.git' + '@' + '2d7424305d1d24d9c26c463b7a45eb58cc7d3362',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -2031,7 +2031,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'Eb4APgoJZ3_83LRHTwiBySA-MUE9hihesIhwgMmvsusC',
+        'version': 'I5bPsXwE_x8V6gBxZOrEf9pBjfuIWX6N9MhW-gADsYUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4167,7 +4167,7 @@
 
   'src/ios_internal':  {
       'url': '{chrome_git}/chrome/ios_internal.git' + '@' +
-        'ebe9fdd913d387fc7582c39f71c753a7757c8a89',
+        '9ed042536d45a402fa072578f3d1caaf23e21f62',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc
index 7dd21f82..a14e342 100644
--- a/android_webview/browser/aw_autofill_client.cc
+++ b/android_webview/browser/aw_autofill_client.cc
@@ -357,7 +357,7 @@
            content::SSLStatus::RAN_INSECURE_CONTENT);
 }
 
-void AwAutofillClient::ExecuteCommand(int id) {
+void AwAutofillClient::ExecuteCommand(autofill::Suggestion::FrontendId id) {
   NOTIMPLEMENTED();
 }
 
@@ -443,7 +443,7 @@
       label = ConvertUTF16ToJavaString(env, suggestions[i].labels[0][0].value);
 
     Java_AwAutofillClient_addToAutofillSuggestionArray(
-        env, data_array, i, name, label, suggestions[i].frontend_id);
+        env, data_array, i, name, label, suggestions[i].frontend_id.as_int());
   }
   ui::ViewAndroid* view_android = GetWebContents().GetNativeView();
   if (!view_android)
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h
index 6d698c5..6b37de8 100644
--- a/android_webview/browser/aw_autofill_client.h
+++ b/android_webview/browser/aw_autofill_client.h
@@ -161,7 +161,7 @@
   void DidFillOrPreviewField(const std::u16string& autofilled_value,
                              const std::u16string& profile_full_name) override;
   bool IsContextSecure() const override;
-  void ExecuteCommand(int id) override;
+  void ExecuteCommand(autofill::Suggestion::FrontendId id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
diff --git a/ash/system/unified/power_button.cc b/ash/system/unified/power_button.cc
index ae68be29..f3c49a9 100644
--- a/ash/system/unified/power_button.cc
+++ b/ash/system/unified/power_button.cc
@@ -14,6 +14,7 @@
 #include "ash/shutdown_reason.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/icon_button.h"
+#include "ash/style/style_util.h"
 #include "ash/style/typography.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -394,12 +395,16 @@
   set_context_menu_controller(context_menu_.get());
 
   // Installs the customized focus ring path generator for the button.
-  views::FocusRing::Install(button_content_);
-  views::FocusRing::Get(button_content_)
-      ->SetPathGenerator(
-          std::make_unique<HighlightPathGenerator>(/*power_button=*/this));
+  views::HighlightPathGenerator::Install(
+      button_content_,
+      std::make_unique<HighlightPathGenerator>(/*power_button=*/this));
   views::FocusRing::Get(button_content_)
       ->SetColorId(cros_tokens::kCrosSysPrimary);
+
+  // Ripple.
+  StyleUtil::SetUpInkDropForButton(button_content_, gfx::Insets(),
+                                   /*highlight_on_hover=*/false,
+                                   /*highlight_on_focus=*/false);
 }
 
 PowerButton::~PowerButton() = default;
diff --git a/ash/webui/camera_app_ui/resources/css/colors_default.css b/ash/webui/camera_app_ui/resources/css/colors_default.css
index cffe1734..11bb0fd7 100644
--- a/ash/webui/camera_app_ui/resources/css/colors_default.css
+++ b/ash/webui/camera_app_ui/resources/css/colors_default.css
@@ -184,3 +184,7 @@
     color: var(--grey-900);
   }
 }
+
+.review-views .button-group button[i18n-text=label_share] svg-wrapper {
+  color: var(--blue-300);
+}
diff --git a/ash/webui/camera_app_ui/resources/css/review.css b/ash/webui/camera_app_ui/resources/css/review.css
index 679cffa7..4cb49ad 100644
--- a/ash/webui/camera_app_ui/resources/css/review.css
+++ b/ash/webui/camera_app_ui/resources/css/review.css
@@ -42,8 +42,8 @@
   left: calc(var(--left-line) * 2);
 }
 
-.review-views .button-group button[i18n-text=label_share]::before {
-  content: url(/images/review_share.svg);
+.review-views .button-group button[i18n-text=label_share] svg-wrapper {
+  color: var(--cros-sys-on_primary_container);
   display: inline-block;
   line-height: normal;
   margin-inline-end: 5px;
diff --git a/ash/webui/camera_app_ui/resources/images/document_review_share.svg b/ash/webui/camera_app_ui/resources/images/document_review_share.svg
deleted file mode 100644
index 214afaab..0000000
--- a/ash/webui/camera_app_ui/resources/images/document_review_share.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M14 12C13.21 12 12.5 12.31 11.97 12.81L7.91 10.7C7.96 10.47 8 10.24 8 10C8 9.76 7.96 9.53 7.91 9.3L11.96 7.19C12.49 7.69 13.21 8 14 8C15.66 8 17 6.66 17 5C17 3.34 15.66 2 14 2C12.34 2 11 3.34 11 5C11 5.24 11.04 5.48 11.09 5.7L7.04 7.81C6.5 7.31 5.79 7 5 7C3.34 7 2 8.34 2 10C2 11.66 3.34 13 5 13C5.79 13 6.5 12.69 7.04 12.19L11.09 14.31C11.04 14.53 11 14.76 11 15C11 16.66 12.34 18 14 18C15.66 18 17 16.66 17 15C17 13.34 15.66 12 14 12ZM14 4C14.55 4 15 4.45 15 5C15 5.55 14.55 6 14 6C13.45 6 13 5.55 13 5C13 4.45 13.45 4 14 4ZM5 11C4.45 11 4 10.55 4 10C4 9.45 4.45 9 5 9C5.55 9 6 9.45 6 10C6 10.55 5.55 11 5 11ZM14 16C13.45 16 13 15.55 13 15C13 14.45 13.45 14 14 14C14.55 14 15 14.45 15 15C15 15.55 14.55 16 14 16Z"/>
-</svg>
diff --git a/ash/webui/camera_app_ui/resources/images/images.gni b/ash/webui/camera_app_ui/resources/images/images.gni
index 553772c..50a3fd0 100644
--- a/ash/webui/camera_app_ui/resources/images/images.gni
+++ b/ash/webui/camera_app_ui/resources/images/images.gni
@@ -38,7 +38,6 @@
   "crop_document_clockwise_rotate.svg",
   "crop_document_counterclockwise_rotate.svg",
   "document_mode_spinner.svg",
-  "document_review_share.svg",
   "document_review_add_page.svg",
   "document_review_delete_page.svg",
   "document_review_fix_page.svg",
diff --git a/ash/webui/camera_app_ui/resources/images/review_share.svg b/ash/webui/camera_app_ui/resources/images/review_share.svg
index 324417c..214afaab 100644
--- a/ash/webui/camera_app_ui/resources/images/review_share.svg
+++ b/ash/webui/camera_app_ui/resources/images/review_share.svg
@@ -1,3 +1,3 @@
-<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M12 10C11.21 10 10.5 10.31 9.97 10.81L5.91 8.7C5.96 8.47 6 8.24 6 8C6 7.76 5.96 7.53 5.91 7.3L9.96 5.19C10.49 5.69 11.21 6 12 6C13.66 6 15 4.66 15 3C15 1.34 13.66 0 12 0C10.34 0 9 1.34 9 3C9 3.24 9.04 3.48 9.09 3.7L5.04 5.81C4.5 5.31 3.79 5 3 5C1.34 5 0 6.34 0 8C0 9.66 1.34 11 3 11C3.79 11 4.5 10.69 5.04 10.19L9.09 12.31C9.04 12.53 9 12.76 9 13C9 14.66 10.34 16 12 16C13.66 16 15 14.66 15 13C15 11.34 13.66 10 12 10ZM12 2C12.55 2 13 2.45 13 3C13 3.55 12.55 4 12 4C11.45 4 11 3.55 11 3C11 2.45 11.45 2 12 2ZM3 9C2.45 9 2 8.55 2 8C2 7.45 2.45 7 3 7C3.55 7 4 7.45 4 8C4 8.55 3.55 9 3 9ZM12 14C11.45 14 11 13.55 11 13C11 12.45 11.45 12 12 12C12.55 12 13 12.45 13 13C13 13.55 12.55 14 12 14Z" fill="#8AB4F8"/>
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14 12C13.21 12 12.5 12.31 11.97 12.81L7.91 10.7C7.96 10.47 8 10.24 8 10C8 9.76 7.96 9.53 7.91 9.3L11.96 7.19C12.49 7.69 13.21 8 14 8C15.66 8 17 6.66 17 5C17 3.34 15.66 2 14 2C12.34 2 11 3.34 11 5C11 5.24 11.04 5.48 11.09 5.7L7.04 7.81C6.5 7.31 5.79 7 5 7C3.34 7 2 8.34 2 10C2 11.66 3.34 13 5 13C5.79 13 6.5 12.69 7.04 12.19L11.09 14.31C11.04 14.53 11 14.76 11 15C11 16.66 12.34 18 14 18C15.66 18 17 16.66 17 15C17 13.34 15.66 12 14 12ZM14 4C14.55 4 15 4.45 15 5C15 5.55 14.55 6 14 6C13.45 6 13 5.55 13 5C13 4.45 13.45 4 14 4ZM5 11C4.45 11 4 10.55 4 10C4 9.45 4.45 9 5 9C5.55 9 6 9.45 6 10C6 10.55 5.55 11 5 11ZM14 16C13.45 16 13 15.55 13 15C13 14.45 13.45 14 14 14C14.55 14 15 14.45 15 15C15 15.55 14.55 16 14 16Z"/>
 </svg>
diff --git a/ash/webui/camera_app_ui/resources/js/util.ts b/ash/webui/camera_app_ui/resources/js/util.ts
index 3fe20a0..97cfab29 100644
--- a/ash/webui/camera_app_ui/resources/js/util.ts
+++ b/ash/webui/camera_app_ui/resources/js/util.ts
@@ -166,7 +166,16 @@
   }
 
   for (const element of getElements('i18n-text')) {
-    element.textContent = getMessage(element, 'i18n-text');
+    // The element that has i18n-text is assumed to have no direct text node
+    // child other than the one generated by i18n-text, and might have other
+    // elements as child. Remove all the text node in case this is called more
+    // than once, and append the text node.
+    for (const node of Array.from(element.childNodes)) {
+      if (node.nodeType === Node.TEXT_NODE) {
+        node.remove();
+      }
+    }
+    element.append(getMessage(element, 'i18n-text'));
   }
   for (const element of getElements('i18n-tooltip-true')) {
     element.setAttribute(
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera.ts b/ash/webui/camera_app_ui/resources/js/views/camera.ts
index 9246cbf7..29a74bf 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera.ts
@@ -795,12 +795,14 @@
       const positive = new review.OptionGroup<boolean>({
         template: review.ButtonGroupTemplate.POSITIVE,
         options: [
-          new review.Option({text: I18nString.LABEL_SHARE}, {
-            callback: async () => {
-              sendEvent(metrics.GifResultType.SHARE);
-              await util.share(new File([blob], name, {type: MimeType.GIF}));
-            },
-          }),
+          new review.Option(
+              {text: I18nString.LABEL_SHARE, icon: 'review_share.svg'}, {
+                callback: async () => {
+                  sendEvent(metrics.GifResultType.SHARE);
+                  await util.share(
+                      new File([blob], name, {type: MimeType.GIF}));
+                },
+              }),
           new review.Option(
               {text: I18nString.LABEL_SAVE, primary: true}, {exitValue: true}),
         ],
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_preview_mode.ts b/ash/webui/camera_app_ui/resources/js/views/document_preview_mode.ts
index bb3de859..a8981f8 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_preview_mode.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_preview_mode.ts
@@ -80,7 +80,7 @@
         {
           render: (el: HTMLElement) => {
             const {icon, label, container} = makeMenuItemElements();
-            icon.setAttribute('name', 'document_review_share.svg');
+            icon.setAttribute('name', 'review_share.svg');
             label.textContent = getI18nMessage(I18nString.LABEL_SHARE);
             container.append(icon, label);
             el.append(container);
diff --git a/ash/webui/camera_app_ui/resources/js/views/review.ts b/ash/webui/camera_app_ui/resources/js/views/review.ts
index 230e384..734305f3 100644
--- a/ash/webui/camera_app_ui/resources/js/views/review.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/review.ts
@@ -17,6 +17,7 @@
 interface UIArgs {
   text?: I18nString;
   label?: I18nString;
+  icon?: string;
   templateId?: string;
   primary?: boolean;
 }
@@ -162,7 +163,7 @@
     }
     for (const btnGroup of btnGroups) {
       const addButton = ({
-        uiArgs: {text, label, templateId, primary},
+        uiArgs: {text, label, icon, templateId, primary},
         exitValue,
         callback,
         hasPopup,
@@ -177,6 +178,11 @@
         if (label !== undefined) {
           btn.setAttribute('i18n-label', label);
         }
+        if (icon !== undefined) {
+          const iconEl = document.createElement('svg-wrapper');
+          iconEl.name = icon;
+          btn.prepend(iconEl);
+        }
         if (this.primaryBtn === null && primary === true) {
           btn.classList.add('primary');
           this.primaryBtn = btn;
diff --git a/ash/webui/camera_app_ui/resources/utils/cca.py b/ash/webui/camera_app_ui/resources/utils/cca.py
index 51ca3b1..606ae2a 100755
--- a/ash/webui/camera_app_ui/resources/utils/cca.py
+++ b/ash/webui/camera_app_ui/resources/utils/cca.py
@@ -30,14 +30,14 @@
     return ' '.join(shlex.quote(c) for c in cmd)
 
 
-def run(args, cwd=None):
+def run(args):
     logging.debug(f'$ {shell_join(args)}')
-    subprocess.check_call(args, cwd=cwd)
+    subprocess.check_call(args)
 
 
-def check_output(args, cwd=None):
+def check_output(args):
     logging.debug(f'$ {shell_join(args)}')
-    return subprocess.check_output(args, cwd=cwd, text=True)
+    return subprocess.check_output(args, text=True)
 
 
 def run_node(args):
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html
index 62a9810a..a17657d9 100644
--- a/ash/webui/camera_app_ui/resources/views/main.html
+++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -672,7 +672,7 @@
             </button>
             <button class="icon-button dark inkdrop"
               i18n-label="label_share" tabindex="0">
-              <svg-wrapper name="document_review_share.svg"></svg-wrapper>
+              <svg-wrapper name="review_share.svg"></svg-wrapper>
             </button>
             <button class="icon-button dark inkdrop"
               i18n-label="fix_page_button" tabindex="0">
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d764771..d5b4aa9a 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3812,7 +3812,8 @@
       # This test requires RELRO, which is not enabled in component builds.
       # Also, require a debug build, since we only disable stack protectors in
       # debug builds in partition alloc (see below why it's needed).
-      sources += [ "allocator/partition_allocator/pkey_unittest.cc" ]
+      sources +=
+          [ "allocator/partition_allocator/thread_isolation/pkey_unittest.cc" ]
 
       # We want to test the pkey code without access to memory that is not
       # pkey-tagged. This will allow us to catch unintended memory accesses
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index e2e10d5..152e1c7 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -161,8 +161,6 @@
     "partition_stats.cc",
     "partition_stats.h",
     "partition_tls.h",
-    "pkey.cc",
-    "pkey.h",
     "random.cc",
     "random.h",
     "reservation_offset_table.cc",
@@ -174,6 +172,11 @@
     "tagging.h",
     "thread_cache.cc",
     "thread_cache.h",
+    "thread_isolation/alignment.h",
+    "thread_isolation/pkey.cc",
+    "thread_isolation/pkey.h",
+    "thread_isolation/thread_isolation.cc",
+    "thread_isolation/thread_isolation.h",
     "yield_processor.h",
   ]
 
@@ -450,6 +453,7 @@
     "PCSCAN_STACK_SUPPORTED=$pcscan_stack_supported",
 
     "ENABLE_PKEYS=$enable_pkeys",
+    "ENABLE_THREAD_ISOLATION=$enable_pkeys",
   ]
 
   if (is_apple) {
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc
index 69fab42d..47e545f2 100644
--- a/base/allocator/partition_allocator/address_pool_manager.cc
+++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -17,11 +17,10 @@
 #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_notreached.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "build/build_config.h"
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(ENABLE_THREAD_ISOLATION)
 #include <sys/mman.h>
 #endif
 
@@ -301,8 +300,8 @@
   if (IsConfigurablePoolAvailable()) {
     GetPoolStats(kConfigurablePoolHandle, &stats->configurable_pool_stats);
   }
-#if BUILDFLAG(ENABLE_PKEYS)
-  GetPoolStats(kPkeyPoolHandle, &stats->pkey_pool_stats);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  GetPoolStats(kThreadIsolatedPoolHandle, &stats->thread_isolated_pool_stats);
 #endif
   return true;
 }
diff --git a/base/allocator/partition_allocator/address_pool_manager.h b/base/allocator/partition_allocator/address_pool_manager.h
index a2366cb7..7e59851 100644
--- a/base/allocator/partition_allocator/address_pool_manager.h
+++ b/base/allocator/partition_allocator/address_pool_manager.h
@@ -18,6 +18,8 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 #if !BUILDFLAG(HAS_64_BIT_POINTERS)
@@ -96,10 +98,10 @@
 
  private:
   friend class AddressPoolManagerForTesting;
-#if BUILDFLAG(ENABLE_PKEYS)
-  // If we use a pkey pool, we need to tag its metadata with the pkey. Allow the
-  // function to get access to the pool pointer.
-  friend void TagGlobalsWithPkey(int pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // If we use a thread isolated pool, we need to write-protect its metadata.
+  // Allow the function to get access to the pool pointer.
+  friend void WriteProtectThreadIsolatedGlobals(ThreadIsolationOption);
 #endif
 
   constexpr AddressPoolManager() = default;
@@ -162,14 +164,14 @@
   // initialized.
   void GetPoolStats(pool_handle handle, PoolStats* stats);
 
-  // If pkey support is enabled, we need to pkey-tag the pkey pool (which needs
-  // to be last). For this, we need to add padding in front of the pools so that
-  // pkey one starts on a page boundary.
+  // If thread isolation support is enabled, we need to write-protect the
+  // isolated pool (which needs to be last). For this, we need to add padding in
+  // front of the pools so that the isolated one starts on a page boundary.
   struct {
-    char pad_[PA_PKEY_ARRAY_PAD_SZ(Pool, kNumPools)] = {};
+    char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ(Pool, kNumPools)] = {};
     Pool pools_[kNumPools];
-    char pad_after_[PA_PKEY_FILL_PAGE_SZ(sizeof(Pool))] = {};
-  } aligned_pools_ PA_PKEY_ALIGN;
+    char pad_after_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(Pool))] = {};
+  } aligned_pools_ PA_THREAD_ISOLATED_ALIGN;
 
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
 
diff --git a/base/allocator/partition_allocator/address_space_stats.h b/base/allocator/partition_allocator/address_space_stats.h
index a9b4cb0..a603f43 100644
--- a/base/allocator/partition_allocator/address_space_stats.h
+++ b/base/allocator/partition_allocator/address_space_stats.h
@@ -37,8 +37,8 @@
   size_t blocklist_hit_count;
 #endif  // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
-#if BUILDFLAG(ENABLE_PKEYS)
-  PoolStats pkey_pool_stats;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  PoolStats thread_isolated_pool_stats;
 #endif
 };
 
diff --git a/base/allocator/partition_allocator/glossary.md b/base/allocator/partition_allocator/glossary.md
index 34fd688..ded74bd 100644
--- a/base/allocator/partition_allocator/glossary.md
+++ b/base/allocator/partition_allocator/glossary.md
@@ -105,8 +105,9 @@
     primary user (the [V8 Sandbox][v8-sandbox]) can configure it at runtime,
     providing a pre-existing mapping. Its allocations aren't protected by
     BackupRefPtr.
-  * [64-bit only] The pkey pool is returning memory tagged with a memory
-    protection key on supported platforms. It's primary user is [V8 CFI][v8-cfi].
+  * [64-bit only] The thread isolated pool is returning memory protected with
+    per-thread permissions. At the moment, this is implemented for pkeys on x64.
+    It's primary user is [V8 CFI][v8-cfi].
 
 *** promo
 Pools are downgraded into a logical concept in 32-bit environments,
diff --git a/base/allocator/partition_allocator/page_allocator.h b/base/allocator/partition_allocator/page_allocator.h
index e134744f..15248b7 100644
--- a/base/allocator/partition_allocator/page_allocator.h
+++ b/base/allocator/partition_allocator/page_allocator.h
@@ -12,6 +12,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -33,21 +34,23 @@
     kReadWriteExecute,
   };
 
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
   constexpr explicit PageAccessibilityConfiguration(Permissions permissions)
-      : permissions(permissions), pkey(0) {}
-  constexpr PageAccessibilityConfiguration(Permissions permissions, int pkey)
-      : permissions(permissions), pkey(pkey) {}
+      : permissions(permissions) {}
+  constexpr PageAccessibilityConfiguration(
+      Permissions permissions,
+      ThreadIsolationOption thread_isolation)
+      : permissions(permissions), thread_isolation(thread_isolation) {}
 #else
   constexpr explicit PageAccessibilityConfiguration(Permissions permissions)
       : permissions(permissions) {}
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
   Permissions permissions;
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
   // Tag the page with a Memory Protection Key. Use 0 for none.
-  int pkey;
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+  ThreadIsolationOption thread_isolation;
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 };
 
 // Use for De/RecommitSystemPages API.
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h
index 30009c9..7a59e054 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -6,6 +6,7 @@
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_
 
 #include <algorithm>
+#include <atomic>
 #include <cerrno>
 #include <cstdint>
 #include <cstring>
@@ -17,7 +18,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/allocator/partition_allocator/pkey.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_APPLE)
@@ -216,14 +217,16 @@
     uintptr_t address,
     size_t length,
     PageAccessibilityConfiguration accessibility) {
-#if BUILDFLAG(ENABLE_PKEYS)
-  return 0 == PkeyMprotectIfEnabled(reinterpret_cast<void*>(address), length,
-                                    GetAccessFlags(accessibility),
-                                    accessibility.pkey);
-#else
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  if (accessibility.thread_isolation.enabled) {
+    return 0 == MprotectWithThreadIsolation(reinterpret_cast<void*>(address),
+                                            length,
+                                            GetAccessFlags(accessibility),
+                                            accessibility.thread_isolation);
+  }
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
   return 0 == PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length,
                                        GetAccessFlags(accessibility)));
-#endif
 }
 
 void SetSystemPagesAccessInternal(
@@ -231,14 +234,18 @@
     size_t length,
     PageAccessibilityConfiguration accessibility) {
   int access_flags = GetAccessFlags(accessibility);
-#if BUILDFLAG(ENABLE_PKEYS)
-  int ret =
-      PkeyMprotectIfEnabled(reinterpret_cast<void*>(address), length,
-                            GetAccessFlags(accessibility), accessibility.pkey);
-#else
-  int ret = PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length,
-                                     GetAccessFlags(accessibility)));
-#endif
+  int ret;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  if (accessibility.thread_isolation.enabled) {
+    ret = MprotectWithThreadIsolation(reinterpret_cast<void*>(address), length,
+                                      GetAccessFlags(accessibility),
+                                      accessibility.thread_isolation);
+  } else
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  {
+    ret = PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length,
+                                   GetAccessFlags(accessibility)));
+  }
 
   // On Linux, man mprotect(2) states that ENOMEM is returned when (1) internal
   // kernel data structures cannot be allocated, (2) the address range is
diff --git a/base/allocator/partition_allocator/partition_address_space.cc b/base/allocator/partition_allocator/partition_address_space.cc
index 760a1ff..2f5b2d01 100644
--- a/base/allocator/partition_allocator/partition_address_space.cc
+++ b/base/allocator/partition_allocator/partition_address_space.cc
@@ -20,7 +20,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "base/allocator/partition_allocator/pkey.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_IOS)
@@ -31,7 +31,7 @@
 #include <windows.h>
 #endif  // BUILDFLAG(IS_WIN)
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA) || BUILDFLAG(ENABLE_PKEYS)
+#if PA_CONFIG(ENABLE_SHADOW_METADATA) || BUILDFLAG(ENABLE_THREAD_ISOLATION)
 #include <sys/mman.h>
 #endif
 
@@ -79,8 +79,8 @@
 
 }  // namespace
 
-#if BUILDFLAG(ENABLE_PKEYS)
-alignas(PA_PKEY_ALIGN_SZ)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+alignas(PA_THREAD_ISOLATED_ALIGN_SZ)
 #else
 alignas(kPartitionCachelineSize)
 #endif
@@ -294,12 +294,12 @@
   // The ConfigurablePool must only be initialized once.
   PA_CHECK(!IsConfigurablePoolInitialized());
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  // It's possible that the pkey pool has been initialized first, in which case
-  // the setup_ memory has been made read-only. Remove the protection
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // It's possible that the thread isolated pool has been initialized first, in
+  // which case the setup_ memory has been made read-only. Remove the protection
   // temporarily.
-  if (IsPkeyPoolInitialized()) {
-    TagGlobalsWithPkey(kDefaultPkey);
+  if (IsThreadIsolatedPoolInitialized()) {
+    UnprotectThreadIsolatedGlobals();
   }
 #endif
 
@@ -315,49 +315,54 @@
   AddressPoolManager::GetInstance().Add(
       kConfigurablePoolHandle, setup_.configurable_pool_base_address_, size);
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  // Put the pkey protection back in place.
-  if (IsPkeyPoolInitialized()) {
-    TagGlobalsWithPkey(setup_.pkey_);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // Put the metadata protection back in place.
+  if (IsThreadIsolatedPoolInitialized()) {
+    WriteProtectThreadIsolatedGlobals(setup_.thread_isolation_);
   }
 #endif
 }
 
-#if BUILDFLAG(ENABLE_PKEYS)
-void PartitionAddressSpace::InitPkeyPool(int pkey) {
-  // The PkeyPool can't be initialized with conflicting pkeys.
-  if (IsPkeyPoolInitialized()) {
-    PA_CHECK(setup_.pkey_ == pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+void PartitionAddressSpace::InitThreadIsolatedPool(
+    ThreadIsolationOption thread_isolation) {
+  // The ThreadIsolated pool can't be initialized with conflicting settings.
+  if (IsThreadIsolatedPoolInitialized()) {
+    PA_CHECK(setup_.thread_isolation_ == thread_isolation);
     return;
   }
 
-  size_t pool_size = PkeyPoolSize();
-  setup_.pkey_pool_base_address_ =
+  size_t pool_size = ThreadIsolatedPoolSize();
+  setup_.thread_isolated_pool_base_address_ =
       AllocPages(pool_size, pool_size,
                  PageAccessibilityConfiguration(
                      PageAccessibilityConfiguration::kInaccessible),
                  PageTag::kPartitionAlloc);
-  if (!setup_.pkey_pool_base_address_) {
+  if (!setup_.thread_isolated_pool_base_address_) {
     HandlePoolAllocFailure();
   }
 
-  PA_DCHECK(!(setup_.pkey_pool_base_address_ & (pool_size - 1)));
-  setup_.pkey_ = pkey;
+  PA_DCHECK(!(setup_.thread_isolated_pool_base_address_ & (pool_size - 1)));
+  setup_.thread_isolation_ = thread_isolation;
   AddressPoolManager::GetInstance().Add(
-      kPkeyPoolHandle, setup_.pkey_pool_base_address_, pool_size);
+      kThreadIsolatedPoolHandle, setup_.thread_isolated_pool_base_address_,
+      pool_size);
 
-  PA_DCHECK(!IsInPkeyPool(setup_.pkey_pool_base_address_ - 1));
-  PA_DCHECK(IsInPkeyPool(setup_.pkey_pool_base_address_));
-  PA_DCHECK(IsInPkeyPool(setup_.pkey_pool_base_address_ + pool_size - 1));
-  PA_DCHECK(!IsInPkeyPool(setup_.pkey_pool_base_address_ + pool_size));
+  PA_DCHECK(
+      !IsInThreadIsolatedPool(setup_.thread_isolated_pool_base_address_ - 1));
+  PA_DCHECK(IsInThreadIsolatedPool(setup_.thread_isolated_pool_base_address_));
+  PA_DCHECK(IsInThreadIsolatedPool(setup_.thread_isolated_pool_base_address_ +
+                                   pool_size - 1));
+  PA_DCHECK(!IsInThreadIsolatedPool(setup_.thread_isolated_pool_base_address_ +
+                                    pool_size));
 
   // TODO(1362969): support PA_ENABLE_SHADOW_METADATA
 }
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
 void PartitionAddressSpace::UninitForTesting() {
-#if BUILDFLAG(ENABLE_PKEYS)
-  UninitPkeyPoolForTesting();  // IN-TEST
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  UninitThreadIsolatedPoolForTesting();  // IN-TEST
 #endif
 #if PA_CONFIG(GLUE_CORE_POOLS)
   // The core pools (regular & BRP) were allocated using a single allocation of
@@ -384,35 +389,38 @@
 }
 
 void PartitionAddressSpace::UninitConfigurablePoolForTesting() {
-#if BUILDFLAG(ENABLE_PKEYS)
-  // It's possible that the pkey pool has been initialized first, in which case
-  // the setup_ memory has been made read-only. Remove the protection
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // It's possible that the thread isolated pool has been initialized first, in
+  // which case the setup_ memory has been made read-only. Remove the protection
   // temporarily.
-  if (IsPkeyPoolInitialized()) {
-    TagGlobalsWithPkey(kDefaultPkey);
+  if (IsThreadIsolatedPoolInitialized()) {
+    UnprotectThreadIsolatedGlobals();
   }
 #endif
   AddressPoolManager::GetInstance().Remove(kConfigurablePoolHandle);
   setup_.configurable_pool_base_address_ = kUninitializedPoolBaseAddress;
   setup_.configurable_pool_base_mask_ = 0;
-#if BUILDFLAG(ENABLE_PKEYS)
-  // Put the pkey protection back in place.
-  if (IsPkeyPoolInitialized()) {
-    TagGlobalsWithPkey(setup_.pkey_);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // Put the metadata protection back in place.
+  if (IsThreadIsolatedPoolInitialized()) {
+    WriteProtectThreadIsolatedGlobals(setup_.thread_isolation_);
   }
 #endif
 }
 
-#if BUILDFLAG(ENABLE_PKEYS)
-void PartitionAddressSpace::UninitPkeyPoolForTesting() {
-  if (IsPkeyPoolInitialized()) {
-    TagGlobalsWithPkey(kDefaultPkey);
-    PkeySettings::settings.enabled = false;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+void PartitionAddressSpace::UninitThreadIsolatedPoolForTesting() {
+  if (IsThreadIsolatedPoolInitialized()) {
+    UnprotectThreadIsolatedGlobals();
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+    ThreadIsolationSettings::settings.enabled = false;
+#endif
 
-    FreePages(setup_.pkey_pool_base_address_, PkeyPoolSize());
-    AddressPoolManager::GetInstance().Remove(kPkeyPoolHandle);
-    setup_.pkey_pool_base_address_ = kUninitializedPoolBaseAddress;
-    setup_.pkey_ = kInvalidPkey;
+    FreePages(setup_.thread_isolated_pool_base_address_,
+              ThreadIsolatedPoolSize());
+    AddressPoolManager::GetInstance().Remove(kThreadIsolatedPoolHandle);
+    setup_.thread_isolated_pool_base_address_ = kUninitializedPoolBaseAddress;
+    setup_.thread_isolation_.enabled = false;
   }
 }
 #endif
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h
index cd00f80..0f9da77 100644
--- a/base/allocator/partition_allocator/partition_address_space.h
+++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -21,8 +21,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/tagging.h"
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 // The feature is not applicable to 32-bit address space.
@@ -66,10 +67,10 @@
       PA_DCHECK(IsConfigurablePoolInitialized());
       pool = kConfigurablePoolHandle;
       base = setup_.configurable_pool_base_address_;
-#if BUILDFLAG(ENABLE_PKEYS)
-    } else if (IsInPkeyPool(address)) {
-      pool = kPkeyPoolHandle;
-      base = setup_.pkey_pool_base_address_;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    } else if (IsInThreadIsolatedPool(address)) {
+      pool = kThreadIsolatedPoolHandle;
+      base = setup_.thread_isolated_pool_base_address_;
 #endif
     } else {
       PA_NOTREACHED();
@@ -93,16 +94,16 @@
   //
   // This function must only be called from the main thread.
   static void InitConfigurablePool(uintptr_t pool_base, size_t size);
-#if BUILDFLAG(ENABLE_PKEYS)
-  static void InitPkeyPool(int pkey);
-  static void UninitPkeyPoolForTesting();
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  static void InitThreadIsolatedPool(ThreadIsolationOption thread_isolation);
+  static void UninitThreadIsolatedPoolForTesting();
 #endif
   static void UninitForTesting();
   static void UninitConfigurablePoolForTesting();
 
   PA_ALWAYS_INLINE static bool IsInitialized() {
     // Either neither or both regular and BRP pool are initialized. The
-    // configurable and pkey pool are initialized separately.
+    // configurable and thread isolated pool are initialized separately.
     if (setup_.regular_pool_base_address_ != kUninitializedPoolBaseAddress) {
       PA_DCHECK(setup_.brp_pool_base_address_ != kUninitializedPoolBaseAddress);
       return true;
@@ -117,9 +118,10 @@
            kUninitializedPoolBaseAddress;
   }
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  PA_ALWAYS_INLINE static bool IsPkeyPoolInitialized() {
-    return setup_.pkey_pool_base_address_ != kUninitializedPoolBaseAddress;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  PA_ALWAYS_INLINE static bool IsThreadIsolatedPoolInitialized() {
+    return setup_.thread_isolated_pool_base_address_ !=
+           kUninitializedPoolBaseAddress;
   }
 #endif
 
@@ -191,10 +193,11 @@
     return setup_.configurable_pool_base_address_;
   }
 
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
   // Returns false for nullptr.
-  PA_ALWAYS_INLINE static bool IsInPkeyPool(uintptr_t address) {
-    return (address & kPkeyPoolBaseMask) == setup_.pkey_pool_base_address_;
+  PA_ALWAYS_INLINE static bool IsInThreadIsolatedPool(uintptr_t address) {
+    return (address & kThreadIsolatedPoolBaseMask) ==
+           setup_.thread_isolated_pool_base_address_;
   }
 #endif
 
@@ -233,9 +236,9 @@
   }
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  PA_ALWAYS_INLINE static constexpr size_t PkeyPoolSize() {
-    return kPkeyPoolSize;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  PA_ALWAYS_INLINE static constexpr size_t ThreadIsolatedPoolSize() {
+    return kThreadIsolatedPoolSize;
   }
 #endif
 
@@ -262,9 +265,9 @@
   static constexpr size_t kBRPPoolSize = kPoolMaxSize;
   static_assert(base::bits::IsPowerOfTwo(kRegularPoolSize));
   static_assert(base::bits::IsPowerOfTwo(kBRPPoolSize));
-#if BUILDFLAG(ENABLE_PKEYS)
-  static constexpr size_t kPkeyPoolSize = kGiB / 4;
-  static_assert(base::bits::IsPowerOfTwo(kPkeyPoolSize));
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  static constexpr size_t kThreadIsolatedPoolSize = kGiB / 4;
+  static_assert(base::bits::IsPowerOfTwo(kThreadIsolatedPoolSize));
 #endif
   static constexpr size_t kConfigurablePoolMaxSize = kPoolMaxSize;
   static constexpr size_t kConfigurablePoolMinSize = 1 * kGiB;
@@ -299,10 +302,11 @@
   static constexpr uintptr_t kBRPPoolBaseMask = ~kBRPPoolOffsetMask;
 #endif  // !PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  static constexpr uintptr_t kPkeyPoolOffsetMask =
-      static_cast<uintptr_t>(kPkeyPoolSize) - 1;
-  static constexpr uintptr_t kPkeyPoolBaseMask = ~kPkeyPoolOffsetMask;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  static constexpr uintptr_t kThreadIsolatedPoolOffsetMask =
+      static_cast<uintptr_t>(kThreadIsolatedPoolSize) - 1;
+  static constexpr uintptr_t kThreadIsolatedPoolBaseMask =
+      ~kThreadIsolatedPoolOffsetMask;
 #endif
 
   // This must be set to such a value that IsIn*Pool() always returns false when
@@ -318,8 +322,8 @@
         : regular_pool_base_address_(kUninitializedPoolBaseAddress),
           brp_pool_base_address_(kUninitializedPoolBaseAddress),
           configurable_pool_base_address_(kUninitializedPoolBaseAddress),
-#if BUILDFLAG(ENABLE_PKEYS)
-          pkey_pool_base_address_(kUninitializedPoolBaseAddress),
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+          thread_isolated_pool_base_address_(kUninitializedPoolBaseAddress),
 #endif
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
           regular_pool_base_mask_(0),
@@ -328,12 +332,7 @@
           core_pools_base_mask_(0),
 #endif
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
-          configurable_pool_base_mask_(0)
-#if BUILDFLAG(ENABLE_PKEYS)
-          ,
-          pkey_(kInvalidPkey)
-#endif
-    {
+          configurable_pool_base_mask_(0) {
     }
 
     // Using a union to enforce padding.
@@ -342,8 +341,8 @@
         uintptr_t regular_pool_base_address_;
         uintptr_t brp_pool_base_address_;
         uintptr_t configurable_pool_base_address_;
-#if BUILDFLAG(ENABLE_PKEYS)
-        uintptr_t pkey_pool_base_address_;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+        uintptr_t thread_isolated_pool_base_address_;
 #endif
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
         uintptr_t regular_pool_base_mask_;
@@ -353,21 +352,21 @@
 #endif
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
         uintptr_t configurable_pool_base_mask_;
-#if BUILDFLAG(ENABLE_PKEYS)
-        int pkey_;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+        ThreadIsolationOption thread_isolation_;
 #endif
       };
 
-#if BUILDFLAG(ENABLE_PKEYS)
-      // With pkey support, we want to be able to pkey-tag all global metadata
-      // which requires page granularity.
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+      // With thread isolation support, we want to be able to write-protect all
+      // global metadata which requires page granularity.
       char one_page_[SystemPageSize()];
 #else
       char one_cacheline_[kPartitionCachelineSize];
 #endif
     };
   };
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
   static_assert(sizeof(PoolSetup) % SystemPageSize() == 0,
                 "PoolSetup has to fill a page(s)");
 #else
@@ -380,9 +379,9 @@
   // These are write-once fields, frequently accessed thereafter. Make sure they
   // don't share a cacheline with other, potentially writeable data, through
   // alignment and padding.
-#if BUILDFLAG(ENABLE_PKEYS)
-  static_assert(PA_PKEY_ALIGN_SZ >= kPartitionCachelineSize);
-  alignas(PA_PKEY_ALIGN_SZ)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  static_assert(PA_THREAD_ISOLATED_ALIGN_SZ >= kPartitionCachelineSize);
+  alignas(PA_THREAD_ISOLATED_ALIGN_SZ)
 #else
   alignas(kPartitionCachelineSize)
 #endif
@@ -393,10 +392,10 @@
   static std::ptrdiff_t brp_pool_shadow_offset_;
 #endif
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  // If we use a pkey pool, we need to tag its metadata with the pkey. Allow the
-  // function to get access to the PoolSetup.
-  friend void TagGlobalsWithPkey(int pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // If we use thread isolation, we need to write-protect its metadata.
+  // Allow the function to get access to the PoolSetup.
+  friend void WriteProtectThreadIsolatedGlobals(ThreadIsolationOption);
 #endif
 };
 
@@ -431,8 +430,8 @@
 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
          || internal::PartitionAddressSpace::IsInBRPPool(address)
 #endif
-#if BUILDFLAG(ENABLE_PKEYS)
-         || internal::PartitionAddressSpace::IsInPkeyPool(address)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+         || internal::PartitionAddressSpace::IsInThreadIsolatedPool(address)
 #endif
          || internal::PartitionAddressSpace::IsInConfigurablePool(address);
 }
@@ -461,10 +460,11 @@
   return internal::PartitionAddressSpace::IsInConfigurablePool(address);
 }
 
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
 // Returns false for nullptr.
-PA_ALWAYS_INLINE bool IsManagedByPartitionAllocPkeyPool(uintptr_t address) {
-  return internal::PartitionAddressSpace::IsInPkeyPool(address);
+PA_ALWAYS_INLINE bool IsManagedByPartitionAllocThreadIsolatedPool(
+    uintptr_t address) {
+  return internal::PartitionAddressSpace::IsInThreadIsolatedPool(address);
 }
 #endif
 
diff --git a/base/allocator/partition_allocator/partition_alloc-inl.h b/base/allocator/partition_allocator/partition_alloc-inl.h
index e5725de..4dfa4d20 100644
--- a/base/allocator/partition_allocator/partition_alloc-inl.h
+++ b/base/allocator/partition_allocator/partition_alloc-inl.h
@@ -12,9 +12,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/random.h"
 #include "base/allocator/partition_allocator/tagging.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 // Prefetch *x into memory.
@@ -59,8 +59,8 @@
   // faster. Note that for direct-mapped allocations, memory is decomitted at
   // free() time, so freed memory usage cannot happen.
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  LiftPkeyRestrictionsScope lift_pkey_restrictions;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  LiftThreadIsolationScope lift_thread_isolation_restrictions;
 #endif
   size_t size_to_memset = std::min(size, size_t{1} << 19);
   memset(ptr, value, size_to_memset);
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index a77af34..ad224ac 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -101,8 +101,8 @@
 }
 
 void PartitionAllocGlobalUninitForTesting() {
-#if BUILDFLAG(ENABLE_PKEYS)
-  internal::PartitionAddressSpace::UninitPkeyPoolForTesting();
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  internal::PartitionAddressSpace::UninitThreadIsolatedPoolForTesting();
 #endif
   internal::g_oom_handling_function = nullptr;
 }
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h
index b817a24c..53eec16 100644
--- a/base/allocator/partition_allocator/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -270,10 +270,10 @@
 
 // New pool_handles will be added here.
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  // The pkey pool must come last since we pkey_mprotect its entry in the
-  // metadata tables, e.g. AddressPoolManager::aligned_pools_
-  kPkeyPoolHandle,
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // The thread isolated pool must come last since we write-protect its entry in
+  // the metadata tables, e.g. AddressPoolManager::aligned_pools_
+  kThreadIsolatedPoolHandle,
 #endif
   kMaxPoolHandle
 };
@@ -303,10 +303,10 @@
 #endif
 constexpr size_t kMaxSuperPagesInPool = kPoolMaxSize / kSuperPageSize;
 
-#if BUILDFLAG(ENABLE_PKEYS)
-static_assert(
-    kPkeyPoolHandle == kNumPools,
-    "The pkey pool must come last since we pkey_mprotect its metadata.");
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+static_assert(kThreadIsolatedPoolHandle == kNumPools,
+              "The thread isolated pool must come last since we write-protect "
+              "its metadata.");
 #endif
 
 // Slots larger than this size will not receive MTE protection. Pages intended
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 010497b..56604004 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -41,9 +41,9 @@
 #include "base/allocator/partition_allocator/partition_page.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
 #include "base/allocator/partition_allocator/partition_root.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "base/allocator/partition_allocator/tagging.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "base/system/sys_info.h"
 #include "base/test/gtest_util.h"
 #include "build/build_config.h"
@@ -314,7 +314,7 @@
 
   void InitializeAllocator() {
 #if BUILDFLAG(ENABLE_PKEYS)
-    int pkey = PkeyAlloc(UsePkeyPool() ? 0 : PKEY_DISABLE_WRITE);
+    int pkey = PkeyAlloc(UseThreadIsolatedPool() ? 0 : PKEY_DISABLE_WRITE);
     if (pkey != -1) {
       pkey_ = pkey;
     }
@@ -331,9 +331,9 @@
         partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
         partition_alloc::PartitionOptions::UseConfigurablePool::kNo,
         partition_alloc::PartitionOptions::AddDummyRefCount::kDisabled,
-        pkey_ != kInvalidPkey ? pkey_ : kDefaultPkey,
+        partition_alloc::ThreadIsolationOption(pkey_),
     });
-    if (UsePkeyPool() && pkey_ != kInvalidPkey) {
+    if (UseThreadIsolatedPool() && pkey_ != kInvalidPkey) {
       allocator.init({
           partition_alloc::PartitionOptions::AlignedAlloc::kAllowed,
           partition_alloc::PartitionOptions::ThreadCache::kDisabled,
@@ -343,11 +343,11 @@
           partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
           partition_alloc::PartitionOptions::UseConfigurablePool::kNo,
           partition_alloc::PartitionOptions::AddDummyRefCount::kDisabled,
-          pkey_,
+          partition_alloc::ThreadIsolationOption(pkey_),
       });
       return;
     }
-#endif
+#endif  // BUILDFLAG(ENABLE_PKEYS)
     allocator.init({
 #if !BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \
     BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
@@ -575,7 +575,7 @@
     return GetParam().bucket_distribution;
   }
 
-  bool UsePkeyPool() const { return GetParam().use_pkey_pool; }
+  bool UseThreadIsolatedPool() const { return GetParam().use_pkey_pool; }
   bool UseBRPPool() const { return allocator.root()->brp_enabled(); }
 
   partition_alloc::PartitionAllocatorForTesting allocator;
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 045aa3b..7b7ae95 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -303,10 +303,10 @@
       RecommitSystemPages(reservation_start + SystemPageSize(),
                           SystemPageSize(),
 #if PA_CONFIG(ENABLE_SHADOW_METADATA)
-                          root->PageAccessibilityWithPkeyIfEnabled(
+                          root->PageAccessibilityWithThreadIsolationIfEnabled(
                               PageAccessibilityConfiguration::kRead),
 #else
-                          root->PageAccessibilityWithPkeyIfEnabled(
+                          root->PageAccessibilityWithThreadIsolationIfEnabled(
                               PageAccessibilityConfiguration::kReadWrite),
 #endif
                           PageAccessibilityDisposition::kRequireUpdate);
@@ -320,7 +320,7 @@
       ScopedSyscallTimer timer{root};
       RecommitSystemPages(reservation_start + SystemPageSize() * 2,
                           SystemPageSize(),
-                          root->PageAccessibilityWithPkeyIfEnabled(
+                          root->PageAccessibilityWithThreadIsolationIfEnabled(
                               PageAccessibilityConfiguration::kReadWrite),
                           PageAccessibilityDisposition::kRequireUpdate);
     }
@@ -331,7 +331,7 @@
       ScopedSyscallTimer timer{root};
       RecommitSystemPages(ShadowMetadataStart(reservation_start, pool),
                           SystemPageSize(),
-                          root->PageAccessibilityWithPkeyIfEnabled(
+                          root->PageAccessibilityWithThreadIsolationIfEnabled(
                               PageAccessibilityConfiguration::kReadWrite),
                           PageAccessibilityDisposition::kRequireUpdate);
     }
@@ -785,10 +785,10 @@
     ScopedSyscallTimer timer{root};
     RecommitSystemPages(super_page + SystemPageSize(), SystemPageSize(),
 #if PA_CONFIG(ENABLE_SHADOW_METADATA)
-                        root->PageAccessibilityWithPkeyIfEnabled(
+                        root->PageAccessibilityWithThreadIsolationIfEnabled(
                             PageAccessibilityConfiguration::kRead),
 #else
-                        root->PageAccessibilityWithPkeyIfEnabled(
+                        root->PageAccessibilityWithThreadIsolationIfEnabled(
                             PageAccessibilityConfiguration::kReadWrite),
 #endif
                         PageAccessibilityDisposition::kRequireUpdate);
@@ -800,7 +800,7 @@
   if (root->ChoosePool() == kBRPPoolHandle) {
     ScopedSyscallTimer timer{root};
     RecommitSystemPages(super_page + SystemPageSize() * 2, SystemPageSize(),
-                        root->PageAccessibilityWithPkeyIfEnabled(
+                        root->PageAccessibilityWithThreadIsolationIfEnabled(
                             PageAccessibilityConfiguration::kReadWrite),
                         PageAccessibilityDisposition::kRequireUpdate);
   }
@@ -811,7 +811,7 @@
     ScopedSyscallTimer timer{root};
     RecommitSystemPages(ShadowMetadataStart(super_page, root->ChoosePool()),
                         SystemPageSize(),
-                        root->PageAccessibilityWithPkeyIfEnabled(
+                        root->PageAccessibilityWithThreadIsolationIfEnabled(
                             PageAccessibilityConfiguration::kReadWrite),
                         PageAccessibilityDisposition::kRequireUpdate);
   }
@@ -872,7 +872,7 @@
     {
       ScopedSyscallTimer timer{root};
       RecommitSystemPages(state_bitmap, state_bitmap_size_to_commit,
-                          root->PageAccessibilityWithPkeyIfEnabled(
+                          root->PageAccessibilityWithThreadIsolationIfEnabled(
                               PageAccessibilityConfiguration::kReadWrite),
                           PageAccessibilityDisposition::kRequireUpdate);
     }
@@ -887,7 +887,7 @@
     PA_DCHECK(SuperPageFreeSlotBitmapAddr(super_page) == freeslot_bitmap_addr);
     ScopedSyscallTimer timer{root};
     RecommitSystemPages(freeslot_bitmap_addr, CommittedFreeSlotBitmapSize(),
-                        root->PageAccessibilityWithPkeyIfEnabled(
+                        root->PageAccessibilityWithThreadIsolationIfEnabled(
                             PageAccessibilityConfiguration::kReadWrite),
                         PageAccessibilityDisposition::kRequireUpdate);
   }
diff --git a/base/allocator/partition_allocator/partition_lock.h b/base/allocator/partition_allocator/partition_lock.h
index 47ccb42..79d3cdb 100644
--- a/base/allocator/partition_allocator/partition_lock.h
+++ b/base/allocator/partition_allocator/partition_lock.h
@@ -14,8 +14,8 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/spinning_mutex.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal {
@@ -25,8 +25,8 @@
   inline constexpr Lock();
   void Acquire() PA_EXCLUSIVE_LOCK_FUNCTION() {
 #if BUILDFLAG(PA_DCHECK_IS_ON)
-#if BUILDFLAG(ENABLE_PKEYS)
-    LiftPkeyRestrictionsScope lift_pkey_restrictions;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    LiftThreadIsolationScope lift_thread_isolation_restrictions;
 #endif
 
     // When PartitionAlloc is malloc(), it can easily become reentrant. For
@@ -74,8 +74,8 @@
   void AssertAcquired() const PA_ASSERT_EXCLUSIVE_LOCK() {
     lock_.AssertAcquired();
 #if BUILDFLAG(PA_DCHECK_IS_ON)
-#if BUILDFLAG(ENABLE_PKEYS)
-    LiftPkeyRestrictionsScope lift_pkey_restrictions;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    LiftThreadIsolationScope lift_thread_isolation_restrictions;
 #endif
     PA_DCHECK(owning_thread_ref_.load(std ::memory_order_acquire) ==
               base::PlatformThread::CurrentRef());
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index e6d9e2f..25212c01 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -341,8 +341,8 @@
 #endif  // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
   {
     PA_DCHECK(pool == kRegularPoolHandle
-#if BUILDFLAG(ENABLE_PKEYS)
-              || pool == kPkeyPoolHandle
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+              || pool == kThreadIsolatedPoolHandle
 #endif
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
               ||
@@ -351,8 +351,8 @@
     );
     // Non-BRP pools don't need adjustment that BRP needs in 32-bit mode.
     PA_DCHECK(IsManagedByPartitionAllocRegularPool(reservation_start) ||
-#if BUILDFLAG(ENABLE_PKEYS)
-              IsManagedByPartitionAllocPkeyPool(reservation_start) ||
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+              IsManagedByPartitionAllocThreadIsolatedPool(reservation_start) ||
 #endif
               IsManagedByPartitionAllocConfigurablePool(reservation_start));
   }
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index ed69eedb..b0e131e 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -24,9 +24,9 @@
 #include "base/allocator/partition_allocator/partition_oom.h"
 #include "base/allocator/partition_allocator/partition_page.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "base/allocator/partition_allocator/tagging.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 #if PA_CONFIG(ENABLE_MAC11_MALLOC_SIZE_HACK) && BUILDFLAG(IS_APPLE)
@@ -688,15 +688,17 @@
 }
 #endif
 
-#if BUILDFLAG(ENABLE_PKEYS)
-void PartitionAllocPkeyInit(int pkey) {
-  PkeySettings::settings.enabled = true;
-  PartitionAddressSpace::InitPkeyPool(pkey);
-  // Call TagGlobalsWithPkey last since we might not have write permissions to
-  // to memory tagged with `pkey` at this point.
-  TagGlobalsWithPkey(pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+void PartitionAllocThreadIsolationInit(ThreadIsolationOption thread_isolation) {
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+  ThreadIsolationSettings::settings.enabled = true;
+#endif
+  PartitionAddressSpace::InitThreadIsolatedPool(thread_isolation);
+  // Call WriteProtectThreadIsolatedGlobals last since we might not have write
+  // permissions to to globals afterwards.
+  WriteProtectThreadIsolatedGlobals(thread_isolation);
 }
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
 }  // namespace internal
 
@@ -773,10 +775,10 @@
   // this function on PartitionRoots without a thread cache.
   PA_CHECK(!flags.with_thread_cache);
   auto pool_handle = ChoosePool();
-#if BUILDFLAG(ENABLE_PKEYS)
-  // The pages managed by pkey will be free-ed at UninitPKeyForTesting().
-  // Don't invoke FreePages() for the pages.
-  if (pool_handle == internal::kPkeyPoolHandle) {
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // The pages managed by thread isolated pool will be free-ed at
+  // UninitThreadIsolatedForTesting(). Don't invoke FreePages() for the pages.
+  if (pool_handle == internal::kThreadIsolatedPoolHandle) {
     return;
   }
   PA_DCHECK(pool_handle < internal::kNumPools);
@@ -920,12 +922,12 @@
     // BRP requires objects to be in a different Pool.
     PA_CHECK(!(flags.use_configurable_pool && brp_enabled()));
 
-#if BUILDFLAG(ENABLE_PKEYS)
-    // BRP and pkey mode use different pools, so they can't be enabled at the
-    // same time.
-    PA_CHECK(opts.pkey == internal::kDefaultPkey ||
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    // BRP and thread isolated mode use different pools, so they can't be
+    // enabled at the same time.
+    PA_CHECK(!opts.thread_isolation.enabled ||
              opts.backup_ref_ptr == PartitionOptions::BackupRefPtr::kDisabled);
-    flags.pkey = opts.pkey;
+    flags.thread_isolation = opts.thread_isolation;
 #endif
 
     // Ref-count messes up alignment needed for AlignedAlloc, making this
@@ -1027,9 +1029,9 @@
   PartitionAllocMallocInitOnce();
 #endif
 
-#if BUILDFLAG(ENABLE_PKEYS)
-  if (flags.pkey != internal::kDefaultPkey) {
-    internal::PartitionAllocPkeyInit(flags.pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  if (flags.thread_isolation.enabled) {
+    internal::PartitionAllocThreadIsolationInit(flags.thread_isolation);
   }
 #endif
 }
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 17ee56c..56c7bfc 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -63,10 +63,10 @@
 #include "base/allocator/partition_allocator/partition_oom.h"
 #include "base/allocator/partition_allocator/partition_page.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "base/allocator/partition_allocator/tagging.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(USE_STARSCAN)
@@ -200,11 +200,11 @@
       BackupRefPtrZapping backup_ref_ptr_zapping,
       UseConfigurablePool use_configurable_pool,
       AddDummyRefCount add_dummy_ref_count = AddDummyRefCount::kDisabled
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
       ,
-      int pkey = internal::kDefaultPkey
+      ThreadIsolationOption thread_isolation = ThreadIsolationOption()
 #endif
-      )
+          )
       : aligned_alloc(aligned_alloc),
         thread_cache(thread_cache),
         quarantine(quarantine),
@@ -212,9 +212,9 @@
         backup_ref_ptr(backup_ref_ptr),
         backup_ref_ptr_zapping(backup_ref_ptr_zapping),
         use_configurable_pool(use_configurable_pool)
-#if BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
         ,
-        pkey(pkey)
+        thread_isolation(thread_isolation)
 #endif
   {
   }
@@ -227,8 +227,8 @@
   BackupRefPtrZapping backup_ref_ptr_zapping;
   UseConfigurablePool use_configurable_pool;
   AddDummyRefCount add_dummy_ref_count = AddDummyRefCount::kDisabled;
-#if BUILDFLAG(ENABLE_PKEYS)
-  int pkey;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  ThreadIsolationOption thread_isolation;
 #endif
 };
 
@@ -294,8 +294,8 @@
     bool memory_tagging_enabled_;
 #endif
 
-#if BUILDFLAG(ENABLE_PKEYS)
-    int pkey;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    ThreadIsolationOption thread_isolation;
 #endif
 
 #if PA_CONFIG(EXTRAS_REQUIRED)
@@ -544,7 +544,7 @@
 
   PA_ALWAYS_INLINE PageAccessibilityConfiguration GetPageAccessibility() const;
   PA_ALWAYS_INLINE PageAccessibilityConfiguration
-      PageAccessibilityWithPkeyIfEnabled(
+      PageAccessibilityWithThreadIsolationIfEnabled(
           PageAccessibilityConfiguration::Permissions) const;
 
   PA_ALWAYS_INLINE size_t
@@ -645,9 +645,9 @@
       return internal::kConfigurablePoolHandle;
     }
 #endif
-#if BUILDFLAG(ENABLE_PKEYS)
-    if (flags.pkey != internal::kDefaultPkey) {
-      return internal::kPkeyPoolHandle;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    if (flags.thread_isolation.enabled) {
+      return internal::kThreadIsolatedPoolHandle;
     }
 #endif
 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
@@ -1763,8 +1763,8 @@
     permissions = PageAccessibilityConfiguration::kReadWriteTagged;
   }
 #endif
-#if BUILDFLAG(ENABLE_PKEYS)
-  return PageAccessibilityConfiguration(permissions, flags.pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  return PageAccessibilityConfiguration(permissions, flags.thread_isolation);
 #else
   return PageAccessibilityConfiguration(permissions);
 #endif
@@ -1772,10 +1772,10 @@
 
 template <bool thread_safe>
 PA_ALWAYS_INLINE PageAccessibilityConfiguration
-PartitionRoot<thread_safe>::PageAccessibilityWithPkeyIfEnabled(
+PartitionRoot<thread_safe>::PageAccessibilityWithThreadIsolationIfEnabled(
     PageAccessibilityConfiguration::Permissions permissions) const {
-#if BUILDFLAG(ENABLE_PKEYS)
-  return PageAccessibilityConfiguration(permissions, flags.pkey);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  return PageAccessibilityConfiguration(permissions, flags.thread_isolation);
 #endif
   return PageAccessibilityConfiguration(permissions);
 }
diff --git a/base/allocator/partition_allocator/pkey.cc b/base/allocator/partition_allocator/pkey.cc
deleted file mode 100644
index de5f1fe2..0000000
--- a/base/allocator/partition_allocator/pkey.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/allocator/partition_allocator/pkey.h"
-#include "base/allocator/partition_allocator/address_pool_manager.h"
-#include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "base/allocator/partition_allocator/reservation_offset_table.h"
-
-#if BUILDFLAG(ENABLE_PKEYS)
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "base/allocator/partition_allocator/partition_alloc_base/cpu.h"
-#include "base/allocator/partition_allocator/partition_alloc_check.h"
-
-#if !BUILDFLAG(IS_LINUX)
-#error "This pkey code is currently only supported on Linux"
-#endif
-
-namespace partition_alloc::internal {
-
-PA_COMPONENT_EXPORT(PARTITION_ALLOC)
-bool CPUHasPkeySupport() {
-  return base::CPU::GetInstanceNoAllocation().has_pku();
-}
-
-PkeySettings PkeySettings::settings PA_PKEY_ALIGN;
-
-PA_COMPONENT_EXPORT(PARTITION_ALLOC)
-int PkeyMprotect(void* addr, size_t len, int prot, int pkey) {
-  return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
-}
-
-int PkeyMprotectIfEnabled(void* addr, size_t len, int prot, int pkey) {
-  if (PA_UNLIKELY(PkeySettings::settings.enabled)) {
-    return PkeyMprotect(addr, len, prot, pkey);
-  }
-
-  PA_CHECK(pkey == 0);
-
-  return mprotect(addr, len, prot);
-}
-
-void TagMemoryWithPkey(int pkey, void* address, size_t size) {
-  PA_DCHECK(
-      (reinterpret_cast<uintptr_t>(address) & PA_PKEY_ALIGN_OFFSET_MASK) == 0);
-  PA_PCHECK(
-      PkeyMprotect(address,
-                   (size + PA_PKEY_ALIGN_OFFSET_MASK) & PA_PKEY_ALIGN_BASE_MASK,
-                   PROT_READ | PROT_WRITE, pkey) == 0);
-}
-
-template <typename T>
-void TagVariableWithPkey(int pkey, T& var) {
-  TagMemoryWithPkey(pkey, &var, sizeof(T));
-}
-
-void TagGlobalsWithPkey(int pkey) {
-  TagVariableWithPkey(pkey, PartitionAddressSpace::setup_);
-
-  AddressPoolManager::Pool* pool =
-      AddressPoolManager::GetInstance().GetPool(kPkeyPoolHandle);
-  TagVariableWithPkey(pkey, *pool);
-
-  uint16_t* pkey_reservation_offset_table =
-      GetReservationOffsetTable(kPkeyPoolHandle);
-  TagMemoryWithPkey(pkey, pkey_reservation_offset_table,
-                    ReservationOffsetTable::kReservationOffsetTableLength);
-
-  TagVariableWithPkey(pkey, PkeySettings::settings);
-}
-
-PA_COMPONENT_EXPORT(PARTITION_ALLOC)
-int PkeyAlloc(int access_rights) {
-  return syscall(SYS_pkey_alloc, 0, access_rights);
-}
-
-PA_COMPONENT_EXPORT(PARTITION_ALLOC)
-void PkeyFree(int pkey) {
-  PA_PCHECK(syscall(SYS_pkey_free, pkey) == 0);
-}
-
-uint32_t Rdpkru() {
-  uint32_t pkru;
-  asm volatile(".byte 0x0f,0x01,0xee\n" : "=a"(pkru) : "c"(0), "d"(0));
-  return pkru;
-}
-
-void Wrpkru(uint32_t pkru) {
-  asm volatile(".byte 0x0f,0x01,0xef\n" : : "a"(pkru), "c"(0), "d"(0));
-}
-
-#if BUILDFLAG(PA_DCHECK_IS_ON)
-
-LiftPkeyRestrictionsScope::LiftPkeyRestrictionsScope()
-    : saved_pkey_value_(kDefaultPkeyValue) {
-  if (!PkeySettings::settings.enabled) {
-    return;
-  }
-  saved_pkey_value_ = Rdpkru();
-  if (saved_pkey_value_ != kDefaultPkeyValue) {
-    Wrpkru(kAllowAllPkeyValue);
-  }
-}
-
-LiftPkeyRestrictionsScope::~LiftPkeyRestrictionsScope() {
-  if (!PkeySettings::settings.enabled) {
-    return;
-  }
-  if (Rdpkru() != saved_pkey_value_) {
-    Wrpkru(saved_pkey_value_);
-  }
-}
-
-#endif  // BUILDFLAG(PA_DCHECK_IS_ON)
-
-}  // namespace partition_alloc::internal
-
-#endif  // BUILDFLAG(ENABLE_PKEYS)
diff --git a/base/allocator/partition_allocator/pkey.h b/base/allocator/partition_allocator/pkey.h
deleted file mode 100644
index 2c91f44..0000000
--- a/base/allocator/partition_allocator/pkey.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// 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_PKEY_H_
-#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
-
-#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
-
-#if BUILDFLAG(ENABLE_PKEYS)
-
-#include "base/allocator/partition_allocator/page_allocator_constants.h"
-#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
-#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
-
-#include <cstddef>
-#include <cstdint>
-
-#if !BUILDFLAG(HAS_64_BIT_POINTERS)
-#error "pkey support requires 64 bit pointers"
-#endif
-
-#define PA_PKEY_ALIGN_SZ SystemPageSize()
-#define PA_PKEY_ALIGN_OFFSET_MASK (PA_PKEY_ALIGN_SZ - 1)
-#define PA_PKEY_ALIGN_BASE_MASK (~PA_PKEY_ALIGN_OFFSET_MASK)
-#define PA_PKEY_ALIGN alignas(PA_PKEY_ALIGN_SZ)
-
-#define PA_PKEY_FILL_PAGE_SZ(size) \
-  ((PA_PKEY_ALIGN_SZ - (size & PA_PKEY_ALIGN_OFFSET_MASK)) % PA_PKEY_ALIGN_SZ)
-// Calculate the required padding so that the last element of a page-aligned
-// array lands on a page boundary. In other words, calculate that padding so
-// that (count-1) elements are a multiple of page size.
-#define PA_PKEY_ARRAY_PAD_SZ(Type, count) \
-  PA_PKEY_FILL_PAGE_SZ(sizeof(Type) * (count - 1))
-
-namespace partition_alloc::internal {
-
-constexpr int kDefaultPkey = 0;
-constexpr int kInvalidPkey = -1;
-
-// Check if the CPU supports pkeys.
-bool CPUHasPkeySupport();
-
-// A wrapper around pkey_mprotect that falls back to regular mprotect if
-// PkeySettings::enabled is false.
-[[nodiscard]] int PkeyMprotectIfEnabled(void* addr,
-                                        size_t len,
-                                        int prot,
-                                        int pkey);
-// A wrapper around pkey_mprotect without fallback.
-[[nodiscard]] int PkeyMprotect(void* addr, size_t len, int prot, int pkey);
-
-// If we set up a pkey pool, we need to tag global variables with the pkey to
-// make them readable in case default pkey access is disabled. Called once
-// during pkey pool initialization.
-void TagGlobalsWithPkey(int pkey);
-
-int PkeyAlloc(int access_rights);
-
-void PkeyFree(int pkey);
-
-// Read the pkru register (the current pkey state).
-uint32_t Rdpkru();
-
-// Write the pkru register (the current pkey state).
-void Wrpkru(uint32_t pkru);
-
-struct PkeySettings {
-  bool enabled = false;
-  char pad_[PA_PKEY_FILL_PAGE_SZ(sizeof(enabled))] = {};
-  static PkeySettings settings PA_PKEY_ALIGN PA_CONSTINIT;
-};
-
-#if BUILDFLAG(PA_DCHECK_IS_ON)
-
-class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LiftPkeyRestrictionsScope {
- public:
-  static constexpr uint32_t kDefaultPkeyValue = 0x55555554;
-  static constexpr uint32_t kAllowAllPkeyValue = 0x0;
-
-  LiftPkeyRestrictionsScope();
-  ~LiftPkeyRestrictionsScope();
-
- private:
-  uint32_t saved_pkey_value_;
-};
-
-#endif  // BUILDFLAG(PA_DCHECK_IS_ON)
-
-}  // namespace partition_alloc::internal
-
-#else  // BUILDFLAG(ENABLE_PKEYS)
-#define PA_PKEY_ALIGN
-#define PA_PKEY_FILL_PAGE_SZ(size) 0
-#define PA_PKEY_ARRAY_PAD_SZ(Type, size) 0
-#endif  // BUILDFLAG(ENABLE_PKEYS)
-
-#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
diff --git a/base/allocator/partition_allocator/reservation_offset_table.cc b/base/allocator/partition_allocator/reservation_offset_table.cc
index 6eac2bc..6b0a421c 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.cc
+++ b/base/allocator/partition_allocator/reservation_offset_table.cc
@@ -10,7 +10,8 @@
 
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
 ReservationOffsetTable::_PaddedReservationOffsetTables
-    ReservationOffsetTable::padded_reservation_offset_tables_ PA_PKEY_ALIGN;
+    ReservationOffsetTable::padded_reservation_offset_tables_
+        PA_THREAD_ISOLATED_ALIGN;
 #else
 ReservationOffsetTable::_ReservationOffsetTable
     ReservationOffsetTable::reservation_offset_table_;
diff --git a/base/allocator/partition_allocator/reservation_offset_table.h b/base/allocator/partition_allocator/reservation_offset_table.h
index 80bfe90..98f94912 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.h
+++ b/base/allocator/partition_allocator/reservation_offset_table.h
@@ -18,8 +18,8 @@
 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/tagging.h"
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal {
@@ -96,16 +96,18 @@
     }
   };
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
-  // If pkey support is enabled, we need to pkey-tag the tables of the pkey
-  // pool. For this, we need to pad the tables so that the pkey ones start on a
-  // page boundary.
+  // If thread isolation support is enabled, we need to write-protect the tables
+  // of the thread isolated pool. For this, we need to pad the tables so that
+  // the thread isolated ones start on a page boundary.
   struct _PaddedReservationOffsetTables {
-    char pad_[PA_PKEY_ARRAY_PAD_SZ(_ReservationOffsetTable, kNumPools)] = {};
+    char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ(_ReservationOffsetTable,
+                                              kNumPools)] = {};
     struct _ReservationOffsetTable tables[kNumPools];
-    char pad_after_[PA_PKEY_FILL_PAGE_SZ(sizeof(_ReservationOffsetTable))] = {};
+    char pad_after_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(
+        sizeof(_ReservationOffsetTable))] = {};
   };
   static PA_CONSTINIT _PaddedReservationOffsetTables
-      padded_reservation_offset_tables_ PA_PKEY_ALIGN;
+      padded_reservation_offset_tables_ PA_THREAD_ISOLATED_ALIGN;
 #else
   // A single table for the entire 32-bit address space.
   static PA_CONSTINIT struct _ReservationOffsetTable reservation_offset_table_;
@@ -183,8 +185,9 @@
   bool is_in_regular_pool = IsManagedByPartitionAllocRegularPool(address);
   bool is_in_configurable_pool =
       IsManagedByPartitionAllocConfigurablePool(address);
-#if BUILDFLAG(ENABLE_PKEYS)
-  bool is_in_pkey_pool = IsManagedByPartitionAllocPkeyPool(address);
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  bool is_in_thread_isolated_pool =
+      IsManagedByPartitionAllocThreadIsolatedPool(address);
 #endif
 
   // When ENABLE_BACKUP_REF_PTR_SUPPORT is off, BRP pool isn't used.
@@ -218,9 +221,9 @@
             IsManagedByPartitionAllocRegularPool(reservation_start));
   PA_DCHECK(is_in_configurable_pool ==
             IsManagedByPartitionAllocConfigurablePool(reservation_start));
-#if BUILDFLAG(ENABLE_PKEYS)
-  PA_DCHECK(is_in_pkey_pool ==
-            IsManagedByPartitionAllocPkeyPool(reservation_start));
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  PA_DCHECK(is_in_thread_isolated_pool ==
+            IsManagedByPartitionAllocThreadIsolatedPool(reservation_start));
 #endif
   PA_DCHECK(*ReservationOffsetPointer(reservation_start) == 0);
 #endif  // BUILDFLAG(PA_DCHECK_IS_ON)
diff --git a/base/allocator/partition_allocator/thread_isolation/alignment.h b/base/allocator/partition_allocator/thread_isolation/alignment.h
new file mode 100644
index 0000000..66301f63
--- /dev/null
+++ b/base/allocator/partition_allocator/thread_isolation/alignment.h
@@ -0,0 +1,38 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_ALIGNMENT_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_ALIGNMENT_H_
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include "base/allocator/partition_allocator/page_allocator_constants.h"
+
+#define PA_THREAD_ISOLATED_ALIGN_SZ partition_alloc::internal::SystemPageSize()
+#define PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK (PA_THREAD_ISOLATED_ALIGN_SZ - 1)
+#define PA_THREAD_ISOLATED_ALIGN_BASE_MASK \
+  (~PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK)
+#define PA_THREAD_ISOLATED_ALIGN alignas(PA_THREAD_ISOLATED_ALIGN_SZ)
+
+#define PA_THREAD_ISOLATED_FILL_PAGE_SZ(size)        \
+  ((PA_THREAD_ISOLATED_ALIGN_SZ -                    \
+    (size & PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK)) % \
+   PA_THREAD_ISOLATED_ALIGN_SZ)
+// Calculate the required padding so that the last element of a page-aligned
+// array lands on a page boundary. In other words, calculate that padding so
+// that (count-1) elements are a multiple of page size.
+#define PA_THREAD_ISOLATED_ARRAY_PAD_SZ(Type, count) \
+  PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(Type) * (count - 1))
+
+#else  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#define PA_THREAD_ISOLATED_ALIGN
+#define PA_THREAD_ISOLATED_FILL_PAGE_SZ(size) 0
+#define PA_THREAD_ISOLATED_ARRAY_PAD_SZ(Type, size) 0
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_ALIGNMENT_H_
diff --git a/base/allocator/partition_allocator/thread_isolation/pkey.cc b/base/allocator/partition_allocator/thread_isolation/pkey.cc
new file mode 100644
index 0000000..9f2f792
--- /dev/null
+++ b/base/allocator/partition_allocator/thread_isolation/pkey.cc
@@ -0,0 +1,89 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/partition_allocator/thread_isolation/pkey.h"
+
+#if BUILDFLAG(ENABLE_PKEYS)
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/allocator/partition_allocator/partition_alloc_base/cpu.h"
+#include "base/allocator/partition_allocator/partition_alloc_check.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
+
+#if !BUILDFLAG(IS_LINUX)
+#error "This pkey code is currently only supported on Linux"
+#endif
+
+namespace partition_alloc::internal {
+
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+bool CPUHasPkeySupport() {
+  return base::CPU::GetInstanceNoAllocation().has_pku();
+}
+
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+int PkeyMprotect(void* addr, size_t len, int prot, int pkey) {
+  return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
+}
+
+void TagMemoryWithPkey(int pkey, void* address, size_t size) {
+  PA_DCHECK((reinterpret_cast<uintptr_t>(address) &
+             PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) == 0);
+  PA_PCHECK(PkeyMprotect(address,
+                         (size + PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) &
+                             PA_THREAD_ISOLATED_ALIGN_BASE_MASK,
+                         PROT_READ | PROT_WRITE, pkey) == 0);
+}
+
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+int PkeyAlloc(int access_rights) {
+  return syscall(SYS_pkey_alloc, 0, access_rights);
+}
+
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void PkeyFree(int pkey) {
+  PA_PCHECK(syscall(SYS_pkey_free, pkey) == 0);
+}
+
+uint32_t Rdpkru() {
+  uint32_t pkru;
+  asm volatile(".byte 0x0f,0x01,0xee\n" : "=a"(pkru) : "c"(0), "d"(0));
+  return pkru;
+}
+
+void Wrpkru(uint32_t pkru) {
+  asm volatile(".byte 0x0f,0x01,0xef\n" : : "a"(pkru), "c"(0), "d"(0));
+}
+
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+
+LiftPkeyRestrictionsScope::LiftPkeyRestrictionsScope()
+    : saved_pkey_value_(kDefaultPkeyValue) {
+  if (!ThreadIsolationSettings::settings.enabled) {
+    return;
+  }
+  saved_pkey_value_ = Rdpkru();
+  if (saved_pkey_value_ != kDefaultPkeyValue) {
+    Wrpkru(kAllowAllPkeyValue);
+  }
+}
+
+LiftPkeyRestrictionsScope::~LiftPkeyRestrictionsScope() {
+  if (!ThreadIsolationSettings::settings.enabled) {
+    return;
+  }
+  if (Rdpkru() != saved_pkey_value_) {
+    Wrpkru(saved_pkey_value_);
+  }
+}
+
+#endif  // BUILDFLAG(PA_DCHECK_IS_ON)
+
+}  // namespace partition_alloc::internal
+
+#endif  // BUILDFLAG(ENABLE_PKEYS)
diff --git a/base/allocator/partition_allocator/thread_isolation/pkey.h b/base/allocator/partition_allocator/thread_isolation/pkey.h
new file mode 100644
index 0000000..418c70c
--- /dev/null
+++ b/base/allocator/partition_allocator/thread_isolation/pkey.h
@@ -0,0 +1,62 @@
+// Copyright 2022 The Chromium Authors
+// 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_THREAD_ISOLATION_PKEY_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_PKEY_H_
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+
+#if BUILDFLAG(ENABLE_PKEYS)
+
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
+
+#include <cstddef>
+#include <cstdint>
+
+namespace partition_alloc::internal {
+
+constexpr int kDefaultPkey = 0;
+constexpr int kInvalidPkey = -1;
+
+// Check if the CPU supports pkeys.
+bool CPUHasPkeySupport();
+
+// A wrapper around the pkey_mprotect syscall.
+[[nodiscard]] int PkeyMprotect(void* addr, size_t len, int prot, int pkey);
+
+void TagMemoryWithPkey(int pkey, void* address, size_t size);
+
+int PkeyAlloc(int access_rights);
+
+void PkeyFree(int pkey);
+
+// Read the pkru register (the current pkey state).
+uint32_t Rdpkru();
+
+// Write the pkru register (the current pkey state).
+void Wrpkru(uint32_t pkru);
+
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LiftPkeyRestrictionsScope {
+ public:
+  static constexpr uint32_t kDefaultPkeyValue = 0x55555554;
+  static constexpr uint32_t kAllowAllPkeyValue = 0x0;
+
+  LiftPkeyRestrictionsScope();
+  ~LiftPkeyRestrictionsScope();
+
+ private:
+  uint32_t saved_pkey_value_;
+};
+
+#endif  // BUILDFLAG(PA_DCHECK_IS_ON)
+
+}  // namespace partition_alloc::internal
+
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_PKEY_H_
diff --git a/base/allocator/partition_allocator/pkey_unittest.cc b/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
similarity index 96%
rename from base/allocator/partition_allocator/pkey_unittest.cc
rename to base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
index 6c1ab64..a4967f2 100644
--- a/base/allocator/partition_allocator/pkey_unittest.cc
+++ b/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
 
 #if BUILDFLAG(ENABLE_PKEYS)
 
@@ -15,7 +16,7 @@
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/no_destructor.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
-#include "base/allocator/partition_allocator/pkey.h"
+#include "base/allocator/partition_allocator/thread_isolation/pkey.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #define ISOLATED_FUNCTION extern "C" __attribute__((used))
@@ -32,7 +33,7 @@
       partition_alloc::PartitionAllocator>
       allocator{};
   partition_alloc::ThreadSafePartitionRoot* allocatorRoot;
-} isolatedGlobals PA_PKEY_ALIGN;
+} isolatedGlobals PA_THREAD_ISOLATED_ALIGN;
 
 int ProtFromSegmentFlags(ElfW(Word) flags) {
   int prot = 0;
@@ -110,7 +111,7 @@
         partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
         partition_alloc::PartitionOptions::UseConfigurablePool::kNo,
         partition_alloc::PartitionOptions::AddDummyRefCount::kDisabled,
-        isolatedGlobals.pkey,
+        partition_alloc::ThreadIsolationOption(isolatedGlobals.pkey),
     });
     isolatedGlobals.allocatorRoot = isolatedGlobals.allocator->root();
 
@@ -250,4 +251,4 @@
 
 }  // namespace partition_alloc::internal
 
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
diff --git a/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc b/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc
new file mode 100644
index 0000000..594e40c
--- /dev/null
+++ b/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc
@@ -0,0 +1,80 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/partition_allocator/thread_isolation/thread_isolation.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include "base/allocator/partition_allocator/address_pool_manager.h"
+#include "base/allocator/partition_allocator/partition_alloc_check.h"
+#include "base/allocator/partition_allocator/partition_alloc_constants.h"
+#include "base/allocator/partition_allocator/reservation_offset_table.h"
+
+#if BUILDFLAG(ENABLE_PKEYS)
+#include "base/allocator/partition_allocator/thread_isolation/pkey.h"
+#endif
+
+namespace partition_alloc::internal {
+
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+ThreadIsolationSettings ThreadIsolationSettings::settings
+    PA_THREAD_ISOLATED_ALIGN;
+#endif
+
+void WriteProtectThreadIsolatedMemory(ThreadIsolationOption thread_isolation,
+                                      void* address,
+                                      size_t size) {
+  PA_DCHECK((reinterpret_cast<uintptr_t>(address) &
+             PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) == 0);
+#if BUILDFLAG(ENABLE_PKEYS)
+  partition_alloc::internal::TagMemoryWithPkey(
+      thread_isolation.enabled ? thread_isolation.pkey : kDefaultPkey, address,
+      size);
+#else
+#error unexpected thread isolation mode
+#endif
+}
+
+template <typename T>
+void WriteProtectThreadIsolatedVariable(ThreadIsolationOption thread_isolation,
+                                        T& var) {
+  WriteProtectThreadIsolatedMemory(thread_isolation, &var, sizeof(T));
+}
+
+int MprotectWithThreadIsolation(void* addr,
+                                size_t len,
+                                int prot,
+                                ThreadIsolationOption thread_isolation) {
+#if BUILDFLAG(ENABLE_PKEYS)
+  return PkeyMprotect(addr, len, prot, thread_isolation.pkey);
+#endif
+}
+
+void WriteProtectThreadIsolatedGlobals(ThreadIsolationOption thread_isolation) {
+  WriteProtectThreadIsolatedVariable(thread_isolation,
+                                     PartitionAddressSpace::setup_);
+
+  AddressPoolManager::Pool* pool =
+      AddressPoolManager::GetInstance().GetPool(kThreadIsolatedPoolHandle);
+  WriteProtectThreadIsolatedVariable(thread_isolation, *pool);
+
+  uint16_t* pkey_reservation_offset_table =
+      GetReservationOffsetTable(kThreadIsolatedPoolHandle);
+  WriteProtectThreadIsolatedMemory(
+      thread_isolation, pkey_reservation_offset_table,
+      ReservationOffsetTable::kReservationOffsetTableLength);
+
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+  WriteProtectThreadIsolatedVariable(thread_isolation,
+                                     ThreadIsolationSettings::settings);
+#endif
+}
+
+void UnprotectThreadIsolatedGlobals() {
+  WriteProtectThreadIsolatedGlobals(ThreadIsolationOption(false));
+}
+
+}  // namespace partition_alloc::internal
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
diff --git a/base/allocator/partition_allocator/thread_isolation/thread_isolation.h b/base/allocator/partition_allocator/thread_isolation/thread_isolation.h
new file mode 100644
index 0000000..79c575c
--- /dev/null
+++ b/base/allocator/partition_allocator/thread_isolation/thread_isolation.h
@@ -0,0 +1,82 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_THREAD_ISOLATION_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_THREAD_ISOLATION_H_
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include <cstddef>
+#include <cstdint>
+
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+
+#if BUILDFLAG(ENABLE_PKEYS)
+#include "base/allocator/partition_allocator/thread_isolation/pkey.h"
+#endif
+
+#if !BUILDFLAG(HAS_64_BIT_POINTERS)
+#error "thread isolation support requires 64 bit pointers"
+#endif
+
+namespace partition_alloc {
+
+struct ThreadIsolationOption {
+  constexpr ThreadIsolationOption() = default;
+  explicit ThreadIsolationOption(bool enabled) : enabled(enabled) {}
+
+#if BUILDFLAG(ENABLE_PKEYS)
+  explicit ThreadIsolationOption(int pkey) : pkey(pkey) {
+    enabled = pkey != internal::kInvalidPkey;
+  }
+  int pkey = -1;
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+
+  bool enabled = false;
+
+  bool operator==(const ThreadIsolationOption& other) const {
+#if BUILDFLAG(ENABLE_PKEYS)
+    if (pkey != other.pkey) {
+      return false;
+    }
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+    return enabled == other.enabled;
+  }
+};
+
+}  // namespace partition_alloc
+
+namespace partition_alloc::internal {
+
+#if BUILDFLAG(PA_DCHECK_IS_ON)
+
+struct ThreadIsolationSettings {
+  bool enabled = false;
+  char pad_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(enabled))] = {};
+  static ThreadIsolationSettings settings PA_THREAD_ISOLATED_ALIGN PA_CONSTINIT;
+};
+
+#if BUILDFLAG(ENABLE_PKEYS)
+
+using LiftThreadIsolationScope = LiftPkeyRestrictionsScope;
+
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+#endif  // BUILDFLAG(PA_DCHECK_IS_ON)
+
+void WriteProtectThreadIsolatedGlobals(ThreadIsolationOption thread_isolation);
+void UnprotectThreadIsolatedGlobals();
+[[nodiscard]] int MprotectWithThreadIsolation(
+    void* addr,
+    size_t len,
+    int prot,
+    ThreadIsolationOption thread_isolation);
+
+}  // namespace partition_alloc::internal
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_ISOLATION_THREAD_ISOLATION_H_
diff --git a/base/trace_event/address_space_dump_provider.cc b/base/trace_event/address_space_dump_provider.cc
index 8fe7265..fbd0c364 100644
--- a/base/trace_event/address_space_dump_provider.cc
+++ b/base/trace_event/address_space_dump_provider.cc
@@ -49,12 +49,12 @@
         address_space_stats->configurable_pool_stats.usage * kSuperPageSize);
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
 
-    // Pkey pool usage is applicable with the appropriate buildflag.
-#if BUILDFLAG(ENABLE_PKEYS)
+    // Thread isolated pool usage is applicable with the appropriate buildflag.
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
     dump->AddScalar(
-        "pkey_pool_usage", MemoryAllocatorDump::kUnitsBytes,
-        address_space_stats->pkey_pool_stats.usage * kSuperPageSize);
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+        "thread_isolated_pool_usage", MemoryAllocatorDump::kUnitsBytes,
+        address_space_stats->thread_isolated_pool_stats.usage * kSuperPageSize);
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
     // Additionally, largest possible reservation is also available on
     // 64-bit platforms.
@@ -74,12 +74,13 @@
                     address_space_stats->configurable_pool_stats
                             .largest_available_reservation *
                         kSuperPageSize);
-#if BUILDFLAG(ENABLE_PKEYS)
-    dump->AddScalar(
-        "pkey_pool_largest_reservation", MemoryAllocatorDump::kUnitsBytes,
-        address_space_stats->pkey_pool_stats.largest_available_reservation *
-            kSuperPageSize);
-#endif  // BUILDFLAG(ENABLE_PKEYS)
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    dump->AddScalar("thread_isolated_pool_largest_reservation",
+                    MemoryAllocatorDump::kUnitsBytes,
+                    address_space_stats->thread_isolated_pool_stats
+                            .largest_available_reservation *
+                        kSuperPageSize);
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
 
 #if !BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
diff --git a/base/values.cc b/base/values.cc
index 706754ff..5ddb575 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1240,10 +1240,6 @@
   return const_cast<Value*>(std::as_const(*this).FindListPath(path));
 }
 
-size_t Value::DictSize() const {
-  return GetDict().size();
-}
-
 bool operator==(const Value& lhs, const Value& rhs) {
   return lhs.data_ == rhs.data_;
 }
diff --git a/base/values.h b/base/values.h
index 89acd5f..f3acf162 100644
--- a/base/values.h
+++ b/base/values.h
@@ -841,9 +841,6 @@
   Value* FindListPath(StringPiece path);
   const Value* FindListPath(StringPiece path) const;
 
-  // DEPRECATED: prefer `Value::Dict::size()`.
-  size_t DictSize() const;
-
   // Note: Do not add more types. See the file-level comment above for why.
 
   // Comparison operators so that Values can easily be used with standard
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
index 863d1d0..3fed32f 100644
--- a/build/config/ios/BUILD.gn
+++ b/build/config/ios/BUILD.gn
@@ -231,6 +231,8 @@
   ]
 }
 
+# TODO(crbug.com/1444308): any target that uses this config will miscompile.
+# This needs to be fixed if we want to use Swift - C++ interop.
 config("enable_swift_cxx_interop") {
   swiftflags = [ "-enable-experimental-cxx-interop" ]
 }
diff --git a/build/config/rust.gni b/build/config/rust.gni
index 70a3f020..c226e5fe 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -21,11 +21,9 @@
   # TODO(crbug.com/1271215): Windows
   # TODO(crbug.com/1442491): Fuchsia
   # TODO(crbug.com/1426472): use_clang_coverage
-  # TODO(crbug.com/1427362): using_sanitizer
   # TODO(crbug.com/1229419): is_official_build
-  enable_rust =
-      !is_mac && !is_ios && !is_win && !is_fuchsia && !is_official_build &&
-      !using_sanitizer && !use_clang_coverage && build_with_chromium
+  enable_rust = !is_mac && !is_ios && !is_win && !is_fuchsia &&
+                !is_official_build && !use_clang_coverage && build_with_chromium
 
   # As we incrementally enable Rust on mainstream builders, we want to enable
   # the toolchain (by switching 'enable_rust' to true) while still disabling
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 723fe089..720e1cbf 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2690,6 +2690,7 @@
       "//chrome/browser/engagement/android:javatests",
       "//chrome/browser/flags:javatests",
       "//chrome/browser/password_check/android:test_java",
+      "//chrome/browser/password_manager/android/pwd_migration:javatests",
       "//chrome/browser/subresource_filter:subresource_filter_javatests",
       "//chrome/browser/touch_to_fill/android:test_java",
       "//chrome/browser/touch_to_fill/payments/android/internal:javatests",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java
index 57253cb..dedbd7bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java
@@ -82,12 +82,17 @@
         mEditorDialog = new EditorDialog(
                 activity, /*deleteRunnable=*/null, browserProfile, /*requiredIndicator=*/false);
         mEditorDialog.setShouldTriggerDoneCallbackBeforeCloseAnimation(true);
+        AddressEditor.Delegate delegate = new AddressEditor.Delegate() {
+            @Override
+            public void onDone(AutofillAddress autofillAddress) {
+                onEdited(autofillAddress);
+            }
+        };
         mAddressEditor = new AddressEditor(
-                mEditorDialog, /*saveToDisk=*/false, isUpdate, isMigrationToAccount);
+                mEditorDialog, delegate, /*saveToDisk=*/false, isUpdate, isMigrationToAccount);
         AutofillAddress autofillAddress = new AutofillAddress(activity, autofillProfile);
         mDialogView.findViewById(R.id.edit_button).setOnClickListener(v -> {
-            mAddressEditor.edit(autofillAddress, /*doneCallback=*/this::onEdited,
-                    /*cancelCallback=*/unused -> {});
+            mAddressEditor.edit(autofillAddress);
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
index 65d72a2..0160595d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
@@ -50,6 +50,7 @@
     private final Map<Integer, EditorFieldModel> mAddressFields = new HashMap<>();
     private final Set<CharSequence> mPhoneNumbers = new HashSet<>();
     private final EditorDialog mEditorDialog;
+    private final Delegate mDelegate;
     private final Context mContext;
     private final boolean mSaveToDisk;
     private final boolean mIsUpdate;
@@ -77,6 +78,17 @@
     private boolean mIsProfileNew;
 
     /**
+     * Delegate used to subscribe to AddressEditor user interactions.
+     */
+    public static interface Delegate {
+        // The user has tapped "Done" button.
+        default void onDone(AutofillAddress autofillAddress) {}
+
+        // The user has canceled editing the address.
+        default void onCancel() {}
+    }
+
+    /**
      * The list of possible address fields for editing is determined statically.
      *
      * @return the list of address fields this address editor supports.
@@ -127,15 +139,18 @@
     /**
      * Builds an address editor.
      *
+     * @param editorDialog Editor's view displayed to the user.
+     * @param delegate Delegate to react to users interactions with the editor.
      * @param saveToDisk Whether to save changes to disk after editing.
      * @param isUpdate Whether an existing address profile is being edited.
      * @param isMigrationToAccount Whether this editor is shown during address profile migration to
      *         Google account.
      */
-    public AddressEditor(EditorDialog editorDialog, boolean saveToDisk, boolean isUpdate,
-            boolean isMigrationToAccount) {
+    public AddressEditor(EditorDialog editorDialog, Delegate delegate, boolean saveToDisk,
+            boolean isUpdate, boolean isMigrationToAccount) {
         Objects.requireNonNull(editorDialog, "editor dialog can't be null");
         mEditorDialog = editorDialog;
+        mDelegate = delegate;
         mContext = editorDialog.getContext();
         mSaveToDisk = saveToDisk;
         mIsUpdate = isUpdate;
@@ -171,15 +186,6 @@
     }
 
     /**
-     * Allows calling |edit| with a single callback used for both 'done' and 'cancel'.
-     * @see #edit(AutofillAddress, Callback, Callback)
-     */
-    public void edit(
-            @Nullable final AutofillAddress toEdit, final Callback<AutofillAddress> callback) {
-        edit(toEdit, callback, callback);
-    }
-
-    /**
      * Builds and shows an editor model with the following fields.
      *
      * [ country dropdown    ] <----- country dropdown is always present.
@@ -195,9 +201,7 @@
      *
      * TODO(crbug.com/1421056): Split this method for better code readability.
      */
-    public void edit(@Nullable final AutofillAddress toEdit,
-            final Callback<AutofillAddress> doneCallback,
-            final Callback<AutofillAddress> cancelCallback) {
+    public void edit(@Nullable final AutofillAddress toEdit) {
         if (mAutofillProfileBridge == null) mAutofillProfileBridge = new AutofillProfileBridge();
 
         mIsProfileNew = toEdit == null;
@@ -311,7 +315,7 @@
 
         // If the user clicks [Cancel], send |toEdit| address back to the caller, which was the
         // original state (could be null, a complete address, a partial address).
-        mEditor.setCancelCallback(() -> cancelCallback.onResult(toEdit));
+        mEditor.setCancelCallback(mDelegate::onCancel);
 
         // If the user clicks [Done], save changes on disk, mark the address "complete" if possible,
         // and send it back to the caller.
@@ -322,7 +326,7 @@
             // for all required fields.
             address.updateAddress(mProfile);
 
-            doneCallback.onResult(address);
+            mDelegate.onDone(address);
         });
 
         // This should be called when all required fields are put in mAddressField.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillProfilesFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillProfilesFragment.java
index 13cae1f..626f4f4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillProfilesFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillProfilesFragment.java
@@ -224,28 +224,31 @@
     }
 
     private void editAddress(EditorDialog dialog, AutofillAddress autofillAddress) {
-        AddressEditor addressEditor = new AddressEditor(dialog,
+        AddressEditor.Delegate delegate = new AddressEditor.Delegate() {
+            // User has either created a new address, or edited an existing address.
+            // We should save changes in any case.
+            @Override
+            public void onDone(AutofillAddress address) {
+                PersonalDataManager.getInstance().setProfile(address.getProfile());
+                SettingsAutofillAndPaymentsObserver.getInstance().notifyOnAddressUpdated(address);
+                if (sObserverForTest != null) {
+                    sObserverForTest.onEditorReadyToEdit();
+                }
+            }
+
+            // User canceled edited meaning that |autofillAddress| has stayed intact.
+            @Override
+            public void onCancel() {
+                if (sObserverForTest != null) {
+                    sObserverForTest.onEditorReadyToEdit();
+                }
+            }
+        };
+        AddressEditor addressEditor = new AddressEditor(dialog, delegate,
                 /*saveToDisk=*/true, /*isUpdate=*/autofillAddress != null,
                 /*isMigrationToAccount=*/false);
 
-        /*
-         * There are four cases for |address| here.
-         * (1) |address| is null: the user canceled address creation
-         * (2) |address| is non-null: the user canceled editing an existing address
-         * (3) |address| is non-null: the user edited an existing address.
-         * (4) |address| is non-null: the user created a new address.
-         * We should save the changes (set the profile) for cases 3 and 4,
-         * and it's OK to set the profile for 2.
-         */
-        addressEditor.edit(autofillAddress, address -> {
-            if (address != null) {
-                PersonalDataManager.getInstance().setProfile(address.getProfile());
-                SettingsAutofillAndPaymentsObserver.getInstance().notifyOnAddressUpdated(address);
-            }
-            if (sObserverForTest != null) {
-                sObserverForTest.onEditorReadyToEdit();
-            }
-        });
+        addressEditor.edit(autofillAddress);
     }
 
     private boolean isAddressSyncEnabled() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AddressEditorRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AddressEditorRenderTest.java
index 60bfc318..7e8d639 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AddressEditorRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AddressEditorRenderTest.java
@@ -113,6 +113,8 @@
     private PersonalDataManager mPersonalDataManager;
     @Mock
     private Profile mProfile;
+    @Mock
+    private AddressEditor.Delegate mDelegate;
 
     private final CoreAccountInfo mAccountInfo =
             CoreAccountInfo.createFromEmailAndGaiaId(USER_EMAIL, "gaia_id");
@@ -198,9 +200,9 @@
         View editor = runOnUiThreadBlocking(() -> {
             EditorDialog dialog =
                     new EditorDialog(getActivity(), /*deleteRunnable=*/null, mProfile);
-            AddressEditor addressEditor = new AddressEditor(dialog, /*saveToDisk=*/false,
+            AddressEditor addressEditor = new AddressEditor(dialog, mDelegate, /*saveToDisk=*/false,
                     /*isUpdate=*/false, /*isMigrationToAccount=*/false);
-            addressEditor.edit(null, (unused) -> {});
+            addressEditor.edit(null);
             return dialog.getDataViewForTest();
         });
         mRenderTestRule.render(editor, "edit_new_address_profile");
@@ -214,9 +216,9 @@
             when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
             EditorDialog dialog =
                     new EditorDialog(getActivity(), /*deleteRunnable=*/null, mProfile);
-            AddressEditor addressEditor = new AddressEditor(dialog, /*saveToDisk=*/false,
+            AddressEditor addressEditor = new AddressEditor(dialog, mDelegate, /*saveToDisk=*/false,
                     /*isUpdate=*/false, /*isMigrationToAccount=*/false);
-            addressEditor.edit(null, (unused) -> {});
+            addressEditor.edit(null);
             return dialog.getDataViewForTest();
         });
         mRenderTestRule.render(editor, "edit_new_account_address_profile");
@@ -230,9 +232,9 @@
             when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
             EditorDialog dialog =
                     new EditorDialog(getActivity(), /*deleteRunnable=*/null, mProfile);
-            AddressEditor addressEditor = new AddressEditor(dialog, /*saveToDisk=*/false,
+            AddressEditor addressEditor = new AddressEditor(dialog, mDelegate, /*saveToDisk=*/false,
                     /*isUpdate=*/false, /*isMigrationToAccount=*/false);
-            addressEditor.edit(new AutofillAddress(getActivity(), sLocalProfile), (unused) -> {});
+            addressEditor.edit(new AutofillAddress(getActivity(), sLocalProfile));
             return dialog.getDataViewForTest();
         });
         mRenderTestRule.render(editor, "edit_local_or_syncable_address_profile");
@@ -246,9 +248,9 @@
             when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
             EditorDialog dialog =
                     new EditorDialog(getActivity(), /*deleteRunnable=*/null, mProfile);
-            AddressEditor addressEditor = new AddressEditor(dialog, /*saveToDisk=*/false,
+            AddressEditor addressEditor = new AddressEditor(dialog, mDelegate, /*saveToDisk=*/false,
                     /*isUpdate=*/false, /*isMigrationToAccount=*/false);
-            addressEditor.edit(new AutofillAddress(getActivity(), sAccountProfile), (unused) -> {});
+            addressEditor.edit(new AutofillAddress(getActivity(), sAccountProfile));
             return dialog.getDataViewForTest();
         });
         mRenderTestRule.render(editor, "edit_account_address_profile");
@@ -262,9 +264,9 @@
             when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
             EditorDialog dialog =
                     new EditorDialog(getActivity(), /*deleteRunnable=*/null, mProfile);
-            AddressEditor addressEditor = new AddressEditor(dialog, /*saveToDisk=*/false,
+            AddressEditor addressEditor = new AddressEditor(dialog, mDelegate, /*saveToDisk=*/false,
                     /*isUpdate=*/false, /*isMigrationToAccount=*/true);
-            addressEditor.edit(new AutofillAddress(getActivity(), sLocalProfile), (unused) -> {});
+            addressEditor.edit(new AutofillAddress(getActivity(), sLocalProfile));
             return dialog.getDataViewForTest();
         });
         mRenderTestRule.render(editor, "migrate_local_or_syncable_address_profile");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePromptTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePromptTest.java
index 60dfa00..980595a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePromptTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePromptTest.java
@@ -293,12 +293,6 @@
         View dialog = mPrompt.getDialogViewForTesting();
         ImageButton editButton = dialog.findViewById(R.id.edit_button);
         editButton.performClick();
-        verify(mAddressEditor).edit(any(), mCallbackCaptor.capture(), any());
-
-        AutofillAddress autofillAddress = new AutofillAddress(mActivity, new AutofillProfile());
-        mCallbackCaptor.getValue().onResult(autofillAddress);
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        verify(mPromptControllerJni, times(1))
-                .onPromptDismissed(eq(NATIVE_SAVE_UPDATE_ADDRESS_PROFILE_PROMPT_CONTROLLER), any());
+        verify(mAddressEditor).edit(any());
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java
index 98b6fa5..9c25538 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java
@@ -6,12 +6,15 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
@@ -33,7 +36,6 @@
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.R;
@@ -115,9 +117,13 @@
     private PersonalDataManager mPersonalDataManager;
     @Mock
     private Profile mProfile;
+    @Mock
+    private AddressEditor.Delegate mDelegate;
 
     @Captor
     private ArgumentCaptor<EditorModel> mEditorModelCapture;
+    @Captor
+    private ArgumentCaptor<AutofillAddress> mAddressCapture;
 
     private final CoreAccountInfo mAccountInfo =
             CoreAccountInfo.createFromEmailAndGaiaId(USER_EMAIL, "gaia_id");
@@ -127,7 +133,6 @@
             List.of(new DropdownKeyValue("US", "United States"),
                     new DropdownKeyValue("DE", "Germany"), new DropdownKeyValue("CU", "Cuba"));
 
-    private Callback<AutofillAddress> mDoneCallback;
     @Nullable
     private AutofillAddress mEditedAutofillAddress;
 
@@ -150,9 +155,6 @@
                 .getRequiredFields(anyString(), anyList());
 
         mActivity = Robolectric.setupActivity(TestActivity.class);
-        mDoneCallback = address -> {
-            mEditedAutofillAddress = address;
-        };
 
         Profile.setLastUsedProfileForTesting(mProfile);
         IdentityServicesProvider.setInstanceForTests(mIdentityServicesProvider);
@@ -307,11 +309,12 @@
     @Test
     @SmallTest
     public void validateCustomDoneButtonText() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
         mAddressEditor.setCustomDoneButtonText("Custom done");
-        mAddressEditor.edit(null, unused -> {});
+        mAddressEditor.edit(null);
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -322,10 +325,11 @@
     @Test
     @SmallTest
     public void validateUIStrings_NewAddressProfile() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(null, unused -> {});
+        mAddressEditor.edit(null);
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -341,10 +345,11 @@
     @SmallTest
     public void validateUIStrings_NewAddressProfile_EligibleForAddressAccountStorage() {
         when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(null, unused -> {});
+        mAddressEditor.edit(null);
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -363,10 +368,11 @@
     @Test
     @SmallTest
     public void validateUIStrings_LocalOrSyncAddressProfile_AddressSyncDisabled() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -381,14 +387,15 @@
     @Test
     @SmallTest
     public void validateUIStrings_LocalOrSyncAddressProfile_AddressSyncEnabled() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         when(mSyncService.isSyncFeatureEnabled()).thenReturn(true);
         when(mSyncService.getSelectedTypes())
                 .thenReturn(Collections.singleton(UserSelectableType.AUTOFILL));
 
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -403,10 +410,11 @@
     @Test
     @SmallTest
     public void validateUIStrings_UpdateLocalOrSyncAddressProfile_AddressSyncDisabled() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -421,14 +429,15 @@
     @Test
     @SmallTest
     public void validateUIStrings_UpdateLocalOrSyncAddressProfile_AddressSyncEnabled() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
         when(mSyncService.isSyncFeatureEnabled()).thenReturn(true);
         when(mSyncService.getSelectedTypes())
                 .thenReturn(Collections.singleton(UserSelectableType.AUTOFILL));
 
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -443,11 +452,12 @@
     @Test
     @SmallTest
     public void validateUIStrings_LocalAddressProfile_MigrationToAccount() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/true);
 
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -466,14 +476,15 @@
     @Test
     @SmallTest
     public void validateUIStrings_SyncAddressProfile_MigrationToAccount() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/true);
         when(mSyncService.isSyncFeatureEnabled()).thenReturn(true);
         when(mSyncService.getSelectedTypes())
                 .thenReturn(Collections.singleton(UserSelectableType.AUTOFILL));
 
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -492,10 +503,11 @@
     @Test
     @SmallTest
     public void validateUIStrings_AccountAddressProfile_SaveInAccountFlow() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -514,10 +526,11 @@
     @Test
     @SmallTest
     public void validateUIStrings_AccountAddressProfile_UpdateAccountProfileFlow() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile));
 
         final String deleteTitle =
                 mActivity.getString(R.string.autofill_delete_address_confirmation_dialog_title);
@@ -539,10 +552,11 @@
             ChromeFeatureList.AUTOFILL_ENABLE_SUPPORT_FOR_HONORIFIC_PREFIXES})
     public void
     validateDefaultFields_NicknamesDisabled_HonorificDisabled() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         Assert.assertNotNull(mEditorModelCapture.getValue());
         List<EditorFieldModel> editorFields = mEditorModelCapture.getValue().getFields();
@@ -578,10 +592,11 @@
     @Test
     @SmallTest
     public void validateDefaultFields() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(new ArrayList());
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         Assert.assertNotNull(mEditorModelCapture.getValue());
         List<EditorFieldModel> editorFields = mEditorModelCapture.getValue().getFields();
@@ -601,10 +616,11 @@
     @SmallTest
     public void validateShownFields_NewAddressProfile() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(null, unused -> {});
+        mAddressEditor.edit(null);
         validateShownFields(mEditorModelCapture.getValue(), new AutofillProfile(),
                 /*shouldMarkFieldsRequired=*/false);
     }
@@ -614,10 +630,11 @@
     public void validateShownFields_NewAddressProfile_EligibleForAddressAccountStorage() {
         when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(null, unused -> { return; });
+        mAddressEditor.edit(null);
         validateShownFields(mEditorModelCapture.getValue(), new AutofillProfile(),
                 /*shouldMarkFieldsRequired=*/true,
                 /*shouldMarkFieldsRequiredWhenAddressFieldEmpty=*/true);
@@ -627,10 +644,11 @@
     @SmallTest
     public void validateShownFields_LocalOrSyncAddressProfile_SaveLocally() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
         validateShownFields(
                 mEditorModelCapture.getValue(), sLocalProfile, /*shouldMarkFieldsRequired=*/false);
     }
@@ -639,10 +657,11 @@
     @SmallTest
     public void validateShownFields_LocalOrSyncAddressProfile_UpdateLocally() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
         validateShownFields(
                 mEditorModelCapture.getValue(), sLocalProfile, /*shouldMarkFieldsRequired=*/false);
     }
@@ -651,10 +670,11 @@
     @SmallTest
     public void validateShownFields_LocalOrSyncAddressProfile_MigrationToAccount() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/true);
 
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
         validateShownFields(
                 mEditorModelCapture.getValue(), sLocalProfile, /*shouldMarkFieldsRequired=*/true);
     }
@@ -663,10 +683,11 @@
     @SmallTest
     public void validateShownFields_AccountProfile_SaveInAccountFlow() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile));
         validateShownFields(
                 mEditorModelCapture.getValue(), sAccountProfile, /*shouldMarkFieldsRequired=*/true);
     }
@@ -675,10 +696,11 @@
     @SmallTest
     public void validateShownFields_AccountProfile_UpdateAlreadySaved() {
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
 
-        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sAccountProfile));
         validateShownFields(
                 mEditorModelCapture.getValue(), sAccountProfile, /*shouldMarkFieldsRequired=*/true);
     }
@@ -686,7 +708,8 @@
     @Test
     @SmallTest
     public void edit_ChangeCountry_FieldsSetChanges() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(List.of(new AddressUiComponent(AddressField.SORTING_CODE,
                                          "sorting code label", false, true)),
@@ -694,7 +717,7 @@
         setUpAddressUiComponents(List.of(new AddressUiComponent(AddressField.STREET_ADDRESS,
                                          "street address label", true, true)),
                 "DE");
-        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile), unused -> {});
+        mAddressEditor.edit(new AutofillAddress(mActivity, sLocalProfile));
 
         Assert.assertNotNull(mEditorModelCapture.getValue());
         List<EditorFieldModel> editorFields = mEditorModelCapture.getValue().getFields();
@@ -736,10 +759,11 @@
     @SmallTest
     public void edit_NewAddressProfile_EligibleForAddressAccountStorage() {
         when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor.edit(null, mDoneCallback);
+        mAddressEditor.edit(null);
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -754,18 +778,22 @@
         editorFields.get(9).setValue("Street address");
         editorModel.done();
 
-        Assert.assertNotNull(mEditedAutofillAddress);
-        Assert.assertEquals(Source.ACCOUNT, mEditedAutofillAddress.getProfile().getSource());
+        verify(mDelegate, times(1)).onDone(mAddressCapture.capture());
+        verify(mDelegate, times(0)).onCancel();
+        AutofillAddress address = mAddressCapture.getValue();
+        Assert.assertNotNull(address);
+        Assert.assertEquals(Source.ACCOUNT, address.getProfile().getSource());
     }
 
     @Test
     @SmallTest
     public void edit_AlterAddressProfile_Cancel() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         AutofillProfile toEdit = new AutofillProfile(sLocalProfile);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback);
+        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit));
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -778,23 +806,19 @@
         editorFields.get(3).setValue("New admin area");
         editorModel.cancel();
 
-        Assert.assertNotNull(mEditedAutofillAddress);
-        Assert.assertEquals(
-                sLocalProfile.getFullName(), mEditedAutofillAddress.getProfile().getFullName());
-        Assert.assertEquals(sLocalProfile.getHonorificPrefix(),
-                mEditedAutofillAddress.getProfile().getHonorificPrefix());
-        Assert.assertEquals(
-                sLocalProfile.getRegion(), mEditedAutofillAddress.getProfile().getRegion());
+        verify(mDelegate, times(0)).onDone(any());
+        verify(mDelegate, times(1)).onCancel();
     }
 
     @Test
     @SmallTest
     public void edit_AlterAddressProfile_CommitChanges() {
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         AutofillProfile toEdit = new AutofillProfile(sLocalProfile);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
-        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback);
+        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit));
 
         Assert.assertNotNull(mEditorModelCapture.getValue());
         EditorModel editorModel = mEditorModelCapture.getValue();
@@ -807,12 +831,13 @@
         editorFields.get(6).setValue("New organization");
         editorModel.done();
 
-        Assert.assertNotNull(mEditedAutofillAddress);
-        Assert.assertEquals("New locality", mEditedAutofillAddress.getProfile().getLocality());
-        Assert.assertEquals("New dependent locality",
-                mEditedAutofillAddress.getProfile().getDependentLocality());
-        Assert.assertEquals(
-                "New organization", mEditedAutofillAddress.getProfile().getCompanyName());
+        verify(mDelegate, times(1)).onDone(mAddressCapture.capture());
+        verify(mDelegate, times(0)).onCancel();
+        AutofillAddress address = mAddressCapture.getValue();
+        Assert.assertNotNull(address);
+        Assert.assertEquals("New locality", address.getProfile().getLocality());
+        Assert.assertEquals("New dependent locality", address.getProfile().getDependentLocality());
+        Assert.assertEquals("New organization", address.getProfile().getCompanyName());
     }
 
     @Test
@@ -820,11 +845,12 @@
     public void accountSavingDisallowedForUnsupportedCountry() {
         when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true);
         when(mPersonalDataManager.isCountryEligibleForAccountStorage(eq("CU"))).thenReturn(false);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS, "US");
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS, "CU");
-        mAddressEditor.edit(null, mDoneCallback);
+        mAddressEditor.edit(null);
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -842,20 +868,23 @@
         editorFields.get(9).setValue("Street address");
         editorModel.done();
 
-        Assert.assertNotNull(mEditedAutofillAddress);
-        Assert.assertEquals(
-                Source.LOCAL_OR_SYNCABLE, mEditedAutofillAddress.getProfile().getSource());
+        verify(mDelegate, times(1)).onDone(mAddressCapture.capture());
+        verify(mDelegate, times(0)).onCancel();
+        AutofillAddress address = mAddressCapture.getValue();
+        Assert.assertNotNull(address);
+        Assert.assertEquals(Source.LOCAL_OR_SYNCABLE, address.getProfile().getSource());
     }
 
     @Test
     @SmallTest
     public void countryDropDownExcludesUnsupportedCountries_saveInAccountFlow() {
         when(mPersonalDataManager.isCountryEligibleForAccountStorage(eq("CU"))).thenReturn(false);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
         AutofillProfile toEdit = new AutofillProfile(sAccountProfile);
-        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback);
+        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit));
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -869,11 +898,12 @@
     @SmallTest
     public void countryDropDownExcludesUnsupportedCountries_MigrationFlow() {
         when(mPersonalDataManager.isCountryEligibleForAccountStorage(eq("CU"))).thenReturn(false);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/false,
+        mAddressEditor = new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false,
+                /*isUpdate=*/false,
                 /*isMigrationToAccount=*/true);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
         AutofillProfile toEdit = new AutofillProfile(sLocalProfile);
-        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback);
+        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit));
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
@@ -887,11 +917,12 @@
     @SmallTest
     public void countryDropDownExcludesUnsupportedCountries_editExistingAccountProfile() {
         when(mPersonalDataManager.isCountryEligibleForAccountStorage(eq("CU"))).thenReturn(false);
-        mAddressEditor = new AddressEditor(mEditorDialog, /*saveToDisk=*/false, /*isUpdate=*/true,
-                /*isMigrationToAccount=*/false);
+        mAddressEditor =
+                new AddressEditor(mEditorDialog, mDelegate, /*saveToDisk=*/false, /*isUpdate=*/true,
+                        /*isMigrationToAccount=*/false);
         setUpAddressUiComponents(SUPPORTED_ADDRESS_FIELDS);
         AutofillProfile toEdit = new AutofillProfile(sAccountProfile);
-        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback);
+        mAddressEditor.edit(new AutofillAddress(mActivity, toEdit));
 
         EditorModel editorModel = mEditorModelCapture.getValue();
         Assert.assertNotNull(editorModel);
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 32f1c43..cc0b9b6 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-115.0.5759.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-115.0.5761.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7242577..106be4c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -489,6 +489,8 @@
     "enterprise/connectors/interstitials/enterprise_warn_page.h",
     "enterprise/reporting/legacy_tech/legacy_tech_report_policy_handler.cc",
     "enterprise/reporting/legacy_tech/legacy_tech_report_policy_handler.h",
+    "enterprise/reporting/legacy_tech/legacy_tech_url_matcher.cc",
+    "enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h",
     "enterprise/reporting/prefs.cc",
     "enterprise/reporting/prefs.h",
     "enterprise/reporting/profile_report_generator_delegate_base.cc",
@@ -3305,6 +3307,7 @@
       "//chrome/browser/signin/services/android:jni_headers",
       "//chrome/browser/sync/android:jni_headers",
       "//chrome/browser/tab:jni_headers",
+      "//chrome/browser/touch_to_fill/password_generation/android:public",
       "//chrome/browser/touch_to_fill/payments/android:public",
       "//chrome/browser/ui/android/layouts:android",
       "//chrome/browser/ui/webui/feed_internals:mojo_bindings",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5f61cc1..2fd12c7f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -9333,6 +9333,10 @@
      kOsDesktop,
      FEATURE_VALUE_TYPE(
          permissions::features::kRecordPermissionExpirationTimestamps)},
+
+    {"safety-hub", flag_descriptions::kSafetyHubName,
+     flag_descriptions::kSafetyHubDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kSafetyHub)},
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/android/chrome_backup_agent.cc b/chrome/browser/android/chrome_backup_agent.cc
index 5d2c7f1..89cc236 100644
--- a/chrome/browser/android/chrome_backup_agent.cc
+++ b/chrome/browser/android/chrome_backup_agent.cc
@@ -18,8 +18,6 @@
 
 namespace {
 
-// TODO(crbug.com/1305213): The data type toggles shouldn't be individually
-// listed here.
 static_assert(46 == syncer::GetNumModelTypes(),
               "If the new type has a corresponding pref, add it here");
 const char* backed_up_preferences_[] = {
diff --git a/chrome/browser/android/reading_list/reading_list_manager_factory.cc b/chrome/browser/android/reading_list/reading_list_manager_factory.cc
index 8c7d22a1..b713efbf 100644
--- a/chrome/browser/android/reading_list/reading_list_manager_factory.cc
+++ b/chrome/browser/android/reading_list/reading_list_manager_factory.cc
@@ -25,7 +25,12 @@
 ReadingListManagerFactory::ReadingListManagerFactory()
     : ProfileKeyedServiceFactory(
           "ReadingListManager",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ReadingListModelFactory::GetInstance());
 }
 
diff --git a/chrome/browser/android/webapk/webapk_install_service_factory.cc b/chrome/browser/android/webapk/webapk_install_service_factory.cc
index 75d0242..b18f0db 100644
--- a/chrome/browser/android/webapk/webapk_install_service_factory.cc
+++ b/chrome/browser/android/webapk/webapk_install_service_factory.cc
@@ -21,7 +21,12 @@
 WebApkInstallServiceFactory::WebApkInstallServiceFactory()
     : ProfileKeyedServiceFactory(
           "WebApkInstallService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 WebApkInstallServiceFactory::~WebApkInstallServiceFactory() {}
 
diff --git a/chrome/browser/apps/guest_view/app_view_browsertest.cc b/chrome/browser/apps/guest_view/app_view_browsertest.cc
index 451e2fb..75c2581d 100644
--- a/chrome/browser/apps/guest_view/app_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/app_view_browsertest.cc
@@ -78,7 +78,7 @@
 
     ExtensionTestMessageListener done_listener("TEST_PASSED");
     done_listener.set_failure_message("TEST_FAILED");
-    if (!content::ExecuteScript(
+    if (!content::ExecJs(
             embedder_web_contents,
             base::StringPrintf("runTest('%s', '%s')", test_name.c_str(),
                                app_to_embed.c_str()))) {
@@ -253,12 +253,12 @@
   const extensions::Extension* bad_app =
       LoadAndLaunchPlatformApp("app_view/bad_app", "AppViewTest.LAUNCHED");
   // The host app attemps to embed the guest
-  EXPECT_TRUE(content::ExecuteScript(
-      extensions::AppWindowRegistry::Get(browser()->profile())
-          ->GetCurrentAppWindowForApp(host_app->id())
-          ->web_contents(),
-      base::StringPrintf("onAppCommand('%s', '%s');", "EMBED",
-                         guest_app->id().c_str())));
+  EXPECT_TRUE(
+      content::ExecJs(extensions::AppWindowRegistry::Get(browser()->profile())
+                          ->GetCurrentAppWindowForApp(host_app->id())
+                          ->web_contents(),
+                      base::StringPrintf("onAppCommand('%s', '%s');", "EMBED",
+                                         guest_app->id().c_str())));
   ExtensionTestMessageListener on_embed_requested_listener(
       "AppViewTest.EmbedRequested");
   EXPECT_TRUE(on_embed_requested_listener.WaitUntilSatisfied());
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 85d5d28..fc27b70 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -276,7 +276,7 @@
 
   content::TitleWatcher title_watcher(web_contents, expected_title);
   title_watcher.AlsoWaitForTitle(error_title);
-  EXPECT_TRUE(content::ExecuteScript(web_contents, script));
+  EXPECT_TRUE(content::ExecJs(web_contents, script));
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 }
 
@@ -708,7 +708,7 @@
     ExtensionTestMessageListener done_listener("TEST_PASSED");
     done_listener.set_failure_message("TEST_FAILED");
     // Note that domAutomationController may not exist for some tests so we
-    // must use the async version of ExecuteScript.
+    // must use the ExecuteScriptAsync.
     content::ExecuteScriptAsync(
         embedder_web_contents,
         base::StringPrintf("try { "
@@ -737,10 +737,9 @@
 
     ExtensionTestMessageListener test_run_listener("PASSED");
     test_run_listener.set_failure_message("FAILED");
-    EXPECT_TRUE(
-        content::ExecuteScript(
-            embedder_web_contents,
-            base::StringPrintf("startDenyTest('%s')", test_name.c_str())));
+    EXPECT_TRUE(content::ExecJs(
+        embedder_web_contents,
+        base::StringPrintf("startDenyTest('%s')", test_name.c_str())));
     ASSERT_TRUE(test_run_listener.WaitUntilSatisfied());
   }
 
@@ -754,10 +753,9 @@
   }
 
   void SendMessageToEmbedder(const std::string& message) {
-    EXPECT_TRUE(
-        content::ExecuteScript(
-            GetEmbedderWebContents(),
-            base::StringPrintf("onAppCommand('%s');", message.c_str())));
+    EXPECT_TRUE(content::ExecJs(
+        GetEmbedderWebContents(),
+        base::StringPrintf("onAppCommand('%s');", message.c_str())));
   }
 
   void SendMessageToGuestAndWait(const std::string& message,
@@ -767,7 +765,7 @@
       listener = std::make_unique<ExtensionTestMessageListener>(wait_message);
     }
 
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         GetGuestViewManager()->WaitForSingleGuestRenderFrameHostCreated(),
         base::StringPrintf("onAppCommand('%s');", message.c_str())));
 
@@ -1004,12 +1002,12 @@
 
   // Just in case we get console error messages from the guest, we should
   // surface them in the test output.
-  EXPECT_TRUE(content::ExecuteScript(
-      embedder,
-      "wv = document.getElementsByTagName('webview')[0];"
-      "wv.addEventListener('consolemessage', function (e) {"
-      "  console.log('WebViewTest Guest: ' + e.message);"
-      "});"));
+  EXPECT_TRUE(
+      content::ExecJs(embedder,
+                      "wv = document.getElementsByTagName('webview')[0];"
+                      "wv.addEventListener('consolemessage', function (e) {"
+                      "  console.log('WebViewTest Guest: ' + e.message);"
+                      "});"));
 
   // Inject JS to start audio.
   GURL audio_url = embedded_test_server()->GetURL(
@@ -1020,7 +1018,7 @@
       "document.body.appendChild(ae);"
       "ae.play();",
       audio_url.spec().c_str());
-  EXPECT_TRUE(content::ExecuteScript(guest, setup_audio_script));
+  EXPECT_TRUE(content::ExecJs(guest, setup_audio_script));
 
   // Wait for audio to start.
   embedder_obs.WaitForCurrentlyAudible(true);
@@ -1844,12 +1842,12 @@
   // Create a subframe in the second guest.  This is needed because the crash
   // in crbug.com/1013553 only happened when trying to incorrectly create
   // proxies for a subframe.
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       guest2, "document.body.appendChild(document.createElement('iframe'));"));
 
   // Update the opener of |guest1| to point to |guest2|.  This triggers
   // creation of proxies on the new opener chain, which should not crash.
-  EXPECT_TRUE(content::ExecuteScript(guest2, "window.open('', 'foo');"));
+  EXPECT_TRUE(content::ExecJs(guest2, "window.open('', 'foo');"));
 
   // Ensure both guests have the proper opener relationship set up.  Namely,
   // each guest's opener should point to the other guest, creating a cycle.
@@ -2061,9 +2059,8 @@
   // Run the test and wait until the guest WebContents is available and has
   // finished loading.
   ExtensionTestMessageListener guest_loaded_listener("guest-loaded");
-  EXPECT_TRUE(content::ExecuteScript(
-                  embedder_web_contents,
-                  "runTest('testRemoveWebviewOnExit')"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents,
+                              "runTest('testRemoveWebviewOnExit')"));
   guest_observer.Wait();
 
   content::Source<content::NavigationController> source =
@@ -2079,9 +2076,8 @@
       source->DeprecatedGetWebContents());
 
   // Tell the embedder to kill the guest.
-  EXPECT_TRUE(content::ExecuteScript(
-                  embedder_web_contents,
-                  "removeWebviewOnExitDoCrash();"));
+  EXPECT_TRUE(
+      content::ExecJs(embedder_web_contents, "removeWebviewOnExitDoCrash();"));
 
   // Wait until the guest WebContents is destroyed.
   destroyed_watcher.Wait();
@@ -2170,8 +2166,7 @@
     content::WebContents* embedder_web_contents =
         GetFirstAppWindowWebContents();
     ExtensionTestMessageListener guest_added("GuestAddedToDom");
-    EXPECT_TRUE(
-        content::ExecuteScript(embedder_web_contents, "createGuest();"));
+    EXPECT_TRUE(content::ExecJs(embedder_web_contents, "createGuest();"));
     ASSERT_TRUE(guest_added.WaitUntilSatisfied());
     auto* guest_main_frame =
         GetGuestViewManager()->WaitForSingleGuestRenderFrameHostCreated();
@@ -2188,9 +2183,9 @@
     ASSERT_TRUE(guest_main_frame);
 
     content::TestFrameNavigationObserver guest_navi_obs(guest_main_frame);
-    ASSERT_TRUE(content::ExecuteScript(
-        embedder_web_contents,
-        content::JsReplace("loadGuestUrl($1);", guest_url)));
+    ASSERT_TRUE(
+        content::ExecJs(embedder_web_contents,
+                        content::JsReplace("loadGuestUrl($1);", guest_url)));
     guest_navi_obs.Wait();
 
     // Do not dereference `guest_main_frame` beyond here as it can be destroyed
@@ -2658,11 +2653,9 @@
 
   ExtensionTestMessageListener done_listener("TEST_PASSED");
   done_listener.set_failure_message("TEST_FAILED");
-  EXPECT_TRUE(
-      content::ExecuteScript(
-          embedder_web_contents,
-          base::StringPrintf("startAllowTest('%s')",
-                             test_name.c_str())));
+  EXPECT_TRUE(content::ExecJs(
+      embedder_web_contents,
+      base::StringPrintf("startAllowTest('%s')", test_name.c_str())));
   ASSERT_TRUE(done_listener.WaitUntilSatisfied());
 
   mock->WaitForRequestMediaPermission();
@@ -2878,7 +2871,7 @@
   // does not show up.
   ExtensionTestMessageListener prevent_default_listener(
       "WebViewTest.CONTEXT_MENU_DEFAULT_PREVENTED");
-  EXPECT_TRUE(content::ExecuteScript(embedder, "registerPreventDefault()"));
+  EXPECT_TRUE(content::ExecJs(embedder, "registerPreventDefault()"));
   ContextMenuShownObserver context_menu_shown_observer;
 
   OpenContextMenu(guest_main_frame);
@@ -2951,10 +2944,8 @@
 
   ExtensionTestMessageListener done_listener("TEST_PASSED");
   done_listener.set_failure_message("TEST_FAILED");
-  EXPECT_TRUE(
-      content::ExecuteScript(
-          embedder_web_contents,
-          base::StringPrintf("startCheckTest('')")));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents,
+                              base::StringPrintf("startCheckTest('')")));
   ASSERT_TRUE(done_listener.WaitUntilSatisfied());
 
   mock->WaitForCheckMediaPermission();
@@ -3340,20 +3331,20 @@
 
   // Start test.
   // 1. Guest requests a download that its embedder denies.
-  EXPECT_TRUE(content::ExecuteScript(guest_render_frame_host,
-                                     "startDownload('download-link-1')"));
+  EXPECT_TRUE(content::ExecJs(guest_render_frame_host,
+                              "startDownload('download-link-1')"));
   mock_delegate->WaitForCanDownload(false);  // Expect to not allow.
   mock_delegate->Reset();
 
   // 2. Guest requests a download that its embedder allows.
-  EXPECT_TRUE(content::ExecuteScript(guest_render_frame_host,
-                                     "startDownload('download-link-2')"));
+  EXPECT_TRUE(content::ExecJs(guest_render_frame_host,
+                              "startDownload('download-link-2')"));
   mock_delegate->WaitForCanDownload(true);  // Expect to allow.
   mock_delegate->Reset();
 
   // 3. Guest requests a download that its embedder ignores, this implies deny.
-  EXPECT_TRUE(content::ExecuteScript(guest_render_frame_host,
-                                     "startDownload('download-link-3')"));
+  EXPECT_TRUE(content::ExecJs(guest_render_frame_host,
+                              "startDownload('download-link-3')"));
   mock_delegate->WaitForCanDownload(false);  // Expect to not allow.
   completion_observer->WaitForFinished();
 }
@@ -3459,7 +3450,7 @@
     content::DownloadTestObserverInterrupted interrupted_observer(
         download_manager, 1,
         content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         web_contents,
         base::StringPrintf(
             "startDownload('%s', '%s?cookie=%s')", cookie.c_str(),
@@ -3549,7 +3540,7 @@
         download_manager, 1,
         content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
 
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         web_contents,
         base::StringPrintf(
             "startDownload('%s', '%s?cookie=%s')", cookie.c_str(),
@@ -3912,7 +3903,7 @@
   content::RenderFrameHost* guest = GetGuestView()->GetGuestMainFrame();
 
   content::TestFrameNavigationObserver fail_if_webview_navigates(guest);
-  ASSERT_TRUE(content::ExecuteScript(
+  ASSERT_TRUE(content::ExecJs(
       embedder, content::JsReplace(
                     "var webview = document.querySelector('webview'); "
                     "webview.loadDataWithBaseUrl('data:text/html,hello', $1);",
@@ -4598,8 +4589,8 @@
   // Reload guest and make sure it appears.
   content::TestFrameNavigationObserver load_observer(
       GetGuestView()->GetGuestMainFrame());
-  EXPECT_TRUE(ExecuteScript(GetEmbedderWebContents(),
-                            "document.querySelector('webview').reload()"));
+  EXPECT_TRUE(ExecJs(GetEmbedderWebContents(),
+                     "document.querySelector('webview').reload()"));
   load_observer.Wait();
   EXPECT_TRUE(GetGuestView()->GetGuestMainFrame()->GetView());
   // Ensure that the guest produces a new frame.
@@ -5226,9 +5217,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         guest->GetGuestMainFrame());
-    EXPECT_TRUE(
-        ExecuteScript(guest->GetGuestMainFrame(),
-                      "location.href = '" + isolated_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(guest->GetGuestMainFrame(),
+                       "location.href = '" + isolated_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -5239,8 +5229,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         guest->GetGuestMainFrame());
-    EXPECT_TRUE(ExecuteScript(guest->GetGuestMainFrame(),
-                              "location.href = '" + foo_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(guest->GetGuestMainFrame(),
+                       "location.href = '" + foo_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -5309,8 +5299,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         guest->GetGuestMainFrame());
-    EXPECT_TRUE(ExecuteScript(guest->GetGuestMainFrame(),
-                              "location.href = '" + foo_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(guest->GetGuestMainFrame(),
+                       "location.href = '" + foo_url.spec() + "';"));
     load_observer.Wait();
   }
   EXPECT_TRUE(NavigateToURLFromRenderer(
@@ -5507,7 +5497,7 @@
           document.body.appendChild(iframe);
       )";
 
-  EXPECT_TRUE(content::ExecuteScript(guest, setup_iframe_script));
+  EXPECT_TRUE(content::ExecJs(guest, setup_iframe_script));
   content::RenderFrameHost* webview_subframe = ChildFrameAt(guest, 0);
   EXPECT_TRUE(content::NavigateToURLFromRenderer(webview_subframe, iframe_url));
 
@@ -5769,7 +5759,7 @@
       url, content::MessageLoopRunner::QuitMode::IMMEDIATE,
       /*ignore_uncommitted_navigations=*/false);
   error_observer.WatchExistingWebContents();
-  EXPECT_TRUE(ExecuteScript(guest, "location.href = '" + url.spec() + "';"));
+  EXPECT_TRUE(ExecJs(guest, "location.href = '" + url.spec() + "';"));
   error_observer.Wait();
   EXPECT_FALSE(error_observer.last_navigation_succeeded());
   EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
@@ -5816,8 +5806,7 @@
       embedded_test_server()->GetURL("a.test", "/iframe.html");
   {
     content::TestNavigationObserver load_observer(guest);
-    EXPECT_TRUE(
-        ExecuteScript(guest, "location.href = '" + start_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(guest, "location.href = '" + start_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -5889,8 +5878,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         GetGuestRenderFrameHost());
-    EXPECT_TRUE(ExecuteScript(GetGuestRenderFrameHost(),
-                              "location.href = '" + error_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(GetGuestRenderFrameHost(),
+                       "location.href = '" + error_url.spec() + "';"));
     load_observer.Wait();
     EXPECT_FALSE(load_observer.last_navigation_succeeded());
     EXPECT_TRUE(GetGuestRenderFrameHost()->IsErrorDocument());
@@ -5919,9 +5908,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         GetGuestRenderFrameHost());
-    EXPECT_TRUE(ExecuteScript(
-        embedder,
-        "document.querySelector('webview').src = '" + error_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(embedder, "document.querySelector('webview').src = '" +
+                                     error_url.spec() + "';"));
     load_observer.Wait();
     EXPECT_FALSE(load_observer.last_navigation_succeeded());
     EXPECT_TRUE(GetGuestRenderFrameHost()->IsErrorDocument());
@@ -5963,8 +5951,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         GetGuestRenderFrameHost());
-    EXPECT_TRUE(ExecuteScript(GetGuestRenderFrameHost(),
-                              "location.href = '" + first_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(GetGuestRenderFrameHost(),
+                       "location.href = '" + first_url.spec() + "';"));
     load_observer.Wait();
     EXPECT_TRUE(load_observer.last_navigation_succeeded());
   }
@@ -5977,8 +5965,8 @@
   const GURL error_url = GURL("unknownscheme:foo");
   {
     content::TestFrameNavigationObserver load_observer(guest_subframe);
-    EXPECT_TRUE(ExecuteScript(guest_subframe,
-                              "location.href = '" + error_url.spec() + "';"));
+    EXPECT_TRUE(
+        ExecJs(guest_subframe, "location.href = '" + error_url.spec() + "';"));
     load_observer.Wait();
     EXPECT_FALSE(load_observer.last_navigation_succeeded());
     auto* error_rfh = ChildFrameAt(GetGuestRenderFrameHost(), 0);
@@ -6007,8 +5995,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         GetGuestRenderFrameHost());
-    EXPECT_TRUE(ExecuteScript(GetGuestRenderFrameHost(),
-                              "location.href = '" + first_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(GetGuestRenderFrameHost(),
+                       "location.href = '" + first_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -6131,9 +6119,8 @@
   {
     content::TestFrameNavigationObserver load_observer(
         GetGuestRenderFrameHost());
-    EXPECT_TRUE(ExecuteScript(
-        embedder,
-        "document.querySelector('webview').src = '" + blank_url.spec() + "';"));
+    EXPECT_TRUE(ExecJs(embedder, "document.querySelector('webview').src = '" +
+                                     blank_url.spec() + "';"));
     load_observer.Wait();
   }
   scoped_refptr<content::SiteInstance> fourth_instance =
@@ -6208,7 +6195,7 @@
         chrome.test.sendMessage("Hello from content script!");
     )";
 
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder, content::JsReplace(kContentScriptTemplate, kContentScript)));
 
     // Ensure the new content script is now tracked for the <webview> in the
@@ -6249,8 +6236,8 @@
   // Remove the <webview> and ensure no guests remain in WebViewRendererState.
   {
     content::RenderFrameDeletedObserver deleted_observer(main_frame);
-    EXPECT_TRUE(content::ExecuteScript(
-        embedder, "document.querySelector('webview').remove()"));
+    EXPECT_TRUE(content::ExecJs(embedder,
+                                "document.querySelector('webview').remove()"));
     deleted_observer.WaitUntilDeleted();
     ASSERT_EQ(0u, web_view_renderer_state->guest_count_for_testing());
   }
@@ -6294,7 +6281,7 @@
         chrome.test.sendMessage("Hello from content script!");
     )";
 
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder, content::JsReplace(kContentScriptTemplate, kContentScript)));
   }
 
@@ -6353,7 +6340,7 @@
       content::ChildFrameAt(guest->GetGuestMainFrame(), 0);
   EXPECT_TRUE(NavigateToURLFromRenderer(subframe, frame_url));
   // Attach a second <webview>.
-  ASSERT_TRUE(content::ExecuteScript(
+  ASSERT_TRUE(content::ExecJs(
       GetEmbedderWebContents(),
       base::StringPrintf("const w = document.createElement('webview');"
                          "w.src = '%s';"
@@ -6455,8 +6442,8 @@
       embedded_test_server()->GetURL("a.test", "/iframe.html");
   {
     content::TestFrameNavigationObserver load_observer(main_frame);
-    EXPECT_TRUE(ExecuteScript(main_frame,
-                              "location.href = '" + start_url.spec() + "';"));
+    EXPECT_TRUE(
+        ExecJs(main_frame, "location.href = '" + start_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -6520,8 +6507,8 @@
       embedded_test_server()->GetURL("isolated.com", "/iframe.html");
   {
     content::TestFrameNavigationObserver load_observer(main_frame);
-    EXPECT_TRUE(ExecuteScript(main_frame,
-                              "location.href = '" + start_url.spec() + "';"));
+    EXPECT_TRUE(
+        ExecJs(main_frame, "location.href = '" + start_url.spec() + "';"));
     load_observer.Wait();
   }
 
@@ -6541,7 +6528,7 @@
   {
     content::TestFrameNavigationObserver subframe_load_observer(subframe);
     EXPECT_TRUE(
-        ExecuteScript(subframe, "location.href = '" + frame_url.spec() + "';"));
+        ExecJs(subframe, "location.href = '" + frame_url.spec() + "';"));
     subframe_load_observer.Wait();
   }
   subframe = content::ChildFrameAt(main_frame, 0);
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 4af0fda3..cf46b19 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -299,7 +299,7 @@
     auto done_listener =
         std::make_unique<ExtensionTestMessageListener>("TEST_PASSED");
     done_listener->set_failure_message("TEST_FAILED");
-    if (!content::ExecuteScript(
+    if (!content::ExecJs(
             *embedder_web_contents,
             base::StringPrintf("runTest('%s')", test_name.c_str()))) {
       LOG(ERROR) << "UNABLE TO START TEST";
@@ -324,7 +324,7 @@
   }
 
   void SendMessageToEmbedder(const std::string& message) {
-    ASSERT_TRUE(content::ExecuteScript(
+    ASSERT_TRUE(content::ExecJs(
         GetFirstAppWindowWebContents(),
         base::StringPrintf("onAppMessage('%s');", message.c_str())));
   }
@@ -734,7 +734,7 @@
 
   ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED");
   next_step_listener.set_failure_message("TEST_STEP_FAILED");
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       embedder_web_contents,
       "window.runCommand('testFocusTracksEmbedderRunNextStep');"));
 
@@ -814,7 +814,7 @@
   // Try to focus an iframe in the guest.
   content::MainThreadFrameObserver embedder_observer(embedder_rwh);
   content::MainThreadFrameObserver guest_observer(guest_rwh);
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       guest_rfh,
       "document.body.appendChild(document.createElement('iframe')); "
       "document.querySelector('iframe').focus()"));
@@ -826,8 +826,8 @@
   EXPECT_NE(guest_rfh, embedder_web_contents->GetFocusedFrame());
 
   // Try to focus the guest from the embedder.
-  EXPECT_TRUE(content::ExecuteScript(
-      embedder_web_contents, "document.querySelector('webview').focus()"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents,
+                              "document.querySelector('webview').focus()"));
   embedder_observer.Wait();
   guest_observer.Wait();
   // Guest should be focused.
@@ -839,13 +839,13 @@
       (iframe_inside_guest == embedder_web_contents->GetFocusedFrame()));
 
   // Try to focus an iframe in the embedder.
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       embedder_web_contents,
       "document.body.appendChild(document.createElement('iframe'))"));
   content::RenderFrameHost* iframe_rfh = ChildFrameAt(embedder_rfh, 1);
   content::FrameFocusedObserver iframe_focus_observer(iframe_rfh);
-  EXPECT_TRUE(content::ExecuteScript(
-      embedder_web_contents, "document.querySelector('iframe').focus()"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents,
+                              "document.querySelector('iframe').focus()"));
   // Embedder is allowed to steal focus from guest.
   iframe_focus_observer.Wait();
   EXPECT_TRUE(content::IsRenderWidgetHostFocused(embedder_rwh));
@@ -969,8 +969,8 @@
   ExtensionTestMessageListener ready_back_key_listener("ReadyForBackKey");
   ExtensionTestMessageListener ready_forward_key_listener("ReadyForForwardKey");
 
-  EXPECT_TRUE(content::ExecuteScript(embedder_web_contents,
-                                     "runTest('testBackForwardKeys')"));
+  EXPECT_TRUE(
+      content::ExecJs(embedder_web_contents, "runTest('testBackForwardKeys')"));
 
   ASSERT_TRUE(ready_back_key_listener.WaitUntilSatisfied());
   SendBackShortcutToPlatformApp();
@@ -1039,7 +1039,7 @@
         embedder_web_contents, 0, blink::WebMouseEvent::Button::kLeft,
         guest_rfh->GetView()->TransformPointToRootCoordSpace(
             gfx::Point(10, 10)));
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder_web_contents,
         "window.runCommand('testFocusRestoredRunNextStep', 1);"));
   }
@@ -1053,7 +1053,7 @@
     content::SimulateMouseClickAt(embedder_web_contents, 0,
                                   blink::WebMouseEvent::Button::kLeft,
                                   gfx::Point(200, 20));
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder_web_contents,
         "window.runCommand('testFocusRestoredRunNextStep', 2);"));
   }
@@ -1069,7 +1069,7 @@
         embedder_web_contents, 0, blink::WebMouseEvent::Button::kLeft,
         guest_rfh->GetView()->TransformPointToRootCoordSpace(
             gfx::Point(10, 10)));
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder_web_contents,
         "window.runCommand('testFocusRestoredRunNextStep', 3)"));
   }
@@ -1121,9 +1121,9 @@
     ui::CompositionText composition;
     composition.text = u"InputTest123";
     text_input_client->SetCompositionText(composition);
-    EXPECT_TRUE(content::ExecuteScript(
-        embedder_web_contents,
-        "window.runCommand('testInputMethodRunNextStep', 1);"));
+    EXPECT_TRUE(
+        content::ExecJs(embedder_web_contents,
+                        "window.runCommand('testInputMethodRunNextStep', 1);"));
 
     // Wait for the next step to complete.
     ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
@@ -1137,9 +1137,9 @@
     composition.text = u"InputTest456";
     text_input_client->SetCompositionText(composition);
     text_input_client->ConfirmCompositionText(/* keep_selection */ false);
-    EXPECT_TRUE(content::ExecuteScript(
-        embedder_web_contents,
-        "window.runCommand('testInputMethodRunNextStep', 2);"));
+    EXPECT_TRUE(
+        content::ExecJs(embedder_web_contents,
+                        "window.runCommand('testInputMethodRunNextStep', 2);"));
 
     // Wait for the next step to complete.
     ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
@@ -1163,9 +1163,9 @@
     // Now we delete 'Test' in 'InputTest456', as the caret is after 'T':
     // delete before 1 character ('T') and after 3 characters ('est').
     text_input_client->ExtendSelectionAndDelete(1, 3);
-    EXPECT_TRUE(content::ExecuteScript(
-        embedder_web_contents,
-        "window.runCommand('testInputMethodRunNextStep', 3);"));
+    EXPECT_TRUE(
+        content::ExecJs(embedder_web_contents,
+                        "window.runCommand('testInputMethodRunNextStep', 3);"));
 
     // Wait for the next step to complete.
     ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
@@ -1381,7 +1381,7 @@
       GetPlatformAppWindow(), ui::VKEY_C, false, false, false, false));
 
   next_step_listener.Reset();
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       embedder_web_contents(),
       "window.runCommand('testKeyboardFocusRunNextStep', 'aBc');"));
 
@@ -1430,9 +1430,9 @@
   const extensions::Extension* extension =
       LoadAndLaunchPlatformApp("minimal", "Launched");
   extensions::AppWindow* window = GetFirstAppWindowForApp(extension->id());
-  EXPECT_TRUE(content::ExecuteScript(
-      embedder_web_contents(),
-      "window.runCommand('monitorGuestEvent', 'focus');"));
+  EXPECT_TRUE(
+      content::ExecJs(embedder_web_contents(),
+                      "window.runCommand('monitorGuestEvent', 'focus');"));
 
   ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
       GetPlatformAppWindow(), ui::VKEY_F, false, false, false, false));
@@ -1445,9 +1445,8 @@
   CloseAppWindow(window);
   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
   next_step_listener.Reset();
-  EXPECT_TRUE(
-      content::ExecuteScript(embedder_web_contents(),
-                             "window.runCommand('waitGuestEvent', 'focus');"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents(),
+                              "window.runCommand('waitGuestEvent', 'focus');"));
   ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
 
   ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
@@ -1458,7 +1457,7 @@
       GetPlatformAppWindow(), ui::VKEY_Z, false, false, false, false));
 
   next_step_listener.Reset();
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       embedder_web_contents(),
       "window.runCommand('testKeyboardFocusRunNextStep', 'aBcxYz');"));
 
@@ -1483,7 +1482,7 @@
   // it.  Hence, have the guest request pointer lock and wait for its
   // destruction.
   content::RenderFrameDeletedObserver observer(guest_rfh);
-  EXPECT_TRUE(content::ExecuteScript(
+  EXPECT_TRUE(content::ExecJs(
       guest_rfh, "document.querySelector('div').requestPointerLock()"));
   observer.WaitUntilDeleted();
 
@@ -1657,8 +1656,8 @@
   content::RenderFrameHost* guest_rfh =
       GetGuestViewManager()->WaitForSingleGuestRenderFrameHostCreated();
   content::FrameFocusedObserver focus_observer(guest_rfh);
-  EXPECT_TRUE(content::ExecuteScript(
-      embedder_web_contents, "document.querySelector('webview').focus()"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents,
+                              "document.querySelector('webview').focus()"));
   focus_observer.Wait();
   ASSERT_TRUE(
       content::IsRenderWidgetHostFocused(guest_rfh->GetRenderWidgetHost()));
@@ -1678,8 +1677,7 @@
   const GURL guest_url =
       embedded_test_server()->GetURL("a.test", "/title1.html");
   content::TestFrameNavigationObserver observer(guest_rfh);
-  EXPECT_TRUE(
-      ExecuteScript(guest_rfh, "location.href = '" + guest_url.spec() + "';"));
+  EXPECT_TRUE(ExecJs(guest_rfh, "location.href = '" + guest_url.spec() + "';"));
   observer.Wait();
   EXPECT_TRUE(observer.last_navigation_succeeded());
 
diff --git a/chrome/browser/apps/platform_apps/app_load_service_factory.cc b/chrome/browser/apps/platform_apps/app_load_service_factory.cc
index 49db479..07cb306d6 100644
--- a/chrome/browser/apps/platform_apps/app_load_service_factory.cc
+++ b/chrome/browser/apps/platform_apps/app_load_service_factory.cc
@@ -29,7 +29,12 @@
 AppLoadServiceFactory::AppLoadServiceFactory()
     : ProfileKeyedServiceFactory(
           "AppLoadService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::AppWindowRegistry::Factory::GetInstance());
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
diff --git a/chrome/browser/apps/platform_apps/app_termination_observer.cc b/chrome/browser/apps/platform_apps/app_termination_observer.cc
index cc26b7d..2259fbe 100644
--- a/chrome/browser/apps/platform_apps/app_termination_observer.cc
+++ b/chrome/browser/apps/platform_apps/app_termination_observer.cc
@@ -32,7 +32,12 @@
 AppTerminationObserverFactory::AppTerminationObserverFactory()
     : ProfileKeyedServiceFactory(
           "AppTerminationObserver",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 KeyedService* AppTerminationObserverFactory::BuildServiceInstanceFor(
     content::BrowserContext* browser_context) const {
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.cc b/chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.cc
index 35a6b40..5fe887d 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.cc
@@ -47,7 +47,12 @@
           "ArcAppListPrefs",
           // This matches the logic in ExtensionSyncServiceFactory, which uses
           // the original browser context.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(NotificationDisplayServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/app_list/arc/arc_package_syncable_service_factory.cc b/chrome/browser/ash/app_list/arc/arc_package_syncable_service_factory.cc
index 4910cd2..cb6f127da 100644
--- a/chrome/browser/ash/app_list/arc/arc_package_syncable_service_factory.cc
+++ b/chrome/browser/ash/app_list/arc/arc_package_syncable_service_factory.cc
@@ -31,7 +31,12 @@
           "ArcPackageSyncableService",
           // This matches the logic in ExtensionSyncServiceFactory, which uses
           // the original browser context.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ArcAppListPrefsFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/app_list/arc/arc_usb_host_permission_manager_factory.cc b/chrome/browser/ash/app_list/arc/arc_usb_host_permission_manager_factory.cc
index b22e3e3..6ce985b 100644
--- a/chrome/browser/ash/app_list/arc/arc_usb_host_permission_manager_factory.cc
+++ b/chrome/browser/ash/app_list/arc/arc_usb_host_permission_manager_factory.cc
@@ -30,7 +30,12 @@
           "ArcUsbHostPermissionManager",
           // This matches the logic in ExtensionSyncServiceFactory, which uses
           // the original browser context.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ArcAppListPrefsFactory::GetInstance());
   DependsOn(ArcUsbHostBridge::GetFactory());
 }
diff --git a/chrome/browser/ash/app_list/arc/arc_vpn_provider_manager_factory.cc b/chrome/browser/ash/app_list/arc/arc_vpn_provider_manager_factory.cc
index a661065..9d4740eb 100644
--- a/chrome/browser/ash/app_list/arc/arc_vpn_provider_manager_factory.cc
+++ b/chrome/browser/ash/app_list/arc/arc_vpn_provider_manager_factory.cc
@@ -27,7 +27,12 @@
           "ArcVpnProviderManager",
           // This matches the logic in ExtensionSyncServiceFactory, which uses
           // the original browser context.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ArcAppListPrefsFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/app_restore/full_restore_service_factory.cc b/chrome/browser/ash/app_restore/full_restore_service_factory.cc
index f7b2cd8..ad940a25 100644
--- a/chrome/browser/ash/app_restore/full_restore_service_factory.cc
+++ b/chrome/browser/ash/app_restore/full_restore_service_factory.cc
@@ -47,13 +47,12 @@
 }
 
 FullRestoreServiceFactory::FullRestoreServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "FullRestoreService",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithSystem(ProfileSelection::kNone)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {
+    : ProfileKeyedServiceFactory("FullRestoreService",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithSystem(ProfileSelection::kNone)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {
   DependsOn(NotificationDisplayServiceFactory::GetInstance());
   DependsOn(apps::AppServiceProxyFactory::GetInstance());
 }
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 c665a31..9e0ecbc 100644
--- a/chrome/browser/ash/apps/apk_web_app_service_factory.cc
+++ b/chrome/browser/ash/apps/apk_web_app_service_factory.cc
@@ -31,7 +31,12 @@
 ApkWebAppServiceFactory::ApkWebAppServiceFactory()
     : ProfileKeyedServiceFactory(
           "ApkWebAppService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ArcAppListPrefsFactory::GetInstance());
   DependsOn(web_app::WebAppProviderFactory::GetInstance());
 }
diff --git a/chrome/browser/ash/arc/fileapi/arc_documents_provider_root_map_factory.cc b/chrome/browser/ash/arc/fileapi/arc_documents_provider_root_map_factory.cc
index 8d13625..5b0914dc9 100644
--- a/chrome/browser/ash/arc/fileapi/arc_documents_provider_root_map_factory.cc
+++ b/chrome/browser/ash/arc/fileapi/arc_documents_provider_root_map_factory.cc
@@ -22,7 +22,12 @@
 ArcDocumentsProviderRootMapFactory::ArcDocumentsProviderRootMapFactory()
     : ProfileKeyedServiceFactory(
           "ArcDocumentsProviderRootMap",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ArcFileSystemOperationRunner::GetFactory());
 }
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_service_factory.cc b/chrome/browser/ash/bruschetta/bruschetta_service_factory.cc
index ae585ed..06f0694 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_service_factory.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_service_factory.cc
@@ -27,14 +27,13 @@
 }
 
 BruschettaServiceFactory::BruschettaServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "BruschettaService",
-          // Takes care of not creating the service for OTR and non user
-          // profiles.
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {}
+    : ProfileKeyedServiceFactory("BruschettaService",
+                                 // Takes care of not creating the service for
+                                 // OTR and non user profiles.
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {}
 
 BruschettaServiceFactory::~BruschettaServiceFactory() = default;
 
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.cc
index a192512..9ea8e40 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.cc
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.cc
@@ -43,12 +43,11 @@
 
 CertProvisioningSchedulerUserServiceFactory::
     CertProvisioningSchedulerUserServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "CertProvisioningSchedulerUserService",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {
+    : ProfileKeyedServiceFactory("CertProvisioningSchedulerUserService",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {
   DependsOn(platform_keys::PlatformKeysServiceFactory::GetInstance());
   DependsOn(invalidation::ProfileInvalidationProviderFactory::GetInstance());
 }
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index c4caa69..72a16f2 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -1772,7 +1772,12 @@
 DriveIntegrationServiceFactory::DriveIntegrationServiceFactory()
     : ProfileKeyedServiceFactory(
           "DriveIntegrationService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(DriveNotificationManagerFactory::GetInstance());
   DependsOn(DownloadCoreServiceFactory::GetInstance());
diff --git a/chrome/browser/ash/file_system_provider/service_factory.cc b/chrome/browser/ash/file_system_provider/service_factory.cc
index ce027b1..950a74e 100644
--- a/chrome/browser/ash/file_system_provider/service_factory.cc
+++ b/chrome/browser/ash/file_system_provider/service_factory.cc
@@ -33,7 +33,12 @@
 ServiceFactory::ServiceFactory()
     : ProfileKeyedServiceFactory(
           "Service",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
   DependsOn(extensions::ExtensionSystemFactory::GetInstance());
   DependsOn(NotificationDisplayServiceFactory::GetInstance());
diff --git a/chrome/browser/ash/fileapi/recent_model_factory.cc b/chrome/browser/ash/fileapi/recent_model_factory.cc
index f1cfc40..92b6a2a 100644
--- a/chrome/browser/ash/fileapi/recent_model_factory.cc
+++ b/chrome/browser/ash/fileapi/recent_model_factory.cc
@@ -24,7 +24,12 @@
 RecentModelFactory::RecentModelFactory()
     : ProfileKeyedServiceFactory(
           "RecentModel",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(arc::ArcDocumentsProviderRootMapFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/login/security_token_session_controller_factory.cc b/chrome/browser/ash/login/security_token_session_controller_factory.cc
index dd940938..5a1e322 100644
--- a/chrome/browser/ash/login/security_token_session_controller_factory.cc
+++ b/chrome/browser/ash/login/security_token_session_controller_factory.cc
@@ -21,7 +21,12 @@
 SecurityTokenSessionControllerFactory::SecurityTokenSessionControllerFactory()
     : ProfileKeyedServiceFactory(
           "SecurityTokenSessionController",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(chromeos::CertificateProviderServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc
index a29ea07f..1fab8f7d 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc
@@ -33,12 +33,11 @@
 }  // namespace
 
 OwnerSettingsServiceAshFactory::OwnerSettingsServiceAshFactory()
-    : ProfileKeyedServiceFactory(
-          "OwnerSettingsService",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {}
+    : ProfileKeyedServiceFactory("OwnerSettingsService",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {}
 
 OwnerSettingsServiceAshFactory::~OwnerSettingsServiceAshFactory() = default;
 
diff --git a/chrome/browser/ash/platform_keys/key_permissions/user_private_token_kpm_service_factory.cc b/chrome/browser/ash/platform_keys/key_permissions/user_private_token_kpm_service_factory.cc
index 5843696..38bc25f67 100644
--- a/chrome/browser/ash/platform_keys/key_permissions/user_private_token_kpm_service_factory.cc
+++ b/chrome/browser/ash/platform_keys/key_permissions/user_private_token_kpm_service_factory.cc
@@ -62,12 +62,11 @@
 
 UserPrivateTokenKeyPermissionsManagerServiceFactory::
     UserPrivateTokenKeyPermissionsManagerServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "UserPrivateTokenKeyPermissionsManagerService",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {
+    : ProfileKeyedServiceFactory("UserPrivateTokenKeyPermissionsManagerService",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {
   DependsOn(PlatformKeysServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/platform_keys/platform_keys_service_factory.cc b/chrome/browser/ash/platform_keys/platform_keys_service_factory.cc
index 30d3148..69af643 100644
--- a/chrome/browser/ash/platform_keys/platform_keys_service_factory.cc
+++ b/chrome/browser/ash/platform_keys/platform_keys_service_factory.cc
@@ -169,7 +169,12 @@
 PlatformKeysServiceFactory::PlatformKeysServiceFactory()
     : ProfileKeyedServiceFactory(
           "PlatformKeysService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(NssServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.cc b/chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.cc
index 28bed26..61b5aba 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.cc
@@ -24,7 +24,12 @@
 PluginVmInstallerFactory::PluginVmInstallerFactory()
     : ProfileKeyedServiceFactory(
           "PluginVmInstaller",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(BackgroundDownloadServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/policy/core/browser_policy_connector_ash.h b/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
index e4fae74..20f4a6f 100644
--- a/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
+++ b/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
@@ -136,17 +136,20 @@
   // Delegates to `ash::InstallAttributes::Get()`.
   ash::InstallAttributes* GetInstallAttributes() const;
 
-  // May be nullptr, e.g. for devices managed by Active Directory.
+  // May be nullptr.
+  // TODO(b/281771191) Document when this can return nullptr.
   DeviceCloudPolicyManagerAsh* GetDeviceCloudPolicyManager() const {
     return device_cloud_policy_manager_;
   }
 
-  // May be nullptr, e.g. for devices managed by Active Directory.
+  // May be nullptr.
+  // TODO(b/281771191) Document when this can return nullptr.
   DeviceLocalAccountPolicyService* GetDeviceLocalAccountPolicyService() const {
     return device_local_account_policy_service_.get();
   }
 
-  // May be nullptr, e.g. for devices managed by Active Directory.
+  // May be nullptr.
+  // TODO(b/281771191) Document when this can return nullptr.
   ServerBackedStateKeysBroker* GetStateKeysBroker() const {
     return state_keys_broker_.get();
   }
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
index b50f5a49..8940b67 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
@@ -103,7 +103,7 @@
 
   // State key retrieved from session_manager. Used for state retrieval
   // request. Computed by StateKeys step.
-  std::string state_key;
+  absl::optional<std::string> state_key;
 
   // Maintains the required data and methods to communicate with the PSM
   // server. In particular, it holds the plaintext id we are want to check
@@ -503,7 +503,9 @@
                        std::move(completion_callback), base::TimeTicks::Now()));
 
     auto* request = config->request()->mutable_device_state_retrieval_request();
-    request->set_server_backed_state_key(context.state_key);
+    if (context.state_key.has_value()) {
+      request->set_server_backed_state_key(context.state_key.value());
+    }
     request->set_brand_code(std::string(context.rlz_brand_code));
     request->set_serial_number(std::string(context.serial_number));
 
@@ -849,11 +851,8 @@
   }
 
   void OnStateKeysRetrieved(absl::optional<std::string> state_key) {
-    if (!state_key) {
-      LOG(ERROR) << "Failed to obtain state keys";
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
-    }
-    context_.state_key = *state_key;
+    LOG_IF(WARNING, !state_key) << "Failed to obtain state keys";
+    context_.state_key = state_key;
     context_.psm_rlwe_client = context_.rlwe_client_factory.Run(
         ConstructPlainttextId(context_.rlz_brand_code, context_.serial_number));
     oprf_.Request(context_, base::BindOnce(&Sequence::OnOprfRequestDone,
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
index f8856e9..1b1755e 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
@@ -314,15 +314,20 @@
   EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
 }
 
-TEST_F(EnrollmentStateFetcherTest, StateKeysMissing) {
+TEST_F(EnrollmentStateFetcherTest, ProceedWithMissingStateKeys) {
   ExpectOwnershipCheck();
   EXPECT_CALL(state_key_broker_, RequestStateKeys)
       .WillRepeatedly(
           base::test::RunOnceCallback<0>(std::vector<std::string>{}));
+  ExpectOprfRequest();
+  ExpectQueryRequest();
+  EXPECT_CALL(job_creation_handler_, OnJobCreation(JobWithStateRequest(
+                                         /*state_key=*/std::string(),
+                                         kTestSerialNumber, kTestBrandCode)))
+      .WillOnce(
+          fake_dm_service_->SendJobOKAsync(em::DeviceManagementResponse()));
 
-  AutoEnrollmentState state = FetchEnrollmentState();
-
-  EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  FetchEnrollmentState();
 }
 
 TEST_F(EnrollmentStateFetcherTest, EmptyOprfResponse) {
@@ -500,6 +505,38 @@
   EXPECT_TRUE(device_state.empty());
 }
 
+TEST_F(EnrollmentStateFetcherTest, PackagedLicenseWithoutEnrollment) {
+  ExpectOwnershipCheck();
+  ExpectStateKeysRequest();
+  ExpectOprfRequest();
+  ExpectQueryRequest();
+  em::DeviceManagementResponse response;
+  auto* state_response = response.mutable_device_state_retrieval_response()
+                             ->mutable_initial_state_response();
+  state_response->set_initial_enrollment_mode(
+      em::DeviceInitialEnrollmentStateResponse::INITIAL_ENROLLMENT_MODE_NONE);
+  state_response->set_license_packaging_sku(
+      enterprise_management::DeviceInitialEnrollmentStateResponse::
+          CHROME_TERMINAL);
+  state_response->set_is_license_packaged_with_device(true);
+  EXPECT_CALL(job_creation_handler_,
+              OnJobCreation(JobWithStateRequest(
+                  kTestStateKey, kTestSerialNumber, kTestBrandCode)))
+      .WillOnce(fake_dm_service_->SendJobOKAsync(response));
+
+  AutoEnrollmentState state = FetchEnrollmentState();
+
+  EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  const base::Value::Dict& device_state =
+      local_state_.GetDict(prefs::kServerBackedDeviceState);
+  EXPECT_FALSE(device_state.FindString(kDeviceStateMode));
+  ASSERT_TRUE(device_state.FindBool(kDeviceStatePackagedLicense));
+  EXPECT_EQ(*device_state.FindBool(kDeviceStatePackagedLicense), true);
+  ASSERT_TRUE(device_state.FindString(kDeviceStateLicenseType));
+  EXPECT_EQ(*device_state.FindString(kDeviceStateLicenseType),
+            kDeviceStateLicenseTypeTerminal);
+}
+
 TEST_F(EnrollmentStateFetcherTest, InitialEnrollmentEnforced) {
   ExpectOwnershipCheck();
   ExpectStateKeysRequest();
diff --git a/chrome/browser/ash/printing/cups_print_job_manager_factory.cc b/chrome/browser/ash/printing/cups_print_job_manager_factory.cc
index 1fe795d..2ab3c9d 100644
--- a/chrome/browser/ash/printing/cups_print_job_manager_factory.cc
+++ b/chrome/browser/ash/printing/cups_print_job_manager_factory.cc
@@ -32,7 +32,12 @@
 CupsPrintJobManagerFactory::CupsPrintJobManagerFactory()
     : ProfileKeyedServiceFactory(
           "CupsPrintJobManagerFactory",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(SyncedPrintersManagerFactory::GetInstance());
   DependsOn(CupsPrintersManagerFactory::GetInstance());
 }
diff --git a/chrome/browser/ash/printing/history/print_job_history_service_factory.cc b/chrome/browser/ash/printing/history/print_job_history_service_factory.cc
index 0ede284..3927e71 100644
--- a/chrome/browser/ash/printing/history/print_job_history_service_factory.cc
+++ b/chrome/browser/ash/printing/history/print_job_history_service_factory.cc
@@ -35,7 +35,7 @@
     : ProfileKeyedServiceFactory(
           "PrintJobHistoryService",
           ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
+              .WithGuest(ProfileSelection::kOriginalOnly)
               // We do not want an instance of PrintJobHistory on the lock
               // screen.  The result is multiple print job notifications.
               // https://crbug.com/1011532
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
index 017a926c..d025528 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
@@ -30,7 +30,12 @@
 AuthorizationZonesManagerFactory::AuthorizationZonesManagerFactory()
     : ProfileKeyedServiceFactory(
           "AuthorizationZonesManagerFactory",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 AuthorizationZonesManagerFactory::~AuthorizationZonesManagerFactory() = default;
 
diff --git a/chrome/browser/ash/printing/synced_printers_manager_factory.cc b/chrome/browser/ash/printing/synced_printers_manager_factory.cc
index 0f8a3d6..68078e8c 100644
--- a/chrome/browser/ash/printing/synced_printers_manager_factory.cc
+++ b/chrome/browser/ash/printing/synced_printers_manager_factory.cc
@@ -42,7 +42,12 @@
 SyncedPrintersManagerFactory::SyncedPrintersManagerFactory()
     : ProfileKeyedServiceFactory(
           "SyncedPrintersManager",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
index c55bc87..921cb73 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
@@ -30,13 +30,12 @@
 }
 
 RemoteAppsManagerFactory::RemoteAppsManagerFactory()
-    : ProfileKeyedServiceFactory(
-          "RemoteAppsManager",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithSystem(ProfileSelection::kNone)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {
+    : ProfileKeyedServiceFactory("RemoteAppsManager",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithSystem(ProfileSelection::kNone)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {
   DependsOn(app_list::AppListSyncableServiceFactory::GetInstance());
   DependsOn(apps::AppServiceProxyFactory::GetInstance());
   DependsOn(extensions::EventRouterFactory::GetInstance());
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager_factory.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager_factory.cc
index f9f46f8..c80da47b 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager_factory.cc
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager_factory.cc
@@ -29,7 +29,7 @@
     : ProfileKeyedServiceFactory(
           "LorgnetteScannerManager",
           ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
+              .WithGuest(ProfileSelection::kOriginalOnly)
               .WithAshInternals(ProfileSelection::kNone)
               // Prevent an instance of LorgnetteScannerManager from being
               // created on the lock screen.
diff --git a/chrome/browser/ash/smb_client/smb_service_factory.cc b/chrome/browser/ash/smb_client/smb_service_factory.cc
index 240135a6..644707c 100644
--- a/chrome/browser/ash/smb_client/smb_service_factory.cc
+++ b/chrome/browser/ash/smb_client/smb_service_factory.cc
@@ -48,7 +48,12 @@
 SmbServiceFactory::SmbServiceFactory()
     : ProfileKeyedServiceFactory(
           /*name=*/"SmbService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(file_system_provider::ServiceFactory::GetInstance());
   DependsOn(AuthPolicyCredentialsManagerFactory::GetInstance());
   DependsOn(KerberosCredentialsManagerFactory::GetInstance());
diff --git a/chrome/browser/assist_ranker/assist_ranker_service_factory.cc b/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
index 3874e90..9b2ced5 100644
--- a/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
+++ b/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
@@ -28,7 +28,12 @@
 AssistRankerServiceFactory::AssistRankerServiceFactory()
     : ProfileKeyedServiceFactory(
           "AssistRankerService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 AssistRankerServiceFactory::~AssistRankerServiceFactory() {}
 
diff --git a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
index 6d3208b..2db0b17f 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
+++ b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
@@ -48,7 +48,12 @@
 AutocompleteClassifierFactory::AutocompleteClassifierFactory()
     : ProfileKeyedServiceFactory(
           "AutocompleteClassifier",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   DependsOn(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
diff --git a/chrome/browser/autocomplete/in_memory_url_index_factory.cc b/chrome/browser/autocomplete/in_memory_url_index_factory.cc
index 59cec137..42da735 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_factory.cc
+++ b/chrome/browser/autocomplete/in_memory_url_index_factory.cc
@@ -27,7 +27,12 @@
 InMemoryURLIndexFactory::InMemoryURLIndexFactory()
     : ProfileKeyedServiceFactory(
           "InMemoryURLIndex",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(HistoryServiceFactory::GetInstance());
   DependsOn(TemplateURLServiceFactory::GetInstance());
diff --git a/chrome/browser/autofill/autofill_image_fetcher_factory.cc b/chrome/browser/autofill/autofill_image_fetcher_factory.cc
index 4e18a4f..2614e1b 100644
--- a/chrome/browser/autofill/autofill_image_fetcher_factory.cc
+++ b/chrome/browser/autofill/autofill_image_fetcher_factory.cc
@@ -27,7 +27,12 @@
 AutofillImageFetcherFactory::AutofillImageFetcherFactory()
     : ProfileKeyedServiceFactory(
           "AutofillImageFetcher",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 AutofillImageFetcherFactory::~AutofillImageFetcherFactory() = default;
 
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.h b/chrome/browser/autofill/mock_autofill_popup_controller.h
index b6063e0f..74c6bb85 100644
--- a/chrome/browser/autofill/mock_autofill_popup_controller.h
+++ b/chrome/browser/autofill/mock_autofill_popup_controller.h
@@ -85,7 +85,7 @@
   MOCK_METHOD(void, SelectSuggestion, (absl::optional<size_t>), (override));
   MOCK_METHOD(PopupType, GetPopupType, (), (const override));
 
-  void set_suggestions(const std::vector<int>& ids) {
+  void set_suggestions(const std::vector<Suggestion::FrontendId>& ids) {
     for (const auto& id : ids) {
       // Accessibility requires all focusable AutofillPopupItemView to have
       // ui::AXNodeData with non-empty names. We specify dummy values and labels
diff --git a/chrome/browser/certificate_provider/certificate_provider_service_factory.cc b/chrome/browser/certificate_provider/certificate_provider_service_factory.cc
index 73b33bc..807ed784 100644
--- a/chrome/browser/certificate_provider/certificate_provider_service_factory.cc
+++ b/chrome/browser/certificate_provider/certificate_provider_service_factory.cc
@@ -316,7 +316,12 @@
 CertificateProviderServiceFactory::CertificateProviderServiceFactory()
     : ProfileKeyedServiceFactory(
           "CertificateProviderService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::EventRouterFactory::GetInstance());
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index b4dff1a..9785ce8 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -260,6 +260,7 @@
     "//chrome/common:constants",
     "//chrome/common:non_code_constants",
     "//chromeos/components/kcer",
+    "//chromeos/components/kcer:key_permissions_proto",
     "//chromeos/dbus/dlp",
     "//chromeos/ui/base",
     "//components/app_constants",
@@ -498,6 +499,7 @@
     "//chrome/common/extensions/api",
     "//chrome/test:test_support",
     "//chromeos/components/kcer",
+    "//chromeos/components/kcer:key_permissions_proto",
     "//chromeos/crosapi/mojom",
     "//chromeos/dbus/dlp",
     "//components/account_id",
diff --git a/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_api.cc b/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_api.cc
index 820a8ec..48e93af 100644
--- a/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_api.cc
+++ b/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_api.cc
@@ -560,6 +560,12 @@
           this, context_remote.InitWithNewPipeAndPassReceiver(), scard_context);
       context_result =
           SmartCardCreateContextResult::NewContext(std::move(context_remote));
+
+      // It's neither expected nor supported for the provider to recycle a
+      // scard_context value so soon.
+      CHECK(!context_data_map_.contains(scard_context));
+
+      context_data_map_[scard_context] = ContextData();
     } else {
       LOG(ERROR) << "Provider reported an invalid scard_context value: "
                  << scard_context.GetUnsafeValue();
@@ -575,12 +581,6 @@
   CHECK(std::holds_alternative<CreateContextCallback>(pending->callback));
   std::move(std::get<CreateContextCallback>(pending->callback))
       .Run(std::move(context_result));
-
-  // It's neither expected nor supported for the provider to recycle a
-  // scard_context value so soon.
-  CHECK(!context_data_map_.contains(scard_context));
-
-  context_data_map_[scard_context] = ContextData();
 }
 
 void SmartCardProviderPrivateAPI::ReportReleaseContextResult(
diff --git a/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_apitest.cc b/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_apitest.cc
index 78f1ed3..090cd26 100644
--- a/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/smart_card_provider_private/smart_card_provider_private_apitest.cc
@@ -264,6 +264,19 @@
   EXPECT_THAT(CreateContext(), IsError(SmartCardError::kNoService));
 }
 
+IN_PROC_BROWSER_TEST_F(SmartCardProviderPrivateApiTest,
+                       EstablishContextResponseTimeoutTwice) {
+  ProviderAPI().SetResponseTimeLimitForTesting(base::Seconds(1));
+
+  LoadFakeProviderExtension(R"(
+      chrome.smartCardProviderPrivate.onEstablishContextRequested.addListener(
+          function(requestId){});
+    )");
+
+  EXPECT_THAT(CreateContext(), IsError(SmartCardError::kNoService));
+  EXPECT_THAT(CreateContext(), IsError(SmartCardError::kNoService));
+}
+
 IN_PROC_BROWSER_TEST_F(SmartCardProviderPrivateApiTest, CreateContext) {
   LoadFakeProviderExtension(kEstablishContextJs);
   auto context_result = CreateContext();
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
index 8187a5f2..2a20743 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
@@ -22,6 +22,7 @@
 #include "net/cert/pem.h"
 #include "net/test/cert_builder.h"
 #include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // The tests here provide only the minimal coverage for the basic functionality
@@ -29,6 +30,8 @@
 // fuzzer.
 // TODO(244408716): Implement the fuzzer.
 
+using testing::UnorderedElementsAre;
+
 namespace kcer {
 
 // Test-only overloads for better errors from EXPECT_EQ, etc.
@@ -43,14 +46,12 @@
 
 namespace {
 
-enum class KeyType { kRsa, kEc };
-
 std::string KeyTypeToStr(KeyType key_type) {
   switch (key_type) {
     case KeyType::kRsa:
       return "kRsa";
-    case KeyType::kEc:
-      return "kEc";
+    case KeyType::kEcc:
+      return "kEcc";
   }
 }
 
@@ -288,6 +289,9 @@
   base::test::TestFuture<base::expected<bool, Error>> does_key_exist_waiter;
   kcer->DoesPrivateKeyExist(PrivateKeyHandle(PublicKeySpki()),
                             does_key_exist_waiter.GetCallback());
+  base::test::TestFuture<base::expected<KeyInfo, Error>> get_key_info_waiter;
+  kcer->GetKeyInfo(PrivateKeyHandle(PublicKeySpki()),
+                   get_key_info_waiter.GetCallback());
   base::test::TestFuture<base::expected<void, Error>> set_nickname_waiter;
   kcer->SetKeyNickname(PrivateKeyHandle(PublicKeySpki()), "new_nickname",
                        set_nickname_waiter.GetCallback());
@@ -325,6 +329,9 @@
   ASSERT_FALSE(does_key_exist_waiter.Get().has_value());
   EXPECT_EQ(does_key_exist_waiter.Get().error(),
             Error::kTokenInitializationFailed);
+  ASSERT_FALSE(get_key_info_waiter.Get().has_value());
+  EXPECT_EQ(get_key_info_waiter.Get().error(),
+            Error::kTokenInitializationFailed);
   ASSERT_FALSE(set_nickname_waiter.Get().has_value());
   EXPECT_EQ(set_nickname_waiter.Get().error(),
             Error::kTokenInitializationFailed);
@@ -333,6 +340,119 @@
             Error::kTokenInitializationFailed);
 }
 
+// Test RSA specific fields from GetKeyInfo's result.
+TEST_F(KcerNssTest, GetKeyInfoForRsaKey) {
+  TokenHolder user_token(Token::kUser);
+  user_token.Initialize();
+
+  std::unique_ptr<Kcer> kcer = internal::CreateKcer(
+      IOTaskRunner(), user_token.GetWeakPtr(), /*device_token=*/nullptr);
+
+  // Generate new key.
+  base::test::TestFuture<base::expected<PublicKey, Error>> generate_waiter;
+  kcer->GenerateRsaKey(Token::kUser, /*modulus_length_bits=*/2048,
+                       /*hardware_backed=*/true, generate_waiter.GetCallback());
+  ASSERT_TRUE(generate_waiter.Get().has_value());
+  const PublicKey& public_key = generate_waiter.Get().value();
+
+  base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+  kcer->GetKeyInfo(PrivateKeyHandle(public_key), key_info_waiter.GetCallback());
+  ASSERT_TRUE(key_info_waiter.Get().has_value());
+  const KeyInfo& key_info = key_info_waiter.Get().value();
+  EXPECT_EQ(key_info.key_type, KeyType::kRsa);
+  EXPECT_THAT(
+      key_info.supported_signing_schemes,
+      UnorderedElementsAre(
+          SigningScheme::kRsaPkcs1Sha1, SigningScheme::kRsaPkcs1Sha256,
+          SigningScheme::kRsaPkcs1Sha384, SigningScheme::kRsaPkcs1Sha512,
+          SigningScheme::kRsaPssRsaeSha256, SigningScheme::kRsaPssRsaeSha384,
+          SigningScheme::kRsaPssRsaeSha512));
+}
+
+// Test ECC specific fields from GetKeyInfo's result.
+TEST_F(KcerNssTest, GetKeyInfoForEccKey) {
+  TokenHolder user_token(Token::kUser);
+  user_token.Initialize();
+
+  std::unique_ptr<Kcer> kcer = internal::CreateKcer(
+      IOTaskRunner(), user_token.GetWeakPtr(), /*device_token=*/nullptr);
+
+  // Generate new key.
+  base::test::TestFuture<base::expected<PublicKey, Error>> generate_waiter;
+  kcer->GenerateEcKey(Token::kUser, EllipticCurve::kP256,
+                      /*hardware_backed=*/true, generate_waiter.GetCallback());
+  ASSERT_TRUE(generate_waiter.Get().has_value());
+  const PublicKey& public_key = generate_waiter.Get().value();
+
+  base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+  kcer->GetKeyInfo(PrivateKeyHandle(public_key), key_info_waiter.GetCallback());
+  ASSERT_TRUE(key_info_waiter.Get().has_value());
+  const KeyInfo& key_info = key_info_waiter.Get().value();
+  EXPECT_EQ(key_info.key_type, KeyType::kEcc);
+  EXPECT_THAT(key_info.supported_signing_schemes,
+              UnorderedElementsAre(SigningScheme::kEcdsaSecp256r1Sha256,
+                                   SigningScheme::kEcdsaSecp384r1Sha384,
+                                   SigningScheme::kEcdsaSecp521r1Sha512));
+}
+
+// Test generic fields from GetKeyInfo's result and they get updated after
+// related Set* methods.
+TEST_F(KcerNssTest, GetKeyInfoGeneric) {
+  TokenHolder user_token(Token::kUser);
+  user_token.Initialize();
+
+  std::unique_ptr<Kcer> kcer = internal::CreateKcer(
+      IOTaskRunner(), user_token.GetWeakPtr(), /*device_token=*/nullptr);
+
+  // Generate new key.
+  base::test::TestFuture<base::expected<PublicKey, Error>> generate_waiter;
+  kcer->GenerateEcKey(Token::kUser, EllipticCurve::kP256,
+                      /*hardware_backed=*/true, generate_waiter.GetCallback());
+  ASSERT_TRUE(generate_waiter.Get().has_value());
+  const PublicKey& public_key = generate_waiter.Get().value();
+
+  {
+    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
+                     key_info_waiter.GetCallback());
+    ASSERT_TRUE(key_info_waiter.Get().has_value());
+    const KeyInfo& key_info = key_info_waiter.Get().value();
+    // Hardware- vs software-backed indicators on real devices are provided by
+    // Chaps and are wrong in unit tests.
+    EXPECT_EQ(key_info.is_hardware_backed, true);
+    // NSS sets an empty nickname by default, doesn't have to be like this in
+    // general.
+    ASSERT_TRUE(key_info.nickname.has_value());
+    EXPECT_EQ(key_info.nickname.value(), "");
+    EXPECT_FALSE(key_info.key_permissions.has_value());
+    EXPECT_FALSE(key_info.cert_provisioning_profile_id.has_value());
+  }
+
+  constexpr char kNickname[] = "new_nickname";
+  base::test::TestFuture<base::expected<void, Error>> set_nickname_waiter;
+  kcer->SetKeyNickname(PrivateKeyHandle(public_key), kNickname,
+                       set_nickname_waiter.GetCallback());
+  ASSERT_TRUE(set_nickname_waiter.Get().has_value());
+
+  {
+    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
+                     key_info_waiter.GetCallback());
+    ASSERT_TRUE(key_info_waiter.Get().has_value());
+    const KeyInfo& key_info = key_info_waiter.Get().value();
+    // Hardware- vs software-backed indicators on real devices are provided by
+    // Chaps and are wrong in unit tests.
+    EXPECT_EQ(key_info.is_hardware_backed, true);
+    ASSERT_TRUE(key_info.nickname.has_value());
+    EXPECT_EQ(key_info.nickname.value(), kNickname);
+    EXPECT_FALSE(key_info.key_permissions.has_value());
+    EXPECT_FALSE(key_info.cert_provisioning_profile_id.has_value());
+  }
+
+  // TODO(244408716): Test setting and reading other key attributes when that's
+  // implemented.
+}
+
 // Test different ways to call DoesPrivateKeyExist() method and that it returns
 // correct results when Kcer has access to one token.
 TEST_F(KcerNssTest, DoesPrivateKeyExistOneToken) {
@@ -434,7 +554,7 @@
                            /*hardware_backed=*/true,
                            generate_waiter.GetCallback());
       break;
-    case KeyType::kEc:
+    case KeyType::kEcc:
       kcer->GenerateEcKey(Token::kDevice, EllipticCurve::kP256,
                           /*hardware_backed=*/true,
                           generate_waiter.GetCallback());
@@ -523,7 +643,7 @@
                            /*hardware_backed=*/true,
                            generate_waiter.GetCallback());
       break;
-    case KeyType::kEc:
+    case KeyType::kEcc:
       kcer->GenerateEcKey(Token::kUser, EllipticCurve::kP256,
                           /*hardware_backed=*/true,
                           generate_waiter.GetCallback());
@@ -582,7 +702,7 @@
 
 INSTANTIATE_TEST_SUITE_P(AllKeyTypes,
                          KcerNssAllKeyTypesTest,
-                         testing::Values(KeyType::kRsa, KeyType::kEc),
+                         testing::Values(KeyType::kRsa, KeyType::kEcc),
                          // Make test names more readable:
                          [](const auto& info) {
                            return KeyTypeToStr(info.param);
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
index cbb688cc..80e52b6 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
@@ -6,7 +6,9 @@
 
 #include <certdb.h>
 #include <pkcs11.h>
+#include <secerr.h>
 #include <stdint.h>
+
 #include <queue>
 #include <string>
 #include <vector>
@@ -19,6 +21,7 @@
 #include "chrome/browser/chromeos/kcer_nss/cert_cache_nss.h"
 #include "chrome/browser/chromeos/platform_keys/chaps_util.h"
 #include "chromeos/components/kcer/kcer_token.h"
+#include "chromeos/components/kcer/key_permissions.pb.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/nss_key_util.h"
@@ -29,6 +32,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util_nss.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/cros_system_api/constants/pkcs11_custom_attributes.h"
 
 // General pattern for implementing KcerToken methods:
 // * The received callbacks for the results must already be bound to correct
@@ -295,6 +299,171 @@
   std::move(callback).Run({});
 }
 
+std::vector<SigningScheme> GetSigningSchemes(bool supports_pss,
+                                             KeyType key_type) {
+  std::vector<SigningScheme> result;
+
+  switch (key_type) {
+      // Supported signing schemes for RSA also depend on the key length, but
+      // NSS doesn't seem to provide a convenient interface to read it. In
+      // practice 2048 bits is enough for all RSA signatures, smaller keys are
+      // not really used in practice nowadays and the SSL code is expected to
+      // also double check and shrink the list.
+    case KeyType::kRsa:
+      result.insert(result.end(), {
+                                      SigningScheme::kRsaPkcs1Sha1,
+                                      SigningScheme::kRsaPkcs1Sha256,
+                                      SigningScheme::kRsaPkcs1Sha384,
+                                      SigningScheme::kRsaPkcs1Sha512,
+                                  });
+      if (supports_pss) {
+        result.insert(result.end(), {
+                                        SigningScheme::kRsaPssRsaeSha256,
+                                        SigningScheme::kRsaPssRsaeSha384,
+                                        SigningScheme::kRsaPssRsaeSha512,
+                                    });
+      }
+      break;
+    case KeyType::kEcc:
+      result.insert(result.end(), {
+                                      SigningScheme::kEcdsaSecp256r1Sha256,
+                                      SigningScheme::kEcdsaSecp384r1Sha384,
+                                      SigningScheme::kEcdsaSecp521r1Sha512,
+                                  });
+  }
+
+  return result;
+}
+
+base::expected<absl::optional<chaps::KeyPermissions>, Error>
+GetKeyPermissionsOnWorkerThread(
+    const crypto::ScopedSECKEYPrivateKey& sec_private_key) {
+  crypto::ScopedSECItem key_permissions_attribute(
+      SECITEM_AllocItem(/*arena=*/nullptr,
+                        /*item=*/nullptr,
+                        /*len=*/0));
+
+  SECStatus status = PK11_ReadRawAttribute(
+      /*objType=*/PK11_TypePrivKey, sec_private_key.get(),
+      pkcs11_custom_attributes::kCkaChromeOsKeyPermissions,
+      key_permissions_attribute.get());
+
+  if (status != SECSuccess) {
+    // CKR_ATTRIBUTE_TYPE_INVALID is a cryptoki function return value which is
+    // returned by Chaps if the attribute was not set before for the key. NSS
+    // maps this error to SEC_ERROR_BAD_DATA. This error is captured here so
+    // as not to return an |error| in cases of retrieving unset key attributes
+    // and to return nullopt |attribute_value| instead.
+    int error = PORT_GetError();
+    if (error == SEC_ERROR_BAD_DATA) {
+      return absl::nullopt;
+    } else {
+      return base::unexpected(Error::kFailedToReadAttribute);
+    }
+  }
+
+  chaps::KeyPermissions key_permissions;
+  if (!key_permissions.ParseFromArray(key_permissions_attribute->data,
+                                      key_permissions_attribute->len)) {
+    return base::unexpected(Error::kFailedToParseKeyPermissions);
+  }
+  return key_permissions;
+}
+
+base::expected<absl::optional<std::string>, Error>
+GetCertProvisioningIdOnWorkerThread(
+    const crypto::ScopedSECKEYPrivateKey& sec_private_key) {
+  crypto::ScopedSECItem cert_prov_attribute(SECITEM_AllocItem(/*arena=*/nullptr,
+                                                              /*item=*/nullptr,
+                                                              /*len=*/0));
+
+  SECStatus status = PK11_ReadRawAttribute(
+      /*objType=*/PK11_TypePrivKey, sec_private_key.get(),
+      pkcs11_custom_attributes::kCkaChromeOsBuiltinProvisioningProfileId,
+      cert_prov_attribute.get());
+
+  if (status != SECSuccess) {
+    // CKR_ATTRIBUTE_TYPE_INVALID is a cryptoki function return value which is
+    // returned by Chaps if the attribute was not set before for the key. NSS
+    // maps this error to SEC_ERROR_BAD_DATA. This error is captured here so
+    // as not to return an |error| in cases of retrieving unset key attributes
+    // and to return nullopt |attribute_value| instead.
+    int error = PORT_GetError();
+    if (error == SEC_ERROR_BAD_DATA) {
+      return absl::nullopt;
+    } else {
+      return base::unexpected(Error::kFailedToReadAttribute);
+    }
+  }
+
+  return std::string(cert_prov_attribute->data,
+                     cert_prov_attribute->data + cert_prov_attribute->len);
+}
+
+void GetKeyInfoOnWorkerThread(crypto::ScopedPK11Slot slot,
+                              PrivateKeyHandle key,
+                              Kcer::GetKeyInfoCallback callback) {
+  KeyInfo key_info;
+
+  base::expected<crypto::ScopedSECKEYPrivateKey, Error> private_key =
+      GetSECKEYPrivateKey(slot, key);
+  if (!private_key.has_value()) {
+    return std::move(callback).Run(base::unexpected(private_key.error()));
+  }
+  const crypto::ScopedSECKEYPrivateKey& sec_private_key = private_key.value();
+
+  constexpr CK_ATTRIBUTE_TYPE kKeyInSoftware = CKA_VENDOR_DEFINED + 5;
+  // All keys in chaps without the attribute are hardware backed.
+  key_info.is_hardware_backed = !PK11_HasAttributeSet(
+      slot.get(), sec_private_key->pkcs11ID, kKeyInSoftware,
+      /*haslock=*/PR_FALSE);
+
+  switch (SECKEY_GetPrivateKeyType(sec_private_key.get())) {
+    case rsaKey:
+      key_info.key_type = KeyType::kRsa;
+      break;
+    case ecKey:
+      key_info.key_type = KeyType::kEcc;
+      break;
+    default:
+      return std::move(callback).Run(base::unexpected(Error::kUnknownKeyType));
+  }
+
+  key_info.supported_signing_schemes = GetSigningSchemes(
+      PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_PSS), key_info.key_type);
+
+  char* nickname = PK11_GetPrivateKeyNickname(sec_private_key.get());
+  if (nickname) {
+    key_info.nickname = nickname;
+    PORT_Free(nickname);
+  }
+
+  // TODO(miersh): Temporary disable the code because on some builds unit tests
+  // fail to read custom attributes. This will be re-enabled in a following CL
+  // when custom attributes are mapped into unused normal attributes in tests.
+#if 0
+  base::expected<absl::optional<chaps::KeyPermissions>, Error> key_permissions =
+      GetKeyPermissionsOnWorkerThread(sec_private_key);
+  if (!key_permissions.has_value()) {
+    return std::move(callback).Run(base::unexpected(key_permissions.error()));
+  }
+  key_info.key_permissions = std::move(key_permissions).value();
+
+  base::expected<absl::optional<std::string>, Error> cert_prov_id =
+      GetCertProvisioningIdOnWorkerThread(sec_private_key);
+  if (!cert_prov_id.has_value()) {
+    return std::move(callback).Run(base::unexpected(cert_prov_id.error()));
+  }
+  key_info.cert_provisioning_profile_id = std::move(cert_prov_id).value();
+#endif
+  // TODO(miersh): Temporary suppress "unused method" warnings. This should be
+  // removed together with the "#if 0" above.
+  (void)GetKeyPermissionsOnWorkerThread;
+  (void)GetCertProvisioningIdOnWorkerThread;
+
+  return std::move(callback).Run(std::move(key_info));
+}
+
 void SetKeyNicknameOnWorkerThread(crypto::ScopedPK11Slot slot,
                                   PrivateKeyHandle key,
                                   std::string nickname,
@@ -581,7 +750,24 @@
 void KcerTokenImplNss::GetKeyInfo(PrivateKeyHandle key,
                                   Kcer::GetKeyInfoCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  // TODO(244408716): Implement.
+
+  if (UNLIKELY(state_ == State::kInitializationFailed)) {
+    return HandleInitializationFailed(std::move(callback));
+  } else if (is_blocked_) {
+    return task_queue_.push(base::BindOnce(
+        &KcerTokenImplNss::GetKeyInfo, weak_factory_.GetWeakPtr(),
+        std::move(key), std::move(callback)));
+  }
+
+  // Block task queue, attach unblocking task to the callback.
+  auto unblocking_callback = std::move(callback).Then(BlockQueueGetUnblocker());
+
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&GetKeyInfoOnWorkerThread,
+                     crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
+                     std::move(key), std::move(unblocking_callback)));
 }
 
 void KcerTokenImplNss::SetKeyNickname(PrivateKeyHandle key,
diff --git a/chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.cc b/chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.cc
index 100b9c4a..991a8874 100644
--- a/chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.cc
+++ b/chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.cc
@@ -87,7 +87,12 @@
 ExtensionPlatformKeysServiceFactory::ExtensionPlatformKeysServiceFactory()
     : ProfileKeyedServiceFactory(
           "ExtensionPlatformKeysService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   DependsOn(crosapi::KeystoreServiceFactoryAsh::GetInstance());
 #endif
diff --git a/chrome/browser/commerce/shopping_service_factory.cc b/chrome/browser/commerce/shopping_service_factory.cc
index 104021c..a3f77e3 100644
--- a/chrome/browser/commerce/shopping_service_factory.cc
+++ b/chrome/browser/commerce/shopping_service_factory.cc
@@ -50,7 +50,12 @@
 ShoppingServiceFactory::ShoppingServiceFactory()
     : ProfileKeyedServiceFactory(
           "ShoppingService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance());
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index e4895aec..eece42d 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -330,9 +330,9 @@
 
   // Set a cookie with JavaScript.
   void JSWriteCookie(Browser* browser) {
-    bool rv = content::ExecuteScript(
-        browser->tab_strip_model()->GetActiveWebContents(),
-        "document.cookie = 'name=Good;Max-Age=3600'");
+    bool rv =
+        content::ExecJs(browser->tab_strip_model()->GetActiveWebContents(),
+                        "document.cookie = 'name=Good;Max-Age=3600'");
     CHECK(rv);
   }
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc b/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
index 5431306..4dff9152 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
@@ -31,7 +31,12 @@
     : ProfileKeyedServiceFactory(
           "ProtocolHandlerRegistry",
           // Allows the produced registry to be used in incognito mode.
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 ProtocolHandlerRegistryFactory::~ProtocolHandlerRegistryFactory() {
 }
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index 451ce4e..57d5584 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -430,10 +430,10 @@
 
  protected:
   void InjectBeforeUnloadListener(content::WebContents* web_contents) {
-    ASSERT_TRUE(content::ExecuteScript(
-        web_contents,
-        "window.addEventListener('beforeunload',"
-        "function(event) { event.returnValue = 'Foo'; });"));
+    ASSERT_TRUE(
+        content::ExecJs(web_contents,
+                        "window.addEventListener('beforeunload',"
+                        "function(event) { event.returnValue = 'Foo'; });"));
     content::PrepContentsForBeforeUnloadTest(web_contents);
   }
 
@@ -472,7 +472,7 @@
     content::WindowedNotificationObserver observer(
         content::NOTIFICATION_LOAD_STOP,
         content::NotificationService::AllSources());
-    ASSERT_TRUE(content::ExecuteScript(
+    ASSERT_TRUE(content::ExecJs(
         DevToolsWindowTesting::Get(devtools_window)->main_web_contents(),
         "window.open(\"\", \"\", \"location=0\");"));
     observer.Wait();
@@ -952,7 +952,7 @@
   DevToolsWindowTesting::Get(devtools_window)
       ->SetCloseCallback(runner->QuitClosure());
 
-  ASSERT_TRUE(content::ExecuteScript(
+  ASSERT_TRUE(content::ExecJs(
       DevToolsWindowTesting::Get(devtools_window)->main_web_contents(),
       "window.addEventListener('beforeunload',"
       "function(event) { while (true); });"));
@@ -1139,7 +1139,7 @@
   content::TestNavigationManager web_about_blank_manager(main_web_contents(),
                                                          about_blank_url);
 
-  ASSERT_TRUE(content::ExecuteScript(web_frame_rfh, about_blank_javascript));
+  ASSERT_TRUE(content::ExecJs(web_frame_rfh, about_blank_javascript));
 
   ASSERT_TRUE(web_about_blank_manager.WaitForNavigationFinished());
   // After navigation, the frame may change.
@@ -1161,7 +1161,7 @@
   content::TestNavigationManager renavigation_manager(main_web_contents(),
                                                       extension_simple_url);
 
-  ASSERT_TRUE(content::ExecuteScript(web_frame_rfh, renavigation_javascript));
+  ASSERT_TRUE(content::ExecJs(web_frame_rfh, renavigation_javascript));
 
   ASSERT_TRUE(renavigation_manager.WaitForNavigationFinished());
 
@@ -1562,7 +1562,7 @@
       main_web_contents()->GetPrimaryMainFrame();
 
   content::TestNavigationManager manager(main_web_contents(), devtools_url);
-  ASSERT_TRUE(content::ExecuteScript(main_devtools_rfh, javascript));
+  ASSERT_TRUE(content::ExecJs(main_devtools_rfh, javascript));
   ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   std::vector<RenderFrameHost*> rfhs =
@@ -2036,8 +2036,8 @@
                 ->popup_controller_for_testing()) {
       controller->DisableThresholdForTesting(true);
     }
-    ASSERT_TRUE(content::ExecuteScript(inspected_contents_,
-                                       "console.log('didShowSuggestions');"));
+    ASSERT_TRUE(content::ExecJs(inspected_contents_,
+                                "console.log('didShowSuggestions');"));
   }
 
   void OnTextFieldChanged() override {}
@@ -2118,9 +2118,9 @@
   GURL url = embedded_test_server()->GetURL(kNavigateBackTestPage);
   ui_test_utils::UrlLoadObserver observer(
       url, content::NotificationService::AllSources());
-  ASSERT_TRUE(content::ExecuteScript(
-      main_web_contents(),
-      std::string("window.location = \"") + url.spec() + "\""));
+  ASSERT_TRUE(
+      content::ExecJs(main_web_contents(),
+                      std::string("window.location = \"") + url.spec() + "\""));
   observer.Wait();
 
   ASSERT_TRUE(main_web_contents()->GetLastCommittedURL().SchemeIs(
@@ -2255,8 +2255,8 @@
   OpenDevToolsWindow(kWindowOpenTestPage, false);
   DevToolsWindowTesting::Get(window_)->SetOpenNewWindowForPopups(true);
   DevToolsWindowCreationObserver observer;
-  ASSERT_TRUE(content::ExecuteScript(
-      GetInspectedTab(), "window.open('window_open.html', '_blank');"));
+  ASSERT_TRUE(content::ExecJs(GetInspectedTab(),
+                              "window.open('window_open.html', '_blank');"));
   observer.WaitForLoad();
   DispatchOnTestSuite(observer.devtools_window(), "waitForDebuggerPaused");
   DevToolsWindowTesting::CloseDevToolsWindowSync(observer.devtools_window());
@@ -2935,10 +2935,10 @@
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(content::ExecuteScript(
-      tab,
-      "window.addEventListener('beforeunload',"
-      "function(event) { event.returnValue = 'Foo'; });"));
+  ASSERT_TRUE(
+      content::ExecJs(tab,
+                      "window.addEventListener('beforeunload',"
+                      "function(event) { event.returnValue = 'Foo'; });"));
   content::PrepContentsForBeforeUnloadTest(tab);
   BrowserHandler handler(nullptr, std::string());
   handler.Close();
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
index 9ec3a425..d0557ff 100644
--- a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -52,7 +52,12 @@
           "DomDistillerService",
           // Makes normal profile and off-the-record profile use same service
           // instance.
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 DomDistillerServiceFactory::~DomDistillerServiceFactory() {}
 
diff --git a/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.cc b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.cc
new file mode 100644
index 0000000..b093fbe
--- /dev/null
+++ b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.cc
@@ -0,0 +1,78 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h"
+
+#include "base/functional/bind.h"
+#include "chrome/browser/enterprise/reporting/prefs.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/prefs/pref_service.h"
+#include "components/url_matcher/url_util.h"
+#include "url/gurl.h"
+
+namespace enterprise_reporting {
+
+LegacyTechURLMatcher::LegacyTechURLMatcher(Profile* profile)
+    : profile_(profile) {
+  pref_change_.Init(profile->GetPrefs());
+  pref_change_.Add(kCloudLegacyTechReportAllowlist,
+                   base::BindRepeating(&LegacyTechURLMatcher::OnPrefUpdated,
+                                       base::Unretained(this)));
+
+  OnPrefUpdated();
+}
+
+LegacyTechURLMatcher::~LegacyTechURLMatcher() = default;
+
+void LegacyTechURLMatcher::OnPrefUpdated() {
+  base::MatcherStringPattern::ID id = 0;
+  url_matcher::URLMatcherConditionSet::Vector conditions;
+  url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
+  for (const auto& url :
+       profile_->GetPrefs()->GetList(kCloudLegacyTechReportAllowlist)) {
+    url_matcher::util::FilterComponents components;
+    url_matcher::util::FilterToComponents(
+        url.GetString(), &components.scheme, &components.host,
+        &components.match_subdomains, &components.port, &components.path,
+        &components.query);
+
+    // Scheme, port and query in the pattern will be ignored while subdomains
+    // must be fully specified.
+    components.scheme = "";
+    components.match_subdomains = false;
+    components.port = 0;
+    components.query = "";
+
+    auto condition = url_matcher::util::CreateConditionSet(
+        url_matcher_.get(), id++, components.scheme, components.host,
+        components.match_subdomains, components.port, components.path,
+        components.query, components.allow);
+    conditions.push_back(condition);
+    path_length_.push_back(components.path.size());
+  }
+  url_matcher_->AddConditionSets(conditions);
+}
+
+absl::optional<std::string> LegacyTechURLMatcher::GetMatchedURL(
+    const GURL& url) const {
+  std::set<base::MatcherStringPattern::ID> matched_ids =
+      url_matcher_->MatchURL(url);
+
+  if (matched_ids.empty()) {
+    return absl::nullopt;
+  }
+  size_t maximum_path_length = 0;
+  base::MatcherStringPattern::ID maximum_path_id;
+  for (const auto id : matched_ids) {
+    if (path_length_[id] >= maximum_path_length) {
+      maximum_path_id = id;
+      maximum_path_length = path_length_[id];
+    }
+  }
+  return profile_->GetPrefs()
+      ->GetList(kCloudLegacyTechReportAllowlist)[maximum_path_id]
+      .GetString();
+}
+
+}  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h
new file mode 100644
index 0000000..7675cfbf
--- /dev/null
+++ b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ENTERPRISE_REPORTING_LEGACY_TECH_LEGACY_TECH_URL_MATCHER_H_
+#define CHROME_BROWSER_ENTERPRISE_REPORTING_LEGACY_TECH_LEGACY_TECH_URL_MATCHER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/url_matcher/url_matcher.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+class GURL;
+class Profile;
+
+namespace enterprise_reporting {
+
+class LegacyTechURLMatcher {
+ public:
+  explicit LegacyTechURLMatcher(Profile* profile);
+  LegacyTechURLMatcher(const LegacyTechURLMatcher&) = delete;
+  LegacyTechURLMatcher& operator=(const LegacyTechURLMatcher&) = delete;
+  ~LegacyTechURLMatcher();
+
+  void OnPrefUpdated();
+
+  absl::optional<std::string> GetMatchedURL(const GURL& url) const;
+
+ private:
+  raw_ptr<Profile> profile_;
+  PrefChangeRegistrar pref_change_;
+
+  std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
+  std::vector<size_t> path_length_;
+};
+
+}  // namespace enterprise_reporting
+
+#endif  // CHROME_BROWSER_ENTERPRISE_REPORTING_LEGACY_TECH_LEGACY_TECH_URL_MATCHER_H_
diff --git a/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher_unittest.cc b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher_unittest.cc
new file mode 100644
index 0000000..2bf8ee0
--- /dev/null
+++ b/chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher.h"
+
+#include "build/build_config.h"
+#include "chrome/browser/enterprise/reporting/prefs.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace enterprise_reporting {
+
+class LegacyURLMatcherTest : public ::testing::Test {
+ public:
+  LegacyURLMatcherTest() = default;
+  ~LegacyURLMatcherTest() override = default;
+
+  void SetPolicy(const std::vector<std::string>& urls) {
+    base::Value::List policy;
+    for (const auto& url : urls) {
+      policy.Append(base::Value(url));
+    }
+    profile_.GetTestingPrefService()->SetManagedPref(
+        kCloudLegacyTechReportAllowlist,
+        std::make_unique<base::Value>(std::move(policy)));
+  }
+
+  TestingProfile* profile() { return &profile_; }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+};
+
+TEST_F(LegacyURLMatcherTest, Match) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"www.example.com"});
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("https://www.example.com")));
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/")));
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("http://www.example.com/path")));
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/path")));
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("https://www.example.com:8088/path")));
+  EXPECT_EQ(
+      "www.example.com",
+      *matcher.GetMatchedURL(GURL("https://www.example.com/path?query=text")));
+}
+
+TEST_F(LegacyURLMatcherTest, NotMatch) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"www.example.com"});
+  EXPECT_FALSE(matcher.GetMatchedURL(GURL("https://www.example2.com")));
+  EXPECT_FALSE(matcher.GetMatchedURL(GURL("https://example.com")));
+  EXPECT_FALSE(matcher.GetMatchedURL(GURL("https://chat.example2.com")));
+}
+
+TEST_F(LegacyURLMatcherTest, PathPrecedence) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"www.example.com", "www.example.com/p1", "www.example.com/p1/p2"});
+  EXPECT_EQ("www.example.com",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/p2")));
+  EXPECT_EQ("www.example.com/p1",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/p1")));
+  EXPECT_EQ("www.example.com/p1",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/p1/p3")));
+  EXPECT_EQ("www.example.com/p1/p2",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/p1/p2/p3")));
+}
+
+TEST_F(LegacyURLMatcherTest, IgnoredPart) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"http://www.example.com:8088/path?query=text#abc",
+             "https://www.example2.com/"});
+  EXPECT_EQ("http://www.example.com:8088/path?query=text#abc",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/path")));
+  EXPECT_FALSE(matcher.GetMatchedURL(GURL("https://www.example.com/p2")));
+
+  EXPECT_EQ("https://www.example2.com/",
+            *matcher.GetMatchedURL(GURL("http://www.example2.com")));
+}
+
+TEST_F(LegacyURLMatcherTest, Update) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"www.example.com/p1"});
+  EXPECT_FALSE(matcher.GetMatchedURL(GURL("https://www.example2.com/p2")));
+  SetPolicy({"www.example.com/p2", "www.example.com/p1"});
+  EXPECT_EQ("www.example.com/p2",
+            *matcher.GetMatchedURL(GURL("https://www.example.com/p2")));
+}
+
+TEST_F(LegacyURLMatcherTest, Localhost) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"localhost", "localhost/path"});
+  EXPECT_EQ("localhost/path",
+            *matcher.GetMatchedURL(GURL("https://localhost/path2")));
+}
+
+TEST_F(LegacyURLMatcherTest, File) {
+  LegacyTechURLMatcher matcher{profile()};
+
+#if BUILDFLAG(IS_WIN)
+  std::string path = "file://c:\\\\path";
+#else
+  std::string path = "file:///home/path";
+#endif
+
+  SetPolicy({path});
+  EXPECT_EQ(path, *matcher.GetMatchedURL(GURL(path)));
+}
+
+TEST_F(LegacyURLMatcherTest, Chrome) {
+  LegacyTechURLMatcher matcher{profile()};
+  SetPolicy({"chrome://policy"});
+  EXPECT_EQ("chrome://policy",
+            *matcher.GetMatchedURL(GURL("chrome://policy/log")));
+}
+
+}  // namespace enterprise_reporting
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
index 4d19e03..df134fc 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
@@ -29,7 +29,12 @@
 AutofillPrivateEventRouterFactory::AutofillPrivateEventRouterFactory()
     : ProfileKeyedServiceFactory(
           "AutofillPrivateEventRouter",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
   DependsOn(autofill::PersonalDataManagerFactory::GetInstance());
 }
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
index 231c2c5..b0051da1 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -350,7 +350,7 @@
   }
 
   void ExecuteJavascript(const std::string& function) const {
-    ASSERT_TRUE(content::ExecuteScript(GetExtensionMainFrame(), function));
+    ASSERT_TRUE(content::ExecJs(GetExtensionMainFrame(), function));
   }
 
   // Calls |function| in the extension. |function| needs to return a bool or a
@@ -471,7 +471,7 @@
     // Proceed through the interstitial to set an SSL bypass for this host.
     content::TestNavigationObserver nav_observer(tab,
                                                  /*number_of_navigations=*/1);
-    ASSERT_TRUE(content::ExecuteScript(
+    ASSERT_TRUE(content::ExecJs(
         tab, "window.certificateErrorPageController.proceed();"));
     nav_observer.Wait();
 
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
index 40bf47b6..35220e4 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
@@ -9,7 +9,9 @@
 
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/common/chrome_features.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -116,17 +118,11 @@
   std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
   EXPECT_CALL(delegate_,
               OnGaiaRemoteConsentFlowApproved(kConsentResult, kGaiaId));
-  flow->OnConsentResultSet(kConsentResult, kWindowKey);
+  flow->ReactToConsentResult(kConsentResult);
   histogram_tester()->ExpectUniqueSample(kResultHistogramName,
                                          GaiaRemoteConsentFlow::NONE, 1);
 }
 
-TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult_WrongWindowIgnored) {
-  std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
-  // No call is expected.
-  flow->OnConsentResultSet(kConsentResult, "another_window_key");
-}
-
 TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult_TwoWindows) {
   std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
   const char kWindowKey2[] = "window_key2";
@@ -136,11 +132,11 @@
 
   const char kConsentResult2[] = "CAESCkVOQ1JZUFRFRDI";
   EXPECT_CALL(delegate2, OnGaiaRemoteConsentFlowApproved(kConsentResult2, ""));
-  flow2->OnConsentResultSet(kConsentResult2, kWindowKey2);
+  flow2->ReactToConsentResult(kConsentResult2);
 
   EXPECT_CALL(delegate_,
               OnGaiaRemoteConsentFlowApproved(kConsentResult, kGaiaId));
-  flow->OnConsentResultSet(kConsentResult, kWindowKey);
+  flow->ReactToConsentResult(kConsentResult);
   histogram_tester()->ExpectUniqueSample(kResultHistogramName,
                                          GaiaRemoteConsentFlow::NONE, 2);
 }
@@ -151,7 +147,7 @@
   EXPECT_CALL(delegate_,
               OnGaiaRemoteConsentFlowFailed(
                   GaiaRemoteConsentFlow::Failure::INVALID_CONSENT_RESULT));
-  flow->OnConsentResultSet(kInvalidConsentResult, kWindowKey);
+  flow->ReactToConsentResult(kInvalidConsentResult);
   histogram_tester()->ExpectUniqueSample(
       kResultHistogramName, GaiaRemoteConsentFlow::INVALID_CONSENT_RESULT, 1);
 }
@@ -161,24 +157,11 @@
   std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
   EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
                              GaiaRemoteConsentFlow::Failure::NO_GRANT));
-  flow->OnConsentResultSet(kNoGrantConsentResult, kWindowKey);
+  flow->ReactToConsentResult(kNoGrantConsentResult);
   histogram_tester()->ExpectUniqueSample(kResultHistogramName,
                                          GaiaRemoteConsentFlow::NO_GRANT, 1);
 }
 
-TEST_F(IdentityGaiaRemoteConsentFlowTest, SetAccountsFailure) {
-  std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
-  EXPECT_CALL(
-      delegate_,
-      OnGaiaRemoteConsentFlowFailed(
-          GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED));
-  flow->OnSetAccountsComplete(
-      signin::SetAccountsInCookieResult::kPersistentError);
-  histogram_tester()->ExpectUniqueSample(
-      kResultHistogramName,
-      GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED, 1);
-}
-
 TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_WindowClosed) {
   std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
   EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
@@ -197,4 +180,39 @@
                                          GaiaRemoteConsentFlow::LOAD_FAILED, 1);
 }
 
+// The following tests are only meaningful if the feature
+// `kWebAuthFlowInBrowserTab` is disabled
+class IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest
+    : public IdentityGaiaRemoteConsentFlowTest {
+ public:
+  IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest() {
+    scoped_feature_list_.InitAndDisableFeature(
+        features::kWebAuthFlowInBrowserTab);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest,
+       ConsentResult_WrongWindowIgnored) {
+  std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+  // No call is expected.
+  flow->OnConsentResultSet(kConsentResult, "another_window_key");
+}
+
+TEST_F(IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest,
+       SetAccountsFailure) {
+  std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+  EXPECT_CALL(
+      delegate_,
+      OnGaiaRemoteConsentFlowFailed(
+          GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED));
+  flow->OnSetAccountsComplete(
+      signin::SetAccountsInCookieResult::kPersistentError);
+  histogram_tester()->ExpectUniqueSample(
+      kResultHistogramName,
+      GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED, 1);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 0af9810..9eabf88 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -49,6 +49,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -3754,7 +3755,10 @@
   if (use_tab_feature_enabled()) {
     url_obvserver.Wait();
 
-    TabStripModel* tabs = browser()->tab_strip_model();
+    Browser* popup_browser = chrome::FindBrowserWithWebContents(
+        function->GetWebAuthFlowForTesting()->web_contents());
+    TabStripModel* tabs = popup_browser->tab_strip_model();
+    EXPECT_NE(browser(), popup_browser);
     ASSERT_EQ(tabs->GetActiveWebContents()->GetURL(), auth_url);
     tabs->CloseWebContentsAt(tabs->active_index(), 0);
   } else {
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
index e57133f..55a2394 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
@@ -606,9 +606,6 @@
 // creation twice.
 IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
                        InteractiveNewTabCreatedWithAuthURL_ThenCloseTab) {
-  TabStripModel* tabs = browser()->tab_strip_model();
-  int initial_tab_count = tabs->count();
-
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
   content::TestNavigationObserver navigation_observer(auth_url);
   navigation_observer.StartWatchingNewWebContents();
@@ -622,7 +619,9 @@
 
   navigation_observer.Wait();
 
-  EXPECT_EQ(tabs->count(), initial_tab_count + 1);
+  Browser* popup_browser = chrome::FindBrowserWithWebContents(web_contents());
+  TabStripModel* tabs = popup_browser->tab_strip_model();
+  EXPECT_NE(browser(), popup_browser);
   EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), auth_url);
 
   // Check info bar exists and displays proper message with extension name.
@@ -645,9 +644,6 @@
 IN_PROC_BROWSER_TEST_F(
     WebAuthFlowWithBrowserTabBrowserTest,
     InteractiveNewTabCreatedWithAuthURL_ThenChangeURLBeforeAuthResult) {
-  TabStripModel* tabs = browser()->tab_strip_model();
-  int initial_tab_count = tabs->count();
-
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
   content::TestNavigationObserver navigation_observer(auth_url);
   navigation_observer.StartWatchingNewWebContents();
@@ -670,6 +666,10 @@
       web_auth_flow()->GetInfoBarDelegateForTesting();
   ASSERT_TRUE(auth_info_bar);
 
+  Browser* popup_browser = chrome::FindBrowserWithWebContents(web_contents());
+  TabStripModel* tabs = popup_browser->tab_strip_model();
+  EXPECT_NE(browser(), popup_browser);
+
   GURL new_url = embedded_test_server()->GetURL("a.com", "/new.html");
   EXPECT_CALL(mock(),
               OnAuthFlowFailure(WebAuthFlow::Failure::USER_NAVIGATED_AWAY));
@@ -683,7 +683,6 @@
   // New tab is not expected to be closed, it is now used for navigation and not
   // part of the flow anymore.
   EXPECT_EQ(web_contents(), nullptr);
-  EXPECT_EQ(tabs->count(), initial_tab_count + 1);
   EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), new_url);
   // Infobar should be closed on navigation.
   EXPECT_FALSE(auth_info_bar);
@@ -742,9 +741,6 @@
 
 IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
                        InteractiveNewTabCreatedWithAuthURL_NoInfoBarByDefault) {
-  TabStripModel* tabs = browser()->tab_strip_model();
-  int initial_tab_count = tabs->count();
-
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
   content::TestNavigationObserver navigation_observer(auth_url);
   navigation_observer.StartWatchingNewWebContents();
@@ -755,7 +751,9 @@
 
   navigation_observer.Wait();
 
-  EXPECT_EQ(tabs->count(), initial_tab_count + 1);
+  Browser* popup_browser = chrome::FindBrowserWithWebContents(web_contents());
+  TabStripModel* tabs = popup_browser->tab_strip_model();
+  EXPECT_NE(browser(), popup_browser);
   EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), auth_url);
 
   // Check info bar is not created if not set via
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
index 6fb11b6..da0024a03 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
@@ -29,7 +29,12 @@
 LanguageSettingsPrivateDelegateFactory::LanguageSettingsPrivateDelegateFactory()
     : ProfileKeyedServiceFactory(
           "LanguageSettingsPrivateDelegate",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
   DependsOn(SpellcheckServiceFactory::GetInstance());
 }
diff --git a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
index ba8833e..aae7ddf7 100644
--- a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
+++ b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
@@ -27,13 +27,6 @@
 #include "extensions/test/test_extension_dir.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "base/test/gtest_tags.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/chrome_content_browser_client.h"
-#include "content/public/common/content_client.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 namespace extensions {
 
 namespace {
@@ -102,16 +95,6 @@
   run_loop.Run();
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-class ContentBrowserClientMock : public ChromeContentBrowserClient {
- public:
-  MOCK_METHOD(bool,
-              IsGetDisplayMediaSetSelectAllScreensAllowed,
-              (content::BrowserContext * context, const url::Origin& origin),
-              (override));
-};
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 }  // namespace
 
 class OffscreenApiTest : public ExtensionApiTest {
@@ -431,153 +414,6 @@
   EXPECT_FALSE(manager->GetOffscreenDocumentForExtension(*extension));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-class GetAllScreensMediaOffscreenApiTest : public OffscreenApiTest {
- public:
-  GetAllScreensMediaOffscreenApiTest() = default;
-  ~GetAllScreensMediaOffscreenApiTest() override = default;
-
-  void SetUpOnMainThread() override {
-    OffscreenApiTest::SetUpOnMainThread();
-    browser_client_ = std::make_unique<ContentBrowserClientMock>();
-    content::SetBrowserClientForTesting(browser_client_.get());
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    OffscreenApiTest::SetUpCommandLine(command_line);
-    scoped_feature_list_.InitFromCommandLine(
-        /*enable_features=*/
-        "GetAllScreensMedia",
-        /*disable_features=*/"");
-  }
-
- protected:
-  ContentBrowserClientMock& content_browser_client() {
-    return *browser_client_;
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-  std::unique_ptr<ContentBrowserClientMock> browser_client_;
-};
-
-// This test checks if the `getAllScreensMedia` API is available and fully
-// functional in offscreen documents on ChromeOS ash.
-IN_PROC_BROWSER_TEST_F(GetAllScreensMediaOffscreenApiTest,
-                       GetAllScreensMediaAllowed) {
-  // This test corresponds to a critical user journey (CUJ)
-  // (go/cros-cuj-tracker) for ChromeOS commercial.
-  // This tag links the test to a CUJ and allows close tracking whether a user
-  // journey is fully functional.
-  base::AddTagToTestResult("feature_id",
-                           "screenplay-f3601ae4-bff7-495a-a51f-3c0997a46445");
-  EXPECT_CALL(
-      content_browser_client(),
-      IsGetDisplayMediaSetSelectAllScreensAllowed(testing::_, testing::_))
-      .WillOnce(testing::Return(true));
-
-  static constexpr char kManifest[] =
-      R"({
-           "name": "Offscreen Document Test",
-           "manifest_version": 3,
-           "version": "0.1",
-           "background": {"service_worker": "background.js"},
-           "permissions": ["offscreen"]
-         })";
-  // An offscreen document that knows how to capture all screens.
-  static constexpr char kOffscreenJs[] =
-      R"(
-        let streams;
-
-        async function captureAllScreens() {
-          try {
-            streams = await navigator.mediaDevices.getAllScreensMedia();
-            if (streams === null || streams.length == 0) {
-              return false;
-            }
-
-            let allStreamsOk = true;
-            streams.forEach((stream) => {
-              const videoTracks = stream.getVideoTracks();
-              if (videoTracks.length == 0) {
-                allStreamsOk = false;
-                return;
-              }
-
-              const videoTrack = videoTracks[0];
-              if (typeof videoTrack.screenDetailed !== "function") {
-                allStreamsOk = false;
-                return;
-              }
-            });
-
-            chrome.test.sendScriptResult(allStreamsOk);
-            return;
-          } catch(e) {
-            console.error('Unexcpected exception: ' + e);
-            chrome.test.sendScriptResult(false);
-          }
-        }
-
-        function stopCapture() {
-          streams.forEach((stream) => {
-            stream.getVideoTracks()[0].stop();
-          });
-        }
-
-        chrome.runtime.onMessage.addListener(async (msg) => {
-          if (msg == 'capture') {
-            await captureAllScreens();
-          } else if (msg == 'stop') {
-            stopCapture();
-          } else {
-            console.error('Unexpected message: ' + msg);
-          }
-        }))";
-  TestExtensionDir test_dir;
-  test_dir.WriteManifest(kManifest);
-  test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "// Blank.");
-  test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
-                     R"(<html><script src="offscreen.js"></script></html>)");
-  test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.js"), kOffscreenJs);
-
-  scoped_refptr<const Extension> extension =
-      LoadExtension(test_dir.UnpackedPath());
-  ASSERT_TRUE(extension);
-
-  // Create a new offscreen document for audio playback and wait for it to load.
-  OffscreenDocumentManager* manager = OffscreenDocumentManager::Get(profile());
-  ProgrammaticallyCreateOffscreenDocument(*extension, *profile(),
-                                          "DISPLAY_MEDIA");
-  OffscreenDocumentHost* document =
-      manager->GetOffscreenDocumentForExtension(*extension);
-  ASSERT_TRUE(document);
-  content::WaitForLoadStop(document->host_contents());
-
-  // Begin the screen capture.
-  {
-    base::Value result = BackgroundScriptExecutor::ExecuteScript(
-        profile(), extension->id(), "chrome.runtime.sendMessage('capture');",
-        BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
-    ASSERT_TRUE(result.is_bool());
-    EXPECT_TRUE(result.GetBool());
-  }
-
-  // The document should be kept alive.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(manager->GetOffscreenDocumentForExtension(*extension));
-
-  // Now, stop the capture.
-  {
-    BackgroundScriptExecutor::ExecuteScriptAsync(
-        profile(), extension->id(), "chrome.runtime.sendMessage('stop');");
-  }
-
-  // TODO(crbug.com/1443432): Add check if document gets shut down after the
-  // screen capture with `getAllScreensMedia` is stopped.
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 class OffscreenApiTestWithoutCommandLineFlag : public OffscreenApiTest {
  public:
   OffscreenApiTestWithoutCommandLineFlag() = default;
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
index a508c87..2b5d924 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
@@ -28,7 +28,12 @@
 PasswordsPrivateEventRouterFactory::PasswordsPrivateEventRouterFactory()
     : ProfileKeyedServiceFactory(
           "PasswordsPrivateEventRouter",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
 }
 
diff --git a/chrome/browser/extensions/blocklist_factory.cc b/chrome/browser/extensions/blocklist_factory.cc
index 5c079323..ca46d8ee4 100644
--- a/chrome/browser/extensions/blocklist_factory.cc
+++ b/chrome/browser/extensions/blocklist_factory.cc
@@ -28,7 +28,12 @@
     : ProfileKeyedServiceFactory(
           "Blocklist",
           // Redirected in incognito.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
 }
 
diff --git a/chrome/browser/extensions/chrome_app_icon_service_factory.cc b/chrome/browser/extensions/chrome_app_icon_service_factory.cc
index 0adbe843..20ccd17 100644
--- a/chrome/browser/extensions/chrome_app_icon_service_factory.cc
+++ b/chrome/browser/extensions/chrome_app_icon_service_factory.cc
@@ -24,7 +24,12 @@
 ChromeAppIconServiceFactory::ChromeAppIconServiceFactory()
     : ProfileKeyedServiceFactory(
           "ChromeAppIconService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionRegistryFactory::GetInstance());
 }
 
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 07398eb..e4847f02 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -237,9 +237,16 @@
     content::BrowserContext* context,
     bool force_guest_profile,
     bool force_system_profile) {
-  const ProfileSelections selections =
-      ProfileSelections::BuildRedirectedInIncognito(force_guest_profile,
-                                                    force_system_profile);
+  ProfileSelections::Builder builder;
+  builder.WithRegular(ProfileSelection::kRedirectedToOriginal);
+  if (force_guest_profile) {
+    builder.WithGuest(ProfileSelection::kRedirectedToOriginal);
+  }
+  if (force_system_profile) {
+    builder.WithSystem(ProfileSelection::kRedirectedToOriginal);
+  }
+
+  const ProfileSelections selections = builder.Build();
   return selections.ApplyProfileSelection(Profile::FromBrowserContext(context));
 }
 
@@ -256,6 +263,7 @@
   if (force_system_profile) {
     builder.WithSystem(ProfileSelection::kOwnInstance);
   }
+
   const ProfileSelections selections = builder.Build();
   return selections.ApplyProfileSelection(Profile::FromBrowserContext(context));
 }
@@ -271,6 +279,7 @@
   if (force_system_profile) {
     builder.WithSystem(ProfileSelection::kOriginalOnly);
   }
+
   ProfileSelections selections = builder.Build();
   return selections.ApplyProfileSelection(Profile::FromBrowserContext(context));
 }
diff --git a/chrome/browser/extensions/cws_info_service_factory.cc b/chrome/browser/extensions/cws_info_service_factory.cc
index b88c534..cf505df 100644
--- a/chrome/browser/extensions/cws_info_service_factory.cc
+++ b/chrome/browser/extensions/cws_info_service_factory.cc
@@ -31,7 +31,12 @@
 CWSInfoServiceFactory::CWSInfoServiceFactory()
     : ProfileKeyedServiceFactory(
           "CWSInfoService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
 }
diff --git a/chrome/browser/extensions/error_console/error_console_factory.cc b/chrome/browser/extensions/error_console/error_console_factory.cc
index e1eb830..0ab9dce 100644
--- a/chrome/browser/extensions/error_console/error_console_factory.cc
+++ b/chrome/browser/extensions/error_console/error_console_factory.cc
@@ -28,7 +28,12 @@
 ErrorConsoleFactory::ErrorConsoleFactory()
     : ProfileKeyedServiceFactory(
           "ErrorConsole",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionRegistryFactory::GetInstance());
 }
 
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index 6aff8062..8f5273c 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -915,7 +915,12 @@
 ExtensionManagementFactory::ExtensionManagementFactory()
     : ProfileKeyedServiceFactory(
           "ExtensionManagement",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(InstallStageTrackerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/extensions/extension_sync_service_factory.cc b/chrome/browser/extensions/extension_sync_service_factory.cc
index acf3475..b87b136 100644
--- a/chrome/browser/extensions/extension_sync_service_factory.cc
+++ b/chrome/browser/extensions/extension_sync_service_factory.cc
@@ -28,7 +28,12 @@
 ExtensionSyncServiceFactory::ExtensionSyncServiceFactory()
     : ProfileKeyedServiceFactory(
           "ExtensionSyncService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
   DependsOn(extensions::ExtensionSystemFactory::GetInstance());
diff --git a/chrome/browser/extensions/extension_system_factory.cc b/chrome/browser/extensions/extension_system_factory.cc
index e432156..e449f48 100644
--- a/chrome/browser/extensions/extension_system_factory.cc
+++ b/chrome/browser/extensions/extension_system_factory.cc
@@ -41,7 +41,12 @@
 ExtensionSystemSharedFactory::ExtensionSystemSharedFactory()
     : ProfileKeyedServiceFactory(
           "ExtensionSystemShared",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionPrefsFactory::GetInstance());
   DependsOn(ExtensionManagementFactory::GetInstance());
   // This depends on ExtensionService, which depends on ExtensionRegistry.
diff --git a/chrome/browser/extensions/install_tracker_factory.cc b/chrome/browser/extensions/install_tracker_factory.cc
index f6fe45a..0d2655f5 100644
--- a/chrome/browser/extensions/install_tracker_factory.cc
+++ b/chrome/browser/extensions/install_tracker_factory.cc
@@ -29,7 +29,12 @@
           "InstallTracker",
           // The installs themselves are routed to the non-incognito profile and
           // so should the install progress.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
   DependsOn(ExtensionPrefsFactory::GetInstance());
 }
diff --git a/chrome/browser/extensions/install_verifier_factory.cc b/chrome/browser/extensions/install_verifier_factory.cc
index 2df9e8cc..91980671 100644
--- a/chrome/browser/extensions/install_verifier_factory.cc
+++ b/chrome/browser/extensions/install_verifier_factory.cc
@@ -30,7 +30,12 @@
 InstallVerifierFactory::InstallVerifierFactory()
     : ProfileKeyedServiceFactory(
           "InstallVerifier",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionPrefsFactory::GetInstance());
   DependsOn(ExtensionRegistryFactory::GetInstance());
 }
diff --git a/chrome/browser/extensions/menu_manager_factory.cc b/chrome/browser/extensions/menu_manager_factory.cc
index 3809f44..910d517 100644
--- a/chrome/browser/extensions/menu_manager_factory.cc
+++ b/chrome/browser/extensions/menu_manager_factory.cc
@@ -35,7 +35,12 @@
 MenuManagerFactory::MenuManagerFactory()
     : ProfileKeyedServiceFactory(
           "MenuManager",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
 }
 
diff --git a/chrome/browser/extensions/warning_badge_service_factory.cc b/chrome/browser/extensions/warning_badge_service_factory.cc
index baa96cb1..32ebb3ea 100644
--- a/chrome/browser/extensions/warning_badge_service_factory.cc
+++ b/chrome/browser/extensions/warning_badge_service_factory.cc
@@ -28,7 +28,12 @@
 WarningBadgeServiceFactory::WarningBadgeServiceFactory()
     : ProfileKeyedServiceFactory(
           "WarningBadgeService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(WarningServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
index a71bc8b..7e3ff21 100644
--- a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
+++ b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
@@ -46,7 +46,12 @@
 HistoryUiFaviconRequestHandlerFactory::HistoryUiFaviconRequestHandlerFactory()
     : ProfileKeyedServiceFactory(
           "HistoryUiFaviconRequestHandler",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(FaviconServiceFactory::GetInstance());
   DependsOn(LargeIconServiceFactory::GetInstance());
   DependsOn(SyncServiceFactory::GetInstance());
diff --git a/chrome/browser/favicon/large_icon_service_factory.cc b/chrome/browser/favicon/large_icon_service_factory.cc
index a7e29d54..0531763f 100644
--- a/chrome/browser/favicon/large_icon_service_factory.cc
+++ b/chrome/browser/favicon/large_icon_service_factory.cc
@@ -51,7 +51,12 @@
 LargeIconServiceFactory::LargeIconServiceFactory()
     : ProfileKeyedServiceFactory(
           "LargeIconService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(FaviconServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/feature_engagement/tracker_factory.cc b/chrome/browser/feature_engagement/tracker_factory.cc
index d604b2db..0bd36458 100644
--- a/chrome/browser/feature_engagement/tracker_factory.cc
+++ b/chrome/browser/feature_engagement/tracker_factory.cc
@@ -32,7 +32,12 @@
 TrackerFactory::TrackerFactory()
     : ProfileKeyedServiceFactory(
           "feature_engagement::Tracker",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 TrackerFactory::~TrackerFactory() = default;
 
diff --git a/chrome/browser/feedback/feedback_uploader_factory_chrome.cc b/chrome/browser/feedback/feedback_uploader_factory_chrome.cc
index 60bf2535..e6e03922 100644
--- a/chrome/browser/feedback/feedback_uploader_factory_chrome.cc
+++ b/chrome/browser/feedback/feedback_uploader_factory_chrome.cc
@@ -31,8 +31,13 @@
 
 content::BrowserContext* FeedbackUploaderFactoryChrome::GetBrowserContextToUse(
     content::BrowserContext* context) const {
-  return ProfileSelections::BuildRedirectedInIncognito().ApplyProfileSelection(
-      Profile::FromBrowserContext(context));
+  return ProfileSelections::Builder()
+      .WithRegular(ProfileSelection::kRedirectedToOriginal)
+      // TODO(crbug.com/1418376): Check if this service is needed in
+      // Guest mode.
+      .WithGuest(ProfileSelection::kRedirectedToOriginal)
+      .Build()
+      .ApplyProfileSelection(Profile::FromBrowserContext(context));
 }
 
 bool FeedbackUploaderFactoryChrome::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service_factory.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service_factory.cc
index 568d2d8..4c533644 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service_factory.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service_factory.cc
@@ -50,7 +50,12 @@
 FirstPartySetsPolicyServiceFactory::FirstPartySetsPolicyServiceFactory()
     : ProfileKeyedServiceFactory(
           "FirstPartySetsPolicyService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 FirstPartySetsPolicyServiceFactory::~FirstPartySetsPolicyServiceFactory() =
     default;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 68c871a..5ce90605 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -6549,6 +6549,13 @@
     "expiry_milestone": 120
   },
   {
+    "name": "safety-hub",
+    "owners": [
+      "sideyilmaz"
+    ],
+    "expiry_milestone": 125
+  },
+  {
     "name": "sanitizer-api",
     "owners": [ "//third_party/blink/renderer/modules/sanitizer_api/OWNERS" ],
     "expiry_milestone": 109
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 923dc336..b82e6096c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2830,6 +2830,10 @@
     "When enabled, adds the unused sites permission module to Safety Check on "
     "desktop. The module will be shown depending on the browser state.";
 
+const char kSafetyHubName[] = "Safety Hub";
+const char kSafetyHubDescription[] =
+    "When enabled, Safety Hub will be visible in settings.";
+
 const char kSameAppWindowCycleName[] = "Cros Labs: Same App Window Cycling";
 const char kSameAppWindowCycleDescription[] =
     "Use Alt+` to cycle through the windows of the active application.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 39bc77b..eb9cf6d7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1597,6 +1597,9 @@
 extern const char kSafetyCheckUnusedSitePermissionsName[];
 extern const char kSafetyCheckUnusedSitePermissionsDescription[];
 
+extern const char kSafetyHubName[];
+extern const char kSafetyHubDescription[];
+
 extern const char kSameAppWindowCycleName[];
 extern const char kSameAppWindowCycleDescription[];
 
diff --git a/chrome/browser/font_pref_change_notifier_factory.cc b/chrome/browser/font_pref_change_notifier_factory.cc
index 3a95f263..e695c47 100644
--- a/chrome/browser/font_pref_change_notifier_factory.cc
+++ b/chrome/browser/font_pref_change_notifier_factory.cc
@@ -10,7 +10,12 @@
 FontPrefChangeNotifierFactory::FontPrefChangeNotifierFactory()
     : ProfileKeyedServiceFactory(
           "FontPrefChangeNotifier",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 FontPrefChangeNotifierFactory::~FontPrefChangeNotifierFactory() = default;
 
diff --git a/chrome/browser/history/history_service_factory.cc b/chrome/browser/history/history_service_factory.cc
index 54e05c5..6b849756 100644
--- a/chrome/browser/history/history_service_factory.cc
+++ b/chrome/browser/history/history_service_factory.cc
@@ -89,7 +89,12 @@
 HistoryServiceFactory::HistoryServiceFactory()
     : ProfileKeyedServiceFactory(
           "HistoryService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(BookmarkModelFactory::GetInstance());
 }
 
diff --git a/chrome/browser/lacros/cert/cert_db_initializer_factory.cc b/chrome/browser/lacros/cert/cert_db_initializer_factory.cc
index 8c2549a..5bcbe255 100644
--- a/chrome/browser/lacros/cert/cert_db_initializer_factory.cc
+++ b/chrome/browser/lacros/cert/cert_db_initializer_factory.cc
@@ -28,7 +28,12 @@
 CertDbInitializerFactory::CertDbInitializerFactory()
     : ProfileKeyedServiceFactory(
           "CertDbInitializerFactory",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 bool CertDbInitializerFactory::ServiceIsCreatedWithBrowserContext() const {
   return should_create_with_browser_context_;
diff --git a/chrome/browser/language/language_model_manager_factory.cc b/chrome/browser/language/language_model_manager_factory.cc
index 0e913da..db84c47 100644
--- a/chrome/browser/language/language_model_manager_factory.cc
+++ b/chrome/browser/language/language_model_manager_factory.cc
@@ -169,7 +169,12 @@
     : ProfileKeyedServiceFactory(
           "LanguageModelManager",
           // Use the original profile's language model even in Incognito mode.
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 LanguageModelManagerFactory::~LanguageModelManagerFactory() {}
 
diff --git a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
index 87a8abb..8749c0de 100644
--- a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
@@ -166,7 +166,7 @@
       return false;
     }
 
-    if (!content::ExecuteScript(tab_contents, javascript)) {
+    if (!content::ExecJs(tab_contents, javascript)) {
       LOG(ERROR) << "Failed to execute the following javascript: " <<
           javascript;
       return false;
diff --git a/chrome/browser/media/webrtc/webrtc_video_display_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_video_display_perf_browsertest.cc
index 8aa6d97..95b16a0 100644
--- a/chrome/browser/media/webrtc/webrtc_video_display_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_video_display_perf_browsertest.cc
@@ -219,9 +219,9 @@
     // connection(s) are up.
     content::WebContents* webrtc_internals_tab =
         OpenWebrtcInternalsTab(browser());
-    EXPECT_TRUE(content::ExecuteScript(
-        webrtc_internals_tab,
-        "currentGetStatsMethod = OPTION_GETSTATS_LEGACY"));
+    EXPECT_TRUE(
+        content::ExecJs(webrtc_internals_tab,
+                        "currentGetStatsMethod = OPTION_GETSTATS_LEGACY"));
 
     content::WebContents* left_tab =
         OpenPageAndGetUserMediaInNewTabWithConstraints(
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_factory.cc b/chrome/browser/media_galleries/media_galleries_preferences_factory.cc
index d3fb748..5f736c1 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_factory.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_factory.cc
@@ -24,7 +24,12 @@
 MediaGalleriesPreferencesFactory::MediaGalleriesPreferencesFactory()
     : ProfileKeyedServiceFactory(
           "MediaGalleriesPreferences",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 MediaGalleriesPreferencesFactory::~MediaGalleriesPreferencesFactory() {}
 
diff --git a/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.cc b/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.cc
index 181ad24c..acb31bcc 100644
--- a/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.cc
+++ b/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.cc
@@ -42,7 +42,7 @@
           // and syncing in their regular profile and that is browsing in
           // incognito profile, Chromium will record the session time as being
           // signed in and syncing.
-          ProfileSelections::BuildRedirectedInIncognitoNonExperimental()) {
+          ProfileSelections::BuildRedirectedInIncognito()) {
   DependsOn(SyncServiceFactory::GetInstance());
   DependsOn(IdentityManagerFactory::GetInstance());
 }
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 3044688..92ad50a30 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -619,14 +619,14 @@
     },
     Metric{
         .uma_name = "PartitionAlloc.AddressSpace."
-                    "PkeyPoolLargestAvailableReservation",
+                    "ThreadIsolatedPoolLargestAvailableReservation",
         .metric_size = MetricSize::kLarge,
-        .metric = "pkey_pool_largest_reservation",
+        .metric = "thread_isolated_pool_largest_reservation",
     },
     Metric{
-        .uma_name = "PartitionAlloc.AddressSpace.PkeyPoolUsage",
+        .uma_name = "PartitionAlloc.AddressSpace.ThreadIsolatedPoolUsage",
         .metric_size = MetricSize::kLarge,
-        .metric = "pkey_pool_usage",
+        .metric = "thread_isolated_pool_usage",
     },
 };
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/chrome/browser/notifications/metrics/notification_metrics_logger_factory.cc b/chrome/browser/notifications/metrics/notification_metrics_logger_factory.cc
index 8b227a5f..9272918 100644
--- a/chrome/browser/notifications/metrics/notification_metrics_logger_factory.cc
+++ b/chrome/browser/notifications/metrics/notification_metrics_logger_factory.cc
@@ -24,7 +24,12 @@
 NotificationMetricsLoggerFactory::NotificationMetricsLoggerFactory()
     : ProfileKeyedServiceFactory(
           "NotificationMetricsLogger",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 KeyedService* NotificationMetricsLoggerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
index 254035a7..2d1b4b9 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
@@ -22,7 +22,12 @@
 HttpsEngagementServiceFactory::HttpsEngagementServiceFactory()
     : ProfileKeyedServiceFactory(
           "HttpEngagementKeyService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 HttpsEngagementServiceFactory::~HttpsEngagementServiceFactory() {}
 
diff --git a/chrome/browser/password_manager/affiliation_service_factory.cc b/chrome/browser/password_manager/affiliation_service_factory.cc
index 91411f1..037a75a 100644
--- a/chrome/browser/password_manager/affiliation_service_factory.cc
+++ b/chrome/browser/password_manager/affiliation_service_factory.cc
@@ -19,7 +19,7 @@
 AffiliationServiceFactory::AffiliationServiceFactory()
     : ProfileKeyedServiceFactory(
           "AffiliationService",
-          ProfileSelections::BuildRedirectedInIncognitoNonExperimental()) {}
+          ProfileSelections::BuildRedirectedInIncognito()) {}
 
 AffiliationServiceFactory::~AffiliationServiceFactory() = default;
 
diff --git a/chrome/browser/password_manager/android/password_generation_controller.h b/chrome/browser/password_manager/android/password_generation_controller.h
index 7c3eb22..2f80050 100644
--- a/chrome/browser/password_manager/android/password_generation_controller.h
+++ b/chrome/browser/password_manager/android/password_generation_controller.h
@@ -14,7 +14,7 @@
 #include "ui/gfx/geometry/rect.h"
 
 namespace password_manager {
-class PasswordManagerDriver;
+class ContentPasswordManagerDriver;
 }  // namespace password_manager
 
 // Interface for the controller responsible for overseeing the UI flow for
@@ -43,8 +43,8 @@
   static PasswordGenerationController* GetOrCreate(
       content::WebContents* web_contents);
 
-  // Returns a reference to the PasswordGenerationController associated with the
-  // |web_contents| or null if there is no such instance.
+  // Returns a reference to the PasswordGenerationController associated with
+  // the |web_contents| or null if there is no such instance.
   static PasswordGenerationController* GetIfExisting(
       content::WebContents* web_contents);
 
@@ -54,7 +54,7 @@
 
   // Returns the driver associated with the frame that is considered active
   // for generation.
-  virtual base::WeakPtr<password_manager::PasswordManagerDriver>
+  virtual base::WeakPtr<password_manager::ContentPasswordManagerDriver>
   GetActiveFrameDriver() const = 0;
 
   // This signals that the focus has moved. |focused_field_type| tells
@@ -62,12 +62,12 @@
   // field. This event sets/unsets the active frame for generation.
   virtual void FocusedInputChanged(
       autofill::mojom::FocusedFieldType focused_field_type,
-      base::WeakPtr<password_manager::PasswordManagerDriver> driver) = 0;
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver) = 0;
 
   // Notifies the UI that automatic password generation is available.
   // A button should be displayed in the accessory bar.
   virtual void OnAutomaticGenerationAvailable(
-      base::WeakPtr<password_manager::PasswordManagerDriver>
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver>
           target_frame_driver,
       const autofill::password_generation::PasswordGenerationUIData& ui_data,
       gfx::RectF element_bounds_in_screen_space) = 0;
@@ -75,7 +75,7 @@
   // This is called after the user requested manual generation and the
   // corresponding setup was done in the renderer.
   virtual void ShowManualGenerationDialog(
-      const password_manager::PasswordManagerDriver* target_frame_driver,
+      const password_manager::ContentPasswordManagerDriver* target_frame_driver,
       const autofill::password_generation::PasswordGenerationUIData&
           ui_data) = 0;
 
@@ -96,7 +96,7 @@
   // (automatic or manual).
   virtual void GeneratedPasswordAccepted(
       const std::u16string& password,
-      base::WeakPtr<password_manager::PasswordManagerDriver> driver,
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver,
       autofill::password_generation::PasswordGenerationType type) = 0;
 
   // Called from the modal dialog if the user rejected the generated password.
@@ -105,6 +105,13 @@
   virtual void GeneratedPasswordRejected(
       autofill::password_generation::PasswordGenerationType type) = 0;
 
+  // Should be reset on page navigation.
+  virtual void HideBottomSheetIfNeeded() = 0;
+
+  // Called when content::WebContents render frame is deleted.
+  virtual void RenderFrameDeleted(
+      content::RenderFrameHost* render_frame_host) = 0;
+
   // -----------------
   // Member accessors:
   // -----------------
@@ -112,6 +119,9 @@
   virtual gfx::NativeWindow top_level_native_window() = 0;
 
   virtual content::WebContents* web_contents() = 0;
+
+  virtual autofill::FieldSignature get_field_signature_for_testing() = 0;
+  virtual autofill::FormSignature get_form_signature_for_testing() = 0;
 };
 
 #endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_GENERATION_CONTROLLER_H_
diff --git a/chrome/browser/password_manager/android/password_generation_controller_impl.cc b/chrome/browser/password_manager/android/password_generation_controller_impl.cc
index c1dad2a..ded095a 100644
--- a/chrome/browser/password_manager/android/password_generation_controller_impl.cc
+++ b/chrome/browser/password_manager/android/password_generation_controller_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/password_manager/android/password_generation_controller_impl.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/functional/bind.h"
@@ -15,16 +16,18 @@
 #include "chrome/browser/password_manager/android/password_accessory_controller.h"
 #include "chrome/browser/password_manager/android/password_generation_dialog_view_interface.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/autofill/core/common/signatures.h"
 #include "components/autofill/core/common/unique_ids.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/core/browser/password_form.h"
 #include "components/password_manager/core/browser/password_generation_frame_helper.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
-#include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 
 using autofill::mojom::FocusedFieldType;
 using autofill::password_generation::PasswordGenerationType;
@@ -74,13 +77,14 @@
   uint32_t max_password_length;
 };
 
-base::WeakPtr<password_manager::PasswordManagerDriver>
+base::WeakPtr<password_manager::ContentPasswordManagerDriver>
 PasswordGenerationControllerImpl::GetActiveFrameDriver() const {
   return active_frame_driver_;
 }
 
 void PasswordGenerationControllerImpl::OnAutomaticGenerationAvailable(
-    base::WeakPtr<password_manager::PasswordManagerDriver> target_frame_driver,
+    base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+        target_frame_driver,
     const autofill::password_generation::PasswordGenerationUIData& ui_data,
     gfx::RectF element_bounds_in_screen_space) {
   // We can't be sure that the active frame driver would be set in the
@@ -104,6 +108,20 @@
 
   generation_element_data_ = std::make_unique<GenerationElementData>(ui_data);
 
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordGenerationBottomSheet) &&
+      touch_to_fill_generation_state_ == TouchToFillState::kNone) {
+    touch_to_fill_generation_controller_ =
+        std::make_unique<TouchToFillPasswordGenerationController>(
+            active_frame_driver_);
+    touch_to_fill_generation_controller_->ShowTouchToFill();
+    touch_to_fill_generation_state_ = TouchToFillState::kIsShowing;
+    return;
+  }
+  if (touch_to_fill_generation_state_ == TouchToFillState::kIsShowing) {
+    return;
+  }
+
   if (!manual_filling_controller_) {
     manual_filling_controller_ =
         ManualFillingController::GetOrCreate(&GetWebContents());
@@ -114,7 +132,7 @@
 }
 
 void PasswordGenerationControllerImpl::ShowManualGenerationDialog(
-    const password_manager::PasswordManagerDriver* target_frame_driver,
+    const password_manager::ContentPasswordManagerDriver* target_frame_driver,
     const autofill::password_generation::PasswordGenerationUIData& ui_data) {
   if (!IsActiveFrameDriver(target_frame_driver) ||
       !manual_generation_requested_)
@@ -125,7 +143,7 @@
 
 void PasswordGenerationControllerImpl::FocusedInputChanged(
     autofill::mojom::FocusedFieldType focused_field_type,
-    base::WeakPtr<password_manager::PasswordManagerDriver> driver) {
+    base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver) {
   TRACE_EVENT0("passwords",
                "PasswordGenerationControllerImpl::FocusedInputChanged");
   // It's probably a duplicate notification.
@@ -133,7 +151,7 @@
       focused_field_type == FocusedFieldType::kFillablePasswordField) {
     return;
   }
-  ResetState();
+  ResetFocusState();
   if (focused_field_type == FocusedFieldType::kFillablePasswordField)
     active_frame_driver_ = std::move(driver);
 }
@@ -150,7 +168,7 @@
 
 void PasswordGenerationControllerImpl::GeneratedPasswordAccepted(
     const std::u16string& password,
-    base::WeakPtr<password_manager::PasswordManagerDriver> driver,
+    base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver,
     PasswordGenerationType type) {
   if (!driver)
     return;
@@ -159,12 +177,12 @@
   driver->GeneratedPasswordAccepted(
       generation_element_data_->form_data,
       generation_element_data_->generation_element_id, password);
-  ResetState();
+  ResetFocusState();
 }
 
 void PasswordGenerationControllerImpl::GeneratedPasswordRejected(
     PasswordGenerationType type) {
-  ResetState();
+  ResetFocusState();
   password_manager::metrics_util::LogGenerationDialogChoice(
       GenerationDialogChoice::kRejected, type);
 }
@@ -177,6 +195,16 @@
   return &GetWebContents();
 }
 
+autofill::FieldSignature
+PasswordGenerationControllerImpl::get_field_signature_for_testing() {
+  return generation_element_data_->field_signature;
+}
+
+autofill::FormSignature
+PasswordGenerationControllerImpl::get_form_signature_for_testing() {
+  return generation_element_data_->form_signature;
+}
+
 // static
 void PasswordGenerationControllerImpl::CreateForWebContentsForTesting(
     content::WebContents* web_contents,
@@ -238,13 +266,13 @@
 }
 
 bool PasswordGenerationControllerImpl::IsActiveFrameDriver(
-    const password_manager::PasswordManagerDriver* driver) const {
+    const password_manager::ContentPasswordManagerDriver* driver) const {
   if (!active_frame_driver_)
     return false;
   return active_frame_driver_.get() == driver;
 }
 
-void PasswordGenerationControllerImpl::ResetState() {
+void PasswordGenerationControllerImpl::ResetFocusState() {
   if (manual_filling_controller_)
     manual_filling_controller_->OnAutomaticGenerationStatusChanged(false);
   active_frame_driver_.reset();
@@ -253,4 +281,21 @@
   manual_generation_requested_ = false;
 }
 
+void PasswordGenerationControllerImpl::HideBottomSheetIfNeeded() {
+  if (touch_to_fill_generation_state_ != TouchToFillState::kNone) {
+    touch_to_fill_generation_state_ = TouchToFillState::kNone;
+    // TODO (crbug.com/1421753): Destroy the
+    // touch_to_fill_generation_controller_ when the bottom sheet is dismissed.
+    touch_to_fill_generation_controller_.reset();
+  }
+}
+
+void PasswordGenerationControllerImpl::RenderFrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  if (active_frame_driver_ &&
+      active_frame_driver_->render_frame_host() == render_frame_host) {
+    HideBottomSheetIfNeeded();
+  }
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(PasswordGenerationControllerImpl);
diff --git a/chrome/browser/password_manager/android/password_generation_controller_impl.h b/chrome/browser/password_manager/android/password_generation_controller_impl.h
index 4ff1426..beaf52b3 100644
--- a/chrome/browser/password_manager/android/password_generation_controller_impl.h
+++ b/chrome/browser/password_manager/android/password_generation_controller_impl.h
@@ -16,9 +16,10 @@
 
 class ManualFillingController;
 class PasswordGenerationDialogViewInterface;
+class TouchToFillPasswordGenerationController;
 
 namespace password_manager {
-class PasswordManagerDriver;
+class ContentPasswordManagerDriver;
 class PasswordManagerClient;
 }  // namespace password_manager
 
@@ -43,30 +44,35 @@
   ~PasswordGenerationControllerImpl() override;
 
   // PasswordGenerationController:
-  base::WeakPtr<password_manager::PasswordManagerDriver> GetActiveFrameDriver()
-      const override;
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+  GetActiveFrameDriver() const override;
   void FocusedInputChanged(
       autofill::mojom::FocusedFieldType focused_field_type,
-      base::WeakPtr<password_manager::PasswordManagerDriver> driver) override;
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver)
+      override;
   void OnAutomaticGenerationAvailable(
-      base::WeakPtr<password_manager::PasswordManagerDriver>
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver>
           target_frame_driver,
       const autofill::password_generation::PasswordGenerationUIData& ui_data,
       gfx::RectF element_bounds_in_screen_space) override;
   void ShowManualGenerationDialog(
-      const password_manager::PasswordManagerDriver* target_frame_driver,
+      const password_manager::ContentPasswordManagerDriver* target_frame_driver,
       const autofill::password_generation::PasswordGenerationUIData& ui_data)
       override;
   void OnGenerationRequested(
       autofill::password_generation::PasswordGenerationType type) override;
   void GeneratedPasswordAccepted(
       const std::u16string& password,
-      base::WeakPtr<password_manager::PasswordManagerDriver> driver,
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver,
       autofill::password_generation::PasswordGenerationType type) override;
   void GeneratedPasswordRejected(
       autofill::password_generation::PasswordGenerationType type) override;
+  void HideBottomSheetIfNeeded() override;
+  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   gfx::NativeWindow top_level_native_window() override;
   content::WebContents* web_contents() override;
+  autofill::FieldSignature get_field_signature_for_testing() override;
+  autofill::FormSignature get_form_signature_for_testing() override;
 
   // Like |CreateForWebContents|, it creates the controller and attaches it to
   // the given |web_contents|. Additionally, it allows injecting mocks for
@@ -86,6 +92,12 @@
   // their signatures and the maximum password size.
   struct GenerationElementData;
 
+  enum class TouchToFillState {
+    kNone,
+    kIsShowing,
+    kWasShown,
+  };
+
   friend class content::WebContentsUserData<PasswordGenerationControllerImpl>;
 
   // Constructor that allows to inject a mock or fake dependencies
@@ -100,7 +112,7 @@
   // The active frame is the latest focused frame that received a field focus
   // event.
   bool IsActiveFrameDriver(
-      const password_manager::PasswordManagerDriver* driver) const;
+      const password_manager::ContentPasswordManagerDriver* driver) const;
 
   // Called to show the generation modal dialog. |manual| - whether the
   // dialog was shown for a manual or automatic generation flow. This is used
@@ -109,7 +121,7 @@
 
   // Resets the current active frame driver, as well as the dialog if shown
   // and the generation element data.
-  void ResetState();
+  void ResetFocusState();
 
   // The PasswordManagerClient associated with the current |web_contents_|.
   // Used to tell the renderer that manual generation was requested.
@@ -122,11 +134,15 @@
   // Password manager driver for the currently active frame. This is set
   // when a password field focus event arrives from the renderer and unset
   // whenever a focus event for a non-password field is received.
-  base::WeakPtr<password_manager::PasswordManagerDriver> active_frame_driver_;
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+      active_frame_driver_;
 
   // The manual filling controller object to forward client requests to.
   base::WeakPtr<ManualFillingController> manual_filling_controller_;
 
+  std::unique_ptr<TouchToFillPasswordGenerationController>
+      touch_to_fill_generation_controller_;
+
   // Modal dialog view meant to display the generated password.
   std::unique_ptr<PasswordGenerationDialogViewInterface> dialog_view_;
 
@@ -137,6 +153,9 @@
   // unexpected or delayed manual generation responses from the renderer.
   bool manual_generation_requested_ = false;
 
+  // Whether password generation bottom sheet was already shown.
+  TouchToFillState touch_to_fill_generation_state_ = TouchToFillState::kNone;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/password_manager/android/password_generation_controller_impl_unittest.cc b/chrome/browser/password_manager/android/password_generation_controller_impl_unittest.cc
index eab63d56..f591b1f 100644
--- a/chrome/browser/password_manager/android/password_generation_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/android/password_generation_controller_impl_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/common/password_generation_util.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/core/browser/mock_password_store_interface.h"
 #include "components/password_manager/core/browser/password_autofill_manager.h"
 #include "components/password_manager/core/browser/password_generation_frame_helper.h"
@@ -25,6 +26,7 @@
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "content/public/browser/web_contents.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -37,6 +39,7 @@
 using autofill::mojom::FocusedFieldType;
 using autofill::password_generation::PasswordGenerationUIData;
 using base::ASCIIToUTF16;
+using password_manager::ContentPasswordManagerDriver;
 using password_manager::MockPasswordStoreInterface;
 using password_manager::PasswordForm;
 using testing::_;
@@ -57,6 +60,11 @@
   password_manager::PasswordStoreInterface* GetProfilePasswordStore()
       const override;
 
+  MOCK_METHOD((const password_manager::PasswordManager*),
+              GetPasswordManager,
+              (),
+              (const, override));
+
  private:
   scoped_refptr<MockPasswordStoreInterface> mock_password_store_;
 };
@@ -72,52 +80,19 @@
   return mock_password_store_.get();
 }
 
-class MockPasswordManagerDriver
-    : public password_manager::StubPasswordManagerDriver {
- public:
-  MockPasswordManagerDriver() = default;
-
-  MockPasswordManagerDriver(const MockPasswordManagerDriver&) = delete;
-  MockPasswordManagerDriver& operator=(const MockPasswordManagerDriver&) =
-      delete;
-
-  MOCK_METHOD1(GeneratedPasswordAccepted, void(const std::u16string&));
-  MOCK_METHOD0(GetPasswordGenerationHelper,
-               password_manager::PasswordGenerationFrameHelper*());
-  MOCK_METHOD0(GetPasswordManager, password_manager::PasswordManager*());
-  MOCK_METHOD0(GetPasswordAutofillManager,
-               password_manager::PasswordAutofillManager*());
-};
-
-class MockPasswordGenerationHelper
-    : public password_manager::PasswordGenerationFrameHelper {
- public:
-  MockPasswordGenerationHelper(const MockPasswordGenerationHelper&) = delete;
-  MockPasswordGenerationHelper& operator=(const MockPasswordGenerationHelper&) =
-      delete;
-
-  MockPasswordGenerationHelper(password_manager::PasswordManagerClient* client,
-                               password_manager::PasswordManagerDriver* driver)
-      : password_manager::PasswordGenerationFrameHelper(client, driver) {}
-
-  MOCK_METHOD4(GeneratePassword,
-               std::u16string(const GURL&,
-                              autofill::FormSignature,
-                              autofill::FieldSignature,
-                              uint32_t));
-};
-
 // Mock modal dialog view used to bypass the need of a valid top level window.
 class MockPasswordGenerationDialogView
     : public PasswordGenerationDialogViewInterface {
  public:
   MockPasswordGenerationDialogView() = default;
 
-  MOCK_METHOD3(Show,
-               void(std::u16string&,
-                    base::WeakPtr<password_manager::PasswordManagerDriver>,
-                    PasswordGenerationType));
-  MOCK_METHOD0(Destroy, void());
+  MOCK_METHOD(void,
+              Show,
+              (std::u16string&,
+               base::WeakPtr<password_manager::ContentPasswordManagerDriver>,
+               PasswordGenerationType),
+              (override));
+  MOCK_METHOD(void, Destroy, (), ());
 
   MockPasswordGenerationDialogView(const MockPasswordGenerationDialogView&) =
       delete;
@@ -162,39 +137,31 @@
  public:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+
     test_pwd_manager_client_ = std::make_unique<TestPasswordManagerClient>();
+    password_manager_ = std::make_unique<password_manager::PasswordManager>(
+        test_pwd_manager_client_.get());
+    ON_CALL(*test_pwd_manager_client_, GetPasswordManager())
+        .WillByDefault(Return(password_manager_.get()));
+
     PasswordGenerationControllerImpl::CreateForWebContentsForTesting(
         web_contents(), test_pwd_manager_client_.get(),
         mock_manual_filling_controller_.AsWeakPtr(),
         mock_dialog_factory_.Get());
 
-    password_manager_ = std::make_unique<password_manager::PasswordManager>(
-        test_pwd_manager_client_.get());
-    mock_password_manager_driver_ =
-        std::make_unique<NiceMock<MockPasswordManagerDriver>>();
-    mock_another_password_manager_driver_ =
-        std::make_unique<NiceMock<MockPasswordManagerDriver>>();
+    password_manager_driver_ = std::make_unique<ContentPasswordManagerDriver>(
+        main_rfh(), test_pwd_manager_client_.get(), &test_autofill_client_);
+    another_password_manager_driver_ =
+        std::make_unique<ContentPasswordManagerDriver>(
+            main_rfh(), test_pwd_manager_client_.get(), &test_autofill_client_);
 
     // TODO(crbug.com/969051): Remove once kAutofillKeyboardAccessory is
     // enabled.
     password_autofill_manager_ =
         std::make_unique<password_manager::PasswordAutofillManager>(
-            mock_password_manager_driver_.get(), &test_autofill_client_,
+            password_manager_driver_.get(), &test_autofill_client_,
             test_pwd_manager_client_.get());
 
-    ON_CALL(*mock_password_manager_driver_, GetPasswordManager())
-        .WillByDefault(Return(password_manager_.get()));
-    ON_CALL(*mock_password_manager_driver_, GetPasswordAutofillManager())
-        .WillByDefault(Return(password_autofill_manager_.get()));
-    ON_CALL(*mock_another_password_manager_driver_, GetPasswordManager())
-        .WillByDefault(Return(password_manager_.get()));
-    ON_CALL(*mock_another_password_manager_driver_,
-            GetPasswordAutofillManager())
-        .WillByDefault(Return(password_autofill_manager_.get()));
-
-    mock_generation_helper_ =
-        std::make_unique<NiceMock<MockPasswordGenerationHelper>>(
-            nullptr, mock_password_manager_driver_.get());
     mock_dialog_ =
         std::make_unique<NiceMock<MockPasswordGenerationDialogView>>();
 
@@ -202,13 +169,23 @@
                 OnAutomaticGenerationStatusChanged(false));
     controller()->FocusedInputChanged(
         FocusedFieldType::kFillablePasswordField,
-        base::AsWeakPtr(mock_password_manager_driver_.get()));
+        base::AsWeakPtr(password_manager_driver_.get()));
   }
 
   PasswordGenerationController* controller() {
     return PasswordGenerationControllerImpl::FromWebContents(web_contents());
   }
 
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+  active_driver() {
+    return base::AsWeakPtr(password_manager_driver_.get());
+  }
+
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+  non_active_driver() {
+    return base::AsWeakPtr(another_password_manager_driver_.get());
+  }
+
   const base::MockCallback<
       PasswordGenerationControllerImpl::CreateDialogFactory>&
   mock_dialog_factory() {
@@ -216,21 +193,11 @@
   }
 
  protected:
-  // Sets up mocks needed by the generation flow and signals the
-  // |PasswordGenerationController| that generation is available.
-  void InitializeAutomaticGeneration(const std::u16string& password);
-
-  // Sets up mocks needed by the generation flow.
-  void InitializeManualGeneration(const std::u16string& password);
-
   StrictMock<MockManualFillingController> mock_manual_filling_controller_;
 
-  std::unique_ptr<NiceMock<MockPasswordManagerDriver>>
-      mock_password_manager_driver_;
-  std::unique_ptr<NiceMock<MockPasswordManagerDriver>>
-      mock_another_password_manager_driver_;
-  std::unique_ptr<NiceMock<MockPasswordGenerationHelper>>
-      mock_generation_helper_;
+  std::unique_ptr<ContentPasswordManagerDriver> password_manager_driver_;
+  std::unique_ptr<ContentPasswordManagerDriver>
+      another_password_manager_driver_;
   std::unique_ptr<NiceMock<MockPasswordGenerationDialogView>> mock_dialog_;
 
  private:
@@ -244,31 +211,6 @@
   autofill::TestAutofillClient test_autofill_client_;
 };
 
-void PasswordGenerationControllerTest::InitializeAutomaticGeneration(
-    const std::u16string& password) {
-  ON_CALL(*mock_password_manager_driver_, GetPasswordGenerationHelper())
-      .WillByDefault(Return(mock_generation_helper_.get()));
-
-  EXPECT_CALL(mock_manual_filling_controller_,
-              OnAutomaticGenerationStatusChanged(true));
-
-  controller()->OnAutomaticGenerationAvailable(
-      mock_password_manager_driver_->AsWeakPtr(), GetTestGenerationUIData1(),
-      gfx::RectF(100, 20));
-
-  ON_CALL(*mock_generation_helper_, GeneratePassword(_, _, _, _))
-      .WillByDefault(Return(password));
-}
-
-void PasswordGenerationControllerTest::InitializeManualGeneration(
-    const std::u16string& password) {
-  ON_CALL(*mock_password_manager_driver_, GetPasswordGenerationHelper())
-      .WillByDefault(Return(mock_generation_helper_.get()));
-
-  ON_CALL(*mock_generation_helper_, GeneratePassword(_, _, _, _))
-      .WillByDefault(Return(password));
-}
-
 TEST_F(PasswordGenerationControllerTest, IsNotRecreatedForSameWebContents) {
   PasswordGenerationController* initial_controller =
       PasswordGenerationControllerImpl::FromWebContents(web_contents());
@@ -282,8 +224,7 @@
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(true));
   controller()->OnAutomaticGenerationAvailable(
-      mock_password_manager_driver_->AsWeakPtr(), GetTestGenerationUIData1(),
-      gfx::RectF(100, 20));
+      active_driver(), GetTestGenerationUIData1(), gfx::RectF(100, 20));
 }
 
 // Tests that if AutomaticGenerationAvailable is called for different
@@ -296,33 +237,25 @@
               OnAutomaticGenerationStatusChanged(true))
       .Times(2);
   controller()->OnAutomaticGenerationAvailable(
-      mock_password_manager_driver_->AsWeakPtr(), GetTestGenerationUIData1(),
-      gfx::RectF(100, 20));
+      active_driver(), GetTestGenerationUIData1(), gfx::RectF(100, 20));
   PasswordGenerationUIData new_ui_data = GetTestGenerationUIData2();
-  controller()->OnAutomaticGenerationAvailable(
-      mock_password_manager_driver_->AsWeakPtr(), new_ui_data,
-      gfx::RectF(100, 20));
+  controller()->OnAutomaticGenerationAvailable(active_driver(), new_ui_data,
+                                               gfx::RectF(100, 20));
 
   autofill::FormSignature form_signature =
       autofill::CalculateFormSignature(new_ui_data.form_data);
   autofill::FieldSignature field_signature =
       autofill::CalculateFieldSignatureByNameAndType(
           new_ui_data.generation_element, "password");
+  EXPECT_EQ(controller()->get_form_signature_for_testing(), form_signature);
+  EXPECT_EQ(controller()->get_field_signature_for_testing(), field_signature);
 
-  std::u16string generated_password = u"t3stp@ssw0rd";
   NiceMock<MockPasswordGenerationDialogView>* raw_dialog_view =
       mock_dialog_.get();
   EXPECT_CALL(mock_dialog_factory(), Run)
       .WillOnce(Return(ByMove(std::move(mock_dialog_))));
-  EXPECT_CALL(*mock_password_manager_driver_, GetPasswordGenerationHelper())
-      .WillOnce(Return(mock_generation_helper_.get()));
-  EXPECT_CALL(*mock_generation_helper_,
-              GeneratePassword(_, form_signature, field_signature,
-                               uint32_t(new_ui_data.max_length)))
-      .WillOnce(Return(generated_password));
   EXPECT_CALL(*raw_dialog_view,
-              Show(generated_password,
-                   PointsToSameAddress(mock_password_manager_driver_.get()),
+              Show(_, PointsToSameAddress(password_manager_driver_.get()),
                    PasswordGenerationType::kAutomatic));
   controller()->OnGenerationRequested(PasswordGenerationType::kAutomatic);
 }
@@ -334,14 +267,12 @@
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(true));
   controller()->OnAutomaticGenerationAvailable(
-      mock_password_manager_driver_->AsWeakPtr(), GetTestGenerationUIData1(),
-      gfx::RectF(100, 20));
+      active_driver(), GetTestGenerationUIData1(), gfx::RectF(100, 20));
 
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
-  controller()->GeneratedPasswordAccepted(
-      u"t3stp@ssw0rd", mock_password_manager_driver_->AsWeakPtr(),
-      PasswordGenerationType::kAutomatic);
+  controller()->GeneratedPasswordAccepted(u"t3stp@ssw0rd", active_driver(),
+                                          PasswordGenerationType::kAutomatic);
 
   histogram_tester.ExpectUniqueSample(
       "KeyboardAccessory.GenerationDialogChoice.Automatic",
@@ -365,19 +296,17 @@
        RecordsGeneratedPasswordAcceptedManual) {
   base::HistogramTester histogram_tester;
 
-  InitializeManualGeneration(u"t3stp@ssw0rd");
   controller()->OnGenerationRequested(PasswordGenerationType::kManual);
 
   EXPECT_CALL(mock_dialog_factory(), Run)
       .WillOnce(Return(ByMove(std::move(mock_dialog_))));
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
 
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
-  controller()->GeneratedPasswordAccepted(
-      u"t3stp@ssw0rd", mock_password_manager_driver_->AsWeakPtr(),
-      PasswordGenerationType::kManual);
+  controller()->GeneratedPasswordAccepted(u"t3stp@ssw0rd", active_driver(),
+                                          PasswordGenerationType::kManual);
 
   histogram_tester.ExpectUniqueSample(
       "KeyboardAccessory.GenerationDialogChoice.Manual",
@@ -408,8 +337,7 @@
       .Times(AtMost(2));
 
   controller()->OnAutomaticGenerationAvailable(
-      mock_another_password_manager_driver_->AsWeakPtr(),
-      GetTestGenerationUIData2(), gfx::RectF(100, 20));
+      non_active_driver(), GetTestGenerationUIData2(), gfx::RectF(100, 20));
 }
 
 TEST_F(PasswordGenerationControllerTest,
@@ -417,9 +345,8 @@
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
 
-  MockPasswordManagerDriver new_driver;
   controller()->FocusedInputChanged(FocusedFieldType::kFillableUsernameField,
-                                    base::AsWeakPtr(&new_driver));
+                                    active_driver());
   EXPECT_FALSE(controller()->GetActiveFrameDriver());
 }
 
@@ -428,15 +355,13 @@
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
 
-  MockPasswordManagerDriver new_driver;
   controller()->FocusedInputChanged(FocusedFieldType::kFillablePasswordField,
-                                    base::AsWeakPtr(&new_driver));
-  EXPECT_EQ(&new_driver, controller()->GetActiveFrameDriver().get());
+                                    non_active_driver());
+  EXPECT_EQ(another_password_manager_driver_.get(),
+            controller()->GetActiveFrameDriver().get());
 }
 
 TEST_F(PasswordGenerationControllerTest, HidesDialogWhenFocusChanges) {
-  std::u16string test_password = u"t3stp@ssw0rd";
-  InitializeManualGeneration(test_password);
   controller()->OnGenerationRequested(PasswordGenerationType::kManual);
 
   NiceMock<MockPasswordGenerationDialogView>* raw_dialog_view =
@@ -444,23 +369,19 @@
   EXPECT_CALL(mock_dialog_factory(), Run)
       .WillOnce(Return(ByMove(std::move(mock_dialog_))));
   EXPECT_CALL(*raw_dialog_view,
-              Show(test_password,
-                   PointsToSameAddress(mock_password_manager_driver_.get()),
+              Show(_, PointsToSameAddress(password_manager_driver_.get()),
                    PasswordGenerationType::kManual));
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
   EXPECT_CALL(*raw_dialog_view, Destroy());
-  controller()->FocusedInputChanged(
-      FocusedFieldType::kFillableUsernameField,
-      mock_another_password_manager_driver_->AsWeakPtr());
+  controller()->FocusedInputChanged(FocusedFieldType::kFillableUsernameField,
+                                    non_active_driver());
   Mock::VerifyAndClearExpectations(raw_dialog_view);
 }
 
 TEST_F(PasswordGenerationControllerTest, ShowManualDialogForActiveFrame) {
-  std::u16string test_password = u"t3stp@ssw0rd";
-  InitializeManualGeneration(test_password);
   controller()->OnGenerationRequested(PasswordGenerationType::kManual);
 
   NiceMock<MockPasswordGenerationDialogView>* raw_dialog_view =
@@ -468,24 +389,20 @@
   EXPECT_CALL(mock_dialog_factory(), Run)
       .WillOnce(Return(ByMove(std::move(mock_dialog_))));
   EXPECT_CALL(*raw_dialog_view,
-              Show(test_password,
-                   PointsToSameAddress(mock_password_manager_driver_.get()),
+              Show(_, PointsToSameAddress(password_manager_driver_.get()),
                    PasswordGenerationType::kManual));
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
 }
 
 TEST_F(PasswordGenerationControllerTest,
        RejectShowManualDialogForNonActiveFrame) {
-  MockPasswordManagerDriver wrong_driver;
   EXPECT_CALL(mock_dialog_factory(), Run).Times(0);
-  controller()->ShowManualGenerationDialog(&wrong_driver,
-                                           GetTestGenerationUIData1());
+  controller()->ShowManualGenerationDialog(
+      another_password_manager_driver_.get(), GetTestGenerationUIData1());
 }
 
 TEST_F(PasswordGenerationControllerTest, DontShowDialogIfAlreadyShown) {
-  std::u16string test_password = u"t3stp@ssw0rd";
-  InitializeManualGeneration(test_password);
   controller()->OnGenerationRequested(PasswordGenerationType::kManual);
 
   NiceMock<MockPasswordGenerationDialogView>* raw_dialog_view =
@@ -494,27 +411,39 @@
       .WillOnce(Return(ByMove(std::move(mock_dialog_))));
 
   EXPECT_CALL(*raw_dialog_view,
-              Show(test_password,
-                   PointsToSameAddress(mock_password_manager_driver_.get()),
+              Show(_, PointsToSameAddress(password_manager_driver_.get()),
                    PasswordGenerationType::kManual));
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
 
   EXPECT_CALL(mock_dialog_factory(), Run).Times(0);
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
 }
 
 TEST_F(PasswordGenerationControllerTest, DontShowManualDialogIfFocusChanged) {
-  InitializeManualGeneration(u"t3stp@ssw0rd");
   controller()->OnGenerationRequested(PasswordGenerationType::kManual);
 
   EXPECT_CALL(mock_manual_filling_controller_,
               OnAutomaticGenerationStatusChanged(false));
-  controller()->FocusedInputChanged(
-      FocusedFieldType::kFillablePasswordField,
-      mock_another_password_manager_driver_->AsWeakPtr());
+  controller()->FocusedInputChanged(FocusedFieldType::kFillablePasswordField,
+                                    non_active_driver());
   EXPECT_CALL(mock_dialog_factory(), Run).Times(0);
-  controller()->ShowManualGenerationDialog(mock_password_manager_driver_.get(),
+  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                            GetTestGenerationUIData1());
 }
+
+TEST_F(PasswordGenerationControllerTest,
+       DoesNotCallKeyboardAccessoryWhenGenerationBottomSheetRequired) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      password_manager::features::kPasswordGenerationBottomSheet);
+
+  // Keyboard accessory shouldn't be called.
+  EXPECT_CALL(mock_manual_filling_controller_,
+              OnAutomaticGenerationStatusChanged)
+      .Times(0);
+  controller()->OnAutomaticGenerationAvailable(
+      active_driver(), GetTestGenerationUIData1(), gfx::RectF(100, 20));
+  controller()->HideBottomSheetIfNeeded();
+}
diff --git a/chrome/browser/password_manager/android/password_generation_dialog_view_interface.h b/chrome/browser/password_manager/android/password_generation_dialog_view_interface.h
index 20fb23d..f60d9ed3 100644
--- a/chrome/browser/password_manager/android/password_generation_dialog_view_interface.h
+++ b/chrome/browser/password_manager/android/password_generation_dialog_view_interface.h
@@ -12,7 +12,7 @@
 class PasswordGenerationController;
 
 namespace password_manager {
-class PasswordManagerDriver;
+class ContentPasswordManagerDriver;
 }  // namespace password_manager
 
 class PasswordGenerationDialogViewInterface {
@@ -27,7 +27,7 @@
   // Used for metrics.
   virtual void Show(
       std::u16string& password,
-      base::WeakPtr<password_manager::PasswordManagerDriver>
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver>
           target_frame_driver,
       autofill::password_generation::PasswordGenerationType type) = 0;
 
diff --git a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
index e7c740f..06a64cd 100644
--- a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
+++ b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
@@ -29,6 +29,7 @@
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 
   deps = [
+    ":java_resources",
     "//base:base_java",
     "//base:jni_java",
     "//components/browser_ui/bottomsheet/android:java",
@@ -41,23 +42,64 @@
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java",
+    "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java",
+    "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java",
   ]
+
+  resources_package = "org.chromium.chrome.browser.pwd_migration"
 }
 
 robolectric_library("junit") {
   testonly = true
 
-  sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerRobolectricTest.java" ]
+  sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java" ]
 
   deps = [
     ":java",
+    "//base:base_java",
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
     "//chrome/test/android:chrome_java_test_support_common",
     "//components/browser_ui/bottomsheet/android:java",
+    "//components/browser_ui/bottomsheet/android/test:java",
+    "//third_party/espresso:espresso_core_java",
     "//third_party/hamcrest:hamcrest_library_java",
     "//third_party/junit:junit",
     "//third_party/mockito:mockito_java",
     "//ui/android:ui_java",
   ]
 }
+
+android_library("javatests") {
+  testonly = true
+  resources_package = "org.chromium.chrome.browser.pwd_migration"
+
+  # Consult izuzic@ before adding more tests to this target.
+  # This target will exist only temporary.
+  sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java" ]
+
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//chrome/android:chrome_java",
+    "//chrome/browser/flags:java",
+    "//chrome/test/android:chrome_java_integration_test_support",
+    "//chrome/test/android:chrome_java_test_support_common",
+    "//components/browser_ui/bottomsheet/android:java",
+    "//components/browser_ui/bottomsheet/android/test:java",
+    "//content/public/test/android:content_java_test_support",
+    "//third_party/android_deps:espresso_java",
+    "//third_party/androidx:androidx_test_core_java",
+    "//third_party/androidx:androidx_test_runner_java",
+    "//third_party/hamcrest:hamcrest_library_java",
+    "//third_party/junit:junit",
+    "//third_party/mockito:mockito_java",
+    "//ui/android:ui_java",
+  ]
+}
+
+android_resources("java_resources") {
+  deps = [ "//ui/android:ui_java_resources" ]
+  sources = [ "java/res/layout/pwd_migration_warning.xml" ]
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
new file mode 100644
index 0000000..ea7c4f2
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<RelativeLayout
+    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_height="wrap_content"
+    android:layout_width="match_parent"
+    android:orientation="vertical"/>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerRobolectricTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java
similarity index 83%
rename from chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerRobolectricTest.java
rename to chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java
index de5352e..54aab2f2 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerRobolectricTest.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java
@@ -4,9 +4,8 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
-import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
 
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
@@ -38,7 +37,7 @@
  */
 @RunWith(BaseRobolectricTestRunner.class)
 @Batch(Batch.PER_CLASS)
-public class PasswordMigrationWarningControllerRobolectricTest {
+public class PasswordMigrationWarningControllerTest {
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
@@ -51,7 +50,7 @@
     @Mock
     private BottomSheetController mBottomSheetController;
 
-    public PasswordMigrationWarningControllerRobolectricTest() {}
+    public PasswordMigrationWarningControllerTest() {}
 
     @Before
     public void setUp() {
@@ -60,13 +59,9 @@
     }
 
     @Test
-    public void testShowWarningUpdatesModel() {
+    public void testCreatesValidDefaultModel() {
         PropertyModel model = mCoordinator.getModelForTesting();
         assertNotNull(model.get(DISMISS_HANDLER));
-        assertThat(model.get(VISIBLE), is(false));
-
-        mCoordinator.showWarning();
-
-        assertThat(model.get(VISIBLE), is(true));
+        assertFalse(model.get(VISIBLE));
     }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
index a4044d27..a774ea9 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
@@ -11,6 +11,7 @@
 
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /** The coordinator of the password migration warning. */
 public class PasswordMigrationWarningCoordinator {
@@ -21,6 +22,8 @@
             @Nullable Context context, BottomSheetController sheetController) {
         mMediator.initialize(
                 PasswordMigrationWarningProperties.createDefaultModel(mMediator::onDismissed));
+        setUpModelChangeProcessors(
+                mMediator.getModel(), new PasswordMigrationWarningView(context, sheetController));
     }
 
     public void showWarning() {
@@ -31,4 +34,9 @@
     PropertyModel getModelForTesting() {
         return mMediator.getModel();
     }
+
+    static void setUpModelChangeProcessors(PropertyModel model, PasswordMigrationWarningView view) {
+        PropertyModelChangeProcessor.create(
+                model, view, PasswordMigrationWarningViewBinder::bindPasswordMigrationWarningView);
+    }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
new file mode 100644
index 0000000..6749e9b
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
@@ -0,0 +1,134 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.Callback;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
+
+/**
+ * This class is responsible for rendering the bottom sheet that shows the passwords
+ * migration warning.
+ */
+class PasswordMigrationWarningView implements BottomSheetContent {
+    private final BottomSheetController mBottomSheetController;
+    private Callback<Integer> mDismissHandler;
+    private final RelativeLayout mContentView;
+
+    private final BottomSheetObserver mBottomSheetObserver = new EmptyBottomSheetObserver() {
+        @Override
+        public void onSheetClosed(@BottomSheetController.StateChangeReason int reason) {
+            super.onSheetClosed(reason);
+            assert mDismissHandler != null;
+            mDismissHandler.onResult(reason);
+            mBottomSheetController.removeObserver(mBottomSheetObserver);
+        }
+
+        @Override
+        public void onSheetStateChanged(int newState, int reason) {
+            super.onSheetStateChanged(newState, reason);
+            if (newState != BottomSheetController.SheetState.HIDDEN) return;
+            // This is a fail-safe for cases where onSheetClosed isn't triggered.
+            mDismissHandler.onResult(BottomSheetController.StateChangeReason.NONE);
+            mBottomSheetController.removeObserver(mBottomSheetObserver);
+        }
+    };
+
+    PasswordMigrationWarningView(Context context, BottomSheetController bottomSheetController) {
+        mBottomSheetController = bottomSheetController;
+        mContentView = (RelativeLayout) LayoutInflater.from(context).inflate(
+                R.layout.pwd_migration_warning, null);
+    }
+
+    void setDismissHandler(Callback<Integer> dismissHandler) {
+        mDismissHandler = dismissHandler;
+    }
+
+    boolean setVisible(boolean isVisible) {
+        if (!isVisible) {
+            mBottomSheetController.hideContent(this, true);
+            return true;
+        }
+        mBottomSheetController.addObserver(mBottomSheetObserver);
+        if (!mBottomSheetController.requestShowContent(this, true)) {
+            mBottomSheetController.removeObserver(mBottomSheetObserver);
+            return false;
+        }
+        return true;
+    }
+
+    @Nullable
+    @Override
+    public View getContentView() {
+        return mContentView;
+    }
+
+    @Nullable
+    @Override
+    public View getToolbarView() {
+        return null;
+    }
+
+    @Override
+    public int getVerticalScrollOffset() {
+        return 0;
+    }
+
+    @Override
+    public void destroy() {}
+
+    @Override
+    public int getPriority() {
+        return BottomSheetContent.ContentPriority.HIGH;
+    }
+
+    @Override
+    public boolean swipeToDismissEnabled() {
+        return false;
+    }
+
+    @Override
+    public int getSheetContentDescriptionStringId() {
+        // TODO(crbug.com/1440104): Introduce and use proper string.
+        return android.R.string.ok;
+    }
+
+    @Override
+    public int getSheetHalfHeightAccessibilityStringId() {
+        // TODO(crbug.com/1440104): Introduce and use proper string.
+        return android.R.string.ok;
+    }
+
+    @Override
+    public int getSheetFullHeightAccessibilityStringId() {
+        // TODO(crbug.com/1440104): Introduce and use proper string.
+        return android.R.string.ok;
+    }
+
+    @Override
+    public int getSheetClosedAccessibilityStringId() {
+        // TODO(crbug.com/1440104): Introduce and use proper string.
+        return android.R.string.ok;
+    }
+
+    @Override
+    public float getHalfHeightRatio() {
+        return HeightMode.DISABLED;
+    }
+
+    @Override
+    public int getPeekHeight() {
+        return HeightMode.DISABLED;
+    }
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java
new file mode 100644
index 0000000..ba17aa65
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
+
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Provides functions that map {@link PasswordMigrationWarningProperties} changes in a {@link
+ * PropertyModel} to the suitable method in {@link PasswordMigrationWarningView}.
+ */
+class PasswordMigrationWarningViewBinder {
+    /**
+     * Called whenever a property in the given model changes. It updates the given view accordingly.
+     * @param model The observed {@link PropertyModel}. Its data need to be reflected in the view.
+     * @param view The {@link PasswordMigrationWarningView} to update.
+     * @param propertyKey The {@link PropertyKey} which changed.
+     */
+    static void bindPasswordMigrationWarningView(
+            PropertyModel model, PasswordMigrationWarningView view, PropertyKey propertyKey) {
+        if (propertyKey == DISMISS_HANDLER) {
+            view.setDismissHandler(model.get(DISMISS_HANDLER));
+        } else if (propertyKey == VISIBLE) {
+            boolean visibilityChangeSuccessful = view.setVisible(model.get(VISIBLE));
+            if (!visibilityChangeSuccessful && model.get(VISIBLE)) {
+                assert model.get(DISMISS_HANDLER) != null;
+                model.get(DISMISS_HANDLER).onResult(BottomSheetController.StateChangeReason.NONE);
+            }
+        } else {
+            assert false : "Unhandled update to property:" + propertyKey;
+        }
+    }
+
+    private PasswordMigrationWarningViewBinder() {}
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java
new file mode 100644
index 0000000..66a8f12a
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java
@@ -0,0 +1,104 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
+
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.verify;
+
+import static org.chromium.base.test.util.CriteriaHelper.pollUiThread;
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
+import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import org.chromium.base.Callback;
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+/** Tests for {@link PasswordMigrationWarningView} */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@Batch(Batch.PER_CLASS)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class PasswordMigrationWarningViewTest {
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    @Mock
+    private Callback<Integer> mDismissCallback;
+
+    private BottomSheetController mBottomSheetController;
+    private PasswordMigrationWarningView mView;
+    private PropertyModel mModel;
+
+    @Before
+    public void setupTest() throws InterruptedException {
+        MockitoAnnotations.initMocks(this);
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mBottomSheetController = mActivityTestRule.getActivity()
+                                         .getRootUiCoordinatorForTesting()
+                                         .getBottomSheetController();
+        runOnUiThreadBlocking(() -> {
+            mModel = PasswordMigrationWarningProperties.createDefaultModel(mDismissCallback);
+            mView = new PasswordMigrationWarningView(
+                    mActivityTestRule.getActivity(), mBottomSheetController);
+            PropertyModelChangeProcessor.create(mModel, mView,
+                    PasswordMigrationWarningViewBinder::bindPasswordMigrationWarningView);
+        });
+    }
+
+    @Test
+    @MediumTest
+    public void testVisibilityChangedByModel() {
+        // After setting the visibility to true, the view should exist and be visible.
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true));
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+        assertThat(mView.getContentView().isShown(), is(true));
+
+        // After hiding the view, the view should still exist but be invisible.
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, false));
+        pollUiThread(() -> getBottomSheetState() == BottomSheetController.SheetState.HIDDEN);
+        assertThat(mView.getContentView().isShown(), is(false));
+    }
+
+    @Test
+    @MediumTest
+    public void testDismissesWhenHidden() {
+        // The sheet is shown.
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true));
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+        // The sheet is hidden.
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, false));
+        pollUiThread(() -> getBottomSheetState() == BottomSheetController.SheetState.HIDDEN);
+
+        // The dismiss callback was called.
+        verify(mDismissCallback).onResult(BottomSheetController.StateChangeReason.NONE);
+    }
+
+    private @SheetState int getBottomSheetState() {
+        return mBottomSheetController.getSheetState();
+    }
+}
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 1190405..580e4156 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -135,6 +135,7 @@
 #include "chrome/browser/password_manager/android/password_generation_controller.h"
 #include "chrome/browser/password_manager/android/password_manager_launcher_android.h"
 #include "chrome/browser/password_manager/android/password_manager_ui_util_android.h"
+#include "chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h"
 #include "chrome/browser/touch_to_fill/touch_to_fill_controller.h"
 #include "chrome/browser/touch_to_fill/touch_to_fill_controller_autofill_delegate.h"
 #include "components/messages/android/messages_feature.h"
@@ -1007,7 +1008,7 @@
       ui_data.bounds);
 
   generation_controller->OnAutomaticGenerationAvailable(
-      driver->AsWeakPtr(), ui_data, element_bounds_in_screen_space);
+      base::AsWeakPtr(driver), ui_data, element_bounds_in_screen_space);
 #else
   password_manager::ContentPasswordManagerDriver* driver =
       driver_factory_->GetDriverForFrame(rfh);
@@ -1306,6 +1307,19 @@
   HideFillingUI();
 }
 
+void ChromePasswordManagerClient::RenderFrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+#if BUILDFLAG(IS_ANDROID)
+  PasswordGenerationController* generation_controller =
+      PasswordGenerationController::GetIfExisting(web_contents());
+  // If the render frame for which the password generation was offered is
+  // deleted then hide the UI.
+  if (generation_controller) {
+    generation_controller->RenderFrameDeleted(render_frame_host);
+  }
+#endif  // BUILDFLAG(IS_ANDROID)
+}
+
 void ChromePasswordManagerClient::WebContentsDestroyed() {
   // crbug/1090011
   // Drop the connection before the WebContentsObserver destructors are invoked.
@@ -1336,6 +1350,12 @@
   // Hides all the manual filling UI if the controller already exists.
   if (mf_controller)
     mf_controller->Hide();
+
+  PasswordGenerationController* generation_controller =
+      PasswordGenerationController::GetIfExisting(web_contents());
+  if (generation_controller) {
+    generation_controller->HideBottomSheetIfNeeded();
+  }
 #endif  // BUILDFLAG(IS_ANDROID)
 }
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 2cc8975..efc3a3a 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -320,6 +320,7 @@
 
   // content::WebContentsObserver overrides.
   void PrimaryPageChanged(content::Page& page) override;
+  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void WebContentsDestroyed() override;
 
   // Given |bounds| in the renderers coordinate system, return the same bounds
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 8ad85828..65302e1 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -1073,7 +1073,7 @@
   PasswordGenerationController* pwd_generation_controller =
       PasswordGenerationController::GetOrCreate(web_contents());
   pwd_generation_controller->FocusedInputChanged(
-      FocusedFieldType::kFillablePasswordField, driver.get()->AsWeakPtr());
+      FocusedFieldType::kFillablePasswordField, base::AsWeakPtr(driver.get()));
 
   ChromePasswordManagerClient* client = GetClient();
 
diff --git a/chrome/browser/password_manager/password_manager_settings_service_factory.cc b/chrome/browser/password_manager/password_manager_settings_service_factory.cc
index 5f7a249..f136f6d 100644
--- a/chrome/browser/password_manager/password_manager_settings_service_factory.cc
+++ b/chrome/browser/password_manager/password_manager_settings_service_factory.cc
@@ -39,7 +39,12 @@
           // used, but since this service is used to access settings which are
           // not specific to incognito the service can still be used as for the
           // regular profile.
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
 #if BUILDFLAG(IS_ANDROID)
   // The sync status is necessary on Android to decide which prefs to check.
   DependsOn(SyncServiceFactory::GetInstance());
diff --git a/chrome/browser/password_manager/password_reuse_manager_factory.cc b/chrome/browser/password_manager/password_reuse_manager_factory.cc
index ac0bbe7..34e4a3c 100644
--- a/chrome/browser/password_manager/password_reuse_manager_factory.cc
+++ b/chrome/browser/password_manager/password_reuse_manager_factory.cc
@@ -44,7 +44,12 @@
 PasswordReuseManagerFactory::PasswordReuseManagerFactory()
     : ProfileKeyedServiceFactory(
           "PasswordReuseManager",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(PasswordStoreFactory::GetInstance());
   DependsOn(AccountPasswordStoreFactory::GetInstance());
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 22c6c21..7a830f0 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -58,7 +58,12 @@
 PasswordStoreFactory::PasswordStoreFactory()
     : RefcountedProfileKeyedServiceFactory(
           "PasswordStore",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(AffiliationServiceFactory::GetInstance());
   DependsOn(AffiliationsPrefetcherFactory::GetInstance());
   DependsOn(CredentialsCleanerRunnerFactory::GetInstance());
diff --git a/chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.cc b/chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.cc
index 45d845e7..eb74a1093 100644
--- a/chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.cc
+++ b/chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.cc
@@ -103,7 +103,12 @@
 AdaptiveQuietNotificationPermissionUiEnabler::Factory::Factory()
     : ProfileKeyedServiceFactory(
           "AdaptiveQuietNotificationPermissionUiEnabler",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(HostContentSettingsMapFactory::GetInstance());
 }
 
diff --git a/chrome/browser/plugins/plugin_prefs_factory.cc b/chrome/browser/plugins/plugin_prefs_factory.cc
index 73f0635..c3d5b95 100644
--- a/chrome/browser/plugins/plugin_prefs_factory.cc
+++ b/chrome/browser/plugins/plugin_prefs_factory.cc
@@ -36,7 +36,12 @@
 PluginPrefsFactory::PluginPrefsFactory()
     : RefcountedProfileKeyedServiceFactory(
           "PluginPrefs",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 PluginPrefsFactory::~PluginPrefsFactory() {}
 
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
index 79d35675..15650c2 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
@@ -721,6 +721,27 @@
     return;
   }
 
+  // Check for users waiting for graduation: If a user was ever reported as both
+  // restricted and unrestricted it means they are ready for graduation.
+  const bool restricted_notice_acknowledged = pref_service_->GetBoolean(
+      prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged);
+  const bool user_reported_restricted =
+      pref_service_->GetBoolean(prefs::kPrivacySandboxM1Restricted);
+  const bool user_reported_unrestricted =
+      pref_service_->GetBoolean(prefs::kPrivacySandboxM1Unrestricted);
+
+  if (user_reported_restricted && user_reported_unrestricted) {
+    base::UmaHistogramEnumeration(
+        privacy_sandbox_prompt_startup_histogram,
+        restricted_notice_acknowledged
+            ? PromptStartupState::
+                  kWaitingForGraduationRestrictedNoticeFlowCompleted
+            : PromptStartupState::
+                  kWaitingForGraduationRestrictedNoticeFlowNotCompleted);
+
+    return;
+  }
+
   const bool row_notice_acknowledged =
       pref_service_->GetBoolean(prefs::kPrivacySandboxM1RowNoticeAcknowledged);
   const bool eaa_notice_acknowledged =
@@ -730,9 +751,6 @@
   // required when the restricted prompt is shown, and both return
   // unconditionally.
   if (privacy_sandbox_settings_->IsSubjectToM1NoticeRestricted()) {
-    const bool restricted_notice_acknowledged = pref_service_->GetBoolean(
-        prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged);
-
     // Acknowledgement of any of the prompt types implies acknowledgement of the
     // restricted notice as well.
     if (row_notice_acknowledged || eaa_notice_acknowledged) {
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
index 0ad5c2ee..fc392af 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
@@ -388,6 +388,8 @@
   FRIEND_TEST_ALL_PREFIXES(
       PrivacySandboxServiceM1RestrictedNoticePromptTest,
       RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed);
+  FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceM1RestrictedNoticePromptTest,
+                           RecordPrivacySandbox4StartupMetrics_GraduationFlow);
 
   // Should be used only for tests when mocking the service.
   PrivacySandboxService();
@@ -477,10 +479,12 @@
     kRestrictedNoticePromptWaiting = 12,
     kRestrictedNoticeFlowCompleted = 13,
     kRestrictedNoticeNotShownDueToFullNoticeAcknowledged = 14,
+    kWaitingForGraduationRestrictedNoticeFlowNotCompleted = 15,
+    kWaitingForGraduationRestrictedNoticeFlowCompleted = 16,
 
     // Add values above this line with a corresponding label in
     // tools/metrics/histograms/enums.xml
-    kMaxValue = kRestrictedNoticeNotShownDueToFullNoticeAcknowledged,
+    kMaxValue = kWaitingForGraduationRestrictedNoticeFlowCompleted,
   };
 
   // Helper function to log first party sets state.
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
index 39f505d..ed62eadc 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
@@ -4424,6 +4424,87 @@
       /*expected_count=*/2);
 }
 
+TEST_F(PrivacySandboxServiceM1RestrictedNoticePromptTest,
+       RecordPrivacySandbox4StartupMetrics_GraduationFlow) {
+  const std::string privacy_sandbox_prompt_startup_histogram =
+      "Settings.PrivacySandbox.PromptStartupState";
+
+  // Ensure prompt not suppressed.
+  prefs()->SetInteger(
+      prefs::kPrivacySandboxM1PromptSuppressed,
+      static_cast<int>(PrivacySandboxService::PromptSuppressedReason::kNone));
+
+  // Restricted Notice flow NOT completed & user ready for graduation.
+  {
+    base::HistogramTester histogram_tester;
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
+                        false);
+    // User waiting for graduation
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Unrestricted, true);
+
+    privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
+    histogram_tester.ExpectBucketCount(
+        privacy_sandbox_prompt_startup_histogram,
+        static_cast<int>(
+            PrivacySandboxService::PromptStartupState::
+                kWaitingForGraduationRestrictedNoticeFlowNotCompleted),
+        /*expected_count=*/1);
+  }
+
+  // Restricted Notice flow completed & user ready for graduation.
+  {
+    base::HistogramTester histogram_tester;
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
+                        true);
+    // User waiting for graduation
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Unrestricted, true);
+
+    privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
+    histogram_tester.ExpectBucketCount(
+        privacy_sandbox_prompt_startup_histogram,
+        static_cast<int>(
+            PrivacySandboxService::PromptStartupState::
+                kWaitingForGraduationRestrictedNoticeFlowCompleted),
+        /*expected_count=*/1);
+  }
+
+  // Restricted Notice flow completed & user NOT ready for graduation.
+  {
+    base::HistogramTester histogram_tester;
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
+                        true);
+    // User NOT waiting for graduation
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Unrestricted, false);
+
+    privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
+    histogram_tester.ExpectBucketCount(
+        privacy_sandbox_prompt_startup_histogram,
+        static_cast<int>(PrivacySandboxService::PromptStartupState::
+                             kRestrictedNoticeFlowCompleted),
+        /*expected_count=*/1);
+  }
+
+  // Restricted Notice flow NOT completed & user NOT ready for graduation.
+  {
+    base::HistogramTester histogram_tester;
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1RestrictedNoticeAcknowledged,
+                        false);
+    // User NOT waiting for graduation
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Restricted, true);
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1Unrestricted, false);
+
+    privacy_sandbox_service()->RecordPrivacySandbox4StartupMetrics();
+    histogram_tester.ExpectBucketCount(
+        privacy_sandbox_prompt_startup_histogram,
+        static_cast<int>(PrivacySandboxService::PromptStartupState::
+                             kRestrictedNoticePromptWaiting),
+        /*expected_count=*/1);
+  }
+}
+
 class PrivacySandboxServiceM1RestrictedNoticeShownToGuardianTest
     : public PrivacySandboxServiceM1PromptTest {
  public:
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
index 7ea32c9e..fa13b63 100644
--- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc
+++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -149,15 +149,10 @@
     // tests. If a feature is integrated in the fieldtrial_testing_config.json,
     // it might not be considered under an official build. Adding it under a
     // InitWithFeatures to activate it would neglect that difference.
-    //
-    // Force init `kSystemProfileSelectionDefaultNone` to make sure that this
-    // test catches all new creation of services for System Profile, even during
-    // the transition period when the feature experiment is partially active.
-    //
+
     // clang-format off
     feature_list_.InitWithFeatures(
         {
-          kSystemProfileSelectionDefaultNone,
 #if !BUILDFLAG(IS_ANDROID)
           features::kTrustSafetySentimentSurvey,
 #endif  // !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/profiles/profile_keyed_service_factory.h b/chrome/browser/profiles/profile_keyed_service_factory.h
index f674426..8e13d1f1 100644
--- a/chrome/browser/profiles/profile_keyed_service_factory.h
+++ b/chrome/browser/profiles/profile_keyed_service_factory.h
@@ -36,7 +36,7 @@
 //   MyRedirectingKeyedServiceFactory()
 //       : ProfileKeyedServiceFactory(
 //             "MyRedirectingKeyedService",
-//             ProfileSelections::BuildRedirectedInIncognitoNonExperimental())
+//             ProfileSelections::BuildRedirectedInIncognito())
 //             {}
 //   }
 // };
diff --git a/chrome/browser/profiles/profile_keyed_service_factory.md b/chrome/browser/profiles/profile_keyed_service_factory.md
index 0779b95..a11a754 100644
--- a/chrome/browser/profiles/profile_keyed_service_factory.md
+++ b/chrome/browser/profiles/profile_keyed_service_factory.md
@@ -27,7 +27,6 @@
 services with no checks on profile types, meaning that most existing services
 are created for mostly all profile types. Changing the default behavior per
 profile type allows for a clearer and better targeted usage of KeyedServices.
-This is done through experiments described below.
 
 This work is mirrored on to `RefCountedProfileKeyedServiceFactory` for keyed
 services that are ref counted.
@@ -114,61 +113,12 @@
 
 The default values that are set are:
 - Regular Profile: kOriginalOnly.
-- Guest Profile: Follows Regular Profile value unless the corresponding
-experiment is active (details below).
-- System Profile: Follows Regular Profile value unless the corresponding
-experiment is active (details below).
+- Guest Profile: kNone
+- System Profile: kNone
 - Ash Internal Profiles: Follows Regular Profile value.
 
-`ProfileSelections` also has some predefined static builders in its interface,
-initially those were created to accommodate easily for the experiemnts that are
-running (introducing force values to bypass the experiemnts). However it is
-recommended that any value that needs to be set (different that the default one)
-to be explicitly stated, and not creating a new static predefined builder for
-that.
-
-## Experiments and default behaviors for irregular Profiles
-
-Given that a lot of existing keyed services are created for non regular profiles
-because of the previous default behavior, it is a complex and risky transition
-to do when trying to remove or add services for some profiles.
-
-- System Profile:
-
-The target of the experiment is on the System Profile. Analysis showed that most
-services should not be needed on the System Profile. The following experiment
-goal is to default the System Profile `ProfileSelection` to
-`ProfileSelection::kNone` so that no services will be created, unless explicitly
-stated.
-
-`kSystemProfileSelectionDefaultNone`: When enabled, this feature flag changes
-the default `ProfileSelection` for the System Profile to be `kNone`. When the
-feature flag is disabled, the previous behavior remains: which is following the
-same behavior as the Regular Profile. This approach considers that no keyed
-service is needed unless proven otherwise.
-Force values on experimental builders can be used to easily bypass the
-experiment. If set to true, enforce the value set to the Regular Profile to also
-affect the System Profile so that the experiment condition is bypassed.
-
-- Guest Profile:
-
-For Guest Profile type, analysis showed that more services are actually needed,
-and we have no generic or easy way to determine which ones are needed.
-Therefore we cannot use the same approach with the same kind of exeperiment on
-affecting default value directly.
-
-However, work has been done to turn the default value to
-`ProfileSelection::kNone`, but keeping all existing factories have the same
-behavior, most of the time following the value set to the Regular Profile (which
-was the old default behavior), by using a specific set of "experimental"
-`ProfileSelection::Builder` with force values. This way future factories have to
-explicitly state the fact they have to construct services for the Guest Profile
-(preferably not using the experimental builders).
-By default all existing force values in experimental builders are set to true,
-setting them to false will stop creating the service for the Guest Profile.
-
-### Experiment status
-- `kSystemProfileSelectionDefaultNone`: Experiment started: [Bug](crbug/1376461).
+`ProfileSelections` also has some predefined static builders in its interface
+that provides common usages with standard behaviors.
 
 ### Future work
 It seems that the Ash internal profiles are very similar to the System Profile,
diff --git a/chrome/browser/profiles/profile_keyed_service_factory_unittest.cc b/chrome/browser/profiles/profile_keyed_service_factory_unittest.cc
index 511ac4d3..87b6341 100644
--- a/chrome/browser/profiles/profile_keyed_service_factory_unittest.cc
+++ b/chrome/browser/profiles/profile_keyed_service_factory_unittest.cc
@@ -64,27 +64,11 @@
   }
 };
 
-// Param:
-// - bool system_experiment: used to activate/deactivate the
-// `kSystemProfileSelectionDefaultNone` experiment.
-class ProfileKeyedServiceFactoryUnittest
-    : public testing::Test,
-      public ::testing::WithParamInterface<bool> {
+class ProfileKeyedServiceFactoryUnittest : public testing::Test {
  public:
   void SetUp() override {
     testing::Test::SetUp();
     profile_testing_helper_.SetUp();
-
-    // TODO(rsult): move the below code to be in the
-    // `ProfileSelectionsTestWithParams` constructor, once the System and Guest
-    // Profiles can be created with the experiment activated.
-    bool activate_system_experiment = GetParam();
-    std::vector<base::test::FeatureRef> enabled_features;
-    std::vector<base::test::FeatureRef> disabled_features;
-    activate_system_experiment
-        ? enabled_features.push_back(kSystemProfileSelectionDefaultNone)
-        : disabled_features.push_back(kSystemProfileSelectionDefaultNone);
-    feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
  protected:
@@ -96,10 +80,6 @@
               expected_profile);
   }
 
-  bool IsSystemExperimentActive() const {
-    return base::FeatureList::IsEnabled(kSystemProfileSelectionDefaultNone);
-  }
-
   TestingProfile* regular_profile() {
     return profile_testing_helper_.regular_profile();
   }
@@ -134,7 +114,7 @@
   DefaultFactoryTest() : ProfileKeyedServiceFactoryTest("DefaultFactory") {}
 };
 
-TEST_P(ProfileKeyedServiceFactoryUnittest, DefaultFactoryTest) {
+TEST_F(ProfileKeyedServiceFactoryUnittest, DefaultFactoryTest) {
   DefaultFactoryTest factory;
   TestProfileToUse(factory, regular_profile(), regular_profile());
   TestProfileToUse(factory, incognito_profile(), nullptr);
@@ -143,9 +123,7 @@
   TestProfileToUse(factory, guest_profile_otr(), nullptr);
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileToUse(factory, system_profile(),
-                   system_experiment ? nullptr : system_profile());
+  TestProfileToUse(factory, system_profile(), nullptr);
   TestProfileToUse(factory, system_profile_otr(), nullptr);
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
 }
@@ -154,47 +132,24 @@
 class PredefinedProfileSelectionsFactoryTest
     : public ProfileKeyedServiceFactoryTest {
  public:
-  // Simulates the normal default value for Guest Profile. Guest Profile will
-  // then follow the behavior of the Regular Profile.
-  explicit PredefinedProfileSelectionsFactoryTest(bool force_guest = true)
+  PredefinedProfileSelectionsFactoryTest()
       : ProfileKeyedServiceFactoryTest(
             "PredefinedProfileSelectionsFactoryTest",
-            ProfileSelections::BuildRedirectedInIncognito(force_guest)) {}
+            ProfileSelections::BuildRedirectedInIncognito()) {}
 };
 
-TEST_P(ProfileKeyedServiceFactoryUnittest,
+TEST_F(ProfileKeyedServiceFactoryUnittest,
        PredefinedProfileSelectionsFactoryTest) {
   PredefinedProfileSelectionsFactoryTest factory;
   TestProfileToUse(factory, regular_profile(), regular_profile());
   TestProfileToUse(factory, incognito_profile(), regular_profile());
 
-  TestProfileToUse(factory, guest_profile(), guest_profile());
-  TestProfileToUse(factory, guest_profile_otr(), guest_profile());
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileToUse(factory, system_profile(),
-                   system_experiment ? nullptr : system_profile());
-  TestProfileToUse(factory, system_profile_otr(),
-                   system_experiment ? nullptr : system_profile());
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-}
-
-TEST_P(ProfileKeyedServiceFactoryUnittest,
-       PredefinedProfileSelectionsFactoryTest_WithForceGuestFalse) {
-  PredefinedProfileSelectionsFactoryTest factory(/*force_guest=*/false);
-  TestProfileToUse(factory, regular_profile(), regular_profile());
-  TestProfileToUse(factory, incognito_profile(), regular_profile());
-
   TestProfileToUse(factory, guest_profile(), nullptr);
   TestProfileToUse(factory, guest_profile_otr(), nullptr);
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileToUse(factory, system_profile(),
-                   system_experiment ? nullptr : system_profile());
-  TestProfileToUse(factory, system_profile_otr(),
-                   system_experiment ? nullptr : system_profile());
+  TestProfileToUse(factory, system_profile(), nullptr);
+  TestProfileToUse(factory, system_profile_otr(), nullptr);
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
 }
 
@@ -213,7 +168,7 @@
                 .Build()) {}
 };
 
-TEST_P(ProfileKeyedServiceFactoryUnittest,
+TEST_F(ProfileKeyedServiceFactoryUnittest,
        CustomizedProfileSelectionsFactoryTest) {
   CustomizedProfileSelectionsFactoryTest factory;
   TestProfileToUse(factory, regular_profile(), regular_profile());
@@ -237,7 +192,7 @@
             "DefaultRefcountedFactoryTest") {}
 };
 
-TEST_P(ProfileKeyedServiceFactoryUnittest, DefaultRefcountedFactoryTest) {
+TEST_F(ProfileKeyedServiceFactoryUnittest, DefaultRefcountedFactoryTest) {
   DefaultRefcountedFactoryTest factory;
   TestProfileToUse(factory, regular_profile(), regular_profile());
   TestProfileToUse(factory, incognito_profile(), nullptr);
@@ -246,9 +201,7 @@
   TestProfileToUse(factory, guest_profile_otr(), nullptr);
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileToUse(factory, system_profile(),
-                   system_experiment ? nullptr : system_profile());
+  TestProfileToUse(factory, system_profile(), nullptr);
   TestProfileToUse(factory, system_profile_otr(), nullptr);
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
 }
@@ -268,7 +221,7 @@
                 .Build()) {}
 };
 
-TEST_P(ProfileKeyedServiceFactoryUnittest,
+TEST_F(ProfileKeyedServiceFactoryUnittest,
        PredefinedRefcountedProfileSelectionsFactoryTest) {
   PredefinedRefcountedProfileSelectionsFactoryTest factory;
   TestProfileToUse(factory, regular_profile(), regular_profile());
@@ -278,14 +231,7 @@
   TestProfileToUse(factory, guest_profile_otr(), guest_profile_otr());
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileToUse(factory, system_profile(),
-                   system_experiment ? nullptr : system_profile());
-  TestProfileToUse(factory, system_profile_otr(),
-                   system_experiment ? nullptr : system_profile_otr());
+  TestProfileToUse(factory, system_profile(), nullptr);
+  TestProfileToUse(factory, system_profile_otr(), nullptr);
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
 }
-
-INSTANTIATE_TEST_SUITE_P(ExperimentalProfileKeyedServiceFactory,
-                         ProfileKeyedServiceFactoryUnittest,
-                         ::testing::Bool());
diff --git a/chrome/browser/profiles/profile_selections.cc b/chrome/browser/profiles/profile_selections.cc
index 02d2775f..725d7b3 100644
--- a/chrome/browser/profiles/profile_selections.cc
+++ b/chrome/browser/profiles/profile_selections.cc
@@ -13,20 +13,13 @@
 #include "chrome/common/chrome_constants.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-BASE_FEATURE(kSystemProfileSelectionDefaultNone,
-             "SystemProfileSelectionDefaultNone",
-             base::FeatureState::FEATURE_ENABLED_BY_DEFAULT);
-
 bool AreKeyedServicesDisabledForProfileByDefault(const Profile* profile) {
+  // By default disable all services for System Profile.
+  // Even though having no services is also the default value for Guest Profile,
+  // this is not really the case in practice because a lot of Service Factories
+  // override the default value for the `ProfileSelection` of the Guest Profile.
   if (profile && profile->IsSystemProfile()) {
-    // The default behavior of the system profile selection depends on the value
-    // of `kSystemProfileSelectionDefaultNone` feature flag.
-    ProfileSelection system_profile_default =
-        base::FeatureList::IsEnabled(kSystemProfileSelectionDefaultNone)
-            ? ProfileSelections::kSystemProfileExperimentDefault
-            : ProfileSelections::kRegularProfileDefault;
-
-    return system_profile_default == ProfileSelection::kNone;
+    return true;
   }
 
   return false;
@@ -109,8 +102,7 @@
       .Build();
 }
 
-ProfileSelections
-ProfileSelections::BuildRedirectedInIncognitoNonExperimental() {
+ProfileSelections ProfileSelections::BuildRedirectedInIncognito() {
   return ProfileSelections::Builder()
       .WithRegular(ProfileSelection::kRedirectedToOriginal)
       .WithGuest(ProfileSelection::kNone)
@@ -126,18 +118,6 @@
       .Build();
 }
 
-ProfileSelections ProfileSelections::BuildRedirectedInIncognito(
-    bool force_guest,
-    bool force_system) {
-  Builder builder;
-  builder.WithRegular(ProfileSelection::kRedirectedToOriginal);
-  if (force_guest)
-    builder.WithGuest(ProfileSelection::kRedirectedToOriginal);
-  if (force_system)
-    builder.WithSystem(ProfileSelection::kRedirectedToOriginal);
-  return builder.Build();
-}
-
 Profile* ProfileSelections::ApplyProfileSelection(Profile* profile) const {
   DCHECK(profile);
 
@@ -186,20 +166,10 @@
   }
 
   if (profile->IsSystemProfile()) {
-    // Default value depends on the experiment
-    // `kSystemProfileSelectionDefaultNone`. If experiment is active default
-    // value is ProfileSelection::kNone, otherwise the behavior is redirected to
-    // the `regular_profile_selection_` value (old default behavior).
-    ProfileSelection system_profile_default =
-        base::FeatureList::IsEnabled(kSystemProfileSelectionDefaultNone)
-            ? ProfileSelections::kSystemProfileExperimentDefault
-            : regular_profile_selection_;
-
-    // If the value for SystemProfileSelection is set, use it.
-    // Otherwise, use the default value set above.
-    // This is used for both original system profile (not user visible) and for
-    // the off-the-record system profile (used in the Profile Picker).
-    return system_profile_selection_.value_or(system_profile_default);
+    // If a value is not set for the System Profile Selection,
+    // `ProfileSelection::kNone` is set by default, meaning no profile will be
+    // selected.
+    return system_profile_selection_.value_or(ProfileSelection::kNone);
   }
 
   NOTREACHED();
diff --git a/chrome/browser/profiles/profile_selections.h b/chrome/browser/profiles/profile_selections.h
index e208532e..bab827bb 100644
--- a/chrome/browser/profiles/profile_selections.h
+++ b/chrome/browser/profiles/profile_selections.h
@@ -9,31 +9,18 @@
 
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-// This feature flag will change the default beahvoir of
-// `ProfileSelections::system_profile_selection_` when the value is not set. The
-// old behavior simply follows `regular_profile_selection_` value, with the
-// experiment active the default value will be `ProfileSelection::kNone`,
-// meaning the default ProfileSelection for System Profile will be no profile.
-// This feature flag will only affect builders that has are marked as
-// `Experimental Builders` below, and any customized builder that will not
-// explicitly use `ProfileSelections::Builder::WithSystem()`.
-BASE_DECLARE_FEATURE(kSystemProfileSelectionDefaultNone);
-
 class Profile;
 
 // A helper function that checks whether Keyed Services should be created for
-// the given `profile` based on the default profile type value. Currently checks
-// if it is the System Profile and if it's equivalent feature flag to disable
-// the creation of Keyed Services (`kSystemProfileSelectionDefaultNone`) is
-// activated.
+// the given `profile` based on the default profile type value. Currently only
+// returns true for a valid System Profile.
+// This method is intended to be used only to bypass multiple factory/service
+// checks.
 bool AreKeyedServicesDisabledForProfileByDefault(const Profile* profile);
 
 // The class `ProfileSelections` and enum `ProfileSelection` are not coupled
-// with the usage of `ProfileKeyedServiceFactory`, however the experiment of
-// changing the default value of `ProfileSelections` behavior is mainly done for
-// the `ProfileKeyedServiceFactory`.
-// If other usages are needed it is best not to use the builders that contains
-// experimental code (mentioned below).
+// with the usage of `ProfileKeyedServiceFactory` and can be used separately to
+// filter out profiles based on their types.
 
 // Enum used to map the logic of selecting the right profile based on the given
 // profile.
@@ -56,12 +43,8 @@
   ProfileSelections(const ProfileSelections& other);
   ~ProfileSelections();
 
-  static const ProfileSelection kRegularProfileDefault =
-      ProfileSelection::kOriginalOnly;
-  static const ProfileSelection kSystemProfileExperimentDefault =
-      ProfileSelection::kNone;
-
-  // Builder to construct the `ProfileSelections` parameters.
+  // Builder to construct the `ProfileSelections` parameters for different
+  // profile types.
   class Builder {
    public:
     Builder();
@@ -93,9 +76,7 @@
     std::unique_ptr<ProfileSelections> selections_;
   };
 
-  // - Predefined `ProfileSelections`
-
-  // Regular builders (independent of the experiments):
+  // - Predefined `ProfileSelections` builders:
 
   // Only select the regular profile.
   // Note: Ash internal profiles are of type Regular. In order to have a
@@ -135,9 +116,7 @@
   static ProfileSelections BuildNoProfilesSelected();
 
   // Only select the regular profile and incognito for regular profiles. No
-  // profiles for Guest and System profiles. "NonExperimental" is added to
-  // differentiate with the experimental behavior during the experiment, once
-  // done it will be the equivalent builder.
+  // profiles for Guest and System profiles.
   // Note: Ash internal profiles are of type Regular. In order to have a
   // different filter for those profiles, a specific builder should be
   // constructed with a value for
@@ -153,9 +132,7 @@
   static ProfileSelections BuildForRegularAndIncognito();
 
   // Redirects incognito profiles to their original regular profile. No
-  // profiles for Guest and System profiles. "NonExperimental" is added to
-  // differentiate with the experimental behavior during the experiment, once
-  // done it will be the equivalent builder.
+  // profiles for Guest and System profiles.
   // Note: Ash internal profiles are of type Regular. In order to have a
   // different filter for those profiles, a specific builder should be
   // constructed with a value for
@@ -168,7 +145,7 @@
   // | System  | no profile | no profile |
   // | Ash Int.| self       | original   |
   // +---------+------------+------------+
-  static ProfileSelections BuildRedirectedInIncognitoNonExperimental();
+  static ProfileSelections BuildRedirectedInIncognito();
 
   // Redirects all OTR profiles to their original profiles.
   // Includes all profile types (Regular, Guest and System).
@@ -182,58 +159,6 @@
   // +---------+------------+------------+
   static ProfileSelections BuildRedirectedToOriginal();
 
-  // Experimental builders:
-  //
-  // Experimental builders (should only be used for the transition from
-  // `BrowserContextKeyedServiceFactory` to `ProfileKeyedServiceFactory`):
-  // The following builder will contain experimental code indirectly, by not
-  // giving a value to Guest and System Profile (unless forced by parameters).
-  // The experiment is targeted to affect usages on
-  // `ProfileKeyedServiceFactory`. During the experiment phase, these builders
-  // will not have very accurate function names, the name is based on the end
-  // result behavior the experiment enforced behavior. With/Without experiment
-  // behavior is described per experimental builder. The parameters force_* will
-  // allow to have an easier transition when adapting to the experiment.
-
-  // Without the experiment:
-  // - Returns Regular for Regular, incognito and other regular OTR profiles.
-  // - Returns Guest Original for GuestOriginal  and GuestOTR (same as Regular).
-  // - Returns System Original for SystemOriginal  and SystemOTR (same as
-  // Regular).
-  //
-  // With the experiment:
-  // - Returns Regular for Regular, incognito and other regular OTR profiles.
-  // - Return nullptr for all Guest and System profiles.
-  //
-  // Without the experiment:
-  // +---------+------------+------------+
-  // |         |  Original  |    OTR     |
-  // +---------+------------+------------+
-  // | Regular | self       | original   |
-  // | Guest   | self       | original   |
-  // | System  | self       | original   |
-  // | Ash Int.| self       | original   |
-  // +---------+------------+------------+
-  //
-  // With the experiment:
-  // +---------+------------+------------+
-  // |         |  Original  |    OTR     |
-  // +---------+------------+------------+
-  // | Regular | self       | original   |
-  // | Guest   | no profile | no profile |
-  // | System  | no profile | no profile |
-  // | Ash Int.| self       | original   |
-  // +---------+------------+------------+
-  //
-  // Parameters: (used during the experiment)
-  // - force_guest: true, force Guest with
-  // `ProfileSelecion::kRedirectedToOriginal`.
-  // - force_system: true, force System with
-  // `ProfileSelecion::kRedirectedToOriginal`.
-  static ProfileSelections BuildRedirectedInIncognito(
-      bool force_guest = true,
-      bool force_system = false);
-
   // Given a Profile and a ProfileSelection enum, returns the right profile
   // (can potentially return nullptr).
   Profile* ApplyProfileSelection(Profile* profile) const;
@@ -242,7 +167,7 @@
   // Default constructor settings sets Regular Profile ->
   // `ProfileSelection::kOriginalOnly`. It should be constructed through the
   // Builder. Value for Guest, System and Ash internals profile not being
-  // overridden will default to the behaviour of Regular Profile.
+  // overridden will default to `ProfileSelection::kNone`.
   ProfileSelections();
 
   void SetProfileSelectionForRegular(ProfileSelection selection);
@@ -256,10 +181,9 @@
 
   // Default value for the mapping of
   // Regular Profile -> `ProfileSelection::kOriginalOnly`
-  // Not assigning values for Guest and System Profiles now defaults to the
-  // behavior of regular profiles. This will change later on to default to
+  // Not assigning values for Guest and System Profiles defaults to
   // `ProfileSelection::kNone`.
-  ProfileSelection regular_profile_selection_ = kRegularProfileDefault;
+  ProfileSelection regular_profile_selection_ = ProfileSelection::kOriginalOnly;
   absl::optional<ProfileSelection> guest_profile_selection_;
   absl::optional<ProfileSelection> system_profile_selection_;
   absl::optional<ProfileSelection> ash_internals_profile_selection_;
diff --git a/chrome/browser/profiles/profile_selections_unittest.cc b/chrome/browser/profiles/profile_selections_unittest.cc
index f83181c..a18c395 100644
--- a/chrome/browser/profiles/profile_selections_unittest.cc
+++ b/chrome/browser/profiles/profile_selections_unittest.cc
@@ -24,6 +24,35 @@
   }
 };
 
+TEST_F(ProfileSelectionsTest, DefaultConstructor) {
+  // This is equivalent to `ProfileSelections()` which is private and can only
+  // be called this way in production.
+  ProfileSelections selections = ProfileSelections::Builder().Build();
+
+  TestProfileSelection(selections, regular_profile(), regular_profile());
+  TestProfileSelection(selections, incognito_profile(), nullptr);
+
+  TestProfileSelection(selections, guest_profile(), nullptr);
+  TestProfileSelection(selections, guest_profile_otr(), nullptr);
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
+  TestProfileSelection(selections, system_profile(), nullptr);
+  TestProfileSelection(selections, system_profile_otr(), nullptr);
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  TestProfileSelection(selections, signin_profile(), signin_profile());
+  TestProfileSelection(selections, signin_profile_otr(), nullptr);
+
+  TestProfileSelection(selections, lockscreen_profile(), lockscreen_profile());
+  TestProfileSelection(selections, lockscreen_profile_otr(), nullptr);
+
+  TestProfileSelection(selections, lockscreenapp_profile(),
+                       lockscreenapp_profile());
+  TestProfileSelection(selections, lockscreenapp_profile_otr(), nullptr);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
 TEST_F(ProfileSelectionsTest, CustomImplementation) {
   ProfileSelections selections =
       ProfileSelections::Builder()
@@ -116,7 +145,7 @@
 
 TEST_F(ProfileSelectionsTest, RedirectedInIncognito) {
   ProfileSelections selections =
-      ProfileSelections::BuildRedirectedInIncognitoNonExperimental();
+      ProfileSelections::BuildRedirectedInIncognito();
 
   TestProfileSelection(selections, regular_profile(), regular_profile());
   TestProfileSelection(selections, incognito_profile(), regular_profile());
@@ -227,116 +256,3 @@
   TestProfileSelection(selections, lockscreenapp_profile_otr(), nullptr);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)s
 }
-
-// Testing Experimental Builders.
-// Params:
-// - bool force_guest: used to bypass experiment and set a fixed value to the
-// Guest ProfielSelection.
-// - bool force_system: used to bypass experiment and set a fixed value to the
-// System ProfielSelection.
-// - bool system_experiment: used to activate/deactivate the
-// `kSystemProfileSelectionDefaultNone` experiment.
-class ProfileSelectionsTestWithParams
-    : public ProfileSelectionsTest,
-      public ::testing::WithParamInterface<std::tuple<bool, bool, bool>> {
- public:
-  void SetUp() override {
-    ProfileSelectionsTest::SetUp();
-
-    // TODO(rsult): move the below code to be in the
-    // `ProfileSelectionsTestWithParams` constructor, once the System and Guest
-    // Profiles can be created with the experiment activated.
-    bool activate_system_experiment = std::get<2>(GetParam());
-    std::vector<base::test::FeatureRef> enabled_features;
-    std::vector<base::test::FeatureRef> disabled_features;
-    activate_system_experiment
-        ? enabled_features.push_back(kSystemProfileSelectionDefaultNone)
-        : disabled_features.push_back(kSystemProfileSelectionDefaultNone);
-    feature_list_.InitWithFeatures(enabled_features, disabled_features);
-  }
-
- protected:
-  bool IsSystemExperimentActive() const {
-    return base::FeatureList::IsEnabled(kSystemProfileSelectionDefaultNone);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_P(ProfileSelectionsTestWithParams, DefaultConstructor) {
-  // This is equivalent to `ProfileSelections()` which is private and can only
-  // be called this way in production.
-  ProfileSelections selections = ProfileSelections::Builder().Build();
-
-  TestProfileSelection(selections, regular_profile(), regular_profile());
-  TestProfileSelection(selections, incognito_profile(), nullptr);
-
-  TestProfileSelection(selections, guest_profile(), nullptr);
-  TestProfileSelection(selections, guest_profile_otr(), nullptr);
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileSelection(selections, system_profile(),
-                       system_experiment ? nullptr : system_profile());
-  TestProfileSelection(selections, system_profile_otr(), nullptr);
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  TestProfileSelection(selections, signin_profile(), signin_profile());
-  TestProfileSelection(selections, signin_profile_otr(), nullptr);
-
-  TestProfileSelection(selections, lockscreen_profile(), lockscreen_profile());
-  TestProfileSelection(selections, lockscreen_profile_otr(), nullptr);
-
-  TestProfileSelection(selections, lockscreenapp_profile(),
-                       lockscreenapp_profile());
-  TestProfileSelection(selections, lockscreenapp_profile_otr(), nullptr);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
-TEST_P(ProfileSelectionsTestWithParams, BuildRedirectedInIncognito) {
-  bool force_guest = std::get<0>(GetParam());
-  bool force_system = std::get<1>(GetParam());
-
-  ProfileSelections selections =
-      ProfileSelections::BuildRedirectedInIncognito(force_guest, force_system);
-
-  TestProfileSelection(selections, regular_profile(), regular_profile());
-  TestProfileSelection(selections, incognito_profile(), regular_profile());
-
-  TestProfileSelection(selections, guest_profile(),
-                       force_guest ? guest_profile() : nullptr);
-  TestProfileSelection(selections, guest_profile_otr(),
-                       force_guest ? guest_profile() : nullptr);
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-  bool system_experiment = IsSystemExperimentActive();
-  TestProfileSelection(
-      selections, system_profile(),
-      force_system || !system_experiment ? system_profile() : nullptr);
-  TestProfileSelection(
-      selections, system_profile_otr(),
-      force_system || !system_experiment ? system_profile() : nullptr);
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  TestProfileSelection(selections, signin_profile(), signin_profile());
-  TestProfileSelection(selections, signin_profile_otr(), signin_profile());
-
-  TestProfileSelection(selections, lockscreen_profile(), lockscreen_profile());
-  TestProfileSelection(selections, lockscreen_profile_otr(),
-                       lockscreen_profile());
-
-  TestProfileSelection(selections, lockscreenapp_profile(),
-                       lockscreenapp_profile());
-  TestProfileSelection(selections, lockscreenapp_profile_otr(),
-                       lockscreenapp_profile());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
-INSTANTIATE_TEST_SUITE_P(ExperimentalBuilders,
-                         ProfileSelectionsTestWithParams,
-                         ::testing::Combine(::testing::Bool(),
-                                            ::testing::Bool(),
-                                            ::testing::Bool()));
diff --git a/chrome/browser/reading_list/reading_list_model_factory.cc b/chrome/browser/reading_list/reading_list_model_factory.cc
index 52b69a0..d7954f1 100644
--- a/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -82,7 +82,12 @@
 ReadingListModelFactory::ReadingListModelFactory()
     : ProfileKeyedServiceFactory(
           "ReadingListModel",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
index 8792e1cf..180598e1 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
@@ -43,7 +43,12 @@
 AdvancedProtectionStatusManagerFactory::AdvancedProtectionStatusManagerFactory()
     : ProfileKeyedServiceFactory(
           "AdvancedProtectionStatusManager",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(IdentityManagerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/safe_browsing/network_context_service_factory.cc b/chrome/browser/safe_browsing/network_context_service_factory.cc
index fc02415..e89cedcf 100644
--- a/chrome/browser/safe_browsing/network_context_service_factory.cc
+++ b/chrome/browser/safe_browsing/network_context_service_factory.cc
@@ -24,7 +24,12 @@
 NetworkContextServiceFactory::NetworkContextServiceFactory()
     : ProfileKeyedServiceFactory(
           "SafeBrowsingNetworkContextService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 NetworkContextServiceFactory::~NetworkContextServiceFactory() = default;
 
diff --git a/chrome/browser/search_engines/template_url_fetcher_factory.cc b/chrome/browser/search_engines/template_url_fetcher_factory.cc
index 1e2a54d..d362a955 100644
--- a/chrome/browser/search_engines/template_url_fetcher_factory.cc
+++ b/chrome/browser/search_engines/template_url_fetcher_factory.cc
@@ -30,7 +30,12 @@
 TemplateURLFetcherFactory::TemplateURLFetcherFactory()
     : ProfileKeyedServiceFactory(
           "TemplateURLFetcher",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(TemplateURLServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc b/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc
index a486991..7134fc5d 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.cc
@@ -100,7 +100,12 @@
             "TtsEngineExtensionObserverChromeOS",
             // If given an incognito profile (including the Chrome OS login
             // profile), share the service with the original profile.
-            ProfileSelections::BuildRedirectedInIncognito()) {
+            ProfileSelections::Builder()
+                .WithRegular(ProfileSelection::kRedirectedToOriginal)
+                // TODO(crbug.com/1418376): Check if this service is needed in
+                // Guest mode.
+                .WithGuest(ProfileSelection::kRedirectedToOriginal)
+                .Build()) {
     DependsOn(extensions::EventRouterFactory::GetInstance());
   }
 
diff --git a/chrome/browser/speech/tts_client_factory_lacros.cc b/chrome/browser/speech/tts_client_factory_lacros.cc
index 1fa0193..857a793 100644
--- a/chrome/browser/speech/tts_client_factory_lacros.cc
+++ b/chrome/browser/speech/tts_client_factory_lacros.cc
@@ -24,7 +24,12 @@
           "TtsClientLacros",
           // For incognito mode, use its original profile as browser context, so
           // that it will have the same tts support as the original profile.
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 TtsClientFactoryLacros::~TtsClientFactoryLacros() = default;
 
diff --git a/chrome/browser/spellchecker/spellcheck_factory.cc b/chrome/browser/spellchecker/spellcheck_factory.cc
index f19aa2f..8bb2683 100644
--- a/chrome/browser/spellchecker/spellcheck_factory.cc
+++ b/chrome/browser/spellchecker/spellcheck_factory.cc
@@ -30,7 +30,12 @@
 SpellcheckServiceFactory::SpellcheckServiceFactory()
     : ProfileKeyedServiceFactory(
           "SpellcheckService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   // TODO(erg): Uncomment these as they are initialized.
   // DependsOn(RequestContextFactory::GetInstance());
 }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
index 70caa09..a257005 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
@@ -552,8 +552,8 @@
   DCHECK(render_frame_host);
   DCHECK(render_frame_host->IsRenderFrameLive());
   std::string command = base::StrCat({"sendCommand(\'", command_name, "\')"});
-  ASSERT_TRUE(content::ExecuteScript(
-      content::ToRenderFrameHost(render_frame_host), command));
+  ASSERT_TRUE(
+      content::ExecJs(content::ToRenderFrameHost(render_frame_host), command));
 }
 
 void SupervisedUserIframeFilterTest::WaitForNavigationFinished(
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.cc b/chrome/browser/supervised_user/supervised_user_service_factory.cc
index b5da991..b8769289 100644
--- a/chrome/browser/supervised_user/supervised_user_service_factory.cc
+++ b/chrome/browser/supervised_user/supervised_user_service_factory.cc
@@ -86,7 +86,12 @@
           base::FeatureList::IsEnabled(
               supervised_user::kUpdateSupervisedUserFactoryCreation)
               ? supervised_user::BuildProfileSelectionsForRegularAndGuest()
-              : ProfileSelections::BuildRedirectedInIncognito()) {
+              : ProfileSelections::Builder()
+                    .WithRegular(ProfileSelection::kRedirectedToOriginal)
+                    // TODO(crbug.com/1418376): Check if this service is needed
+                    // in Guest mode.
+                    .WithGuest(ProfileSelection::kRedirectedToOriginal)
+                    .Build()) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   DependsOn(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
diff --git a/chrome/browser/sync/bookmark_sync_service_factory.cc b/chrome/browser/sync/bookmark_sync_service_factory.cc
index 5951620..3a0a187 100644
--- a/chrome/browser/sync/bookmark_sync_service_factory.cc
+++ b/chrome/browser/sync/bookmark_sync_service_factory.cc
@@ -23,7 +23,12 @@
 BookmarkSyncServiceFactory::BookmarkSyncServiceFactory()
     : ProfileKeyedServiceFactory(
           "BookmarkSyncServiceFactory",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(BookmarkUndoServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/sync/model_type_store_service_factory.cc b/chrome/browser/sync/model_type_store_service_factory.cc
index c743093..fd6339b 100644
--- a/chrome/browser/sync/model_type_store_service_factory.cc
+++ b/chrome/browser/sync/model_type_store_service_factory.cc
@@ -22,7 +22,12 @@
 ModelTypeStoreServiceFactory::ModelTypeStoreServiceFactory()
     : ProfileKeyedServiceFactory(
           "ModelTypeStoreService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 ModelTypeStoreServiceFactory::~ModelTypeStoreServiceFactory() = default;
 
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index 6f773503..5025110 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -91,14 +91,10 @@
   EXPECT_EQ(syncer::SyncService::TransportState::ACTIVE,
             GetSyncService(0)->GetTransportState());
 
-  // Both IsSyncRequested and IsFirstSetupComplete should remain false (i.e.
-  // at their default values). They only get set during the Sync setup flow,
-  // either by the Sync confirmation dialog or by the settings page if going
-  // through the advanced settings flow.
+  // IsFirstSetupComplete should remain false. It only gets set during the Sync
+  // setup flow, either by the Sync confirmation dialog or by the settings page
+  // if going through the advanced settings flow.
   EXPECT_FALSE(GetSyncService(0)->GetUserSettings()->IsFirstSetupComplete());
-  // TODO(crbug.com/906034,crbug.com/973770): Sort out the proper default value
-  // for IsSyncRequested().
-  // EXPECT_FALSE(GetSyncService(0)->GetUserSettings()->IsSyncRequested());
 
   EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
   EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureActive());
diff --git a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
index 364dc31f..b6b6090 100644
--- a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
+++ b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
@@ -44,12 +44,11 @@
 }
 
 WifiConfigurationSyncServiceFactory::WifiConfigurationSyncServiceFactory()
-    : ProfileKeyedServiceFactory(
-          "WifiConfigurationSyncService",
-          ProfileSelections::Builder()
-              .WithGuest(ProfileSelections::kRegularProfileDefault)
-              .WithAshInternals(ProfileSelection::kNone)
-              .Build()) {
+    : ProfileKeyedServiceFactory("WifiConfigurationSyncService",
+                                 ProfileSelections::Builder()
+                                     .WithGuest(ProfileSelection::kOriginalOnly)
+                                     .WithAshInternals(ProfileSelection::kNone)
+                                     .Build()) {
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/themes/theme_service_factory.cc b/chrome/browser/themes/theme_service_factory.cc
index 622dcc8..c8382bb 100644
--- a/chrome/browser/themes/theme_service_factory.cc
+++ b/chrome/browser/themes/theme_service_factory.cc
@@ -71,7 +71,12 @@
 ThemeServiceFactory::ThemeServiceFactory()
     : ProfileKeyedServiceFactory(
           "ThemeService",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
   DependsOn(extensions::ExtensionSystemFactory::GetInstance());
diff --git a/chrome/browser/touch_to_fill/password_generation/android/BUILD.gn b/chrome/browser/touch_to_fill/password_generation/android/BUILD.gn
new file mode 100644
index 0000000..90e5966
--- /dev/null
+++ b/chrome/browser/touch_to_fill/password_generation/android/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD - style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+source_set("public") {
+  deps = [
+    "//base",
+    "//components/password_manager/content/browser:browser",
+  ]
+
+  sources = [
+    "touch_to_fill_password_generation_controller.cc",
+    "touch_to_fill_password_generation_controller.h",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  deps = [
+    ":public",
+    "//base",
+    "//chrome/test:test_support",
+    "//components/password_manager/content/browser:browser",
+    "//content/test:test_support",
+  ]
+
+  sources = [ "touch_to_fill_password_generation_controller_unittest.cc" ]
+}
diff --git a/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.cc b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.cc
new file mode 100644
index 0000000..11a7db80e
--- /dev/null
+++ b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.cc
@@ -0,0 +1,58 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h"
+
+#include "base/check.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+TouchToFillPasswordGenerationController::
+    ~TouchToFillPasswordGenerationController() {
+  RemoveSuppressShowingImeCallback();
+}
+
+TouchToFillPasswordGenerationController::
+    TouchToFillPasswordGenerationController(
+        base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+            frame_driver)
+    : frame_driver_(frame_driver) {
+  suppress_showing_ime_callback_ = base::BindRepeating([]() {
+    // This controller exists only while the TTF is being shown, so
+    // always suppress the keyboard.
+    return true;
+  });
+}
+
+void TouchToFillPasswordGenerationController::ShowTouchToFill() {
+  AddSuppressShowingImeCallback();
+}
+
+void TouchToFillPasswordGenerationController::AddSuppressShowingImeCallback() {
+  if (suppress_showing_ime_callback_added_) {
+    return;
+  }
+  frame_driver_->render_frame_host()
+      ->GetRenderWidgetHost()
+      ->AddSuppressShowingImeCallback(suppress_showing_ime_callback_);
+  suppress_showing_ime_callback_added_ = true;
+}
+
+void TouchToFillPasswordGenerationController::
+    RemoveSuppressShowingImeCallback() {
+  if (!suppress_showing_ime_callback_added_) {
+    return;
+  }
+  if (frame_driver_) {
+    frame_driver_->render_frame_host()
+        ->GetRenderWidgetHost()
+        ->RemoveSuppressShowingImeCallback(suppress_showing_ime_callback_);
+  }
+  suppress_showing_ime_callback_added_ = false;
+}
diff --git a/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h
new file mode 100644
index 0000000..dc41e20
--- /dev/null
+++ b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h
@@ -0,0 +1,48 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_GENERATION_ANDROID_TOUCH_TO_FILL_PASSWORD_GENERATION_CONTROLLER_H_
+#define CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_GENERATION_ANDROID_TOUCH_TO_FILL_PASSWORD_GENERATION_CONTROLLER_H_
+
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace password_manager {
+class ContentPasswordManagerDriver;
+}  // namespace password_manager
+
+// The controller responsible for the password generation bottom sheet UI.
+// It should be created before showing the bottom sheet and destroyed right
+// after the bottom sheet is dismissed.
+class TouchToFillPasswordGenerationController {
+ public:
+  explicit TouchToFillPasswordGenerationController(
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+          frame_driver);
+  TouchToFillPasswordGenerationController(
+      const TouchToFillPasswordGenerationController&) = delete;
+  TouchToFillPasswordGenerationController& operator=(
+      const TouchToFillPasswordGenerationController&) = delete;
+  ~TouchToFillPasswordGenerationController();
+
+  // Shows the password generation bottom sheet.
+  void ShowTouchToFill();
+
+ private:
+  // Suppressing IME input is necessary for Touch-To-Fill.
+  void AddSuppressShowingImeCallback();
+  void RemoveSuppressShowingImeCallback();
+
+  // Password manager driver for the frame on which the Touch-To-Fill was
+  // triggered. Ensure that the bottom sheet should be hidden when the frame is
+  // removed.
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver> frame_driver_;
+
+  content::RenderWidgetHost::SuppressShowingImeCallback
+      suppress_showing_ime_callback_;
+  bool suppress_showing_ime_callback_added_ = false;
+};
+
+#endif  // CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_GENERATION_ANDROID_TOUCH_TO_FILL_PASSWORD_GENERATION_CONTROLLER_H_
diff --git a/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller_unittest.cc b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller_unittest.cc
new file mode 100644
index 0000000..260cbbb
--- /dev/null
+++ b/chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/touch_to_fill/password_generation/android/touch_to_fill_password_generation_controller.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "content/public/test/text_input_test_utils.h"
+#include "ui/base/ime/mojom/text_input_state.mojom.h"
+#include "ui/base/ime/text_input_type.h"
+
+class TouchToFillPasswordGenerationControllerTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    password_mananger_driver_ =
+        std::make_unique<password_manager::ContentPasswordManagerDriver>(
+            main_rfh(), &client_, &test_autofill_client_);
+  }
+
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+  password_mananger_driver() {
+    return base::AsWeakPtr(password_mananger_driver_.get());
+  }
+
+ private:
+  std::unique_ptr<password_manager::ContentPasswordManagerDriver>
+      password_mananger_driver_;
+  password_manager::StubPasswordManagerClient client_;
+  autofill::TestAutofillClient test_autofill_client_;
+};
+
+TEST_F(TouchToFillPasswordGenerationControllerTest,
+       KeyboardIsSuppressedWhileTheBottomSheetIsShown) {
+  auto controller = std::make_unique<TouchToFillPasswordGenerationController>(
+      password_mananger_driver());
+  controller->ShowTouchToFill();
+
+  ui::mojom::TextInputStatePtr initial_state = ui::mojom::TextInputState::New();
+  initial_state->type = ui::TEXT_INPUT_TYPE_PASSWORD;
+  // Simulate the TextInputStateChanged call, which triggers the keyboard.
+  SendTextInputStateChangedToWidget(rvh()->GetWidget(),
+                                    std::move(initial_state));
+  // Keyboard is expected to be suppressed.
+  EXPECT_TRUE(content::GetTextInputStateFromWebContents(web_contents())
+                  ->always_hide_ime);
+
+  controller.reset();
+
+  initial_state = ui::mojom::TextInputState::New();
+  initial_state->type = ui::TEXT_INPUT_TYPE_PASSWORD;
+  // Simulate the TextInputStateChanged call, which triggers the keyboard.
+  SendTextInputStateChangedToWidget(rvh()->GetWidget(),
+                                    std::move(initial_state));
+  // Keyboard is expected to be shown again after resetting the controller.
+  EXPECT_FALSE(content::GetTextInputStateFromWebContents(web_contents())
+                   ->always_hide_ime);
+}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ca99dd38..5bfd07e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5396,14 +5396,14 @@
       "views/toolbar/browser_app_menu_button.h",
       "views/toolbar/chrome_labs_bubble_view.cc",
       "views/toolbar/chrome_labs_bubble_view.h",
-      "views/toolbar/chrome_labs_bubble_view_model.cc",
-      "views/toolbar/chrome_labs_bubble_view_model.h",
       "views/toolbar/chrome_labs_button.cc",
       "views/toolbar/chrome_labs_button.h",
       "views/toolbar/chrome_labs_coordinator.cc",
       "views/toolbar/chrome_labs_coordinator.h",
       "views/toolbar/chrome_labs_item_view.cc",
       "views/toolbar/chrome_labs_item_view.h",
+      "views/toolbar/chrome_labs_model.cc",
+      "views/toolbar/chrome_labs_model.h",
       "views/toolbar/chrome_labs_utils.cc",
       "views/toolbar/chrome_labs_utils.h",
       "views/toolbar/chrome_labs_view_controller.cc",
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
index d452b62c..ba6a755 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
@@ -102,7 +102,7 @@
     Java_AutofillKeyboardAccessoryViewBridge_addToAutofillSuggestionArray(
         env, data_array, position++, ConvertUTF16ToJavaString(env, label),
         ConvertUTF16ToJavaString(env, sublabel), android_icon_id,
-        suggestion.frontend_id,
+        suggestion.frontend_id.as_int(),
         controller_->GetRemovalConfirmationText(i, nullptr, nullptr),
         ConvertUTF8ToJavaString(env, suggestion.feature_for_iph),
         url::GURLAndroid::FromNativeGURL(env, suggestion.custom_icon_url));
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
index a80bd62..7276a4a2 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
@@ -144,8 +144,8 @@
         base::android::ConvertUTF16ToJavaString(env, sublabel),
         base::android::ConvertUTF16ToJavaString(env, secondary_sublabel),
         base::android::ConvertUTF16ToJavaString(env, item_tag), android_icon_id,
-        suggestion.is_icon_at_start, suggestion.frontend_id, is_deletable,
-        is_label_multiline, /*isLabelBold*/ false,
+        suggestion.is_icon_at_start, suggestion.frontend_id.as_int(),
+        is_deletable, is_label_multiline, /*isLabelBold*/ false,
         url::GURLAndroid::FromNativeGURL(env, suggestion.custom_icon_url));
   }
 
diff --git a/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.cc b/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.cc
index 07a1a9bc..99a7ab8 100644
--- a/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.cc
+++ b/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -46,7 +46,8 @@
 
 void PasswordGenerationDialogViewAndroid::Show(
     std::u16string& password,
-    base::WeakPtr<password_manager::PasswordManagerDriver> target_frame_driver,
+    base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+        target_frame_driver,
     autofill::password_generation::PasswordGenerationType type) {
   generation_type_ = type;
   target_frame_driver_ = std::move(target_frame_driver);
diff --git a/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.h b/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.h
index 9cd034d4..2d5d6dc 100644
--- a/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.h
+++ b/chrome/browser/ui/android/passwords/password_generation_dialog_view_android.h
@@ -35,7 +35,7 @@
   // Called to show the dialog. |password| is the generated password.
   void Show(
       std::u16string& password,
-      base::WeakPtr<password_manager::PasswordManagerDriver>
+      base::WeakPtr<password_manager::ContentPasswordManagerDriver>
           target_frame_driver,
       autofill::password_generation::PasswordGenerationType type) override;
 
@@ -58,7 +58,8 @@
   // The driver corresponding to the frame for which the generation request was
   // made. Used to ensure that the accepted password message is sent back to the
   // same frame.
-  base::WeakPtr<password_manager::PasswordManagerDriver> target_frame_driver_;
+  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
+      target_frame_driver_;
 
   // Whether the dialog was shown for manual generation or not. Used for
   // metrics.
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter_unittest.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter_unittest.cc
index b004637..b7f0cf6 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter_unittest.cc
@@ -57,7 +57,7 @@
 Suggestion createPasswordEntry(std::string password,
                                std::string username,
                                std::string psl_origin) {
-  Suggestion s(/*value=*/username, /*label=*/psl_origin, /*icon=*/"",
+  Suggestion s(/*main_text=*/username, /*label=*/psl_origin, /*icon=*/"",
                PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
   s.additional_label = ASCIIToUTF16(password);
   return s;
@@ -73,9 +73,8 @@
 
 std::vector<Suggestion> createSuggestions(int clearItemOffset) {
   std::vector<Suggestion> suggestions = createSuggestions();
-  suggestions.emplace(
-      suggestions.begin() + clearItemOffset,
-      Suggestion("Clear", "", "", PopupItemId::POPUP_ITEM_ID_CLEAR_FORM));
+  suggestions.emplace(suggestions.begin() + clearItemOffset, "Clear", "", "",
+                      PopupItemId::POPUP_ITEM_ID_CLEAR_FORM);
   return suggestions;
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index dae7048..98d783e 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -62,7 +62,7 @@
     base::Milliseconds(500);
 
 // Returns true if the given id refers to an element that can be accepted.
-bool CanAccept(int id) {
+bool CanAccept(PopupItemId id) {
   return id != POPUP_ITEM_ID_SEPARATOR &&
          id != POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE &&
          id != POPUP_ITEM_ID_MIXED_FORM_MESSAGE && id != POPUP_ITEM_ID_TITLE;
@@ -438,7 +438,7 @@
 
   if (index) {
     DCHECK_LT(*index, suggestions_.size());
-    if (!CanAccept(GetSuggestionAt(*index).frontend_id)) {
+    if (!CanAccept(GetSuggestionAt(*index).frontend_id.as_popup_item_id())) {
       index = absl::nullopt;
     }
   }
@@ -461,8 +461,8 @@
   if (suggestions_.empty()) {
     return false;
   }
-  int id = suggestions_[0].frontend_id;
-  return id > 0 || base::Contains(kItemsTriggeringFieldFilling, id) ||
+  Suggestion::FrontendId id = suggestions_[0].frontend_id;
+  return id.as_int() > 0 || base::Contains(kItemsTriggeringFieldFilling, id) ||
          id == POPUP_ITEM_ID_SCAN_CREDIT_CARD;
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
index 62d9359e..d7fa6eb 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -107,9 +107,10 @@
   ~MockAutofillExternalDelegate() override = default;
 
   void DidSelectSuggestion(const std::u16string& value,
-                           int frontend_id,
+                           Suggestion::FrontendId frontend_id,
                            const Suggestion::BackendId& backend_id) override {}
-  bool RemoveSuggestion(const std::u16string& value, int frontend_id) override {
+  bool RemoveSuggestion(const std::u16string& value,
+                        Suggestion::FrontendId frontend_id) override {
     return true;
   }
   base::WeakPtr<AutofillExternalDelegate> GetWeakPtr() {
@@ -226,10 +227,10 @@
   }
 
   // Shows empty suggestions with the frontend ids passed as `ids`.
-  void ShowSuggestions(const std::vector<int>& ids) {
+  void ShowSuggestions(const std::vector<Suggestion::FrontendId>& ids) {
     std::vector<Suggestion> suggestions;
     suggestions.reserve(ids.size());
-    for (int id : ids) {
+    for (Suggestion::FrontendId id : ids) {
       suggestions.emplace_back("", "", "", id);
     }
     popup_controller().Show(std::move(suggestions),
@@ -292,7 +293,8 @@
 };
 
 TEST_F(AutofillPopupControllerUnitTest, RemoveSuggestion) {
-  ShowSuggestions({1, 1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  ShowSuggestions({Suggestion::FrontendId(1), Suggestion::FrontendId(1),
+                   POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Generate a popup, so it can be hidden later. It doesn't matter what the
   // external_delegate thinks is being shown in the process, since we are just
@@ -312,7 +314,7 @@
 }
 
 TEST_F(AutofillPopupControllerUnitTest, UpdateDataListValues) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   // Add one data list entry.
   std::u16string value1 = u"data list value 1";
@@ -344,7 +346,7 @@
   EXPECT_EQ(std::u16string(), result2.main_text.value);
   EXPECT_TRUE(result2.labels.empty());
   EXPECT_EQ(std::u16string(), result2.additional_label);
-  EXPECT_EQ(1, result2.frontend_id);
+  EXPECT_EQ(1, result2.frontend_id.as_int());
 
   // Add two data list entries (which should replace the current one).
   std::u16string value2 = u"data list value 2";
@@ -378,7 +380,7 @@
   popup_controller().UpdateDataListValues(data_list_values, data_list_labels);
 
   ASSERT_EQ(1, popup_controller().GetLineCount());
-  EXPECT_EQ(1, popup_controller().GetSuggestionAt(0).frontend_id);
+  EXPECT_EQ(1, popup_controller().GetSuggestionAt(0).frontend_id.as_int());
 }
 
 TEST_F(AutofillPopupControllerUnitTest, PopupsWithOnlyDataLists) {
@@ -523,7 +525,7 @@
 // This is a regression test for crbug.com/521133 to ensure that we don't crash
 // when suggestions updates race with user selections.
 TEST_F(AutofillPopupControllerUnitTest, SelectInvalidSuggestion) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   EXPECT_CALL(*delegate(), DidAcceptSuggestion).Times(0);
 
@@ -532,7 +534,7 @@
 }
 
 TEST_F(AutofillPopupControllerUnitTest, AcceptSuggestionRespectsTimeout) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   // Calls before the threshold are ignored.
   EXPECT_CALL(*delegate(), DidAcceptSuggestion).Times(0);
@@ -546,7 +548,7 @@
 }
 
 TEST_F(AutofillPopupControllerUnitTest, AcceptSuggestionWithoutThreshold) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   // Calls are accepted immediately.
   EXPECT_CALL(*delegate(), DidAcceptSuggestion).Times(1);
@@ -555,7 +557,7 @@
 
 TEST_F(AutofillPopupControllerUnitTest,
        AcceptSuggestionTimeoutIsUpdatedOnPopupMove) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   // Calls before the threshold are ignored.
   EXPECT_CALL(*delegate(), DidAcceptSuggestion).Times(0);
@@ -566,7 +568,7 @@
   task_environment()->FastForwardBy(base::Milliseconds(400));
   // Show the suggestions again (simulating, e.g., a click somewhere slightly
   // different).
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
 
   EXPECT_CALL(*delegate(), DidAcceptSuggestion).Times(0);
   popup_controller().AcceptSuggestion(0);
@@ -673,7 +675,7 @@
 // Test for successfully firing controls changed event for popup show/hide.
 TEST_F(AutofillPopupControllerAccessibilityUnitTest,
        FireControlsChangedEventDuringShowAndHide) {
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
   // Manually fire the event for popup show since setting the test view results
   // in the fire controls changed event not being sent.
   popup_controller().FireControlsChangedEvent(true);
@@ -691,7 +693,7 @@
   EXPECT_CALL(mock_ax_platform_node_delegate_, GetFromTreeIDAndNodeID)
       .WillOnce(Return(nullptr));
 
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
   // Manually fire the event for popup show since setting the test view results
   // in the fire controls changed event not being sent.
   popup_controller().FireControlsChangedEvent(true);
@@ -706,7 +708,7 @@
   EXPECT_CALL(*autofill_popup_view_, GetAxUniqueId)
       .WillOnce(testing::Return(absl::nullopt));
 
-  ShowSuggestions({1});
+  ShowSuggestions({Suggestion::FrontendId(1)});
   // Manually fire the event for popup show since setting the test view results
   // in the fire controls changed event not being sent.
   popup_controller().FireControlsChangedEvent(true);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index ca96a109..3251275d 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -1067,9 +1067,9 @@
          security_level != security_state::DANGEROUS;
 }
 
-void ChromeAutofillClient::ExecuteCommand(int id) {
+void ChromeAutofillClient::ExecuteCommand(Suggestion::FrontendId id) {
 #if BUILDFLAG(IS_ANDROID)
-  if (id == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
+  if (id.as_popup_item_id() == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
     auto* window = web_contents()->GetNativeView()->GetWindowAndroid();
     if (window) {
       SigninBridge::LaunchSigninActivity(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 01d519d..1fba2a3 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -246,7 +246,7 @@
   void DidFillOrPreviewField(const std::u16string& autofilled_value,
                              const std::u16string& profile_full_name) override;
   bool IsContextSecure() const override;
-  void ExecuteCommand(int id) override;
+  void ExecuteCommand(Suggestion::FrontendId id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   LogManager* GetLogManager() const override;
   FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
index ef29a0d..2db2e85 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
@@ -9,6 +9,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
+#include "base/types/cxx23_to_underlying.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/autofill/autofill_popup_controller_utils.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
@@ -93,7 +94,8 @@
   for (int i = 0; i < _controller->GetLineCount() && i < maxTouchBarItems;
        i++) {
     const autofill::Suggestion& suggestion = _controller->GetSuggestionAt(i);
-    if (suggestion.frontend_id < autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
+    if (suggestion.frontend_id.as_int() <
+        base::to_underlying(autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)) {
       continue;
     }
 
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
index 76d10935..a17858d 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
@@ -47,10 +47,11 @@
     autofill_popup_controller_.set_suggestions(std::move(suggestions));
   }
 
-  void SetSuggestions(const std::vector<int>& frontends_ids) {
+  void SetSuggestions(
+      const std::vector<Suggestion::FrontendId>& frontends_ids) {
     std::vector<Suggestion> suggestions;
     suggestions.reserve(frontends_ids.size());
-    for (int frontend_id : frontends_ids) {
+    for (Suggestion::FrontendId frontend_id : frontends_ids) {
       suggestions.emplace_back("", "", "", frontend_id);
     }
     SetSuggestions(std::move(suggestions));
@@ -74,7 +75,7 @@
   EXPECT_FALSE([touch_bar_controller_ makeTouchBar]);
 
   [touch_bar_controller_ setIsCreditCardPopup:true];
-  SetSuggestions({1, 1});
+  SetSuggestions({Suggestion::FrontendId(1), Suggestion::FrontendId(1)});
   NSTouchBar* touch_bar = [touch_bar_controller_ makeTouchBar];
   EXPECT_TRUE(touch_bar);
   EXPECT_TRUE([[touch_bar customizationIdentifier]
@@ -85,7 +86,8 @@
 // Tests to check that the touch bar doesn't show more than 3 items
 TEST_F(CreditCardAutofillTouchBarControllerUnitTest, TouchBarCardLimit) {
   [touch_bar_controller_ setIsCreditCardPopup:true];
-  SetSuggestions({1, 1, 1, 1});
+  SetSuggestions({Suggestion::FrontendId(1), Suggestion::FrontendId(1),
+                  Suggestion::FrontendId(1), Suggestion::FrontendId(1)});
   NSTouchBar* touch_bar = [touch_bar_controller_ makeTouchBar];
   EXPECT_TRUE(touch_bar);
   EXPECT_TRUE([[touch_bar customizationIdentifier]
@@ -103,7 +105,8 @@
 // Tests for for the credit card button.
 TEST_F(CreditCardAutofillTouchBarControllerUnitTest, CreditCardButtonCheck) {
   [touch_bar_controller_ setIsCreditCardPopup:true];
-  SetSuggestions({Suggestion("bufflehead", "canvasback", "goldeneye", 1)});
+  SetSuggestions({Suggestion("bufflehead", "canvasback", "goldeneye",
+                             Suggestion::FrontendId(1))});
   NSButton* button = [touch_bar_controller_ createCreditCardButtonAtRow:0];
   EXPECT_TRUE(button);
   EXPECT_EQ(0, [button tag]);
diff --git a/chrome/browser/ui/global_error/global_error_service_factory.cc b/chrome/browser/ui/global_error/global_error_service_factory.cc
index cab9397..f5aed3a 100644
--- a/chrome/browser/ui/global_error/global_error_service_factory.cc
+++ b/chrome/browser/ui/global_error/global_error_service_factory.cc
@@ -21,7 +21,12 @@
 GlobalErrorServiceFactory::GlobalErrorServiceFactory()
     : ProfileKeyedServiceFactory(
           "GlobalErrorService",
-          ProfileSelections::BuildRedirectedInIncognito()) {}
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {}
 
 GlobalErrorServiceFactory::~GlobalErrorServiceFactory() = default;
 
diff --git a/chrome/browser/ui/user_education/reopen_tab_in_product_help_factory.cc b/chrome/browser/ui/user_education/reopen_tab_in_product_help_factory.cc
index 6765c87b..6e8c468 100644
--- a/chrome/browser/ui/user_education/reopen_tab_in_product_help_factory.cc
+++ b/chrome/browser/ui/user_education/reopen_tab_in_product_help_factory.cc
@@ -15,7 +15,12 @@
 ReopenTabInProductHelpFactory::ReopenTabInProductHelpFactory()
     : ProfileKeyedServiceFactory(
           "ReopenTabInProductHelp",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(feature_engagement::TrackerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_strategy_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_row_strategy_unittest.cc
index a2903ee..44f2a63 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_strategy_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_strategy_unittest.cc
@@ -42,7 +42,7 @@
 
 struct RowStrategyTestdata {
   // The frontend ids of the suggestions to be shown.
-  std::vector<int> frontend_ids;
+  std::vector<Suggestion::FrontendId> frontend_ids;
   // The index of the suggestion to be tested.
   int line_number;
   // The type of strategy to be tested.
@@ -55,7 +55,8 @@
 
 const RowStrategyTestdata kTestcases[] = {
     RowStrategyTestdata{
-        .frontend_ids = {1, 2, POPUP_ITEM_ID_SEPARATOR,
+        .frontend_ids = {Suggestion::FrontendId(1), Suggestion::FrontendId(2),
+                         POPUP_ITEM_ID_SEPARATOR,
                          POPUP_ITEM_ID_AUTOFILL_OPTIONS},
         .line_number = 1,
         .strategy_type = StrategyType::kSuggestion,
@@ -73,7 +74,8 @@
         .set_index = 1,
     },
     RowStrategyTestdata{
-        .frontend_ids = {1, 2, POPUP_ITEM_ID_SEPARATOR,
+        .frontend_ids = {Suggestion::FrontendId(1), Suggestion::FrontendId(2),
+                         POPUP_ITEM_ID_SEPARATOR,
                          POPUP_ITEM_ID_AUTOFILL_OPTIONS},
         .line_number = 3,
         .strategy_type = StrategyType::kFooter,
@@ -97,10 +99,10 @@
 class PopupRowStrategyTest : public ChromeViewsTestBase {
  public:
   // Sets suggestions in the mocked popup controller.
-  void SetSuggestions(const std::vector<int>& frontend_ids) {
+  void SetSuggestions(const std::vector<Suggestion::FrontendId>& frontend_ids) {
     std::vector<Suggestion> suggestions;
     suggestions.reserve(frontend_ids.size());
-    for (int frontend_id : frontend_ids) {
+    for (Suggestion::FrontendId frontend_id : frontend_ids) {
       // Create a suggestion with empty labels.
       suggestions.emplace_back("Main text", "", "", frontend_id);
     }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
index 0660dbc..d3d57bbe 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
@@ -36,9 +36,10 @@
   base::WeakPtr<AutofillPopupController> controller = popup_view.controller();
   DCHECK(controller);
 
-  int frontend_id = controller->GetSuggestionAt(line_number).frontend_id;
+  Suggestion::FrontendId frontend_id =
+      controller->GetSuggestionAt(line_number).frontend_id;
   std::unique_ptr<PopupRowStrategy> strategy;
-  switch (frontend_id) {
+  switch (frontend_id.as_popup_item_id()) {
     // These frontend ids should never be displayed in a `PopupRowView`.
     case PopupItemId::POPUP_ITEM_ID_SEPARATOR:
     case PopupItemId::POPUP_ITEM_ID_MIXED_FORM_MESSAGE:
@@ -52,7 +53,7 @@
                                                                    line_number);
       break;
     default:
-      if (IsFooterFrontendId(frontend_id)) {
+      if (IsFooterFrontendId(frontend_id.as_popup_item_id())) {
         strategy =
             std::make_unique<PopupFooterStrategy>(controller, line_number);
       } else {
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
index 7d6b3bcb..3b7dce4ff 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -532,7 +532,7 @@
   return arrow;
 }
 
-bool IsFooterFrontendId(int frontend_id) {
+bool IsFooterFrontendId(PopupItemId frontend_id) {
   switch (frontend_id) {
     case PopupItemId::POPUP_ITEM_ID_SCAN_CREDIT_CARD:
     case PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO:
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.h b/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
index f3a6891a..5a13fac56 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_POPUP_POPUP_VIEW_UTILS_H_
 #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_POPUP_POPUP_VIEW_UTILS_H_
 
+#include "components/autofill/core/browser/ui/popup_item_ids.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/bubble/bubble_border.h"
 #include "ui/views/bubble/bubble_border_arrow_utils.h"
@@ -152,7 +153,7 @@
 // Returns whether the suggestion with this `frontend_id` belongs into the
 // footer section of the popup. Returns `false` for separators, which may belong
 // either to the main or the footer section.
-bool IsFooterFrontendId(int frontend_id);
+bool IsFooterFrontendId(PopupItemId frontend_id);
 
 }  // namespace autofill
 
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
index 05cee77..b5b485a 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
@@ -60,7 +60,6 @@
 #include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
-using autofill::PopupItemId;
 using views::BubbleBorder;
 
 namespace autofill {
@@ -91,7 +90,8 @@
 
   // Separators are a special case: They belong into the footer iff the next
   // item exists and is a footer item.
-  int frontend_id = suggestions[line_number].frontend_id;
+  PopupItemId frontend_id =
+      suggestions[line_number].frontend_id.as_popup_item_id();
   return frontend_id == PopupItemId::POPUP_ITEM_ID_SEPARATOR
              ? IsFooterItem(suggestions, line_number + 1)
              : IsFooterFrontendId(frontend_id);
@@ -278,8 +278,9 @@
     if (index->second != PopupRowView::CellType::kContent) {
       return false;
     }
-    int frontend_id = controller_->GetSuggestionAt(index->first).frontend_id;
-    if (frontend_id <= 0 &&
+    Suggestion::FrontendId frontend_id =
+        controller_->GetSuggestionAt(index->first).frontend_id;
+    if (frontend_id.as_int() <= 0 &&
         !base::Contains(kItemsTriggeringFieldFilling, frontend_id) &&
         frontend_id != POPUP_ITEM_ID_SCAN_CREDIT_CARD) {
       return false;
@@ -404,8 +405,9 @@
     for (; current_line_number < kSuggestions.size() &&
            !IsFooterItem(kSuggestions, current_line_number);
          ++current_line_number) {
-      int frontend_id = kSuggestions[current_line_number].frontend_id;
-      switch (frontend_id) {
+      Suggestion::FrontendId frontend_id =
+          kSuggestions[current_line_number].frontend_id;
+      switch (frontend_id.as_popup_item_id()) {
         case PopupItemId::POPUP_ITEM_ID_SEPARATOR:
           rows_.push_back(body_container->AddChildView(
               std::make_unique<PopupSeparatorView>()));
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_browsertest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_browsertest.cc
index 4ab187df..2e85a23f 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_browsertest.cc
@@ -34,9 +34,10 @@
 
 std::vector<Suggestion> CreateAutofillProfileSuggestions() {
   std::vector<Suggestion> suggestions;
-  suggestions.emplace_back("123 Apple St.", "Charles", "accountIcon", 1);
+  suggestions.emplace_back("123 Apple St.", "Charles", "accountIcon",
+                           Suggestion::FrontendId(1));
   suggestions.emplace_back("3734 Elvis Presley Blvd.", "Elvis", "accountIcon",
-                           2);
+                           Suggestion::FrontendId(2));
 
   suggestions.emplace_back(POPUP_ITEM_ID_SEPARATOR);
 
@@ -49,8 +50,9 @@
 }
 
 std::vector<Suggestion> CreateAutocompleteSuggestions() {
-  return {Suggestion("Autocomplete entry 1", "", "", 0),
-          Suggestion("Autocomplete entry 2", "", "", 0)};
+  return {
+      Suggestion("Autocomplete entry 1", "", "", Suggestion::FrontendId(0)),
+      Suggestion("Autocomplete entry 2", "", "", Suggestion::FrontendId(0))};
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
index 135d97c9..b41ce2cb 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
@@ -109,7 +109,7 @@
     view().SchedulePaint();
   }
 
-  void CreateAndShowView(const std::vector<int>& ids) {
+  void CreateAndShowView(const std::vector<Suggestion::FrontendId>& ids) {
     controller().set_suggestions(ids);
     CreateAndShowView();
   }
@@ -208,7 +208,7 @@
 };
 
 TEST_F(PopupViewViewsTest, ShowHideTest) {
-  CreateAndShowView({0});
+  CreateAndShowView({Suggestion::FrontendId(0)});
   EXPECT_CALL(controller(), AcceptSuggestion).Times(0);
   EXPECT_CALL(controller(), AcceptSuggestionWithoutThreshold).Times(0);
   view().Hide();
@@ -217,7 +217,8 @@
 // This is a regression test for crbug.com/1113255.
 TEST_F(PopupViewViewsTest, ShowViewWithOnlyFooterItemsShouldNotCrash) {
   // Set suggestions to have only a footer item.
-  std::vector<int> suggestion_ids = {PopupItemId::POPUP_ITEM_ID_CLEAR_FORM};
+  std::vector<Suggestion::FrontendId> suggestion_ids = {
+      PopupItemId::POPUP_ITEM_ID_CLEAR_FORM};
   controller().set_suggestions(suggestion_ids);
   CreateAndShowView();
 }
@@ -419,8 +420,8 @@
 }
 
 TEST_F(PopupViewViewsTest, MovingSelectionSkipsSeparator) {
-  CreateAndShowView(
-      {1, POPUP_ITEM_ID_SEPARATOR, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView({Suggestion::FrontendId(1), POPUP_ITEM_ID_SEPARATOR,
+                     POPUP_ITEM_ID_AUTOFILL_OPTIONS});
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
 
   // Going one down skips the separator.
@@ -435,7 +436,7 @@
 }
 
 TEST_F(PopupViewViewsTest, MovingSelectionSkipsInsecureFormWarning) {
-  CreateAndShowView({1, POPUP_ITEM_ID_SEPARATOR,
+  CreateAndShowView({Suggestion::FrontendId(1), POPUP_ITEM_ID_SEPARATOR,
                      POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE});
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
 
@@ -458,7 +459,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
       features::kAutofillPopupUseThresholdForKeyboardAndMobileAccept);
-  CreateAndShowView({1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView(
+      {Suggestion::FrontendId(1), POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Select the first item.
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
@@ -474,7 +476,8 @@
 TEST_F(PopupViewViewsTest, FillContentOnEnterUsesThresholdIfFeatureEnabled) {
   base::test::ScopedFeatureList feature_list{
       features::kAutofillPopupUseThresholdForKeyboardAndMobileAccept};
-  CreateAndShowView({1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView(
+      {Suggestion::FrontendId(1), POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Select the first item.
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
@@ -494,7 +497,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
       features::kAutofillPopupUseThresholdForKeyboardAndMobileAccept);
-  CreateAndShowView({1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView(
+      {Suggestion::FrontendId(1), POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Select the first item.
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
@@ -510,7 +514,8 @@
 TEST_F(PopupViewViewsTest, FillOnTabPressedUsesThresholdIfFeatureEnabled) {
   base::test::ScopedFeatureList feature_list{
       features::kAutofillPopupUseThresholdForKeyboardAndMobileAccept};
-  CreateAndShowView({1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView(
+      {Suggestion::FrontendId(1), POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Select the first item.
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
@@ -524,7 +529,8 @@
 }
 
 TEST_F(PopupViewViewsTest, NoFillOnTabPressedWithModifiers) {
-  CreateAndShowView({1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView(
+      {Suggestion::FrontendId(1), POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // Select the first item.
   view().SetSelectedCell(CellIndex{0u, CellType::kContent});
@@ -544,8 +550,8 @@
 // a tab with the autofill settings).
 TEST_F(PopupViewViewsTest, NoAutofillOptionsTriggeredOnTabPressed) {
   // Set up the popup and select the options cell.
-  CreateAndShowView(
-      {1, POPUP_ITEM_ID_SEPARATOR, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView({Suggestion::FrontendId(1), POPUP_ITEM_ID_SEPARATOR,
+                     POPUP_ITEM_ID_AUTOFILL_OPTIONS});
   view().SetSelectedCell(CellIndex{2u, CellType::kContent});
   EXPECT_EQ(view().GetSelectedCell(),
             absl::make_optional<CellIndex>(2u, CellType::kContent));
@@ -560,8 +566,8 @@
 // This is a regression test for crbug.com/1309431 to ensure that we don't crash
 // when we press tab before a line is selected.
 TEST_F(PopupViewViewsTest, TabBeforeSelectingALine) {
-  CreateAndShowView(
-      {1, POPUP_ITEM_ID_SEPARATOR, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView({Suggestion::FrontendId(1), POPUP_ITEM_ID_SEPARATOR,
+                     POPUP_ITEM_ID_AUTOFILL_OPTIONS});
   EXPECT_FALSE(view().GetSelectedCell().has_value());
 
   // The following should not crash:
@@ -569,7 +575,8 @@
 }
 
 TEST_F(PopupViewViewsTest, RemoveLine) {
-  CreateAndShowView({1, 1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView({Suggestion::FrontendId(1), Suggestion::FrontendId(1),
+                     POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   // If no cell is selected, pressing delete has no effect.
   EXPECT_FALSE(view().GetSelectedCell().has_value());
@@ -592,7 +599,8 @@
 
 TEST_F(PopupViewViewsTest, RemoveAutofillRecordsNoAutocompleteDeletionMetrics) {
   base::HistogramTester histogram_tester;
-  CreateAndShowView({1, 1, POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+  CreateAndShowView({Suggestion::FrontendId(1), Suggestion::FrontendId(1),
+                     POPUP_ITEM_ID_AUTOFILL_OPTIONS});
 
   view().SetSelectedCell(CellIndex{1u, CellType::kContent});
 
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
index 4615ec4..080bfd8 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/extension_ui_util.h"
+#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -33,12 +34,14 @@
 #include "components/url_formatter/elide_url.h"
 #include "components/vector_icons/vector_icons.h"
 #include "extensions/common/constants.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/color/color_id.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/bubble/bubble_frame_view.h"
@@ -261,6 +264,23 @@
   return accessible_window_title_;
 }
 
+bool PermissionPromptBubbleBaseView::ShouldIgnoreButtonPressedEventHandling(
+    View* button,
+    const ui::Event& event) const {
+  // Ignore the key pressed event if the button row bounds intersect with PiP
+  // windows bounds.
+  if (!event.IsKeyEvent()) {
+    return false;
+  }
+
+  absl::optional<gfx::Rect> pip_window_bounds =
+      PictureInPictureWindowManager::GetInstance()
+          ->GetPictureInPictureWindowBounds();
+
+  return pip_window_bounds &&
+         pip_window_bounds->Intersects(button->GetBoundsInScreen());
+}
+
 void PermissionPromptBubbleBaseView::AcceptPermission() {
   RecordDecision(permissions::PermissionAction::GRANTED);
   if (delegate_) {
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
index 5018236..10864d2 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
@@ -69,6 +69,11 @@
   std::u16string GetAccessibleWindowTitle() const override;
   std::u16string GetWindowTitle() const override;
 
+  // views::DialogDelegate:
+  bool ShouldIgnoreButtonPressedEventHandling(
+      View* button,
+      const ui::Event& event) const override;
+
   void AcceptPermission();
   void AcceptPermissionThisTime();
   void DenyPermission();
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc
index 1189a08..dae44ca 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -102,13 +102,6 @@
   ~ProfilePickerWidget() override = default;
 
  private:
-  // TODO(crbug.com/1380808): Remove once the cause of the bug is found.
-  void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override {
-    if (profile_picker_view_)
-      profile_picker_view_->OnNativeWidgetSizeChanged(new_size);
-    views::Widget::OnNativeWidgetSizeChanged(new_size);
-  }
-
   const raw_ptr<ProfilePickerView, DanglingUntriaged> profile_picker_view_;
 };
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.h b/chrome/browser/ui/views/profiles/profile_picker_view.h
index bca53f4..448578b 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.h
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.h
@@ -95,13 +95,10 @@
   views::ClientView* CreateClientView(views::Widget* widget) override;
   views::View* GetContentsView() override;
   std::u16string GetAccessibleWindowTitle() const override;
+  gfx::Size CalculatePreferredSize() const override;
   gfx::Size GetMinimumSize() const override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
 
-  // Gets called when the native wiget changes size.
-  // TODO(crbug.com/1380808): Remove once the cause of the bug is found.
-  virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) {}
-
   // Exposed for testing
   enum State {
     // The view has just been created.
@@ -134,9 +131,6 @@
       Profile* picker_profile,
       ClearHostClosure clear_host_callback);
 
-  // TODO(crbug.com/1380808): Make private once the cause of the bug is found.
-  gfx::Size CalculatePreferredSize() const override;
-
  private:
   friend class ProfilePicker;
   FRIEND_TEST_ALL_PREFIXES(ProfilePickerCreationFlowBrowserTest,
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 1bde526..3941737 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -1044,14 +1044,14 @@
 
   // Simulate clicking on a link that opens in a new window.
   const GURL kURL("https://foo.google.com");
-  EXPECT_TRUE(ExecuteScript(web_contents(),
-                            "var link = document.createElement('a');"
-                            "link.href = '" +
-                                kURL.spec() +
-                                "';"
-                                "link.target = '_blank';"
-                                "document.body.appendChild(link);"
-                                "link.click();"));
+  EXPECT_TRUE(ExecJs(web_contents(),
+                     "var link = document.createElement('a');"
+                     "link.href = '" +
+                         kURL.spec() +
+                         "';"
+                         "link.target = '_blank';"
+                         "document.body.appendChild(link);"
+                         "link.click();"));
   // A new pppup browser is displayed (with the specified URL).
   Browser* new_browser = BrowserAddedWaiter(2u).Wait();
   EXPECT_EQ(new_browser->type(), Browser::TYPE_POPUP);
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc
index 20c3554..0f1dcac 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc
@@ -23,7 +23,6 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/display/screen.h"
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/view.h"
 
@@ -155,21 +154,15 @@
 
 void ProfileManagementStepTestView::ShowAndWait(
     absl::optional<gfx::Size> view_size) {
-  LOG(WARNING) << "crbug.com/1380808 - Timing reference: before Display()";
   Display();
 
   // waits for the view to be shown to return. If we don't wait enough
   // and the test is flaky, try to poll the page to check the presence of some
   // UI elements to know when to stop waiting.
-  LOG(WARNING) << "crbug.com/1380808 - Timing reference: before waiting for "
-                  "the view to be shown";
   run_loop_.Run();
 
   if (view_size.has_value())
     GetWidget()->SetSize(view_size.value());
-
-  LOG(WARNING) << "crbug.com/1380808 - Timing reference: finished waiting for "
-                  "the view to be shown";
 }
 
 std::unique_ptr<ProfileManagementFlowController>
@@ -181,22 +174,6 @@
       run_loop_.QuitClosure());
 }
 
-void ProfileManagementStepTestView::OnNativeWidgetSizeChanged(
-    const gfx::Size& new_size) {
-  LOG(WARNING) << "crbug.com/1380808 - OnNativeWidgetSizeChanged: "
-               << new_size.ToString();
-}
-
-gfx::Size ProfileManagementStepTestView::CalculatePreferredSize() const {
-  gfx::Size preferred_size = ProfilePickerView::CalculatePreferredSize();
-  gfx::Size work_area_size = GetWidget()->GetWorkAreaBoundsInScreen().size();
-  LOG(WARNING)
-      << "crbug.com/1380808 - CalculatePreferredSize: work area size is "
-      << work_area_size.ToString() << " and will return "
-      << preferred_size.ToString();
-  return preferred_size;
-}
-
 // -- Other utils --------------------------------------------------------------
 namespace profiles::testing {
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.h b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.h
index 8183e543..96274b4e 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.h
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.h
@@ -82,9 +82,6 @@
       Profile* picker_profile,
       ClearHostClosure clear_host_callback) override;
 
-  void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override;
-  gfx::Size CalculatePreferredSize() const override;
-
  private:
   const ProfileManagementFlowController::Step step_;
   StepControllerFactory step_controller_factory_;
diff --git a/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc b/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc
index a584639..3b99ae7 100644
--- a/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc
+++ b/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc
@@ -134,7 +134,14 @@
   }
 
   // Open the url in a new tab.
-  browser->OpenURL(params);
+  content::WebContents* new_tab_web_contents = browser->OpenURL(params);
+
+  // Open companion side panel for the new tab.
+  if (new_tab_web_contents) {
+    BrowserView::GetBrowserViewForBrowser(browser)
+        ->side_panel_coordinator()
+        ->Show(SidePanelEntry::Id::kSearchCompanion);
+  }
 }
 
 }  // namespace companion
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_browsertest.cc b/chrome/browser/ui/views/toolbar/chrome_labs_browsertest.cc
index 039442f..5fe583ca 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_browsertest.cc
@@ -9,8 +9,8 @@
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "components/flags_ui/feature_entry_macros.h"
 #include "components/version_info/channel.h"
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc
index f466602f..3209c04 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc
@@ -13,9 +13,9 @@
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/flag_descriptions.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_item_view.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/webui/flags/flags_ui.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/google_chrome_strings.h"
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
index 654f947..0ef6258 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
@@ -33,7 +33,7 @@
 #endif
 
 ChromeLabsButton::ChromeLabsButton(BrowserView* browser_view,
-                                   const ChromeLabsBubbleViewModel* model)
+                                   const ChromeLabsModel* model)
     : ToolbarButton(base::BindRepeating(&ChromeLabsButton::ButtonPressed,
                                         base::Unretained(this))),
       browser_view_(browser_view),
@@ -151,7 +151,7 @@
 }
 
 // static
-bool ChromeLabsButton::ShouldShowButton(const ChromeLabsBubbleViewModel* model,
+bool ChromeLabsButton::ShouldShowButton(const ChromeLabsModel* model,
                                         Profile* profile) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.h b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
index 40961880..cf69be7 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
@@ -7,8 +7,8 @@
 
 #include "base/memory/raw_ptr.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/dot_indicator.h"
@@ -20,7 +20,7 @@
  public:
   METADATA_HEADER(ChromeLabsButton);
   explicit ChromeLabsButton(BrowserView* browser_view,
-                            const ChromeLabsBubbleViewModel* model);
+                            const ChromeLabsModel* model);
   ChromeLabsButton(const ChromeLabsButton&) = delete;
   ChromeLabsButton& operator=(const ChromeLabsButton&) = delete;
   ~ChromeLabsButton() override;
@@ -30,8 +30,7 @@
 
   void HideDotIndicator();
 
-  static bool ShouldShowButton(const ChromeLabsBubbleViewModel* model,
-                               Profile* profile);
+  static bool ShouldShowButton(const ChromeLabsModel* model, Profile* profile);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -61,7 +60,7 @@
   bool should_circumvent_device_check_for_testing_ = false;
 #endif
 
-  raw_ptr<const ChromeLabsBubbleViewModel, DanglingUntriaged> model_;
+  raw_ptr<const ChromeLabsModel, DanglingUntriaged> model_;
 
   raw_ptr<views::DotIndicator> new_experiments_indicator_;
 
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc b/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
index f286158..86c236c8 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
+
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/about_flags.h"
@@ -11,7 +12,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/unexpire_flags.h"
 #include "components/flags_ui/feature_entry_macros.h"
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.cc b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.cc
index 39b66d33..30a105d 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.cc
@@ -22,10 +22,9 @@
 #include "chrome/browser/ash/settings/about_flags.h"
 #endif
 
-ChromeLabsCoordinator::ChromeLabsCoordinator(
-    ChromeLabsButton* anchor_view,
-    Browser* browser,
-    const ChromeLabsBubbleViewModel* model)
+ChromeLabsCoordinator::ChromeLabsCoordinator(ChromeLabsButton* anchor_view,
+                                             Browser* browser,
+                                             const ChromeLabsModel* model)
     : anchor_view_(anchor_view), browser_(browser), chrome_labs_model_(model) {}
 
 ChromeLabsCoordinator::~ChromeLabsCoordinator() {
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
index a249bd4..0f3c75b 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
@@ -5,9 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_COORDINATOR_H_
 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_COORDINATOR_H_
 
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
-
 #include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "components/flags_ui/flags_state.h"
 #include "components/flags_ui/flags_storage.h"
 #include "ui/views/view_observer.h"
@@ -27,9 +26,8 @@
     kChromeOsOwnerUserType,
   };
 
-  ChromeLabsCoordinator(ChromeLabsButton* anchor_view,
-                        Browser* browser,
-                        const ChromeLabsBubbleViewModel* model);
+  ChromeLabsCoordinator(ChromeLabsButton* anchor_view, Browser* browser,
+                        const ChromeLabsModel* model);
   ~ChromeLabsCoordinator() override;
 
   bool BubbleExists();
@@ -54,8 +52,7 @@
 
   raw_ptr<ChromeLabsButton, DanglingUntriaged> anchor_view_;
   raw_ptr<Browser, DanglingUntriaged> browser_;
-  raw_ptr<const ChromeLabsBubbleViewModel, DanglingUntriaged>
-      chrome_labs_model_;
+  raw_ptr<const ChromeLabsModel, DanglingUntriaged> chrome_labs_model_;
   raw_ptr<ChromeLabsBubbleView, DanglingUntriaged> chrome_labs_bubble_view_ =
       nullptr;
 
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_item_view.cc b/chrome/browser/ui/views/toolbar/chrome_labs_item_view.cc
index a38c5eb..d02f6e5 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_item_view.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_item_view.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/views/toolbar/chrome_labs_item_view.h"
+
 #include "base/callback_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ref.h"
@@ -12,7 +13,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/flags_ui/feature_entry.h"
 #include "components/user_education/views/new_badge_label.h"
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc b/chrome/browser/ui/views/toolbar/chrome_labs_model.cc
similarity index 92%
rename from chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
rename to chrome/browser/ui/views/toolbar/chrome_labs_model.cc
index a71b0fa..a1fa2d1 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_model.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
+
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -89,11 +90,11 @@
 
 LabInfo::~LabInfo() = default;
 
-ChromeLabsBubbleViewModel::ChromeLabsBubbleViewModel() : lab_info_(GetData()) {}
+ChromeLabsModel::ChromeLabsModel() : lab_info_(GetData()) {}
 
-ChromeLabsBubbleViewModel::~ChromeLabsBubbleViewModel() = default;
+ChromeLabsModel::~ChromeLabsModel() = default;
 
-const std::vector<LabInfo>& ChromeLabsBubbleViewModel::GetLabInfo() const {
+const std::vector<LabInfo>& ChromeLabsModel::GetLabInfo() const {
   return *lab_info_;
 }
 
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h b/chrome/browser/ui/views/toolbar/chrome_labs_model.h
similarity index 77%
rename from chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h
rename to chrome/browser/ui/views/toolbar/chrome_labs_model.h
index e3a047ce..7160c7a 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_model.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUBBLE_VIEW_MODEL_H_
-#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUBBLE_VIEW_MODEL_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_MODEL_H_
+#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_MODEL_H_
 
 #include <string>
 #include <vector>
@@ -32,10 +32,10 @@
   std::vector<std::u16string> translated_feature_variation_descriptions;
 };
 
-class ChromeLabsBubbleViewModel {
+class ChromeLabsModel {
  public:
-  ChromeLabsBubbleViewModel();
-  ~ChromeLabsBubbleViewModel();
+  ChromeLabsModel();
+  ~ChromeLabsModel();
 
   const std::vector<LabInfo>& GetLabInfo() const;
 
@@ -44,9 +44,9 @@
 };
 
 // ScopedChromeLabsModelDataForTesting is intended to be used in test settings
-// to replace the production data in ChromeLabsBubbleViewModel. Upon
-// destruction, ScopedChromeLabsModelDataForTesting will remove the test data
-// from ChromeLabsBubbleViewModel.
+// to replace the production data in ChromeLabsModel. Upon destruction,
+// ScopedChromeLabsModelDataForTesting will remove the test data from
+// ChromeLabsModel.
 
 class ScopedChromeLabsModelDataForTesting {
  public:
@@ -60,4 +60,4 @@
   void SetModelDataForTesting(const std::vector<LabInfo>& test_feature_info);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUBBLE_VIEW_MODEL_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_MODEL_H_
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model_unittest.cc b/chrome/browser/ui/views/toolbar/chrome_labs_model_unittest.cc
similarity index 83%
rename from chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model_unittest.cc
rename to chrome/browser/ui/views/toolbar/chrome_labs_model_unittest.cc
index 49f2546..9bbc2071 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_model_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "base/i18n/case_conversion.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/test/icu_test_util.h"
 #include "chrome/browser/about_flags.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "components/flags_ui/feature_entry.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,11 +23,10 @@
 }
 }  // namespace
 
-class ChromeLabsBubbleViewModelTest : public ChromeViewsTestBase {};
+class ChromeLabsModelTest : public ChromeViewsTestBase {};
 
-TEST_F(ChromeLabsBubbleViewModelTest, CheckFeaturesHaveSupportedTypes) {
-  std::unique_ptr<ChromeLabsBubbleViewModel> model =
-      std::make_unique<ChromeLabsBubbleViewModel>();
+TEST_F(ChromeLabsModelTest, CheckFeaturesHaveSupportedTypes) {
+  std::unique_ptr<ChromeLabsModel> model = std::make_unique<ChromeLabsModel>();
   const std::vector<LabInfo>& all_labs = model->GetLabInfo();
 
   for (const auto& lab : all_labs) {
@@ -43,11 +42,10 @@
 // Experiments in Chrome Labs must features of type
 // FEATURE_WITH_PARAMS_VALUE must have variation descriptions in Chrome Labs
 // match those declared in about_flags.
-TEST_F(ChromeLabsBubbleViewModelTest, CheckFeatureWithParamsVariations) {
+TEST_F(ChromeLabsModelTest, CheckFeatureWithParamsVariations) {
   base::test::ScopedRestoreICUDefaultLocale locale(std::string("en_US"));
 
-  std::unique_ptr<ChromeLabsBubbleViewModel> model =
-      std::make_unique<ChromeLabsBubbleViewModel>();
+  auto model = std::make_unique<ChromeLabsModel>();
   const std::vector<LabInfo>& all_labs = model->GetLabInfo();
   for (const auto& lab : all_labs) {
     const flags_ui::FeatureEntry* entry =
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_unittest.cc b/chrome/browser/ui/views/toolbar/chrome_labs_unittest.cc
index cfd7257..a3a743c2 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.h"
-
 #include "base/containers/cxx20_erase_vector.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -15,10 +13,11 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_item_view.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_utils.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_view_controller.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -158,7 +157,7 @@
         ->GetMenuItemContainerForTesting();
   }
 
-  ChromeLabsBubbleViewModel* chrome_labs_model() {
+  ChromeLabsModel* chrome_labs_model() {
     return browser_view()->toolbar()->chrome_labs_model();
   }
 
@@ -317,7 +316,7 @@
     return chrome_labs_bubble()->GetMenuItemContainerForTesting();
   }
 
-  ChromeLabsBubbleViewModel* chrome_labs_model() {
+  ChromeLabsModel* chrome_labs_model() {
     return browser_view()->toolbar()->chrome_labs_model();
   }
 
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc b/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc
index 4ce7bb9..bd69593c 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc
@@ -48,7 +48,7 @@
 }
 
 void UpdateChromeLabsNewBadgePrefs(Profile* profile,
-                                   const ChromeLabsBubbleViewModel* model) {
+                                   const ChromeLabsModel* model) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   ScopedDictPrefUpdate update(
       profile->GetPrefs(), chrome_labs_prefs::kChromeLabsNewBadgeDictAshChrome);
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_utils.h b/chrome/browser/ui/views/toolbar/chrome_labs_utils.h
index 062e6a6..3aaaf26 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_utils.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_utils.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_UTILS_H_
 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_UTILS_H_
 
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 
 class Profile;
 
@@ -15,6 +15,6 @@
 // Adds new experiments to PrefService and cleans up preferences for
 // experiments that are no longer featured.
 void UpdateChromeLabsNewBadgePrefs(Profile* profile,
-                                   const ChromeLabsBubbleViewModel* model);
+                                   const ChromeLabsModel* model);
 
 #endif  //  CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_UTILS_H_
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc
index 867b7a3e..7038946 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc
@@ -23,8 +23,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/toolbar/chrome_labs_prefs.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_item_view.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_utils.h"
 #include "chrome/common/buildflags.h"
 #include "components/flags_ui/feature_entry.h"
@@ -101,10 +101,8 @@
 }  // namespace
 
 ChromeLabsViewController::ChromeLabsViewController(
-    const ChromeLabsBubbleViewModel* model,
-    ChromeLabsBubbleView* chrome_labs_bubble_view,
-    Browser* browser,
-    flags_ui::FlagsState* flags_state,
+    const ChromeLabsModel* model, ChromeLabsBubbleView* chrome_labs_bubble_view,
+    Browser* browser, flags_ui::FlagsState* flags_state,
     flags_ui::FlagsStorage* flags_storage)
     : model_(model),
       chrome_labs_bubble_view_(chrome_labs_bubble_view),
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.h b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.h
index 37c8b79..79bc5a3f 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.h
@@ -9,7 +9,7 @@
 #include "base/memory/raw_ptr.h"
 
 class Browser;
-class ChromeLabsBubbleViewModel;
+class ChromeLabsModel;
 class ChromeLabsBubbleView;
 struct LabInfo;
 class Profile;
@@ -22,10 +22,9 @@
 
 class ChromeLabsViewController {
  public:
-  ChromeLabsViewController(const ChromeLabsBubbleViewModel* model,
+  ChromeLabsViewController(const ChromeLabsModel* model,
                            ChromeLabsBubbleView* chrome_labs_bubble_view,
-                           Browser* browser,
-                           flags_ui::FlagsState* flags_state,
+                           Browser* browser, flags_ui::FlagsState* flags_state,
                            flags_ui::FlagsStorage* flags_storage);
   ~ChromeLabsViewController() = default;
 
@@ -44,7 +43,7 @@
 
   bool ShouldLabShowNewBadge(Profile* profile, const LabInfo& lab);
 
-  raw_ptr<const ChromeLabsBubbleViewModel, DanglingUntriaged> model_;
+  raw_ptr<const ChromeLabsModel, DanglingUntriaged> model_;
   raw_ptr<ChromeLabsBubbleView, DanglingUntriaged> chrome_labs_bubble_view_;
   base::CallbackListSubscription restart_callback_;
   raw_ptr<Browser> browser_;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index f650013..8189816 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -66,8 +66,8 @@
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
 #include "chrome/browser/ui/views/toolbar/back_forward_button.h"
 #include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_utils.h"
 #include "chrome/browser/ui/views/toolbar/home_button.h"
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
@@ -342,7 +342,7 @@
   }
 
   if (base::FeatureList::IsEnabled(features::kChromeLabs)) {
-    chrome_labs_model_ = std::make_unique<ChromeLabsBubbleViewModel>();
+    chrome_labs_model_ = std::make_unique<ChromeLabsModel>();
     UpdateChromeLabsNewBadgePrefs(browser_->profile(),
                                   chrome_labs_model_.get());
     if (ChromeLabsButton::ShouldShowButton(chrome_labs_model_.get(),
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index b3c20d4..42165ce8 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -21,7 +21,7 @@
 #include "chrome/browser/ui/views/location_bar/custom_tab_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
-#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
+#include "chrome/browser/ui/views/toolbar/chrome_labs_model.h"
 #include "chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h"
 #include "components/prefs/pref_member.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -136,7 +136,7 @@
   // Accessors.
   Browser* browser() const { return browser_; }
   ChromeLabsButton* chrome_labs_button() const { return chrome_labs_button_; }
-  ChromeLabsBubbleViewModel* chrome_labs_model() const {
+  ChromeLabsModel* chrome_labs_model() const {
     return chrome_labs_model_.get();
   }
   DownloadToolbarButtonView* download_button() const {
@@ -287,7 +287,7 @@
 
   AppMenuIconController app_menu_icon_controller_;
 
-  std::unique_ptr<ChromeLabsBubbleViewModel> chrome_labs_model_;
+  std::unique_ptr<ChromeLabsModel> chrome_labs_model_;
 
   // Controls whether or not a home button should be shown on the toolbar.
   BooleanPrefMember show_home_button_;
diff --git a/chrome/browser/ui/webui/management/management_ui.cc b/chrome/browser/ui/webui/management/management_ui.cc
index 4414485..386d6c8 100644
--- a/chrome/browser/ui/webui/management/management_ui.cc
+++ b/chrome/browser/ui/webui/management/management_ui.cc
@@ -204,8 +204,6 @@
   std::string account_manager = connector->GetEnterpriseDomainManager();
 
   if (account_manager.empty())
-    account_manager = connector->GetRealm();
-  if (account_manager.empty())
     account_manager =
         chrome::GetAccountManagerIdentity(profile).value_or(std::string());
   if (account_manager.empty()) {
diff --git a/chrome/browser/ui/webui/ntp/app_resource_cache_factory.cc b/chrome/browser/ui/webui/ntp/app_resource_cache_factory.cc
index 8bd95e68..5cbd28b 100644
--- a/chrome/browser/ui/webui/ntp/app_resource_cache_factory.cc
+++ b/chrome/browser/ui/webui/ntp/app_resource_cache_factory.cc
@@ -22,7 +22,12 @@
 AppResourceCacheFactory::AppResourceCacheFactory()
     : ProfileKeyedServiceFactory(
           "AppResourceCache",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(ThemeServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
index 2090e34..a342694 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
@@ -23,7 +23,12 @@
 NTPResourceCacheFactory::NTPResourceCacheFactory()
     : ProfileKeyedServiceFactory(
           "NTPResourceCache",
-          ProfileSelections::BuildRedirectedInIncognito()) {
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // TODO(crbug.com/1418376): Check if this service is needed in
+              // Guest mode.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              .Build()) {
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(ThemeServiceFactory::GetInstance());
 }
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
index de36117..6335b6e0 100644
--- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -429,7 +429,7 @@
   WaitUntilAnyElementExistsInSigninFrame(web_contents, {"identifierId"});
   std::string js = "document.getElementById('identifierId').value = '" + email +
                    "'; document.getElementById('identifierNext').click();";
-  ASSERT_TRUE(content::ExecuteScript(GetSigninFrame(web_contents), js));
+  ASSERT_TRUE(content::ExecJs(GetSigninFrame(web_contents), js));
 
   // Fill the password input field.
   std::string password_script = kGetPasswordFieldFromDiceSigninPage;
@@ -442,7 +442,7 @@
       "Could not find Dice password field");
   js = password_script + ".value = '" + password + "';";
   js += "document.getElementById('passwordNext').click();";
-  ASSERT_TRUE(content::ExecuteScript(GetSigninFrame(web_contents), js));
+  ASSERT_TRUE(content::ExecJs(GetSigninFrame(web_contents), js));
 }
 
 void SigninInOldGaiaFlow(content::WebContents* web_contents,
@@ -451,12 +451,12 @@
   WaitUntilAnyElementExistsInSigninFrame(web_contents, {"Email"});
   std::string js = "document.getElementById('Email').value = '" + email + ";" +
                    "document.getElementById('next').click();";
-  ASSERT_TRUE(content::ExecuteScript(GetSigninFrame(web_contents), js));
+  ASSERT_TRUE(content::ExecJs(GetSigninFrame(web_contents), js));
 
   WaitUntilAnyElementExistsInSigninFrame(web_contents, {"Passwd"});
   js = "document.getElementById('Passwd').value = '" + password + "';" +
        "document.getElementById('signIn').click();";
-  ASSERT_TRUE(content::ExecuteScript(GetSigninFrame(web_contents), js));
+  ASSERT_TRUE(content::ExecJs(GetSigninFrame(web_contents), js));
 }
 
 void ExecuteJsToSigninInSigninFrame(content::WebContents* web_contents,
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index de50b9c..dc76d33 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1683691139-f0071c2a614b8dbae84eb46d756ff36e98a6a64d.profdata
+chrome-chromeos-amd64-generic-main-1683705582-f0fd4a67ea09b45afb5cedeb9b28224c1bd66714.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index ff87d6b..139d6c5 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1683697968-ed4be0a7b127abd7f743a7c07426f25c69af46db.profdata
+chrome-mac-arm-main-1683719935-268373f4bced8f6cad2c84a9f1f28054d29ab150.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index c35cd95..5335a88 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1683676781-e4349f7606590f8394367293c26164478a696299.profdata
+chrome-win32-main-1683707573-36a3a937b1b1f3e52396f9d1812955b1a4aafab1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index d3e08f8..7470e5b 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1683687395-fb75d49602ddac69c0fb3996cb0d4b213b682797.profdata
+chrome-win64-main-1683707573-21cb7c61e240d36241a2ec301747587c3a057541.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index d51041d..b8d90a6 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -1001,6 +1001,9 @@
     kSafetyCheckNotificationPermissionsLowEnagementLimit{
         &kSafetyCheckNotificationPermissions,
         "low-engagement-notification-count", 4};
+
+// Enables Safety Hub feature.
+BASE_FEATURE(kSafetyHub, "SafetyHub", base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -1536,14 +1539,14 @@
 
 BASE_FEATURE(kWebAuthFlowInBrowserTab,
              "WebAuthFlowInBrowserTab",
-             base::FeatureState::FEATURE_DISABLED_BY_DEFAULT);
+             base::FeatureState::FEATURE_ENABLED_BY_DEFAULT);
 const base::FeatureParam<WebAuthFlowInBrowserTabMode>::Option
     web_auth_flow_modes[] = {
         {WebAuthFlowInBrowserTabMode::kNewTab, "new_tab"},
         {WebAuthFlowInBrowserTabMode::kPopupWindow, "popup_window"}};
 const base::FeatureParam<WebAuthFlowInBrowserTabMode>
     kWebAuthFlowInBrowserTabMode{&kWebAuthFlowInBrowserTab, "browser_tab_mode",
-                                 WebAuthFlowInBrowserTabMode::kNewTab,
+                                 WebAuthFlowInBrowserTabMode::kPopupWindow,
                                  &web_auth_flow_modes};
 
 }  // namespace features
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 1be0f7d..c4b86d5 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -580,6 +580,9 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<int>
     kSafetyCheckNotificationPermissionsLowEnagementLimit;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+BASE_DECLARE_FEATURE(kSafetyHub);
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c6cd3a5..94049a6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5582,6 +5582,7 @@
     "../browser/enterprise/connectors/interstitials/enterprise_page_unittest.cc",
     "../browser/enterprise/identifiers/profile_id_service_factory_unittest.cc",
     "../browser/enterprise/reporting/browser_report_generator_unittest.cc",
+    "../browser/enterprise/reporting/legacy_tech/legacy_tech_url_matcher_unittest.cc",
     "../browser/enterprise/reporting/policy_info_unittest.cc",
     "../browser/enterprise/reporting/profile_report_generator_unittest.cc",
     "../browser/enterprise/reporting/report_generator_unittest.cc",
@@ -6827,6 +6828,7 @@
       "//chrome/browser/share",
       "//chrome/browser/thumbnail:unit_tests",
       "//chrome/browser/thumbnail/cc:features",
+      "//chrome/browser/touch_to_fill/password_generation/android:unit_tests",
       "//chrome/browser/touch_to_fill/payments/android:public",
       "//chrome/services/media_gallery_util:unit_tests",
       "//components/back_forward_cache",
@@ -9133,8 +9135,8 @@
       "../browser/ui/views/tabs/tab_strip_scroll_session_unittest.cc",
       "../browser/ui/views/tabs/tab_strip_unittest.cc",
       "../browser/ui/views/tabs/tab_unittest.cc",
-      "../browser/ui/views/toolbar/chrome_labs_bubble_view_model_unittest.cc",
       "../browser/ui/views/toolbar/chrome_labs_button_unittest.cc",
+      "../browser/ui/views/toolbar/chrome_labs_model_unittest.cc",
       "../browser/ui/views/toolbar/chrome_labs_unittest.cc",
       "../browser/ui/views/toolbar/reload_button_unittest.cc",
       "../browser/ui/views/toolbar/side_panel_toolbar_button_unittest.cc",
diff --git a/chrome/test/base/memory_tracing_browsertest.cc b/chrome/test/base/memory_tracing_browsertest.cc
index 88454949..99e9f93 100644
--- a/chrome/test/base/memory_tracing_browsertest.cc
+++ b/chrome/test/base/memory_tracing_browsertest.cc
@@ -64,7 +64,7 @@
     content::WebContents* wc =
         browser()->tab_strip_model()->GetActiveWebContents();
     ASSERT_TRUE(wc);
-    ASSERT_TRUE(content::ExecuteScript(wc, ";"));
+    ASSERT_TRUE(content::ExecJs(wc, ";"));
   }
 
   void PerformDumpMemoryTestActions(
diff --git a/chromeos/components/kcer/kcer.h b/chromeos/components/kcer/kcer.h
index c9f3d93c..c0d9704 100644
--- a/chromeos/components/kcer/kcer.h
+++ b/chromeos/components/kcer/kcer.h
@@ -59,8 +59,11 @@
   kFailedToImportCertificate = 10,
   kFailedToRemoveCertificate = 11,
   kKeyNotFound = 12,
-  kFailedToGetKeyId = 13,
-  kFailedToWriteAttribute = 14,
+  kUnknownKeyType = 13,
+  kFailedToGetKeyId = 14,
+  kFailedToReadAttribute = 15,
+  kFailedToWriteAttribute = 16,
+  kFailedToParseKeyPermissions = 17,
 };
 
 // Handles for tokens on ChromeOS.
@@ -97,14 +100,12 @@
   kRsaPkcs1Sha256 = SSL_SIGN_RSA_PKCS1_SHA256,
   kRsaPkcs1Sha384 = SSL_SIGN_RSA_PKCS1_SHA384,
   kRsaPkcs1Sha512 = SSL_SIGN_RSA_PKCS1_SHA512,
-  kEcdsaSha1 = SSL_SIGN_ECDSA_SHA1,
   kEcdsaSecp256r1Sha256 = SSL_SIGN_ECDSA_SECP256R1_SHA256,
   kEcdsaSecp384r1Sha384 = SSL_SIGN_ECDSA_SECP384R1_SHA384,
   kEcdsaSecp521r1Sha512 = SSL_SIGN_ECDSA_SECP521R1_SHA512,
   kRsaPssRsaeSha256 = SSL_SIGN_RSA_PSS_RSAE_SHA256,
   kRsaPssRsaeSha384 = SSL_SIGN_RSA_PSS_RSAE_SHA384,
   kRsaPssRsaeSha512 = SSL_SIGN_RSA_PSS_RSAE_SHA512,
-  kEd25519 = SSL_SIGN_ED25519,
 };
 
 class COMPONENT_EXPORT(KCER) PublicKey {
diff --git a/chromeos/components/kcer/kcer_impl.cc b/chromeos/components/kcer/kcer_impl.cc
index 3b684cc7..8c574894 100644
--- a/chromeos/components/kcer/kcer_impl.cc
+++ b/chromeos/components/kcer/kcer_impl.cc
@@ -246,7 +246,35 @@
 }
 
 void KcerImpl::GetKeyInfo(PrivateKeyHandle key, GetKeyInfoCallback callback) {
-  // TODO(244408716): Implement.
+  if (key.GetTokenInternal().has_value()) {
+    return GetKeyInfoWithToken(std::move(callback), std::move(key));
+  }
+
+  auto on_find_key_done =
+      base::BindOnce(&KcerImpl::GetKeyInfoWithToken, weak_factory_.GetWeakPtr(),
+                     std::move(callback));
+  return PopulateTokenForKey(
+      /*key=*/std::move(key), std::move(on_find_key_done));
+}
+
+void KcerImpl::GetKeyInfoWithToken(
+    GetKeyInfoCallback callback,
+    base::expected<PrivateKeyHandle, Error> key_or_error) {
+  if (!key_or_error.has_value()) {
+    return std::move(callback).Run(base::unexpected(key_or_error.error()));
+  }
+  PrivateKeyHandle key = std::move(key_or_error).value();
+
+  const base::WeakPtr<KcerToken>& kcer_token =
+      GetToken(key.GetTokenInternal().value());
+  if (!kcer_token.MaybeValid()) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kTokenIsNotAvailable));
+  }
+  token_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&KcerToken::GetKeyInfo, kcer_token, std::move(key),
+                     base::BindPostTaskToCurrentDefault(std::move(callback))));
 }
 
 void KcerImpl::SetKeyNickname(PrivateKeyHandle key,
diff --git a/chromeos/components/kcer/kcer_impl.h b/chromeos/components/kcer/kcer_impl.h
index c3aaa14..8a0cbd3 100644
--- a/chromeos/components/kcer/kcer_impl.h
+++ b/chromeos/components/kcer/kcer_impl.h
@@ -118,9 +118,14 @@
       DoesKeyExistCallback callback,
       base::expected<absl::optional<Token>, Error> find_key_result);
 
-  void SetKeyNicknameWithToken(std::string nickname,
-                               StatusCallback callback,
-                               base::expected<PrivateKeyHandle, Error> key);
+  void GetKeyInfoWithToken(
+      GetKeyInfoCallback callback,
+      base::expected<PrivateKeyHandle, Error> key_or_error);
+
+  void SetKeyNicknameWithToken(
+      std::string nickname,
+      StatusCallback callback,
+      base::expected<PrivateKeyHandle, Error> key_or_error);
 
   // Task runner for the tokens. Can be nullptr if no tokens are available
   // to the current Kcer instance.
diff --git a/components/autofill/core/browser/autocomplete_history_manager.cc b/components/autofill/core/browser/autocomplete_history_manager.cc
index 2a5db4f..c5e7945 100644
--- a/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -156,14 +156,14 @@
 void AutocompleteHistoryManager::OnRemoveCurrentSingleFieldSuggestion(
     const std::u16string& field_name,
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   if (profile_database_)
     profile_database_->RemoveFormValueForElementName(field_name, value);
 }
 
 void AutocompleteHistoryManager::OnSingleFieldSuggestionSelected(
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   // Try to find the AutofillEntry associated with the given suggestion.
   auto last_entries_iter = last_entries_.find(value);
   if (last_entries_iter == last_entries_.end()) {
diff --git a/components/autofill/core/browser/autocomplete_history_manager.h b/components/autofill/core/browser/autocomplete_history_manager.h
index 5ae47d00..037472c 100644
--- a/components/autofill/core/browser/autocomplete_history_manager.h
+++ b/components/autofill/core/browser/autocomplete_history_manager.h
@@ -54,11 +54,13 @@
   void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
                                   bool is_autocomplete_enabled) override;
   void CancelPendingQueries(const SuggestionsHandler* handler) override;
-  void OnRemoveCurrentSingleFieldSuggestion(const std::u16string& field_name,
-                                            const std::u16string& value,
-                                            int frontend_id) override;
-  void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                       int frontend_id) override;
+  void OnRemoveCurrentSingleFieldSuggestion(
+      const std::u16string& field_name,
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
+  void OnSingleFieldSuggestionSelected(
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
 
   // Initializes the instance with the given parameters.
   // |profile_database_| is a profile-scope DB used to access autocomplete data.
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 2dcf5c9ff..3b7eb4dc 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -20,8 +20,8 @@
 #include "components/autofill/core/browser/payments/legal_message_line.h"
 #include "components/autofill/core/browser/payments/risk_data_loader.h"
 #include "components/autofill/core/browser/ui/fast_checkout_client.h"
-#include "components/autofill/core/browser/ui/popup_item_ids.h"
 #include "components/autofill/core/browser/ui/popup_types.h"
+#include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/aliases.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
@@ -762,7 +762,7 @@
   virtual bool IsContextSecure() const = 0;
 
   // Handles simple actions for the autofill popups.
-  virtual void ExecuteCommand(int id) = 0;
+  virtual void ExecuteCommand(Suggestion::FrontendId id) = 0;
 
   // Returns a LogManager instance. May be null for platforms that don't support
   // this.
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index 5bb33287..e781d1d 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -45,7 +45,7 @@
 
 // Returns true if the suggestion entry is an Autofill warning message.
 // Warning messages should display on top of suggestion list.
-bool IsAutofillWarningEntry(int frontend_id) {
+bool IsAutofillWarningEntry(Suggestion::FrontendId frontend_id) {
   return frontend_id ==
              POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE ||
          frontend_id == POPUP_ITEM_ID_MIXED_FORM_MESSAGE;
@@ -109,7 +109,7 @@
   // suggestions.
   has_autofill_suggestions_ = false;
   for (auto& suggestion : suggestions) {
-    if (suggestion.frontend_id > 0) {
+    if (suggestion.frontend_id.as_int() > 0) {
       has_autofill_suggestions_ = true;
       break;
     }
@@ -209,12 +209,12 @@
 
 void AutofillExternalDelegate::DidSelectSuggestion(
     const std::u16string& value,
-    int frontend_id,
+    Suggestion::FrontendId frontend_id,
     const Suggestion::BackendId& backend_id) {
   ClearPreviewedForm();
 
   // Only preview the data if it is a profile or a virtual card.
-  if (frontend_id > 0) {
+  if (frontend_id.as_int() > 0) {
     FillAutofillFormData(frontend_id, true,
                          AutofillTriggerSource::kKeyboardAccessory);
   } else if (frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY ||
@@ -231,7 +231,7 @@
 
 void AutofillExternalDelegate::DidAcceptSuggestion(const Suggestion& suggestion,
                                                    int position) {
-  switch (suggestion.frontend_id) {
+  switch (suggestion.frontend_id.as_popup_item_id()) {
     case POPUP_ITEM_ID_AUTOFILL_OPTIONS:
       // User selected 'Autofill Options'.
       autofill_metrics::LogAutofillSelectedManageEntry(popup_type_);
@@ -308,7 +308,8 @@
           suggestion.frontend_id, query_form_, query_field_);
       break;
     default:
-      if (suggestion.frontend_id > 0) {  // Denotes an Autofill suggestion.
+      if (suggestion.frontend_id.as_int() >
+          0) {  // Denotes an Autofill suggestion.
         autofill_metrics::LogAutofillSuggestionAcceptedIndex(
             position, popup_type_, manager_->client()->IsOffTheRecord());
       }
@@ -334,16 +335,18 @@
 
 bool AutofillExternalDelegate::GetDeletionConfirmationText(
     const std::u16string& value,
-    int frontend_id,
+    Suggestion::FrontendId frontend_id,
     std::u16string* title,
     std::u16string* body) {
   return manager_->GetDeletionConfirmationText(value, frontend_id, title, body);
 }
 
-bool AutofillExternalDelegate::RemoveSuggestion(const std::u16string& value,
-                                                int frontend_id) {
-  if (frontend_id > 0)
+bool AutofillExternalDelegate::RemoveSuggestion(
+    const std::u16string& value,
+    Suggestion::FrontendId frontend_id) {
+  if (frontend_id.as_int() > 0) {
     return manager_->RemoveAutofillProfileOrCreditCard(frontend_id);
+  }
 
   if (frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
     manager_->RemoveCurrentSingleFieldSuggestion(query_field_.name, value,
@@ -398,7 +401,7 @@
 }
 
 void AutofillExternalDelegate::FillAutofillFormData(
-    int unique_id,
+    Suggestion::FrontendId unique_id,
     bool is_preview,
     const AutofillTriggerSource trigger_source) {
   // If the selected element is a warning we don't want to do anything.
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h
index c97a484..9cb58e6a 100644
--- a/components/autofill/core/browser/autofill_external_delegate.h
+++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -49,14 +49,15 @@
   void OnPopupHidden() override;
   void OnPopupSuppressed() override;
   void DidSelectSuggestion(const std::u16string& value,
-                           int frontend_id,
+                           Suggestion::FrontendId frontend_id,
                            const Suggestion::BackendId& backend_id) override;
   void DidAcceptSuggestion(const Suggestion& suggestion, int position) override;
   bool GetDeletionConfirmationText(const std::u16string& value,
-                                   int frontend_id,
+                                   Suggestion::FrontendId frontend_id,
                                    std::u16string* title,
                                    std::u16string* body) override;
-  bool RemoveSuggestion(const std::u16string& value, int frontend_id) override;
+  bool RemoveSuggestion(const std::u16string& value,
+                        Suggestion::FrontendId frontend_id) override;
   void ClearPreviewedForm() override;
 
   // Returns PopupType::kUnspecified for all popups prior to |onQuery|, or the
@@ -128,7 +129,7 @@
   // If |is_preview| is true then this is just a preview to show the user what
   // would be selected and if |is_preview| is false then the user has selected
   // this data.
-  void FillAutofillFormData(int unique_id,
+  void FillAutofillFormData(Suggestion::FrontendId unique_id,
                             bool is_preview,
                             const AutofillTriggerSource trigger_source);
 
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 1ff39aa..87ab9e9 100644
--- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -45,7 +45,7 @@
 namespace {
 
 // A constant value to use as an Autofill profile ID.
-const int kAutofillProfileId = 1;
+constexpr Suggestion::FrontendId kAutofillProfileId = Suggestion::FrontendId(1);
 
 class MockAutofillDriver : public TestAutofillDriver {
  public:
@@ -89,7 +89,7 @@
                const std::vector<std::u16string>& lables),
               (override));
   MOCK_METHOD(void, HideAutofillPopup, (PopupHidingReason), (override));
-  MOCK_METHOD(void, ExecuteCommand, (int), (override));
+  MOCK_METHOD(void, ExecuteCommand, (Suggestion::FrontendId), (override));
   MOCK_METHOD(void,
               OpenPromoCodeOfferDetailsURL,
               (const GURL& url),
@@ -158,7 +158,7 @@
               (mojom::RendererFormDataAction action,
                const FormData& form,
                const FormFieldData& field,
-               int unique_id,
+               Suggestion::FrontendId unique_id,
                const AutofillTriggerSource trigger_source),
               (override));
   MOCK_METHOD(void,
@@ -244,13 +244,6 @@
 TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
   IssueOnQuery();
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(kAutofillProfileId,
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -261,7 +254,12 @@
   autofill_item[0].frontend_id = kAutofillProfileId;
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(kAutofillProfileId,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 
   EXPECT_CALL(
@@ -284,13 +282,6 @@
 
   IssueOnQuery();
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(kAutofillProfileId,
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -305,7 +296,12 @@
                                             AutoselectFirstSuggestion(false));
   EXPECT_EQ(0, user_action_tester.GetActionCount(
                    "Signin_Impression_FromAutofillDropdown"));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(kAutofillProfileId,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 
   EXPECT_CALL(
@@ -328,10 +324,6 @@
 
   IssueOnQuery();
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids = testing::ElementsAre(
-      static_cast<int>(POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
-
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -344,11 +336,12 @@
                                             AutoselectFirstSuggestion(false));
   EXPECT_EQ(1, user_action_tester.GetActionCount(
                    "Signin_Impression_FromAutofillDropdown"));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 
-  EXPECT_CALL(autofill_client_,
-              ExecuteCommand(autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
+  EXPECT_CALL(autofill_client_, ExecuteCommand(Suggestion::FrontendId(
+                                    POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO)));
   EXPECT_CALL(autofill_client_,
               HideAutofillPopup(PopupHidingReason::kAcceptSuggestion));
 
@@ -371,17 +364,6 @@
   external_delegate_->SetCurrentDataListValues(data_list_items,
                                                data_list_items);
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           kAutofillProfileId,
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -392,12 +374,20 @@
   autofill_item[0].frontend_id = kAutofillProfileId;
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_DATALIST_ENTRY,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     kAutofillProfileId,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 
   // Try calling OnSuggestionsReturned with no Autofill values and ensure
   // the datalist items are still shown.
-  // The enum must be cast to an int to prevent compile errors on linux_rel.
 
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -406,8 +396,7 @@
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(testing::ElementsAre(
-                  static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY))));
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_DATALIST_ENTRY));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -428,17 +417,6 @@
   external_delegate_->SetCurrentDataListValues(data_list_items,
                                                data_list_items);
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           kAutofillProfileId,
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -449,7 +427,16 @@
   autofill_item[0].frontend_id = kAutofillProfileId;
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_DATALIST_ENTRY,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     kAutofillProfileId,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 
   // This would normally get called from ShowAutofillPopup, but it is mocked so
@@ -459,7 +446,6 @@
   // Update the current data list and ensure the popup is updated.
   data_list_items.emplace_back();
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
   EXPECT_CALL(autofill_client_, UpdateAutofillPopupDataListValues(
                                     data_list_items, data_list_items));
 
@@ -481,18 +467,6 @@
   external_delegate_->SetCurrentDataListValues(data_list_values,
                                                data_list_labels);
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-                           static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           kAutofillProfileId,
-#if !BUILDFLAG(IS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -506,7 +480,17 @@
   autofill_item[0].frontend_id = kAutofillProfileId;
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_DATALIST_ENTRY,
+                                     POPUP_ITEM_ID_DATALIST_ENTRY,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     kAutofillProfileId,
+#if !BUILDFLAG(IS_ANDROID)
+                                     POPUP_ITEM_ID_SEPARATOR,
+#endif
+                                     POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -524,15 +508,6 @@
   external_delegate_->SetCurrentDataListValues(data_list_values,
                                                data_list_labels);
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids = testing::ElementsAre(
-      // We are expecting only two data list entries.
-      static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-      static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !BUILDFLAG(IS_ANDROID)
-      static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-      static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY));
   AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client_, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -550,7 +525,14 @@
   autocomplete_items[1].frontend_id = POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY;
   external_delegate_->OnSuggestionsReturned(field_id_, autocomplete_items,
                                             AutoselectFirstSuggestion(false));
-  EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+  EXPECT_THAT(open_args.suggestions,
+              SuggestionVectorIdsAre(
+                  // We are expecting only two data list entries.
+                  POPUP_ITEM_ID_DATALIST_ENTRY, POPUP_ITEM_ID_DATALIST_ENTRY,
+#if !BUILDFLAG(IS_ANDROID)
+                  POPUP_ITEM_ID_SEPARATOR,
+#endif
+                  POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -572,10 +554,9 @@
   external_delegate_->OnSuggestionsReturned(field_id_, autofill_item,
                                             AutoselectFirstSuggestion(false));
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(testing::ElementsAre(static_cast<int>(
-                  POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE))));
+              SuggestionVectorIdsAre(
+                  POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE));
   EXPECT_EQ(open_args.element_bounds, gfx::RectF());
   EXPECT_EQ(open_args.text_direction, base::i18n::UNKNOWN_DIRECTION);
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
@@ -603,10 +584,8 @@
   external_delegate_->OnSuggestionsReturned(field_id_, suggestions,
                                             AutoselectFirstSuggestion(false));
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(testing::ElementsAre(
-                  static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))));
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -617,8 +596,8 @@
   EXPECT_CALL(*browser_autofill_manager_, FillOrPreviewForm(_, _, _, _, _))
       .Times(0);
   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
-  external_delegate_->DidSelectSuggestion(std::u16string(), -1,
-                                          Suggestion::BackendId());
+  external_delegate_->DidSelectSuggestion(
+      std::u16string(), Suggestion::FrontendId(-1), Suggestion::BackendId());
 
   // Ensure it doesn't try to fill the form in with the negative id.
   EXPECT_CALL(autofill_client_,
@@ -626,7 +605,8 @@
   EXPECT_CALL(*browser_autofill_manager_, FillOrPreviewForm(_, _, _, _, _))
       .Times(0);
 
-  external_delegate_->DidAcceptSuggestion(Suggestion(-1), 0);
+  external_delegate_->DidAcceptSuggestion(
+      Suggestion(Suggestion::FrontendId(-1)), 0);
 }
 
 // Test that the Autofill delegate still allows previewing and filling
@@ -650,10 +630,8 @@
   external_delegate_->OnSuggestionsReturned(field_id_, suggestions,
                                             AutoselectFirstSuggestion(false));
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(testing::ElementsAre(
-                  static_cast<int>(POPUP_ITEM_ID_IBAN_ENTRY))));
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_IBAN_ENTRY));
 
   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
   EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue(
@@ -687,10 +665,8 @@
   external_delegate_->OnSuggestionsReturned(field_id_, suggestions,
                                             AutoselectFirstSuggestion(false));
 
-  // The enums must be cast to ints to prevent compile errors on linux_rel.
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(testing::ElementsAre(
-                  static_cast<int>(POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY))));
+              SuggestionVectorIdsAre(POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY));
 
   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
   EXPECT_CALL(*autofill_driver_,
@@ -735,7 +711,7 @@
   EXPECT_CALL(
       *browser_autofill_manager_,
       FillOrPreviewForm(mojom::RendererFormDataAction::kPreview, _, _, _, _));
-  external_delegate_->DidSelectSuggestion(u"baz foo", 1,
+  external_delegate_->DidSelectSuggestion(u"baz foo", Suggestion::FrontendId(1),
                                           Suggestion::BackendId());
 
   // Ensure selecting an autocomplete entry will cause any previews to
@@ -889,8 +865,8 @@
 // Test that autofill client will start the signin flow after the user accepted
 // the suggestion to sign in.
 TEST_F(AutofillExternalDelegateUnitTest, SigninPromoMenuItem) {
-  EXPECT_CALL(autofill_client_,
-              ExecuteCommand(autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
+  EXPECT_CALL(autofill_client_, ExecuteCommand(Suggestion::FrontendId(
+                                    POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO)));
   EXPECT_CALL(autofill_client_,
               HideAutofillPopup(PopupHidingReason::kAcceptSuggestion));
 
@@ -942,8 +918,9 @@
   EXPECT_CALL(*autofill_driver_,
               RendererShouldFillFieldWithValue(field_id_, dummy_string));
   EXPECT_CALL(*autofill_client_.GetMockAutocompleteHistoryManager(),
-              OnSingleFieldSuggestionSelected(dummy_string,
-                                              POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))
+              OnSingleFieldSuggestionSelected(
+                  dummy_string,
+                  Suggestion::FrontendId(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)))
       .Times(1);
   base::HistogramTester histogram_tester;
 
@@ -960,7 +937,8 @@
               RendererShouldFillFieldWithValue(field_id_, dummy_string));
   EXPECT_CALL(*autofill_client_.GetMockMerchantPromoCodeManager(),
               OnSingleFieldSuggestionSelected(
-                  dummy_string, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY))
+                  dummy_string, Suggestion::FrontendId(
+                                    POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY)))
       .Times(1);
   external_delegate_->DidAcceptSuggestion(
       test::CreateAutofillSuggestion(POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY,
@@ -972,9 +950,10 @@
   // Test that IBANs get autofilled.
   EXPECT_CALL(*autofill_driver_,
               RendererShouldFillFieldWithValue(field_id_, ummasked_iban_value));
-  EXPECT_CALL(*autofill_client_.GetMockIBANManager(),
-              OnSingleFieldSuggestionSelected(masked_iban_value,
-                                              POPUP_ITEM_ID_IBAN_ENTRY));
+  EXPECT_CALL(
+      *autofill_client_.GetMockIBANManager(),
+      OnSingleFieldSuggestionSelected(
+          masked_iban_value, Suggestion::FrontendId(POPUP_ITEM_ID_IBAN_ENTRY)));
   external_delegate_->DidAcceptSuggestion(
       test::CreateAutofillSuggestion(
           POPUP_ITEM_ID_IBAN_ENTRY, masked_iban_value,
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc
index 331a467..fb94a801 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -216,7 +216,7 @@
   }
 
   for (Suggestion& suggestion : suggestions) {
-    if (suggestion.frontend_id == 0) {
+    if (suggestion.frontend_id.as_int() == 0) {
       suggestion.frontend_id = MakeFrontendIdFromBackendId(
           suggestion.GetPayload<Suggestion::BackendId>());
     }
@@ -406,10 +406,10 @@
   return card.nickname();
 }
 
-int AutofillSuggestionGenerator::MakeFrontendIdFromBackendId(
+Suggestion::FrontendId AutofillSuggestionGenerator::MakeFrontendIdFromBackendId(
     const Suggestion::BackendId& cc_or_address_backend_id) {
   if (!base::Uuid::ParseCaseInsensitive(*cc_or_address_backend_id).is_valid()) {
-    return 0;
+    return Suggestion::FrontendId();
   }
 
   int& frontend_id = backend_to_frontend_map_[cc_or_address_backend_id];
@@ -419,16 +419,16 @@
   }
   DCHECK_GT(frontend_id, 0);
   DCHECK_EQ(backend_to_frontend_map_.size(), frontend_to_backend_map_.size());
-  return frontend_id;
+  return Suggestion::FrontendId(frontend_id);
 }
 
 Suggestion::BackendId AutofillSuggestionGenerator::GetBackendIdFromFrontendId(
-    int frontend_id) {
-  if (frontend_id <= 0) {
+    Suggestion::FrontendId frontend_id) {
+  if (frontend_id.as_int() <= 0) {
     NOTREACHED();
     return Suggestion::BackendId();
   }
-  const auto it = frontend_to_backend_map_.find(frontend_id);
+  const auto it = frontend_to_backend_map_.find(frontend_id.as_int());
   if (it == frontend_to_backend_map_.end()) {
     NOTREACHED();
     return Suggestion::BackendId();
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.h b/components/autofill/core/browser/autofill_suggestion_generator.h
index b19a1a0..9d8d9ee 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.h
+++ b/components/autofill/core/browser/autofill_suggestion_generator.h
@@ -108,9 +108,10 @@
 
   // Methods for packing and unpacking credit card and profile IDs for sending
   // and receiving to and from the renderer process.
-  int MakeFrontendIdFromBackendId(
+  Suggestion::FrontendId MakeFrontendIdFromBackendId(
       const Suggestion::BackendId& cc_or_address_backend_id);
-  Suggestion::BackendId GetBackendIdFromFrontendId(int frontend_id);
+  Suggestion::BackendId GetBackendIdFromFrontendId(
+      Suggestion::FrontendId frontend_id);
 
   // Helper function to decide whether to show the virtual card option for
   // `candidate_card`.
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index dadb08d4..38f69d0 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -784,7 +784,9 @@
 TEST_F(AutofillSuggestionGeneratorTest, BackendIdAndFrontendIdMappings) {
   // Test that frontend ID retrieval with an invalid backend ID works correctly.
   Suggestion::BackendId backend_id = Suggestion::BackendId();
-  EXPECT_FALSE(suggestion_generator()->MakeFrontendIdFromBackendId(backend_id));
+  EXPECT_EQ(
+      suggestion_generator()->MakeFrontendIdFromBackendId(backend_id).as_int(),
+      0);
 
   // Test that frontend ID retrieval with valid backend IDs works correctly.
   std::string valid_guid_digits = "00000000-0000-0000-0000-000000000000";
@@ -796,9 +798,9 @@
     // AutofillSuggestionGenerator::MakeFrontendIdFromBackendId(~) with a new
     // backend id creates a new entry in the backend_to_frontend_map() and
     // frontend_to_backend_map() maps.
-    const int& frontend_id =
+    Suggestion::FrontendId frontend_id =
         suggestion_generator()->MakeFrontendIdFromBackendId(backend_id);
-    EXPECT_GT(frontend_id, 0);
+    EXPECT_GT(frontend_id.as_int(), 0);
     EXPECT_EQ(static_cast<int>(suggestion_generator()
                                    ->backend_to_frontend_map_for_testing()
                                    .size()),
@@ -831,7 +833,8 @@
 
   // Test that backend ID retrieval with valid frontend IDs works correctly.
   for (int i = 1; i <= 2; i++) {
-    backend_id = suggestion_generator()->GetBackendIdFromFrontendId(i);
+    backend_id = suggestion_generator()->GetBackendIdFromFrontendId(
+        Suggestion::FrontendId(i));
     EXPECT_FALSE(backend_id->empty());
     valid_guid_digits.back() = base::NumberToString(i)[0];
     EXPECT_EQ(*backend_id, valid_guid_digits);
@@ -1126,7 +1129,7 @@
           /*virtual_card_option=*/false,
           /*card_linked_offer_available=*/false);
 
-  EXPECT_EQ(real_card_suggestion.frontend_id, 0);
+  EXPECT_EQ(real_card_suggestion.frontend_id.as_int(), 0);
   EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(),
             Suggestion::BackendId("00000000-0000-0000-0000-000000000001"));
   EXPECT_EQ(VerifyCardArtImageExpectation(real_card_suggestion, card_art_url,
@@ -1145,7 +1148,7 @@
           /*virtual_card_option=*/false,
           /*card_linked_offer_available=*/false);
 
-  EXPECT_EQ(real_card_suggestion.frontend_id, 0);
+  EXPECT_EQ(real_card_suggestion.frontend_id.as_int(), 0);
   EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(),
             Suggestion::BackendId("00000000-0000-0000-0000-000000000001"));
   EXPECT_TRUE(VerifyCardArtImageExpectation(real_card_suggestion, GURL(),
@@ -1187,7 +1190,7 @@
           /*virtual_card_option=*/false,
           /*card_linked_offer_available=*/false);
 
-  EXPECT_EQ(real_card_suggestion.frontend_id, 0);
+  EXPECT_EQ(real_card_suggestion.frontend_id.as_int(), 0);
   EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(),
             Suggestion::BackendId("00000000-0000-0000-0000-000000000002"));
   EXPECT_EQ(VerifyCardArtImageExpectation(real_card_suggestion, card_art_url,
@@ -1328,7 +1331,7 @@
           /*virtual_card_option=*/false,
           /*card_linked_offer_available=*/true);
 
-  EXPECT_EQ(real_card_suggestion.frontend_id, 0);
+  EXPECT_EQ(real_card_suggestion.frontend_id.as_int(), 0);
   EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(),
             Suggestion::BackendId("00000000-0000-0000-0000-000000000001"));
 
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index d311998..8fad68e2 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -1230,7 +1230,7 @@
   }
 }
 
-Suggestion CreateAutofillSuggestion(int frontend_id,
+Suggestion CreateAutofillSuggestion(Suggestion::FrontendId frontend_id,
                                     const std::u16string& main_text_value,
                                     const Suggestion::Payload& payload) {
   Suggestion suggestion;
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h
index 0304a8a6..ab388d17 100644
--- a/components/autofill/core/browser/autofill_test_utils.h
+++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -552,7 +552,7 @@
     ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion);
 
 Suggestion CreateAutofillSuggestion(
-    int frontend_id = 0,
+    Suggestion::FrontendId frontend_id,
     const std::u16string& main_text_value = std::u16string(),
     const Suggestion::Payload& payload = Suggestion::Payload());
 
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 2cd168a..4d4fc942 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -203,8 +203,9 @@
   }
 }
 
-FillDataType GetEventTypeFromSingleFieldSuggestionFrontendId(int frontend_id) {
-  switch (static_cast<PopupItemId>(frontend_id)) {
+FillDataType GetEventTypeFromSingleFieldSuggestionFrontendId(
+    Suggestion::FrontendId frontend_id) {
+  switch (frontend_id.as_popup_item_id()) {
     case POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY:
       return FillDataType::kSingleFieldFormFillerAutocomplete;
     case POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY:
@@ -1352,7 +1353,7 @@
     mojom::RendererFormDataAction action,
     const FormData& form,
     const FormFieldData& field,
-    int unique_id,
+    Suggestion::FrontendId unique_id,
     const AutofillTriggerSource trigger_source) {
   if (!IsValidFormData(form) || !IsValidFormFieldData(field))
     return;
@@ -1576,7 +1577,7 @@
 
 bool BrowserAutofillManager::GetDeletionConfirmationText(
     const std::u16string& value,
-    int identifier,
+    Suggestion::FrontendId identifier,
     std::u16string* title,
     std::u16string* body) {
   if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
@@ -1590,8 +1591,9 @@
     return true;
   }
 
-  if (identifier < 0)
+  if (identifier.as_int() < 0) {
     return false;
+  }
 
   const CreditCard* credit_card = GetCreditCard(identifier);
   const AutofillProfile* profile = GetProfile(identifier);
@@ -1623,7 +1625,8 @@
   return false;  // The ID was valid. The entry may have been deleted in a race.
 }
 
-bool BrowserAutofillManager::RemoveAutofillProfileOrCreditCard(int unique_id) {
+bool BrowserAutofillManager::RemoveAutofillProfileOrCreditCard(
+    Suggestion::FrontendId unique_id) {
   const CreditCard* credit_card = GetCreditCard(unique_id);
   if (credit_card) {
     return credit_card_access_manager_->DeleteCard(credit_card);
@@ -1644,14 +1647,14 @@
 void BrowserAutofillManager::RemoveCurrentSingleFieldSuggestion(
     const std::u16string& name,
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   single_field_form_fill_router_->OnRemoveCurrentSingleFieldSuggestion(
       name, value, frontend_id);
 }
 
 void BrowserAutofillManager::OnSingleFieldSuggestionSelected(
     const std::u16string& value,
-    int frontend_id,
+    Suggestion::FrontendId frontend_id,
     const FormData& form,
     const FormFieldData& field) {
   single_field_form_fill_router_->OnSingleFieldSuggestionSelected(value,
@@ -2142,14 +2145,16 @@
          !client()->GetPersonalDataManager()->GetCreditCards().empty();
 }
 
-CreditCard* BrowserAutofillManager::GetCreditCard(int unique_id) {
+CreditCard* BrowserAutofillManager::GetCreditCard(
+    Suggestion::FrontendId unique_id) {
   Suggestion::BackendId credit_card_id =
       suggestion_generator_->GetBackendIdFromFrontendId(unique_id);
   return client()->GetPersonalDataManager()->GetCreditCardByGUID(
       credit_card_id.value());
 }
 
-AutofillProfile* BrowserAutofillManager::GetProfile(int unique_id) {
+AutofillProfile* BrowserAutofillManager::GetProfile(
+    Suggestion::FrontendId unique_id) {
   Suggestion::BackendId profile_id =
       suggestion_generator_->GetBackendIdFromFrontendId(unique_id);
 
@@ -3455,7 +3460,7 @@
 void BrowserAutofillManager::OnSeePromoCodeOfferDetailsSelected(
     const GURL& offer_details_url,
     const std::u16string& value,
-    int frontend_id,
+    Suggestion::FrontendId frontend_id,
     const FormData& form,
     const FormFieldData& field) {
   client()->OpenPromoCodeOfferDetailsURL(offer_details_url);
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index 665295d..344096a5 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -152,7 +152,7 @@
   virtual void FillOrPreviewForm(mojom::RendererFormDataAction action,
                                  const FormData& form,
                                  const FormFieldData& field,
-                                 int unique_id,
+                                 Suggestion::FrontendId unique_id,
                                  const AutofillTriggerSource trigger_source);
   void FillCreditCardFormImpl(const FormData& form,
                               const FormFieldData& field,
@@ -194,24 +194,24 @@
   // Returns true if the value/identifier is deletable. Fills out
   // |title| and |body| with relevant user-facing text.
   bool GetDeletionConfirmationText(const std::u16string& value,
-                                   int identifier,
+                                   Suggestion::FrontendId identifier,
                                    std::u16string* title,
                                    std::u16string* body);
 
   // Remove the credit card or Autofill profile that matches |unique_id|
   // from the database. Returns true if deletion is allowed.
-  bool RemoveAutofillProfileOrCreditCard(int unique_id);
+  bool RemoveAutofillProfileOrCreditCard(Suggestion::FrontendId unique_id);
 
   // Remove the specified suggestion from single field filling. |frontend_id| is
   // the PopupItemId of the suggestion.
   void RemoveCurrentSingleFieldSuggestion(const std::u16string& name,
                                           const std::u16string& value,
-                                          int frontend_id);
+                                          Suggestion::FrontendId frontend_id);
 
   // Invoked when the user selected |value| in a suggestions list from single
   // field filling. |frontend_id| is the PopupItemId of the suggestion.
   void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                       int frontend_id,
+                                       Suggestion::FrontendId frontend_id,
                                        const FormData& form,
                                        const FormFieldData& field);
 
@@ -314,7 +314,7 @@
   // then logs that the promo code suggestions footer was selected.
   void OnSeePromoCodeOfferDetailsSelected(const GURL& offer_details_url,
                                           const std::u16string& value,
-                                          int frontend_id,
+                                          Suggestion::FrontendId frontend_id,
                                           const FormData& form,
                                           const FormFieldData& field);
 
@@ -532,11 +532,11 @@
   // functions to AutofillSuggestionGenerator.
   // Gets the card referred to by the guid |unique_id|. Returns |nullptr| if
   // card does not exist.
-  CreditCard* GetCreditCard(int unique_id);
+  CreditCard* GetCreditCard(Suggestion::FrontendId unique_id);
 
   // Gets the profile referred to by the guid |unique_id|. Returns |nullptr| if
   // profile does not exist.
-  AutofillProfile* GetProfile(int unique_id);
+  AutofillProfile* GetProfile(Suggestion::FrontendId unique_id);
 
   // Determines whether a fill on |form| initiated from |triggered_field| will
   // wind up filling a credit card number. This is useful to determine if we
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index a33c5a89..7cf59be 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -642,7 +642,7 @@
 
   void FillAutofillFormData(const FormData& form,
                             const FormFieldData& field,
-                            int unique_id) {
+                            Suggestion::FrontendId unique_id) {
     browser_autofill_manager_->OnAskForValuesToFill(
         form, field, {}, AutoselectFirstSuggestion(true),
         FormElementWasClicked(false));
@@ -657,7 +657,7 @@
   // parameter of that call into the |response_data| output parameter.
   void FillAutofillFormDataAndSaveResults(const FormData& input_form,
                                           const FormFieldData& input_field,
-                                          int unique_id,
+                                          Suggestion::FrontendId unique_id,
                                           FormData* response_data) {
     EXPECT_CALL(*autofill_driver_, FillOrPreviewForm(_, _, _, _))
         .WillOnce(DoAll(testing::SaveArg<1>(response_data),
@@ -678,7 +678,7 @@
         action, guid, input_form, input_field, AutofillTriggerSource::kPopup);
   }
 
-  int MakeFrontendId(
+  Suggestion::FrontendId MakeFrontendId(
       const TestBrowserAutofillManager::MakeFrontendIdParams& params) {
     return browser_autofill_manager_->MakeFrontendId(params);
   }
@@ -1405,8 +1405,9 @@
   // Check that suggestions are made for the field that has the autocomplete
   // attribute.
   GetAutofillSuggestions(form, form.fields[0]);
-  CheckSuggestions(form.fields[0].global_id(), Suggestion("Charles", "", "", 1),
-                   Suggestion("Elvis", "", "", 2));
+  CheckSuggestions(form.fields[0].global_id(),
+                   Suggestion("Charles", "", "", Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", "", "", Suggestion::FrontendId(2)));
 
   // Check that there are no suggestions for the field without the autocomplete
   // attribute.
@@ -1435,16 +1436,18 @@
   FormsSeen({form});
 
   GetAutofillSuggestions(form, form.fields[0]);
-  CheckSuggestions(
-      form.fields[0].global_id(),
-      Suggestion("Charles", "Charles Hardin Holley", kAddressEntryIcon, 1),
-      Suggestion("Elvis", "Elvis Aaron Presley", kAddressEntryIcon, 2));
+  CheckSuggestions(form.fields[0].global_id(),
+                   Suggestion("Charles", "Charles Hardin Holley",
+                              kAddressEntryIcon, Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", "Elvis Aaron Presley", kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 
   GetAutofillSuggestions(form, form.fields[1]);
-  CheckSuggestions(
-      form.fields[1].global_id(),
-      Suggestion("Holley", "Charles Hardin Holley", kAddressEntryIcon, 1),
-      Suggestion("Presley", "Elvis Aaron Presley", kAddressEntryIcon, 2));
+  CheckSuggestions(form.fields[1].global_id(),
+                   Suggestion("Holley", "Charles Hardin Holley",
+                              kAddressEntryIcon, Suggestion::FrontendId(1)),
+                   Suggestion("Presley", "Elvis Aaron Presley",
+                              kAddressEntryIcon, Suggestion::FrontendId(2)));
 }
 
 // Test that the call is properly forwarded to its SingleFieldFormFillRouter.
@@ -1454,17 +1457,10 @@
   test::CreateTestAddressFormData(&form);
   FormFieldData field = form.fields[0];
 
-  EXPECT_CALL(*single_field_form_fill_router_,
-              OnSingleFieldSuggestionSelected(test_value,
-                                              POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))
-      .Times(1);
-
-  browser_autofill_manager_->OnSingleFieldSuggestionSelected(
-      test_value, POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, form, field);
-
-  EXPECT_CALL(*single_field_form_fill_router_,
-              OnSingleFieldSuggestionSelected(test_value,
-                                              POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))
+  EXPECT_CALL(
+      *single_field_form_fill_router_,
+      OnSingleFieldSuggestionSelected(
+          test_value, Suggestion::FrontendId(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)))
       .Times(1);
 
   browser_autofill_manager_->OnSingleFieldSuggestionSelected(
@@ -1472,7 +1468,16 @@
 
   EXPECT_CALL(
       *single_field_form_fill_router_,
-      OnSingleFieldSuggestionSelected(test_value, POPUP_ITEM_ID_IBAN_ENTRY))
+      OnSingleFieldSuggestionSelected(
+          test_value, Suggestion::FrontendId(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)))
+      .Times(1);
+
+  browser_autofill_manager_->OnSingleFieldSuggestionSelected(
+      test_value, POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, form, field);
+
+  EXPECT_CALL(*single_field_form_fill_router_,
+              OnSingleFieldSuggestionSelected(
+                  test_value, Suggestion::FrontendId(POPUP_ITEM_ID_IBAN_ENTRY)))
       .Times(1);
 
   browser_autofill_manager_->OnSingleFieldSuggestionSelected(
@@ -1480,7 +1485,8 @@
 
   EXPECT_CALL(*single_field_form_fill_router_,
               OnSingleFieldSuggestionSelected(
-                  test_value, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY))
+                  test_value, Suggestion::FrontendId(
+                                  POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY)))
       .Times(1);
 
   browser_autofill_manager_->OnSingleFieldSuggestionSelected(
@@ -1525,8 +1531,10 @@
   }
   // Test that we sent the right values to the external delegate.
   CheckSuggestions(form.fields[0].global_id(),
-                   Suggestion("Charles", label1, kAddressEntryIcon, 1),
-                   Suggestion("Elvis", label2, kAddressEntryIcon, 2));
+                   Suggestion("Charles", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 }
 
 // Test that we return only matching address profile suggestions when the
@@ -1553,8 +1561,9 @@
       label = "3734 Elvis Presley Blvd.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(field.global_id(),
-                   Suggestion("Elvis", label, kAddressEntryIcon, 1));
+  CheckSuggestions(
+      field.global_id(),
+      Suggestion("Elvis", label, kAddressEntryIcon, Suggestion::FrontendId(1)));
 }
 
 // Tests that we return address profile suggestions values when the section
@@ -1603,19 +1612,22 @@
     case EnabledFeature::kMobileShowOne:
       CheckSuggestions(
           field.global_id(),
-          Suggestion("Googler", "1600 Amphitheater pkwy", kAddressEntryIcon, 1),
-          Suggestion("Grimes", "1234 Smith Blvd.", kAddressEntryIcon, 2));
+          Suggestion("Googler", "1600 Amphitheater pkwy", kAddressEntryIcon,
+                     Suggestion::FrontendId(1)),
+          Suggestion("Grimes", "1234 Smith Blvd.", kAddressEntryIcon,
+                     Suggestion::FrontendId(2)));
       break;
     case EnabledFeature::kNone:
       // Test that we sent the right values to the external delegate. No labels
       // with duplicate values "Grimes" merged.
       CheckSuggestions(
           field.global_id(),
-          Suggestion("Googler", "1600 Amphitheater pkwy", kAddressEntryIcon, 1),
+          Suggestion("Googler", "1600 Amphitheater pkwy", kAddressEntryIcon,
+                     Suggestion::FrontendId(1)),
           Suggestion("Grimes", "1234 Smith Blvd., Carl Grimes",
-                     kAddressEntryIcon, 2),
+                     kAddressEntryIcon, Suggestion::FrontendId(2)),
           Suggestion("Grimes", "1234 Smith Blvd., Robin Grimes",
-                     kAddressEntryIcon, 3));
+                     kAddressEntryIcon, Suggestion::FrontendId(3)));
   }
 }
 
@@ -1648,8 +1660,9 @@
       label = "3734 Elvis Presley Blvd.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(field.global_id(),
-                   Suggestion("Elvis", label, kAddressEntryIcon, 1));
+  CheckSuggestions(
+      field.global_id(),
+      Suggestion("Elvis", label, kAddressEntryIcon, Suggestion::FrontendId(1)));
 }
 
 // Test that we return no suggestions when the form has no relevant fields.
@@ -1718,8 +1731,10 @@
   }
   // Test that we sent the right values to the external delegate.
   CheckSuggestions(form.fields[0].global_id(),
-                   Suggestion("Charles", label1, kAddressEntryIcon, 1),
-                   Suggestion("Elvis", label2, kAddressEntryIcon, 2));
+                   Suggestion("Charles", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 }
 
 // Test that we return no suggestions when autofill is disabled.
@@ -1743,8 +1758,9 @@
        OnSuggestionsReturned_CallsExternalDelegate) {
   FieldGlobalId field_id = test::MakeFieldGlobalId();
   std::vector<Suggestion> suggestions = {
-      Suggestion("Charles", "123 Apple St.", "", 1),
-      Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2)};
+      Suggestion("Charles", "123 Apple St.", "", Suggestion::FrontendId(1)),
+      Suggestion("Elvis", "3734 Elvis Presley Blvd.", "",
+                 Suggestion::FrontendId(2))};
 
   {
     browser_autofill_manager_->OnSuggestionsReturned(
@@ -2063,7 +2079,7 @@
   CheckSuggestions(
       form.fields[0].global_id(),
       Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
-                 "", -26));
+                 "", Suggestion::FrontendId(-26)));
 
   // Clear the test credit cards and try again -- we should still show the
   // mixed form warning.
@@ -2072,7 +2088,7 @@
   CheckSuggestions(
       form.fields[0].global_id(),
       Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
-                 "", -26));
+                 "", Suggestion::FrontendId(-26)));
 }
 
 // Test that we return credit card suggestions for secure pages that have an
@@ -2535,8 +2551,10 @@
 
   // Test that we sent the right values to the external delegate.
   CheckSuggestions(form.fields[0].global_id(),
-                   Suggestion("Charles", label1, kAddressEntryIcon, 1),
-                   Suggestion("Elvis", label2, kAddressEntryIcon, 2));
+                   Suggestion("Charles", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 
   FormFieldData field;
   test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
@@ -2584,7 +2602,7 @@
   CheckSuggestions(field.global_id(),
                    Suggestion(l10n_util::GetStringUTF8(
                                   IDS_AUTOFILL_WARNING_INSECURE_CONNECTION),
-                              "", "", -1));
+                              "", "", Suggestion::FrontendId(-1)));
 
   // Clear the test credit cards and try again -- we shouldn't return a warning.
   personal_data().ClearCreditCards();
@@ -3160,8 +3178,10 @@
   }
   // Test that we sent the right values to the external delegate.
   CheckSuggestions(form.fields[0].global_id(),
-                   Suggestion("Charles", label1, kAddressEntryIcon, 1),
-                   Suggestion("Elvis", label2, kAddressEntryIcon, 2));
+                   Suggestion("Charles", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("Elvis", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 }
 
 // Test that nothing breaks when there are single field form fill (Autocomplete)
@@ -3186,8 +3206,9 @@
   AutocompleteSuggestionsReturned(field.global_id(), suggestions);
 
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(field.global_id(), Suggestion("one", "", "", 0),
-                   Suggestion("two", "", "", 0));
+  CheckSuggestions(field.global_id(),
+                   Suggestion("one", "", "", Suggestion::FrontendId(0)),
+                   Suggestion("two", "", "", Suggestion::FrontendId(0)));
 }
 
 // Test that we do not return duplicate values drawn from multiple profiles when
@@ -3231,8 +3252,9 @@
       label = "3734 Elvis Presley Blvd.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(field.global_id(),
-                   Suggestion("Elvis", label, kAddressEntryIcon, 1));
+  CheckSuggestions(
+      field.global_id(),
+      Suggestion("Elvis", label, kAddressEntryIcon, Suggestion::FrontendId(1)));
 }
 
 TEST_P(SuggestionMatchingTest, GetProfileSuggestions_FancyPhone) {
@@ -3296,10 +3318,11 @@
       label3 = "3734 Elvis Presley Blvd.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(form.fields[9].global_id(),
-                   Suggestion(value1, label1, kAddressEntryIcon, 1),
-                   Suggestion(value2, label2, kAddressEntryIcon, 2),
-                   Suggestion(value3, label3, kAddressEntryIcon, 3));
+  CheckSuggestions(
+      form.fields[9].global_id(),
+      Suggestion(value1, label1, kAddressEntryIcon, Suggestion::FrontendId(1)),
+      Suggestion(value2, label2, kAddressEntryIcon, Suggestion::FrontendId(2)),
+      Suggestion(value3, label3, kAddressEntryIcon, Suggestion::FrontendId(3)));
 }
 
 TEST_F(BrowserAutofillManagerTest,
@@ -3341,14 +3364,16 @@
 
   // Test that we sent the right prefix values to the external delegate.
   CheckSuggestions(form.fields[2].global_id(),
-                   Suggestion("356", "1800FLOWERS", kAddressEntryIcon, 1));
+                   Suggestion("356", "1800FLOWERS", kAddressEntryIcon,
+                              Suggestion::FrontendId(1)));
 
   const FormFieldData& phone_suffix = form.fields[3];
   GetAutofillSuggestions(form, phone_suffix);
 
   // Test that we sent the right suffix values to the external delegate.
   CheckSuggestions(form.fields[3].global_id(),
-                   Suggestion("9377", "1800FLOWERS", kAddressEntryIcon, 1));
+                   Suggestion("9377", "1800FLOWERS", kAddressEntryIcon,
+                              Suggestion::FrontendId(1)));
 }
 
 // Tests that the suggestion consists of phone number without the country code
@@ -3369,9 +3394,9 @@
 
   GetAutofillSuggestions(form, form.fields[9]);
 
-  CheckSuggestions(
-      form.fields[9].global_id(),
-      Suggestion("123456789", "Natty Bumppo", kAddressEntryIcon, 1));
+  CheckSuggestions(form.fields[9].global_id(),
+                   Suggestion("123456789", "Natty Bumppo", kAddressEntryIcon,
+                              Suggestion::FrontendId(1)));
 }
 
 // Tests that we return email profile suggestions values
@@ -3414,9 +3439,9 @@
   personal_data().AddProfile(profile);
 
   GetAutofillSuggestions(form, form.fields[2]);
-  CheckSuggestions(
-      form.fields[2].global_id(),
-      Suggestion("test@example.com", "Natty Bumppo", kAddressEntryIcon, 1));
+  CheckSuggestions(form.fields[2].global_id(),
+                   Suggestion("test@example.com", "Natty Bumppo",
+                              kAddressEntryIcon, Suggestion::FrontendId(1)));
 }
 
 // Test that we correctly fill an address form.
@@ -7678,7 +7703,7 @@
   profile.set_guid(guid);
   personal_data().AddProfile(profile);
 
-  int id = MakeFrontendId({.profile_id = guid});
+  Suggestion::FrontendId id = MakeFrontendId({.profile_id = guid});
 
   browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
 
@@ -7692,7 +7717,7 @@
   credit_card.set_guid(guid);
   personal_data().AddCreditCard(credit_card);
 
-  int id = MakeFrontendId({.credit_card_id = guid});
+  Suggestion::FrontendId id = MakeFrontendId({.credit_card_id = guid});
 
   browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
 
@@ -8158,10 +8183,11 @@
       label2 = "3734 Elvis Presley Blvd.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(
-      field.global_id(),
-      Suggestion("buddy@gmail.com", label1, kAddressEntryIcon, 1),
-      Suggestion("theking@gmail.com", label2, kAddressEntryIcon, 2));
+  CheckSuggestions(field.global_id(),
+                   Suggestion("buddy@gmail.com", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("theking@gmail.com", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 }
 
 // Verify that typing "apple" will match "123 Apple St." when substring matching
@@ -8196,8 +8222,9 @@
       label = "123 Apple St.";
   }
   // Test that we sent the right values to the external delegate.
-  CheckSuggestions(field.global_id(), Suggestion("123 Apple St., unit 6", label,
-                                                 kAddressEntryIcon, 1));
+  CheckSuggestions(field.global_id(),
+                   Suggestion("123 Apple St., unit 6", label, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)));
 }
 
 // Verify that typing "mail" will not match any of the "@gmail.com" email
@@ -8371,8 +8398,10 @@
       label2 = "1234 Smith Blvd., Robin Adam Smith Grimes";
   }
   CheckSuggestions(field.global_id(),
-                   Suggestion("Shawn Smith", label1, kAddressEntryIcon, 1),
-                   Suggestion("Adam Smith", label2, kAddressEntryIcon, 2));
+                   Suggestion("Shawn Smith", label1, kAddressEntryIcon,
+                              Suggestion::FrontendId(1)),
+                   Suggestion("Adam Smith", label2, kAddressEntryIcon,
+                              Suggestion::FrontendId(2)));
 }
 
 TEST_F(BrowserAutofillManagerTest, ShouldUploadForm) {
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address.cc b/components/autofill/core/browser/data_model/autofill_structured_address.cc
index a0d0afa..c3137192 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
 #include "components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h"
 #include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
 #include "components/autofill/core/browser/field_type_utils.h"
@@ -31,9 +32,17 @@
                                 value);
 }
 
-std::u16string AddressComponentWithRewriter::ValueForComparison(
+std::u16string AddressComponentWithRewriter::GetValueForComparison(
     const AddressComponent& other) const {
-  return RewriteValue(NormalizedValue(), GetCommonCountryForMerge(other));
+  return RewriteValue(GetNormalizedValue(), GetCommonCountry(other));
+}
+
+std::u16string
+AddressComponentWithRewriter::GetValueForComparisonForOtherSupportedType(
+    ServerFieldType field_type,
+    const AddressComponent& other) const {
+  return RewriteValue(NormalizeValue(GetValueForOtherSupportedType(field_type)),
+                      GetCommonCountry(other));
 }
 
 StreetNameNode::StreetNameNode(AddressComponent* parent)
@@ -351,7 +360,7 @@
 
 PostalCodeNode::~PostalCodeNode() = default;
 
-std::u16string PostalCodeNode::NormalizedValue() const {
+std::u16string PostalCodeNode::GetNormalizedValue() const {
   return NormalizeValue(GetValue(), /*keep_white_space=*/false);
 }
 
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address.h b/components/autofill/core/browser/data_model/autofill_structured_address.h
index 3511113..0628caa 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address.h
+++ b/components/autofill/core/browser/data_model/autofill_structured_address.h
@@ -21,13 +21,20 @@
 
  protected:
   // Apply a country-specific rewriter to the normalized value.
-  std::u16string ValueForComparison(
+  std::u16string GetValueForComparison(
       const AddressComponent& other) const override;
 
   // Applies the |country_code| specific rewriter to the normalized value. If
   // |country_code| is empty, it defaults to US.
   std::u16string RewriteValue(const std::u16string& value,
                               const std::u16string& country_code) const;
+
+  // This method is used to retrieve the value for a supported field type
+  // different from the storage type, and rewrites it for comparison with
+  // `other`. It must implement the conversion logic specific to each type.
+  std::u16string GetValueForComparisonForOtherSupportedType(
+      ServerFieldType field_type,
+      const AddressComponent& other) const override;
 };
 
 // The name of the street.
@@ -206,7 +213,7 @@
  protected:
   // In contrast to the base class, the normalization removes all white spaces
   // from the value.
-  std::u16string NormalizedValue() const override;
+  std::u16string GetNormalizedValue() const override;
 };
 
 // Stores the sorting code.
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.cc b/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
index ca061b7..e1106ee8 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
@@ -147,7 +147,7 @@
   return true;
 }
 
-std::u16string AddressComponent::GetCommonCountryForMerge(
+std::u16string AddressComponent::GetCommonCountry(
     const AddressComponent& other) const {
   const std::u16string country_a =
       GetRootNode().GetValueForType(ADDRESS_HOME_COUNTRY);
@@ -245,6 +245,12 @@
   return {};
 }
 
+std::u16string AddressComponent::GetValueForComparisonForOtherSupportedType(
+    ServerFieldType field_type,
+    const AddressComponent& other) const {
+  return NormalizeValue(GetValueForOtherSupportedType(field_type));
+}
+
 std::u16string AddressComponent::GetBestFormatString() const {
   // If the component is atomic, the format string is just the value.
   if (IsAtomic())
@@ -362,6 +368,19 @@
              : node_for_type->GetValueForOtherSupportedType(field_type);
 }
 
+std::u16string AddressComponent::GetValueForComparisonForType(
+    ServerFieldType field_type,
+    const AddressComponent& other) const {
+  const AddressComponent* node_for_type = GetNodeForType(field_type);
+  if (!node_for_type) {
+    return {};
+  }
+  return node_for_type->GetStorageType() == field_type
+             ? node_for_type->GetValueForComparison(other)
+             : node_for_type->GetValueForComparisonForOtherSupportedType(
+                   field_type, other);
+}
+
 VerificationStatus AddressComponent::GetVerificationStatusForType(
     ServerFieldType field_type) const {
   const AddressComponent* node_for_type = GetNodeForType(field_type);
@@ -742,9 +761,9 @@
 bool AddressComponent::IsMergeableWithComponent(
     const AddressComponent& newer_component) const {
   const std::u16string older_comparison_value =
-      ValueForComparison(newer_component);
+      GetValueForComparison(newer_component);
   const std::u16string newer_comparison_value =
-      newer_component.ValueForComparison(*this);
+      newer_component.GetValueForComparison(*this);
 
   // If both components are the same, there is nothing to do.
   if (SameAs(newer_component))
@@ -859,8 +878,9 @@
     bool newer_was_more_recently_used) {
   // If both components are the same, there is nothing to do.
 
-  const std::u16string value = ValueForComparison(newer_component);
-  const std::u16string value_newer = newer_component.ValueForComparison(*this);
+  const std::u16string value = GetValueForComparison(newer_component);
+  const std::u16string value_newer =
+      newer_component.GetValueForComparison(*this);
 
   bool newer_component_has_better_or_equal_status =
       !IsLessSignificantVerificationStatus(
@@ -1091,8 +1111,8 @@
 bool AddressComponent::MergeTokenEquivalentComponent(
     const AddressComponent& newer_component) {
   if (!AreSortedTokensEqual(
-          TokenizeValue(ValueForComparison(newer_component)),
-          TokenizeValue(newer_component.ValueForComparison(*this)))) {
+          TokenizeValue(GetValueForComparison(newer_component)),
+          TokenizeValue(newer_component.GetValueForComparison(*this)))) {
     return false;
   }
 
@@ -1319,13 +1339,13 @@
   return result;
 }
 
-std::u16string AddressComponent::NormalizedValue() const {
+std::u16string AddressComponent::GetNormalizedValue() const {
   return NormalizeValue(GetValue());
 }
 
-std::u16string AddressComponent::ValueForComparison(
+std::u16string AddressComponent::GetValueForComparison(
     const AddressComponent& other) const {
-  return NormalizedValue();
+  return GetNormalizedValue();
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
index fe9a86d..244f778 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_component.h
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -210,12 +210,19 @@
   // verification status to |kNoStatus|.
   virtual void UnsetValue();
 
-  // Convenience method to get the value of |type|.
-  // Returns an empty string if |type| is not supported.
+  // Convenience method to get the value of |field_type|.
+  // Returns an empty string if |field_type| is not supported.
   std::u16string GetValueForType(ServerFieldType field_type) const;
 
-  // Convenience method to get the verification status of |type|.
-  // Returns |VerificationStatus::kNoStatus| if |type| is not supported.
+  // Convenience method to get the value of `field_type` to be used for
+  // comparison with `other`. Returns an empty string if `field_type` is not
+  // supported.
+  std::u16string GetValueForComparisonForType(
+      ServerFieldType field_type,
+      const AddressComponent& other) const;
+
+  // Convenience method to get the verification status of `field_type`.
+  // Returns |VerificationStatus::kNoStatus| if `field_type` is not supported.
   VerificationStatus GetVerificationStatusForType(
       ServerFieldType field_type) const;
 
@@ -308,11 +315,11 @@
   bool IsValueForTypeValid(ServerFieldType field_type,
                            bool wipe_if_not = false);
 
-  // While merging two structured addresses, if only one of them has their
+  // While processing two structured addresses, if only one of them has their
   // country set, the other should assume the non-empty one while merging. This
   // is required to do consistent address rewriting.
   // Returns the common country to be used.
-  std::u16string GetCommonCountryForMerge(const AddressComponent& other) const;
+  std::u16string GetCommonCountry(const AddressComponent& other) const;
 
   // Deletes the stored structure and returns true if |IsStructureValid()|
   // returns false.
@@ -362,9 +369,9 @@
   void SetMergeModeForTesting(int merge_mode) { merge_mode_ = merge_mode; }
 
   // Returns the value used for comparison for testing purposes.
-  std::u16string ValueForComparisonForTesting(
+  std::u16string GetValueForComparisonForTesting(
       const AddressComponent& other) const {
-    return ValueForComparison(other);
+    return GetValueForComparison(other);
   }
 #endif
 
@@ -412,6 +419,13 @@
   virtual std::u16string GetValueForOtherSupportedType(
       ServerFieldType field_type) const;
 
+  // This method is used to retrieve the value for a supported field type
+  // different from the storage type, and rewrites it for comparison with
+  // `other`. It must implement the conversion logic specific to each type.
+  virtual std::u16string GetValueForComparisonForOtherSupportedType(
+      ServerFieldType field_type,
+      const AddressComponent& other) const;
+
   // Clears all parsed and formatted values.
   void ClearAllParsedAndFormattedValues();
 
@@ -443,7 +457,7 @@
   // In the default implementation, this converts the value to lower case and
   // removes white spaces. This function may be reimplemented to perform
   // different normalization operations.
-  virtual std::u16string NormalizedValue() const;
+  virtual std::u16string GetNormalizedValue() const;
 
   // Returns a value used for comparison.
   // In the default implementation this is just the normalized value but this
@@ -451,7 +465,7 @@
   // the normalized value.
   // |other| represents the component we are comparing with and is required
   // for consistent rewriting rules.
-  virtual std::u16string ValueForComparison(
+  virtual std::u16string GetValueForComparison(
       const AddressComponent& other) const;
 
   // Returns true if the merging of two token identical values should give
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
index 40695474..7848cfc 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
@@ -356,6 +356,32 @@
             VerificationStatus::kObserved);
 }
 
+// Tests retrieving a value for comparison for a field type.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestGetValueForComparisonForType) {
+  TestCompoundNameAddressComponent compound_name;
+  EXPECT_TRUE(compound_name.SetValueForType(NAME_FIRST, u"First1-First2",
+                                            VerificationStatus::kObserved));
+  EXPECT_TRUE(compound_name.SetValueForTypeAndResetSubstructure(
+      NAME_MIDDLE, u"Middle", VerificationStatus::kObserved));
+  EXPECT_TRUE(compound_name.SetValueForType(NAME_LAST, u"LAST",
+                                            VerificationStatus::kObserved));
+  EXPECT_TRUE(compound_name.CompleteFullTree());
+  EXPECT_EQ(
+      compound_name.GetValueForComparisonForType(NAME_FULL, compound_name),
+      u"first1 first2 middle last");
+  EXPECT_EQ(
+      compound_name.GetValueForComparisonForType(NAME_FIRST, compound_name),
+      u"first1 first2");
+  EXPECT_EQ(compound_name.GetValueForComparisonForType(NAME_MIDDLE_INITIAL,
+                                                       compound_name),
+            u"m");
+  EXPECT_TRUE(
+      compound_name
+          .GetValueForComparisonForType(ADDRESS_HOME_STREET_NAME, compound_name)
+          .empty());
+}
+
 // Tests adding all supported types to the set.
 TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedTypes) {
   ServerFieldTypeSet field_type_set;
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
index 0e82c31..3f1cd74 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
@@ -988,8 +988,8 @@
   // After normalization, the two names should have a single-token-superset
   // relation.
   SortedTokenComparisonResult token_comparison_result =
-      CompareSortedTokens(name.ValueForComparisonForTesting(subset_name),
-                          subset_name.ValueForComparisonForTesting(name));
+      CompareSortedTokens(name.GetValueForComparisonForTesting(subset_name),
+                          subset_name.GetValueForComparisonForTesting(name));
   EXPECT_TRUE(token_comparison_result.IsSingleTokenSuperset());
 
   // Without normalization, the two names should be considered distinct.
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
index df826e2..88a9b45 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
@@ -235,7 +235,7 @@
        .house_number = "1600",
        .floor = "6",
        .apartment = "12"},
-      {.street_address = "1600 Amphitheatre Parkway\nSome UnparseableText",
+      {.street_address = "1600 Amphitheatre Parkway\nSome UnparsableText",
        .street_name = "Amphitheatre Parkway",
        .house_number = "1600"},
       {.street_address = "Av. Paulista, 1098\n1º andar, apto. 101",
@@ -598,29 +598,53 @@
   VerifyTestValues(&address, address_with_wiped_structure);
 }
 
-// Test that the correct country for merging structured addresses is computed.
-TEST(AutofillStructuredAddress, TestGetCommonCountryForMerge) {
+// Test that the correct common country between structured addresses is
+// computed.
+TEST(AutofillStructuredAddress, TestGetCommonCountry) {
   CountryCodeNode country1(nullptr);
   CountryCodeNode country2(nullptr);
 
   // No countries set.
-  EXPECT_EQ(country1.GetCommonCountryForMerge(country2), u"");
-  EXPECT_EQ(country2.GetCommonCountryForMerge(country1), u"");
+  EXPECT_EQ(country1.GetCommonCountry(country2), u"");
+  EXPECT_EQ(country2.GetCommonCountry(country1), u"");
 
   // If exactly one country is set, use it as their common one.
   country1.SetValue(u"AT", VerificationStatus::kObserved);
-  EXPECT_EQ(country1.GetCommonCountryForMerge(country2), u"AT");
-  EXPECT_EQ(country2.GetCommonCountryForMerge(country1), u"AT");
+  EXPECT_EQ(country1.GetCommonCountry(country2), u"AT");
+  EXPECT_EQ(country2.GetCommonCountry(country1), u"AT");
 
   // If both are set to the same value, use it as their common one.
   country2.SetValue(u"AT", VerificationStatus::kObserved);
-  EXPECT_EQ(country1.GetCommonCountryForMerge(country2), u"AT");
-  EXPECT_EQ(country2.GetCommonCountryForMerge(country1), u"AT");
+  EXPECT_EQ(country1.GetCommonCountry(country2), u"AT");
+  EXPECT_EQ(country2.GetCommonCountry(country1), u"AT");
 
   // If both have a different value, there is no common one.
   country2.SetValue(u"DE", VerificationStatus::kObserved);
-  EXPECT_EQ(country1.GetCommonCountryForMerge(country2), u"");
-  EXPECT_EQ(country2.GetCommonCountryForMerge(country1), u"");
+  EXPECT_EQ(country1.GetCommonCountry(country2), u"");
+  EXPECT_EQ(country2.GetCommonCountry(country1), u"");
+}
+
+// Tests retrieving a value for comparison for a field type.
+TEST(AutofillStructuredAddress, TestGetValueForComparisonForType) {
+  CountryCodeNode country_code(nullptr);
+  country_code.SetValue(u"US", VerificationStatus::kObserved);
+  StreetAddressNode street_address(&country_code);
+  EXPECT_TRUE(street_address.SetValueForType(ADDRESS_HOME_STREET_ADDRESS,
+                                             u"Main Street\nOther Street",
+                                             VerificationStatus::kObserved));
+  EXPECT_EQ(street_address.GetValueForComparisonForType(
+                ADDRESS_HOME_STREET_ADDRESS, street_address),
+            u"main st other st");
+  EXPECT_EQ(street_address.GetValueForComparisonForType(ADDRESS_HOME_LINE1,
+                                                        street_address),
+            u"main st");
+  EXPECT_EQ(street_address.GetValueForComparisonForType(ADDRESS_HOME_LINE2,
+                                                        street_address),
+            u"other st");
+  EXPECT_TRUE(
+      street_address
+          .GetValueForComparisonForType(ADDRESS_HOME_LINE3, street_address)
+          .empty());
 }
 
 struct HasNewerStreetAddressPrecedenceInMergingTestCase {
diff --git a/components/autofill/core/browser/iban_manager.cc b/components/autofill/core/browser/iban_manager.cc
index 85c10e4..8f3ace9 100644
--- a/components/autofill/core/browser/iban_manager.cc
+++ b/components/autofill/core/browser/iban_manager.cc
@@ -140,8 +140,9 @@
   uma_recorder_.OnIbanSuggestionsShown(query_handler.field_id_);
 }
 
-void IBANManager::OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                                  int frontend_id) {
+void IBANManager::OnSingleFieldSuggestionSelected(
+    const std::u16string& value,
+    Suggestion::FrontendId frontend_id) {
   uma_recorder_.OnIbanSuggestionSelected();
 }
 
diff --git a/components/autofill/core/browser/iban_manager.h b/components/autofill/core/browser/iban_manager.h
index d7a8f6d8..b5d4fc6 100644
--- a/components/autofill/core/browser/iban_manager.h
+++ b/components/autofill/core/browser/iban_manager.h
@@ -48,11 +48,13 @@
   void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
                                   bool is_autocomplete_enabled) override {}
   void CancelPendingQueries(const SuggestionsHandler* handler) override {}
-  void OnRemoveCurrentSingleFieldSuggestion(const std::u16string& field_name,
-                                            const std::u16string& value,
-                                            int frontend_id) override {}
-  void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                       int frontend_id) override;
+  void OnRemoveCurrentSingleFieldSuggestion(
+      const std::u16string& field_name,
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override {}
+  void OnSingleFieldSuggestionSelected(
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
 
   base::WeakPtr<IBANManager> GetWeakPtr();
 
diff --git a/components/autofill/core/browser/merchant_promo_code_manager.cc b/components/autofill/core/browser/merchant_promo_code_manager.cc
index 9c23315c..0584889 100644
--- a/components/autofill/core/browser/merchant_promo_code_manager.cc
+++ b/components/autofill/core/browser/merchant_promo_code_manager.cc
@@ -58,11 +58,11 @@
 void MerchantPromoCodeManager::OnRemoveCurrentSingleFieldSuggestion(
     const std::u16string& field_name,
     const std::u16string& value,
-    int frontend_id) {}
+    Suggestion::FrontendId frontend_id) {}
 
 void MerchantPromoCodeManager::OnSingleFieldSuggestionSelected(
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   uma_recorder_.OnOfferSuggestionSelected(frontend_id);
 }
 
@@ -106,7 +106,7 @@
 }
 
 void MerchantPromoCodeManager::UMARecorder::OnOfferSuggestionSelected(
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   if (frontend_id == PopupItemId::POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY) {
     // We log every time an individual offer suggestion is selected, regardless
     // if the user is repeatedly autofilling the same field.
diff --git a/components/autofill/core/browser/merchant_promo_code_manager.h b/components/autofill/core/browser/merchant_promo_code_manager.h
index 50dce45..640773e 100644
--- a/components/autofill/core/browser/merchant_promo_code_manager.h
+++ b/components/autofill/core/browser/merchant_promo_code_manager.h
@@ -44,11 +44,13 @@
   void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
                                   bool is_autocomplete_enabled) override;
   void CancelPendingQueries(const SuggestionsHandler* handler) override;
-  void OnRemoveCurrentSingleFieldSuggestion(const std::u16string& field_name,
-                                            const std::u16string& value,
-                                            int frontend_id) override;
-  void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                       int frontend_id) override;
+  void OnRemoveCurrentSingleFieldSuggestion(
+      const std::u16string& field_name,
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
+  void OnSingleFieldSuggestionSelected(
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
 
   // Initializes the instance with the given parameters. |personal_data_manager|
   // is a profile-scope data manager used to retrieve promo code offers from the
@@ -81,7 +83,7 @@
     void OnOffersSuggestionsShown(
         const FieldGlobalId& field_global_id,
         const std::vector<const AutofillOfferData*>& offers);
-    void OnOfferSuggestionSelected(int frontend_id);
+    void OnOfferSuggestionSelected(Suggestion::FrontendId frontend_id);
 
    private:
     // The global id of the field that most recently had suggestions shown.
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
index a62a9e1..58811023 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
@@ -31,7 +31,7 @@
  public:
   MockAutofillClient();
   ~MockAutofillClient() override;
-  MOCK_METHOD(void, ExecuteCommand, (int), (override));
+  MOCK_METHOD(void, ExecuteCommand, (Suggestion::FrontendId), (override));
   MOCK_METHOD(bool, IsTouchToFillCreditCardSupported, (), (override));
   MOCK_METHOD(bool,
               ShowTouchToFillCreditCard,
@@ -172,7 +172,7 @@
         AutofillTriggerSource::kPopup);
   }
 
-  int MakeFrontendId(
+  Suggestion::FrontendId MakeFrontendId(
       const TestBrowserAutofillManager::MakeFrontendIdParams& params) {
     return autofill_manager().MakeFrontendId(params);
   }
diff --git a/components/autofill/core/browser/mock_autocomplete_history_manager.h b/components/autofill/core/browser/mock_autocomplete_history_manager.h
index 0244eb1..dacf958 100644
--- a/components/autofill/core/browser/mock_autocomplete_history_manager.h
+++ b/components/autofill/core/browser/mock_autocomplete_history_manager.h
@@ -40,11 +40,13 @@
               (override));
   MOCK_METHOD(void,
               OnRemoveCurrentSingleFieldSuggestion,
-              (const std::u16string&, const std::u16string&, int),
+              (const std::u16string&,
+               const std::u16string&,
+               Suggestion::FrontendId),
               (override));
   MOCK_METHOD(void,
               OnSingleFieldSuggestionSelected,
-              (const std::u16string&, int),
+              (const std::u16string&, Suggestion::FrontendId),
               (override));
 };
 
diff --git a/components/autofill/core/browser/mock_iban_manager.h b/components/autofill/core/browser/mock_iban_manager.h
index 7af877bf..3fc4915 100644
--- a/components/autofill/core/browser/mock_iban_manager.h
+++ b/components/autofill/core/browser/mock_iban_manager.h
@@ -37,11 +37,13 @@
               (override));
   MOCK_METHOD(void,
               OnRemoveCurrentSingleFieldSuggestion,
-              (const std::u16string&, const std::u16string&, int),
+              (const std::u16string&,
+               const std::u16string&,
+               Suggestion::FrontendId),
               (override));
   MOCK_METHOD(void,
               OnSingleFieldSuggestionSelected,
-              (const std::u16string&, int),
+              (const std::u16string&, Suggestion::FrontendId),
               (override));
 };
 
diff --git a/components/autofill/core/browser/mock_merchant_promo_code_manager.h b/components/autofill/core/browser/mock_merchant_promo_code_manager.h
index 68c4cb0..8b35e1e 100644
--- a/components/autofill/core/browser/mock_merchant_promo_code_manager.h
+++ b/components/autofill/core/browser/mock_merchant_promo_code_manager.h
@@ -36,11 +36,13 @@
               (override));
   MOCK_METHOD(void,
               OnRemoveCurrentSingleFieldSuggestion,
-              (const std::u16string&, const std::u16string&, int),
+              (const std::u16string&,
+               const std::u16string&,
+               Suggestion::FrontendId),
               (override));
   MOCK_METHOD(void,
               OnSingleFieldSuggestionSelected,
-              (const std::u16string&, int),
+              (const std::u16string&, Suggestion::FrontendId),
               (override));
 };
 
diff --git a/components/autofill/core/browser/mock_single_field_form_fill_router.h b/components/autofill/core/browser/mock_single_field_form_fill_router.h
index c3faa4f..2b565665 100644
--- a/components/autofill/core/browser/mock_single_field_form_fill_router.h
+++ b/components/autofill/core/browser/mock_single_field_form_fill_router.h
@@ -46,11 +46,13 @@
               (override));
   MOCK_METHOD(void,
               OnRemoveCurrentSingleFieldSuggestion,
-              (const std::u16string&, const std::u16string&, int),
+              (const std::u16string&,
+               const std::u16string&,
+               Suggestion::FrontendId),
               (override));
   MOCK_METHOD(void,
               OnSingleFieldSuggestionSelected,
-              (const std::u16string&, int),
+              (const std::u16string&, Suggestion::FrontendId),
               (override));
 };
 
diff --git a/components/autofill/core/browser/single_field_form_fill_router.cc b/components/autofill/core/browser/single_field_form_fill_router.cc
index 24934fa1..e1473b1e 100644
--- a/components/autofill/core/browser/single_field_form_fill_router.cc
+++ b/components/autofill/core/browser/single_field_form_fill_router.cc
@@ -102,7 +102,7 @@
 void SingleFieldFormFillRouter::OnRemoveCurrentSingleFieldSuggestion(
     const std::u16string& field_name,
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   if (merchant_promo_code_manager_ &&
       frontend_id == POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY) {
     merchant_promo_code_manager_->OnRemoveCurrentSingleFieldSuggestion(
@@ -118,7 +118,7 @@
 
 void SingleFieldFormFillRouter::OnSingleFieldSuggestionSelected(
     const std::u16string& value,
-    int frontend_id) {
+    Suggestion::FrontendId frontend_id) {
   if (merchant_promo_code_manager_ &&
       (frontend_id == POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY ||
        frontend_id == POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS)) {
diff --git a/components/autofill/core/browser/single_field_form_fill_router.h b/components/autofill/core/browser/single_field_form_fill_router.h
index 43a608a..aa40903 100644
--- a/components/autofill/core/browser/single_field_form_fill_router.h
+++ b/components/autofill/core/browser/single_field_form_fill_router.h
@@ -55,11 +55,13 @@
                                   bool is_autocomplete_enabled) override;
   void CancelPendingQueries(
       const SingleFieldFormFiller::SuggestionsHandler* handler) override;
-  void OnRemoveCurrentSingleFieldSuggestion(const std::u16string& field_name,
-                                            const std::u16string& value,
-                                            int frontend_id) override;
-  void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                       int frontend_id) override;
+  void OnRemoveCurrentSingleFieldSuggestion(
+      const std::u16string& field_name,
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
+  void OnSingleFieldSuggestionSelected(
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) override;
 
  private:
   // Handles autocompleting single fields.
diff --git a/components/autofill/core/browser/single_field_form_filler.h b/components/autofill/core/browser/single_field_form_filler.h
index 55a65a5..2e26353 100644
--- a/components/autofill/core/browser/single_field_form_filler.h
+++ b/components/autofill/core/browser/single_field_form_filler.h
@@ -79,14 +79,15 @@
   virtual void OnRemoveCurrentSingleFieldSuggestion(
       const std::u16string& field_name,
       const std::u16string& value,
-      int frontend_id) = 0;
+      Suggestion::FrontendId frontend_id) = 0;
 
   // Invoked when the user selects |value| in the list of suggestions. For
   // Autocomplete, this function logs the DaysSinceLastUse of the Autocomplete
   // entry associated with |value|. |frontend_id| is the PopupItemId of the
   // suggestion selected.
-  virtual void OnSingleFieldSuggestionSelected(const std::u16string& value,
-                                               int frontend_id) = 0;
+  virtual void OnSingleFieldSuggestionSelected(
+      const std::u16string& value,
+      Suggestion::FrontendId frontend_id) = 0;
 
  protected:
   // Internal data object used to keep a request's context to associate it
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index 518eba5..61e8424 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -432,7 +432,7 @@
     return form_origin_.SchemeIs("https");
   }
 
-  void ExecuteCommand(int id) override {}
+  void ExecuteCommand(Suggestion::FrontendId id) override {}
 
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override {}
 
diff --git a/components/autofill/core/browser/test_browser_autofill_manager.cc b/components/autofill/core/browser/test_browser_autofill_manager.cc
index ebb241c..e52c7bdc 100644
--- a/components/autofill/core/browser/test_browser_autofill_manager.cc
+++ b/components/autofill/core/browser/test_browser_autofill_manager.cc
@@ -189,7 +189,8 @@
   return false;
 }
 
-int TestBrowserAutofillManager::GetPackedCreditCardID(int credit_card_id) {
+Suggestion::FrontendId TestBrowserAutofillManager::GetPackedCreditCardID(
+    int credit_card_id) {
   std::string credit_card_guid =
       base::StringPrintf("00000000-0000-0000-0000-%012d", credit_card_id);
 
@@ -282,7 +283,7 @@
   expected_observed_submission_ = expected;
 }
 
-int TestBrowserAutofillManager::MakeFrontendId(
+Suggestion::FrontendId TestBrowserAutofillManager::MakeFrontendId(
     const MakeFrontendIdParams& params) {
   return suggestion_generator_for_test()->MakeFrontendIdFromBackendId(
       Suggestion::BackendId(params.credit_card_id.empty()
diff --git a/components/autofill/core/browser/test_browser_autofill_manager.h b/components/autofill/core/browser/test_browser_autofill_manager.h
index 2376cfe..632a536 100644
--- a/components/autofill/core/browser/test_browser_autofill_manager.h
+++ b/components/autofill/core/browser/test_browser_autofill_manager.h
@@ -82,7 +82,7 @@
 
   // Unique to TestBrowserAutofillManager:
 
-  int GetPackedCreditCardID(int credit_card_id);
+  Suggestion::FrontendId GetPackedCreditCardID(int credit_card_id);
 
   void AddSeenForm(const FormData& form,
                    const std::vector<ServerFieldType>& field_types,
@@ -137,7 +137,7 @@
     std::string profile_id;
   };
 
-  int MakeFrontendId(const MakeFrontendIdParams& params);
+  Suggestion::FrontendId MakeFrontendId(const MakeFrontendIdParams& params);
 
  private:
   bool autofill_profile_enabled_ = true;
diff --git a/components/autofill/core/browser/ui/autofill_popup_delegate.h b/components/autofill/core/browser/ui/autofill_popup_delegate.h
index c4f71979..38b9173 100644
--- a/components/autofill/core/browser/ui/autofill_popup_delegate.h
+++ b/components/autofill/core/browser/ui/autofill_popup_delegate.h
@@ -38,7 +38,7 @@
   // shown. |frontend_id| is the frontend id of the suggestion. |backend_id| is
   // the guid of the backend data model.
   virtual void DidSelectSuggestion(const std::u16string& value,
-                                   int frontend_id,
+                                   Suggestion::FrontendId frontend_id,
                                    const Suggestion::BackendId& backend_id) = 0;
 
   // Informs the delegate that a row in the popup has been chosen. |suggestion|
@@ -50,14 +50,14 @@
   // Returns whether the given value can be deleted, and if true,
   // fills out |title| and |body|.
   virtual bool GetDeletionConfirmationText(const std::u16string& value,
-                                           int frontend_id,
+                                           Suggestion::FrontendId frontend_id,
                                            std::u16string* title,
                                            std::u16string* body) = 0;
 
   // Delete the described suggestion. Returns true if something was deleted,
   // or false if deletion is not allowed.
   virtual bool RemoveSuggestion(const std::u16string& value,
-                                int frontend_id) = 0;
+                                Suggestion::FrontendId frontend_id) = 0;
 
   // Informs the delegate that the Autofill previewed form should be cleared.
   virtual void ClearPreviewedForm() = 0;
diff --git a/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h b/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
index 9d70f2d5..03a808cc 100644
--- a/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
+++ b/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
@@ -26,7 +26,7 @@
   MOCK_METHOD(void,
               DidSelectSuggestion,
               (const std::u16string& value,
-               int frontend_id,
+               Suggestion::FrontendId frontend_id,
                const Suggestion::BackendId& backend_id),
               (override));
   MOCK_METHOD(void,
@@ -36,13 +36,13 @@
   MOCK_METHOD(bool,
               GetDeletionConfirmationText,
               (const std::u16string& value,
-               int frontend_id,
+               Suggestion::FrontendId frontend_id,
                std::u16string* title,
                std::u16string* body),
               (override));
   MOCK_METHOD(bool,
               RemoveSuggestion,
-              (const std::u16string& value, int frontend_id),
+              (const std::u16string& value, Suggestion::FrontendId frontend_id),
               (override));
   MOCK_METHOD(void, ClearPreviewedForm, (), (override));
   MOCK_METHOD(PopupType, GetPopupType, (), (const, override));
diff --git a/components/autofill/core/browser/ui/popup_item_ids.h b/components/autofill/core/browser/ui/popup_item_ids.h
index f5dfb48c..dcbdade 100644
--- a/components/autofill/core/browser/ui/popup_item_ids.h
+++ b/components/autofill/core/browser/ui/popup_item_ids.h
@@ -2,13 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This enum defines item identifiers for Autofill popup controller.
-
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_POPUP_ITEM_IDS_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_POPUP_ITEM_IDS_H_
 
 namespace autofill {
 
+// This enum defines item identifiers for Autofill popup controller.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.autofill
 // GENERATED_JAVA_PREFIX_TO_STRIP: POPUP_
 enum PopupItemId {
diff --git a/components/autofill/core/browser/ui/suggestion.cc b/components/autofill/core/browser/ui/suggestion.cc
index 24a2480..bf8e93c3 100644
--- a/components/autofill/core/browser/ui/suggestion.cc
+++ b/components/autofill/core/browser/ui/suggestion.cc
@@ -4,12 +4,41 @@
 
 #include "components/autofill/core/browser/ui/suggestion.h"
 
+#include <type_traits>
 #include <utility>
 
 #include "base/strings/utf_string_conversions.h"
 
 namespace autofill {
 
+bool operator==(Suggestion::FrontendId lhs, Suggestion::FrontendId rhs) {
+  return lhs.as_int() == rhs.as_int();
+}
+
+bool operator==(Suggestion::FrontendId lhs, PopupItemId rhs) {
+  return lhs == Suggestion::FrontendId(rhs);
+}
+
+bool operator==(PopupItemId lhs, Suggestion::FrontendId rhs) {
+  return Suggestion::FrontendId(lhs) == rhs;
+}
+
+bool operator!=(Suggestion::FrontendId lhs, Suggestion::FrontendId rhs) {
+  return !(lhs == rhs);
+}
+
+bool operator!=(Suggestion::FrontendId lhs, PopupItemId rhs) {
+  return !(lhs == rhs);
+}
+
+bool operator!=(PopupItemId lhs, Suggestion::FrontendId rhs) {
+  return !(lhs == rhs);
+}
+
+std::ostream& operator<<(std::ostream& os, Suggestion::FrontendId id) {
+  return os << id.as_int();
+}
+
 Suggestion::Text::Text() = default;
 
 Suggestion::Text::Text(std::u16string value,
@@ -39,12 +68,13 @@
 Suggestion::Suggestion(std::u16string main_text)
     : main_text(std::move(main_text), Text::IsPrimary(true)) {}
 
-Suggestion::Suggestion(int frontend_id) : frontend_id(frontend_id) {}
+Suggestion::Suggestion(Suggestion::FrontendId frontend_id)
+    : frontend_id(frontend_id) {}
 
 Suggestion::Suggestion(base::StringPiece main_text,
                        base::StringPiece label,
                        std::string icon,
-                       int frontend_id)
+                       Suggestion::FrontendId frontend_id)
     : frontend_id(frontend_id),
       main_text(base::UTF8ToUTF16(main_text), Text::IsPrimary(true)),
       icon(std::move(icon)) {
@@ -56,7 +86,7 @@
                        base::StringPiece minor_text,
                        base::StringPiece label,
                        std::string icon,
-                       int frontend_id)
+                       Suggestion::FrontendId frontend_id)
     : frontend_id(frontend_id),
       main_text(base::UTF8ToUTF16(main_text), Text::IsPrimary(true)),
       minor_text(base::UTF8ToUTF16(minor_text)),
diff --git a/components/autofill/core/browser/ui/suggestion.h b/components/autofill/core/browser/ui/suggestion.h
index 8cfd5d4..dd729e0 100644
--- a/components/autofill/core/browser/ui/suggestion.h
+++ b/components/autofill/core/browser/ui/suggestion.h
@@ -5,10 +5,12 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SUGGESTION_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SUGGESTION_H_
 
+#include <ostream>
 #include <string>
 
 #include "base/logging.h"
 #include "base/strings/string_piece.h"
+#include "base/types/cxx23_to_underlying.h"
 #include "base/types/strong_alias.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
@@ -25,6 +27,39 @@
   using ValueToFill = base::StrongAlias<struct ValueToFill, std::u16string>;
   using Payload = absl::variant<BackendId, GURL, ValueToFill>;
 
+  // A frontend ID is either a PopupItemId or a raw, non-negative integer ID.
+  //
+  // The non-negative integers represents an AutofillProfile or a CreditCard,
+  // which can be obtained by first converting the frontend ID to a BackendId
+  // using AutofillSuggestionGenerator::GetBackendIdFromFrontendId(), which can
+  // then be passed to the PersonalDataManager.
+  //
+  // Frontend IDs are deprecated and will be eliminated: crbug.com/1394920.
+  //
+  // TODO(crbug.com/1394920): Remove `FrontendId(int)` and `as_int()`.
+  class FrontendId {
+   public:
+    constexpr FrontendId() : value_(0) {}
+    constexpr FrontendId(  // NOLINT(google-explicit-constructor)
+        PopupItemId popup_item_id)
+        : value_(base::to_underlying(popup_item_id)) {}
+    constexpr explicit FrontendId(int int_id) : value_(int_id) {}
+
+    // Returns the content of the variant as `int`, even if it holds a
+    // PopupItemId.
+    int as_int() const { return value_; }
+
+    // Returns the content of the variant as `PopupItemId`, even if it holds a
+    // raw integer.
+    PopupItemId as_popup_item_id() const {
+      return static_cast<PopupItemId>(value_);
+    }
+
+   private:
+    static_assert(std::is_same_v<std::underlying_type_t<PopupItemId>, int>);
+    int value_;
+  };
+
   enum MatchMode {
     PREFIX_MATCH,    // for prefix matched suggestions;
     SUBSTRING_MATCH  // for substring matched suggestions;
@@ -59,18 +94,18 @@
 
   Suggestion();
   explicit Suggestion(std::u16string main_text);
-  explicit Suggestion(int frontend_id);
+  explicit Suggestion(Suggestion::FrontendId frontend_id);
   // Constructor for unit tests. It will convert the strings from UTF-8 to
   // UTF-16.
   Suggestion(base::StringPiece main_text,
              base::StringPiece label,
              std::string icon,
-             int frontend_id);
+             Suggestion::FrontendId frontend_id);
   Suggestion(base::StringPiece main_text,
              base::StringPiece minor_text,
              base::StringPiece label,
              std::string icon,
-             int frontend_id);
+             Suggestion::FrontendId frontend_id);
   Suggestion(const Suggestion& other);
   Suggestion(Suggestion&& other);
   Suggestion& operator=(const Suggestion& other);
@@ -87,7 +122,7 @@
 
 #if DCHECK_IS_ON()
   bool Invariant() const {
-    switch (frontend_id) {
+    switch (frontend_id.as_popup_item_id()) {
       case PopupItemId::POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS:
         return absl::holds_alternative<GURL>(payload);
       case PopupItemId::POPUP_ITEM_ID_IBAN_ENTRY:
@@ -111,7 +146,7 @@
   // ID for the frontend to use in identifying the particular result. Positive
   // values are sent over IPC to identify the item selected. Negative values
   // (see popup_item_ids.h) have special built-in meanings.
-  int frontend_id = 0;
+  Suggestion::FrontendId frontend_id{};
 
   // The texts that will be displayed on the first line in a suggestion. The
   // order of showing the two texts on the first line depends on whether it is
@@ -174,6 +209,15 @@
   absl::optional<std::u16string> acceptance_a11y_announcement;
 };
 
+bool operator==(Suggestion::FrontendId lhs, Suggestion::FrontendId rhs);
+bool operator==(Suggestion::FrontendId lhs, PopupItemId rhs);
+bool operator==(PopupItemId lhs, Suggestion::FrontendId rhs);
+bool operator!=(Suggestion::FrontendId lhs, Suggestion::FrontendId rhs);
+bool operator!=(Suggestion::FrontendId lhs, PopupItemId rhs);
+bool operator!=(PopupItemId lhs, Suggestion::FrontendId rhs);
+
+std::ostream& operator<<(std::ostream& os, Suggestion::FrontendId id);
+
 #if defined(UNIT_TEST)
 inline void PrintTo(const Suggestion& suggestion, std::ostream* os) {
   *os << std::endl
diff --git a/components/autofill/core/browser/ui/suggestion_test_helpers.h b/components/autofill/core/browser/ui/suggestion_test_helpers.h
index ffa601bd..99be719 100644
--- a/components/autofill/core/browser/ui/suggestion_test_helpers.h
+++ b/components/autofill/core/browser/ui/suggestion_test_helpers.h
@@ -16,7 +16,7 @@
 // Gmock matcher that allows checking a member of the Suggestion class in a
 // vector. This wraps a GMock container matcher, converts the suggestion
 // members to a vector, and then runs the container matcher against the result
-// to test an argument. See SuggestionVectorIdsAre() below.
+// to test an argument. See SuggestionVectorMainTextsAre() below.
 template <typename EltType>
 class SuggestionVectorMembersAreMatcher
     : public testing::MatcherInterface<const std::vector<Suggestion>&> {
@@ -52,15 +52,18 @@
 // Use this matcher to compare a sequence vector's IDs to a list. In an
 // EXPECT_CALL statement, use the following for an vector<Suggestion> argument
 // to compare the IDs against a constant list:
-//   SuggestionVectorIdsAre(testing::ElementsAre(1, 2, 3, 4))
-template <class EltsAreMatcher>
-inline testing::Matcher<const std::vector<Suggestion>&> SuggestionVectorIdsAre(
-    const EltsAreMatcher& elts_are_matcher) {
-  return testing::MakeMatcher(new SuggestionVectorMembersAreMatcher<int>(
-      elts_are_matcher, &Suggestion::frontend_id));
+//   SuggestionVectorIdsAre(1, 2, 3, 4)
+template <class... Matchers>
+inline auto SuggestionVectorIdsAre(const Matchers&... matchers) {
+  return ::testing::ElementsAre(
+      ::testing::Field("frontend_id", &Suggestion::frontend_id, matchers)...);
 }
 
-// Like SuggestionVectorIdsAre above, but tests the main_texts.
+// Use this matcher to compare a sequence vector's main_texts to a list. In an
+// EXPECT_CALL statement, use the following for an vector<Suggestion> argument
+// to compare the IDs against a constant list:
+//   SuggestionVectorMainTextsAre(testing::ElementsAre(text1, text2, text3,
+//   text4))
 template <class EltsAreMatcher>
 inline testing::Matcher<const std::vector<Suggestion>&>
 SuggestionVectorMainTextsAre(const EltsAreMatcher& elts_are_matcher) {
@@ -69,7 +72,7 @@
           elts_are_matcher, &Suggestion::main_text));
 }
 
-// Like SuggestionVectorIdsAre above, but tests the labels.
+// Like SuggestionVectorMainTextsAre above, but tests the labels.
 template <class EltsAreMatcher>
 inline testing::Matcher<const std::vector<Suggestion>&>
 SuggestionVectorLabelsAre(const EltsAreMatcher& elts_are_matcher) {
@@ -78,7 +81,7 @@
       elts_are_matcher, &Suggestion::labels));
 }
 
-// Like SuggestionVectorIdsAre above, but tests the icons.
+// Like SuggestionVectorMainTextsAre above, but tests the icons.
 template <class EltsAreMatcher>
 inline testing::Matcher<const std::vector<Suggestion>&>
 SuggestionVectorIconsAre(const EltsAreMatcher& elts_are_matcher) {
@@ -87,7 +90,7 @@
                                                          &Suggestion::icon));
 }
 
-// Like SuggestionVectorIdsAre above, but tests the trailing_icon.
+// Like SuggestionVectorMainTextsAre above, but tests the trailing_icon.
 template <class EltsAreMatcher>
 inline testing::Matcher<const std::vector<Suggestion>&>
 SuggestionVectorStoreIndicatorIconsAre(const EltsAreMatcher& elts_are_matcher) {
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm
index 06bfddba..dcc8628 100644
--- a/components/autofill/ios/browser/autofill_agent.mm
+++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -434,6 +434,9 @@
   DCHECK(completion);
   _suggestionHandledCompletion = [completion copy];
 
+  // TODO(crbug.com/1394920): Make `suggestion.identifier` a `FrontendId`.
+  autofill::Suggestion::FrontendId frontend_id(suggestion.identifier);
+
   if (suggestion.acceptanceA11yAnnouncement != nil) {
     __weak AutofillAgent* weakSelf = self;
     // The announcement is done asyncronously with certain delay to make sure
@@ -462,14 +465,14 @@
         });
   }
 
-  if (suggestion.identifier > 0) {
+  if (frontend_id.as_int() > 0) {
     _pendingAutocompleteFieldID = uniqueFieldID;
     if (_popupDelegate) {
       // TODO(966411): Replace 0 with the index of the selected suggestion.
       autofill::Suggestion autofill_suggestion;
       autofill_suggestion.main_text.value =
           SysNSStringToUTF16(suggestion.value);
-      autofill_suggestion.frontend_id = suggestion.identifier;
+      autofill_suggestion.frontend_id = frontend_id;
       autofill_suggestion.payload = autofill::Suggestion::BackendId();
       _popupDelegate->DidAcceptSuggestion(autofill_suggestion, 0);
     }
@@ -491,14 +494,16 @@
     return;
   }
 
-  if (suggestion.identifier == autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
+  if (frontend_id.as_popup_item_id() ==
+      autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
     // FormSuggestion is a simple, single value that can be filled out now.
     [self fillField:SysNSStringToUTF8(fieldIdentifier)
         uniqueFieldID:uniqueFieldID
              formName:SysNSStringToUTF8(formName)
                 value:SysNSStringToUTF16(suggestion.value)
               inFrame:frame];
-  } else if (suggestion.identifier == autofill::POPUP_ITEM_ID_CLEAR_FORM) {
+  } else if (frontend_id.as_popup_item_id() ==
+             autofill::POPUP_ITEM_ID_CLEAR_FORM) {
     __weak AutofillAgent* weakSelf = self;
     SuggestionHandledCompletion suggestionHandledCompletionCopy =
         [_suggestionHandledCompletion copy];
@@ -514,7 +519,7 @@
           suggestionHandledCompletionCopy();
         }));
 
-  } else if (suggestion.identifier ==
+  } else if (frontend_id.as_popup_item_id() ==
              autofill::POPUP_ITEM_ID_SHOW_ACCOUNT_CARDS) {
     autofill::BrowserAutofillManager* autofillManager =
         [self autofillManagerFromWebState:_webState webFrame:frame];
@@ -522,7 +527,7 @@
       autofillManager->OnUserAcceptedCardsFromAccountOption();
     }
   } else {
-    NOTREACHED() << "unknown identifier " << suggestion.identifier;
+    NOTREACHED() << "unknown identifier " << frontend_id;
   }
 }
 
@@ -623,7 +628,7 @@
     // "clear form" button.
     NSString* value = nil;
     NSString* displayDescription = nil;
-    if (popup_suggestion.frontend_id >= 0) {
+    if (popup_suggestion.frontend_id.as_int() >= 0) {
       // Filter out any key/value suggestions if the user hasn't typed yet.
       if (popup_suggestion.frontend_id ==
               autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY &&
@@ -662,13 +667,13 @@
                                      autofill::PopupType::kCreditCards
                          ? base::SysUTF8ToNSString(popup_suggestion.icon)
                          : nil;
-    FormSuggestion* suggestion =
-        [FormSuggestion suggestionWithValue:value
-                         displayDescription:displayDescription
-                                       icon:icon
-                                 identifier:popup_suggestion.frontend_id
-                             requiresReauth:NO
-                 acceptanceA11yAnnouncement:acceptanceA11yAnnouncement];
+    FormSuggestion* suggestion = [FormSuggestion
+               suggestionWithValue:value
+                displayDescription:displayDescription
+                              icon:icon
+                        identifier:popup_suggestion.frontend_id.as_int()
+                    requiresReauth:NO
+        acceptanceA11yAnnouncement:acceptanceA11yAnnouncement];
 
     if (!popup_suggestion.feature_for_iph.empty()) {
       suggestion.featureForIPH =
diff --git a/components/autofill/ios/browser/autofill_agent_unittests.mm b/components/autofill/ios/browser/autofill_agent_unittests.mm
index 28f456f..0461a58 100644
--- a/components/autofill/ios/browser/autofill_agent_unittests.mm
+++ b/components/autofill/ios/browser/autofill_agent_unittests.mm
@@ -314,8 +314,10 @@
 
   // Make the suggestions available to AutofillAgent.
   std::vector<autofill::Suggestion> autofillSuggestions;
-  autofillSuggestions.push_back(autofill::Suggestion("", "", "", 123));
-  autofillSuggestions.push_back(autofill::Suggestion("", "", "", 321));
+  autofillSuggestions.push_back(
+      autofill::Suggestion("", "", "", autofill::Suggestion::FrontendId(123)));
+  autofillSuggestions.push_back(
+      autofill::Suggestion("", "", "", autofill::Suggestion::FrontendId(321)));
   autofillSuggestions.push_back(
       autofill::Suggestion("", "", "", POPUP_ITEM_ID_CLEAR_FORM));
   [autofill_agent_
@@ -364,8 +366,10 @@
 
   // Make the suggestions available to AutofillAgent.
   std::vector<autofill::Suggestion> autofillSuggestions;
-  autofillSuggestions.push_back(autofill::Suggestion("", "", "", 123));
-  autofillSuggestions.push_back(autofill::Suggestion("", "", "", 321));
+  autofillSuggestions.push_back(
+      autofill::Suggestion("", "", "", autofill::Suggestion::FrontendId(123)));
+  autofillSuggestions.push_back(
+      autofill::Suggestion("", "", "", autofill::Suggestion::FrontendId(321)));
   autofillSuggestions.push_back(
       autofill::Suggestion("", "", "", POPUP_ITEM_ID_CLEAR_FORM));
   [autofill_agent_
diff --git a/components/browser_sync/sync_api_component_factory_impl.cc b/components/browser_sync/sync_api_component_factory_impl.cc
index 37a226d4..48c59d88 100644
--- a/components/browser_sync/sync_api_component_factory_impl.cc
+++ b/components/browser_sync/sync_api_component_factory_impl.cc
@@ -384,7 +384,7 @@
               account_password_store_
                   ? account_password_store_->CreateSyncControllerDelegate()
                   : nullptr,
-              account_password_store_, sync_client_->GetPrefService(),
+              sync_client_->GetPrefService(),
               sync_client_->GetIdentityManager(), sync_service));
     }
   }
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 409928e..742dd6f 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -250,6 +250,7 @@
     "api/src/org/chromium/net/DnsOptions.java",
     "api/src/org/chromium/net/ExperimentalBidirectionalStream.java",
     "api/src/org/chromium/net/ExperimentalCronetEngine.java",
+    "api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java",
     "api/src/org/chromium/net/ExperimentalUrlRequest.java",
     "api/src/org/chromium/net/ICronetEngineBuilder.java",
     "api/src/org/chromium/net/InlineExecutionProhibitedException.java",
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index 4c3dd17..603915ad 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -137,7 +137,13 @@
          * <p>{@hide}
          */
         public Builder(ICronetEngineBuilder builderDelegate) {
-            mBuilderDelegate = builderDelegate;
+            if (builderDelegate instanceof ExperimentalOptionsTranslatingCronetEngineBuilder) {
+                // Already wrapped at the top level, no need to do it again
+                mBuilderDelegate = builderDelegate;
+            } else {
+                mBuilderDelegate =
+                        new ExperimentalOptionsTranslatingCronetEngineBuilder(builderDelegate);
+            }
         }
 
         /**
diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
index 26db9e0..e0bc6e0 100644
--- a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
@@ -7,18 +7,11 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.chromium.net.DnsOptions.StaleDnsOptions;
-
 import java.io.IOException;
 import java.net.Proxy;
 import java.net.URL;
 import java.net.URLConnection;
-import java.util.ArrayList;
 import java.util.Date;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -96,10 +89,6 @@
      * Experimental features may be deprecated in the future. Use at your own risk.
      */
     public static class Builder extends CronetEngine.Builder {
-        private JSONObject mParsedExperimentalOptions;
-        private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches =
-                new ArrayList<>();
-
         /**
          * Constructs a {@link Builder} object that facilitates creating a {@link CronetEngine}. The
          * default configuration enables HTTP/2 and disables QUIC, SDCH and the HTTP cache.
@@ -131,11 +120,7 @@
          * @return the builder to facilitate chaining.
          */
         public Builder setExperimentalOptions(String options) {
-            if (options == null || options.isEmpty()) {
-                mParsedExperimentalOptions = null;
-            } else {
-                mParsedExperimentalOptions = parseExperimentalOptions(options);
-            }
+            mBuilderDelegate.setExperimentalOptions(options);
             return this;
         }
 
@@ -185,244 +170,21 @@
         @Override
         @QuicOptions.Experimental
         public Builder setQuicOptions(QuicOptions options) {
-            // If the delegate builder supports enabling connection migration directly, just use it
-            if (mBuilderDelegate.getSupportedConfigOptions().contains(
-                        ICronetEngineBuilder.QUIC_OPTIONS)) {
-                mBuilderDelegate.setQuicOptions(options);
-                return this;
-            }
-
-            // If not, we'll have to work around it by modifying the experimental options JSON.
-            mExperimentalOptionsPatches.add((experimentalOptions) -> {
-                JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
-
-                // Note: using the experimental APIs always overwrites what's in the experimental
-                // JSON, even though "repeated" fields could in theory be additive.
-                if (!options.getQuicHostAllowlist().isEmpty()) {
-                    quicOptions.put(
-                            "host_whitelist", String.join(",", options.getQuicHostAllowlist()));
-                }
-                if (!options.getEnabledQuicVersions().isEmpty()) {
-                    quicOptions.put(
-                            "quic_version", String.join(",", options.getEnabledQuicVersions()));
-                }
-                if (!options.getConnectionOptions().isEmpty()) {
-                    quicOptions.put(
-                            "connection_options", String.join(",", options.getConnectionOptions()));
-                }
-                if (!options.getClientConnectionOptions().isEmpty()) {
-                    quicOptions.put("client_connection_options",
-                            String.join(",", options.getClientConnectionOptions()));
-                }
-                if (!options.getExtraQuicheFlags().isEmpty()) {
-                    quicOptions.put(
-                            "set_quic_flags", String.join(",", options.getExtraQuicheFlags()));
-                }
-
-                if (options.getInMemoryServerConfigsCacheSize() != null) {
-                    quicOptions.put("max_server_configs_stored_in_properties",
-                            options.getInMemoryServerConfigsCacheSize());
-                }
-
-                if (options.getHandshakeUserAgent() != null) {
-                    quicOptions.put("user_agent_id", options.getHandshakeUserAgent());
-                }
-
-                if (options.getRetryWithoutAltSvcOnQuicErrors() != null) {
-                    quicOptions.put("retry_without_alt_svc_on_quic_errors",
-                            options.getRetryWithoutAltSvcOnQuicErrors());
-                }
-
-                if (options.getEnableTlsZeroRtt() != null) {
-                    quicOptions.put("disable_tls_zero_rtt", !options.getEnableTlsZeroRtt());
-                }
-
-                if (options.getPreCryptoHandshakeIdleTimeoutSeconds() != null) {
-                    quicOptions.put("max_idle_time_before_crypto_handshake_seconds",
-                            options.getPreCryptoHandshakeIdleTimeoutSeconds());
-                }
-
-                if (options.getCryptoHandshakeTimeoutSeconds() != null) {
-                    quicOptions.put("max_time_before_crypto_handshake_seconds",
-                            options.getCryptoHandshakeTimeoutSeconds());
-                }
-
-                if (options.getIdleConnectionTimeoutSeconds() != null) {
-                    quicOptions.put("idle_connection_timeout_seconds",
-                            options.getIdleConnectionTimeoutSeconds());
-                }
-
-                if (options.getRetransmittableOnWireTimeoutMillis() != null) {
-                    quicOptions.put("retransmittable_on_wire_timeout_milliseconds",
-                            options.getRetransmittableOnWireTimeoutMillis());
-                }
-
-                if (options.getCloseSessionsOnIpChange() != null) {
-                    quicOptions.put(
-                            "close_sessions_on_ip_change", options.getCloseSessionsOnIpChange());
-                }
-
-                if (options.getGoawaySessionsOnIpChange() != null) {
-                    quicOptions.put(
-                            "goaway_sessions_on_ip_change", options.getGoawaySessionsOnIpChange());
-                }
-
-                if (options.getInitialBrokenServicePeriodSeconds() != null) {
-                    quicOptions.put("initial_delay_for_broken_alternative_service_seconds",
-                            options.getInitialBrokenServicePeriodSeconds());
-                }
-
-                if (options.getIncreaseBrokenServicePeriodExponentially() != null) {
-                    quicOptions.put("exponential_backoff_on_initial_delay",
-                            options.getIncreaseBrokenServicePeriodExponentially());
-                }
-
-                if (options.getDelayJobsWithAvailableSpdySession() != null) {
-                    quicOptions.put("delay_main_job_with_available_spdy_session",
-                            options.getDelayJobsWithAvailableSpdySession());
-                }
-            });
+            super.setQuicOptions(options);
             return this;
         }
 
         @Override
         @DnsOptions.Experimental
         public Builder setDnsOptions(DnsOptions options) {
-            // If the delegate builder supports enabling connection migration directly, just use it
-            if (mBuilderDelegate.getSupportedConfigOptions().contains(
-                        ICronetEngineBuilder.DNS_OPTIONS)) {
-                mBuilderDelegate.setDnsOptions(options);
-                return this;
-            }
-
-            // If not, we'll have to work around it by modifying the experimental options JSON.
-            mExperimentalOptionsPatches.add((experimentalOptions) -> {
-                JSONObject asyncDnsOptions = createDefaultIfAbsent(experimentalOptions, "AsyncDNS");
-
-                if (options.getUseBuiltInDnsResolver() != null) {
-                    asyncDnsOptions.put("enable", options.getUseBuiltInDnsResolver());
-                }
-
-                JSONObject staleDnsOptions = createDefaultIfAbsent(experimentalOptions, "StaleDNS");
-
-                if (options.getEnableStaleDns() != null) {
-                    staleDnsOptions.put("enable", options.getEnableStaleDns());
-                }
-
-                if (options.getPersistHostCache() != null) {
-                    staleDnsOptions.put("persist_to_disk", options.getPersistHostCache());
-                }
-
-                if (options.getPersistHostCachePeriodMillis() != null) {
-                    staleDnsOptions.put(
-                            "persist_delay_ms", options.getPersistHostCachePeriodMillis());
-                }
-
-                if (options.getStaleDnsOptions() != null) {
-                    StaleDnsOptions staleDnsOptionsJava = options.getStaleDnsOptions();
-
-                    if (staleDnsOptionsJava.getAllowCrossNetworkUsage() != null) {
-                        staleDnsOptions.put("allow_other_network",
-                                staleDnsOptionsJava.getAllowCrossNetworkUsage());
-                    }
-
-                    if (staleDnsOptionsJava.getFreshLookupTimeoutMillis() != null) {
-                        staleDnsOptions.put(
-                                "delay_ms", staleDnsOptionsJava.getFreshLookupTimeoutMillis());
-                    }
-
-                    if (staleDnsOptionsJava.getUseStaleOnNameNotResolved() != null) {
-                        staleDnsOptions.put("use_stale_on_name_not_resolved",
-                                staleDnsOptionsJava.getUseStaleOnNameNotResolved());
-                    }
-
-                    if (staleDnsOptionsJava.getMaxExpiredDelayMillis() != null) {
-                        staleDnsOptions.put("max_expired_time_ms",
-                                staleDnsOptionsJava.getMaxExpiredDelayMillis());
-                    }
-                }
-
-                JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
-                if (options.getPreestablishConnectionsToStaleDnsResults() != null) {
-                    quicOptions.put("race_stale_dns_on_connection",
-                            options.getPreestablishConnectionsToStaleDnsResults());
-                }
-            });
+            super.setDnsOptions(options);
             return this;
         }
 
         @Override
         @ConnectionMigrationOptions.Experimental
         public Builder setConnectionMigrationOptions(ConnectionMigrationOptions options) {
-            // If the delegate builder supports enabling connection migration directly, just use it
-            if (mBuilderDelegate.getSupportedConfigOptions().contains(
-                        ICronetEngineBuilder.CONNECTION_MIGRATION_OPTIONS)) {
-                mBuilderDelegate.setConnectionMigrationOptions(options);
-                return this;
-            }
-
-            // If not, we'll have to work around it by modifying the experimental options JSON.
-            mExperimentalOptionsPatches.add((experimentalOptions) -> {
-                JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
-
-                if (options.getEnableDefaultNetworkMigration() != null) {
-                    quicOptions.put("migrate_sessions_on_network_change_v2",
-                            options.getEnableDefaultNetworkMigration());
-                }
-                if (options.getAllowServerMigration() != null) {
-                    quicOptions.put("allow_server_migration", options.getAllowServerMigration());
-                }
-                if (options.getMigrateIdleConnections() != null) {
-                    quicOptions.put("migrate_idle_sessions", options.getMigrateIdleConnections());
-                }
-                if (options.getIdleMigrationPeriodSeconds() != null) {
-                    quicOptions.put("idle_session_migration_period_seconds",
-                            options.getIdleMigrationPeriodSeconds());
-                }
-                if (options.getRetryPreHandshakeErrorsOnAlternateNetwork() != null) {
-                    quicOptions.put("retry_on_alternate_network_before_handshake",
-                            options.getRetryPreHandshakeErrorsOnAlternateNetwork());
-                }
-                if (options.getMaxTimeOnNonDefaultNetworkSeconds() != null) {
-                    quicOptions.put("max_time_on_non_default_network_seconds",
-                            options.getMaxTimeOnNonDefaultNetworkSeconds());
-                }
-                if (options.getMaxPathDegradingEagerMigrationsCount() != null) {
-                    quicOptions.put("max_migrations_to_non_default_network_on_path_degrading",
-                            options.getMaxPathDegradingEagerMigrationsCount());
-                }
-                if (options.getMaxWriteErrorEagerMigrationsCount() != null) {
-                    quicOptions.put("max_migrations_to_non_default_network_on_write_error",
-                            options.getMaxWriteErrorEagerMigrationsCount());
-                }
-                if (options.getEnablePathDegradationMigration() != null) {
-                    boolean pathDegradationValue = options.getEnablePathDegradationMigration();
-
-                    boolean skipPortMigrationFlag = false;
-
-                    if (options.getAllowNonDefaultNetworkUsage() != null) {
-                        boolean nonDefaultNetworkValue = options.getAllowNonDefaultNetworkUsage();
-                        if (!pathDegradationValue && nonDefaultNetworkValue) {
-                            // Misconfiguration which doesn't translate easily to the JSON flags
-                            throw new IllegalArgumentException(
-                                    "Unable to turn on non-default network usage without path "
-                                    + "degradation migration!");
-                        } else if (pathDegradationValue && nonDefaultNetworkValue) {
-                            // Both values being true results in the non-default network migration
-                            // being enabled.
-                            quicOptions.put("migrate_sessions_early_v2", true);
-                            skipPortMigrationFlag = true;
-                        } else {
-                            quicOptions.put("migrate_sessions_early_v2", false);
-                        }
-                    }
-
-                    if (!skipPortMigrationFlag) {
-                        quicOptions.put("allow_port_migration", pathDegradationValue);
-                    }
-                }
-            });
-
+            super.setConnectionMigrationOptions(options);
             return this;
         }
 
@@ -470,53 +232,8 @@
 
         @Override
         public ExperimentalCronetEngine build() {
-            if (mParsedExperimentalOptions == null && mExperimentalOptionsPatches.isEmpty()) {
-                return mBuilderDelegate.build();
-            }
-
-            if (mParsedExperimentalOptions == null) {
-                mParsedExperimentalOptions = new JSONObject();
-            }
-
-            for (ExperimentalOptionsPatch patch : mExperimentalOptionsPatches) {
-                try {
-                    patch.applyTo(mParsedExperimentalOptions);
-                } catch (JSONException e) {
-                    throw new IllegalStateException("Unable to apply JSON patch!", e);
-                }
-            }
-
-            mBuilderDelegate.setExperimentalOptions(mParsedExperimentalOptions.toString());
             return mBuilderDelegate.build();
         }
-
-        private static JSONObject parseExperimentalOptions(String jsonString) {
-            try {
-                return new JSONObject(jsonString);
-            } catch (JSONException e) {
-                throw new IllegalArgumentException("Experimental options parsing failed", e);
-            }
-        }
-
-        private static JSONObject createDefaultIfAbsent(JSONObject jsonObject, String key) {
-            JSONObject object = jsonObject.optJSONObject(key);
-            if (object == null) {
-                object = new JSONObject();
-                try {
-                    jsonObject.put(key, object);
-                } catch (JSONException e) {
-                    throw new IllegalArgumentException(
-                            "Failed adding a default object for key [" + key + "]", e);
-                }
-            }
-
-            return object;
-        }
-
-        @FunctionalInterface
-        private interface ExperimentalOptionsPatch {
-            void applyTo(JSONObject experimentalOptions) throws JSONException;
-        }
     }
 
     @Override
diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java
new file mode 100644
index 0000000..a363cfcc
--- /dev/null
+++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java
@@ -0,0 +1,430 @@
+// Copyright 2016 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+package org.chromium.net;
+
+import androidx.annotation.VisibleForTesting;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.chromium.net.DnsOptions.StaleDnsOptions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An implementation of ICronetEngineBuilder which handles translation of configuration options to
+ * json-based experimental options, if necessary.
+ *
+ * <p>{@hide internal class}
+ */
+final class ExperimentalOptionsTranslatingCronetEngineBuilder extends ICronetEngineBuilder {
+    private static final Set<Integer> SUPPORTED_OPTIONS = Collections.unmodifiableSet(
+            new HashSet(Arrays.asList(ICronetEngineBuilder.CONNECTION_MIGRATION_OPTIONS,
+                    ICronetEngineBuilder.DNS_OPTIONS, ICronetEngineBuilder.QUIC_OPTIONS)));
+
+    private JSONObject mParsedExperimentalOptions;
+    private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches = new ArrayList<>();
+
+    private final ICronetEngineBuilder mDelegate;
+
+    ExperimentalOptionsTranslatingCronetEngineBuilder(ICronetEngineBuilder delegate) {
+        this.mDelegate = delegate;
+    }
+
+    @Override
+    public ICronetEngineBuilder setQuicOptions(QuicOptions options) {
+        // If the delegate builder supports enabling connection migration directly, just use it
+        if (mDelegate.getSupportedConfigOptions().contains(ICronetEngineBuilder.QUIC_OPTIONS)) {
+            mDelegate.setQuicOptions(options);
+            return this;
+        }
+
+        // If not, we'll have to work around it by modifying the experimental options JSON.
+        mExperimentalOptionsPatches.add((experimentalOptions) -> {
+            JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+
+            // Note: using the experimental APIs always overwrites what's in the experimental
+            // JSON, even though "repeated" fields could in theory be additive.
+            if (!options.getQuicHostAllowlist().isEmpty()) {
+                quicOptions.put("host_whitelist", String.join(",", options.getQuicHostAllowlist()));
+            }
+            if (!options.getEnabledQuicVersions().isEmpty()) {
+                quicOptions.put("quic_version", String.join(",", options.getEnabledQuicVersions()));
+            }
+            if (!options.getConnectionOptions().isEmpty()) {
+                quicOptions.put(
+                        "connection_options", String.join(",", options.getConnectionOptions()));
+            }
+            if (!options.getClientConnectionOptions().isEmpty()) {
+                quicOptions.put("client_connection_options",
+                        String.join(",", options.getClientConnectionOptions()));
+            }
+            if (!options.getExtraQuicheFlags().isEmpty()) {
+                quicOptions.put("set_quic_flags", String.join(",", options.getExtraQuicheFlags()));
+            }
+
+            if (options.getInMemoryServerConfigsCacheSize() != null) {
+                quicOptions.put("max_server_configs_stored_in_properties",
+                        options.getInMemoryServerConfigsCacheSize());
+            }
+
+            if (options.getHandshakeUserAgent() != null) {
+                quicOptions.put("user_agent_id", options.getHandshakeUserAgent());
+            }
+
+            if (options.getRetryWithoutAltSvcOnQuicErrors() != null) {
+                quicOptions.put("retry_without_alt_svc_on_quic_errors",
+                        options.getRetryWithoutAltSvcOnQuicErrors());
+            }
+
+            if (options.getEnableTlsZeroRtt() != null) {
+                quicOptions.put("disable_tls_zero_rtt", !options.getEnableTlsZeroRtt());
+            }
+
+            if (options.getPreCryptoHandshakeIdleTimeoutSeconds() != null) {
+                quicOptions.put("max_idle_time_before_crypto_handshake_seconds",
+                        options.getPreCryptoHandshakeIdleTimeoutSeconds());
+            }
+
+            if (options.getCryptoHandshakeTimeoutSeconds() != null) {
+                quicOptions.put("max_time_before_crypto_handshake_seconds",
+                        options.getCryptoHandshakeTimeoutSeconds());
+            }
+
+            if (options.getIdleConnectionTimeoutSeconds() != null) {
+                quicOptions.put("idle_connection_timeout_seconds",
+                        options.getIdleConnectionTimeoutSeconds());
+            }
+
+            if (options.getRetransmittableOnWireTimeoutMillis() != null) {
+                quicOptions.put("retransmittable_on_wire_timeout_milliseconds",
+                        options.getRetransmittableOnWireTimeoutMillis());
+            }
+
+            if (options.getCloseSessionsOnIpChange() != null) {
+                quicOptions.put(
+                        "close_sessions_on_ip_change", options.getCloseSessionsOnIpChange());
+            }
+
+            if (options.getGoawaySessionsOnIpChange() != null) {
+                quicOptions.put(
+                        "goaway_sessions_on_ip_change", options.getGoawaySessionsOnIpChange());
+            }
+
+            if (options.getInitialBrokenServicePeriodSeconds() != null) {
+                quicOptions.put("initial_delay_for_broken_alternative_service_seconds",
+                        options.getInitialBrokenServicePeriodSeconds());
+            }
+
+            if (options.getIncreaseBrokenServicePeriodExponentially() != null) {
+                quicOptions.put("exponential_backoff_on_initial_delay",
+                        options.getIncreaseBrokenServicePeriodExponentially());
+            }
+
+            if (options.getDelayJobsWithAvailableSpdySession() != null) {
+                quicOptions.put("delay_main_job_with_available_spdy_session",
+                        options.getDelayJobsWithAvailableSpdySession());
+            }
+        });
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setDnsOptions(DnsOptions options) {
+        // If the delegate builder supports enabling connection migration directly, just use it
+        if (mDelegate.getSupportedConfigOptions().contains(ICronetEngineBuilder.DNS_OPTIONS)) {
+            mDelegate.setDnsOptions(options);
+            return this;
+        }
+
+        // If not, we'll have to work around it by modifying the experimental options JSON.
+        mExperimentalOptionsPatches.add((experimentalOptions) -> {
+            JSONObject asyncDnsOptions = createDefaultIfAbsent(experimentalOptions, "AsyncDNS");
+
+            if (options.getUseBuiltInDnsResolver() != null) {
+                asyncDnsOptions.put("enable", options.getUseBuiltInDnsResolver());
+            }
+
+            JSONObject staleDnsOptions = createDefaultIfAbsent(experimentalOptions, "StaleDNS");
+
+            if (options.getEnableStaleDns() != null) {
+                staleDnsOptions.put("enable", options.getEnableStaleDns());
+            }
+
+            if (options.getPersistHostCache() != null) {
+                staleDnsOptions.put("persist_to_disk", options.getPersistHostCache());
+            }
+
+            if (options.getPersistHostCachePeriodMillis() != null) {
+                staleDnsOptions.put("persist_delay_ms", options.getPersistHostCachePeriodMillis());
+            }
+
+            if (options.getStaleDnsOptions() != null) {
+                StaleDnsOptions staleDnsOptionsJava = options.getStaleDnsOptions();
+
+                if (staleDnsOptionsJava.getAllowCrossNetworkUsage() != null) {
+                    staleDnsOptions.put(
+                            "allow_other_network", staleDnsOptionsJava.getAllowCrossNetworkUsage());
+                }
+
+                if (staleDnsOptionsJava.getFreshLookupTimeoutMillis() != null) {
+                    staleDnsOptions.put(
+                            "delay_ms", staleDnsOptionsJava.getFreshLookupTimeoutMillis());
+                }
+
+                if (staleDnsOptionsJava.getUseStaleOnNameNotResolved() != null) {
+                    staleDnsOptions.put("use_stale_on_name_not_resolved",
+                            staleDnsOptionsJava.getUseStaleOnNameNotResolved());
+                }
+
+                if (staleDnsOptionsJava.getMaxExpiredDelayMillis() != null) {
+                    staleDnsOptions.put(
+                            "max_expired_time_ms", staleDnsOptionsJava.getMaxExpiredDelayMillis());
+                }
+            }
+
+            JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+            if (options.getPreestablishConnectionsToStaleDnsResults() != null) {
+                quicOptions.put("race_stale_dns_on_connection",
+                        options.getPreestablishConnectionsToStaleDnsResults());
+            }
+        });
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setConnectionMigrationOptions(ConnectionMigrationOptions options) {
+        // If the delegate builder supports enabling connection migration directly, just use it
+        if (mDelegate.getSupportedConfigOptions().contains(
+                    ICronetEngineBuilder.CONNECTION_MIGRATION_OPTIONS)) {
+            mDelegate.setConnectionMigrationOptions(options);
+            return this;
+        }
+
+        // If not, we'll have to work around it by modifying the experimental options JSON.
+        mExperimentalOptionsPatches.add((experimentalOptions) -> {
+            JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+
+            if (options.getEnableDefaultNetworkMigration() != null) {
+                quicOptions.put("migrate_sessions_on_network_change_v2",
+                        options.getEnableDefaultNetworkMigration());
+            }
+            if (options.getAllowServerMigration() != null) {
+                quicOptions.put("allow_server_migration", options.getAllowServerMigration());
+            }
+            if (options.getMigrateIdleConnections() != null) {
+                quicOptions.put("migrate_idle_sessions", options.getMigrateIdleConnections());
+            }
+            if (options.getIdleMigrationPeriodSeconds() != null) {
+                quicOptions.put("idle_session_migration_period_seconds",
+                        options.getIdleMigrationPeriodSeconds());
+            }
+            if (options.getRetryPreHandshakeErrorsOnAlternateNetwork() != null) {
+                quicOptions.put("retry_on_alternate_network_before_handshake",
+                        options.getRetryPreHandshakeErrorsOnAlternateNetwork());
+            }
+            if (options.getMaxTimeOnNonDefaultNetworkSeconds() != null) {
+                quicOptions.put("max_time_on_non_default_network_seconds",
+                        options.getMaxTimeOnNonDefaultNetworkSeconds());
+            }
+            if (options.getMaxPathDegradingEagerMigrationsCount() != null) {
+                quicOptions.put("max_migrations_to_non_default_network_on_path_degrading",
+                        options.getMaxPathDegradingEagerMigrationsCount());
+            }
+            if (options.getMaxWriteErrorEagerMigrationsCount() != null) {
+                quicOptions.put("max_migrations_to_non_default_network_on_write_error",
+                        options.getMaxWriteErrorEagerMigrationsCount());
+            }
+            if (options.getEnablePathDegradationMigration() != null) {
+                boolean pathDegradationValue = options.getEnablePathDegradationMigration();
+
+                boolean skipPortMigrationFlag = false;
+
+                if (options.getAllowNonDefaultNetworkUsage() != null) {
+                    boolean nonDefaultNetworkValue = options.getAllowNonDefaultNetworkUsage();
+                    if (!pathDegradationValue && nonDefaultNetworkValue) {
+                        // Misconfiguration which doesn't translate easily to the JSON flags
+                        throw new IllegalArgumentException(
+                                "Unable to turn on non-default network usage without path "
+                                + "degradation migration!");
+                    } else if (pathDegradationValue && nonDefaultNetworkValue) {
+                        // Both values being true results in the non-default network migration
+                        // being enabled.
+                        quicOptions.put("migrate_sessions_early_v2", true);
+                        skipPortMigrationFlag = true;
+                    } else {
+                        quicOptions.put("migrate_sessions_early_v2", false);
+                    }
+                }
+
+                if (!skipPortMigrationFlag) {
+                    quicOptions.put("allow_port_migration", pathDegradationValue);
+                }
+            }
+        });
+
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setExperimentalOptions(String options) {
+        if (options == null || options.isEmpty()) {
+            mParsedExperimentalOptions = null;
+        } else {
+            mParsedExperimentalOptions = parseExperimentalOptions(options);
+        }
+        return this;
+    }
+
+    @Override
+    protected Set<Integer> getSupportedConfigOptions() {
+        return SUPPORTED_OPTIONS;
+    }
+
+    @Override
+    public ExperimentalCronetEngine build() {
+        if (mParsedExperimentalOptions == null && mExperimentalOptionsPatches.isEmpty()) {
+            return mDelegate.build();
+        }
+
+        if (mParsedExperimentalOptions == null) {
+            mParsedExperimentalOptions = new JSONObject();
+        }
+
+        for (ExperimentalOptionsPatch patch : mExperimentalOptionsPatches) {
+            try {
+                patch.applyTo(mParsedExperimentalOptions);
+            } catch (JSONException e) {
+                throw new IllegalStateException("Unable to apply JSON patch!", e);
+            }
+        }
+
+        mDelegate.setExperimentalOptions(mParsedExperimentalOptions.toString());
+        return mDelegate.build();
+    }
+
+    private static JSONObject parseExperimentalOptions(String jsonString) {
+        try {
+            return new JSONObject(jsonString);
+        } catch (JSONException e) {
+            throw new IllegalArgumentException("Experimental options parsing failed", e);
+        }
+    }
+
+    private static JSONObject createDefaultIfAbsent(JSONObject jsonObject, String key) {
+        JSONObject object = jsonObject.optJSONObject(key);
+        if (object == null) {
+            object = new JSONObject();
+            try {
+                jsonObject.put(key, object);
+            } catch (JSONException e) {
+                throw new IllegalArgumentException(
+                        "Failed adding a default object for key [" + key + "]", e);
+            }
+        }
+
+        return object;
+    }
+
+    @VisibleForTesting
+    ICronetEngineBuilder getDelegate() {
+        return mDelegate;
+    }
+
+    @FunctionalInterface
+    private interface ExperimentalOptionsPatch {
+        void applyTo(JSONObject experimentalOptions) throws JSONException;
+    }
+
+    // Delegating-only methods
+    @Override
+    public ICronetEngineBuilder addPublicKeyPins(String hostName, Set<byte[]> pinsSha256,
+            boolean includeSubdomains, Date expirationDate) {
+        mDelegate.addPublicKeyPins(hostName, pinsSha256, includeSubdomains, expirationDate);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder addQuicHint(String host, int port, int alternatePort) {
+        mDelegate.addQuicHint(host, port, alternatePort);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enableHttp2(boolean value) {
+        mDelegate.enableHttp2(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enableHttpCache(int cacheMode, long maxSize) {
+        mDelegate.enableHttpCache(cacheMode, maxSize);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean value) {
+        mDelegate.enablePublicKeyPinningBypassForLocalTrustAnchors(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enableQuic(boolean value) {
+        mDelegate.enableQuic(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enableSdch(boolean value) {
+        mDelegate.enableSdch(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder enableBrotli(boolean value) {
+        mDelegate.enableBrotli(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setLibraryLoader(CronetEngine.Builder.LibraryLoader loader) {
+        mDelegate.setLibraryLoader(loader);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setStoragePath(String value) {
+        mDelegate.setStoragePath(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setUserAgent(String userAgent) {
+        mDelegate.setUserAgent(userAgent);
+        return this;
+    }
+
+    @Override
+    public String getDefaultUserAgent() {
+        return mDelegate.getDefaultUserAgent();
+    }
+
+    @Override
+    public ICronetEngineBuilder enableNetworkQualityEstimator(boolean value) {
+        mDelegate.enableNetworkQualityEstimator(value);
+        return this;
+    }
+
+    @Override
+    public ICronetEngineBuilder setThreadPriority(int priority) {
+        mDelegate.setThreadPriority(priority);
+        return this;
+    }
+}
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 5212a1e..6c66e819 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -44,7 +44,6 @@
 import org.chromium.net.CronetTestRule.RequiresMinApi;
 import org.chromium.net.NetworkChangeNotifierAutoDetect.ConnectivityManagerDelegate;
 import org.chromium.net.TestUrlRequestCallback.ResponseStep;
-import org.chromium.net.impl.CronetEngineBuilderImpl;
 import org.chromium.net.impl.CronetLibraryLoader;
 import org.chromium.net.impl.CronetUrlRequestContext;
 import org.chromium.net.impl.NativeCronetEngineBuilderImpl;
@@ -1532,7 +1531,7 @@
         builder.enablePublicKeyPinningBypassForLocalTrustAnchors(false);
         CronetUrlRequestContextTestJni.get().verifyUrlRequestContextConfig(
                 CronetUrlRequestContext.createNativeUrlRequestContextConfig(
-                        (CronetEngineBuilderImpl) builder.mBuilderDelegate),
+                        CronetTestUtil.getCronetEngineBuilderImpl(builder)),
                 getTestStorage(getContext()));
     }
 
@@ -1555,7 +1554,7 @@
         builder.enablePublicKeyPinningBypassForLocalTrustAnchors(false);
         CronetUrlRequestContextTestJni.get().verifyUrlRequestContextQuicOffConfig(
                 CronetUrlRequestContext.createNativeUrlRequestContextConfig(
-                        (CronetEngineBuilderImpl) builder.mBuilderDelegate),
+                        CronetTestUtil.getCronetEngineBuilderImpl(builder)),
                 getTestStorage(getContext()));
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
index 2dc32de..6e07da9 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
@@ -474,10 +474,23 @@
     @Test
     @MediumTest
     @OnlyRunNativeCronet
-    public void testExperimentalOptions_allSet() throws Exception {
+    public void testExperimentalOptions_allSet_viaExperimentalEngine() throws Exception {
         MockCronetBuilderImpl mockBuilderImpl = MockCronetBuilderImpl.withoutNativeSetterSupport();
-        mBuilder = new ExperimentalCronetEngine.Builder(mockBuilderImpl);
+        testExperimentalOptionsAllSetImpl(
+                new ExperimentalCronetEngine.Builder(mockBuilderImpl), mockBuilderImpl);
+    }
 
+    @Test
+    @MediumTest
+    @OnlyRunNativeCronet
+    public void testExperimentalOptions_allSet_viaNonExperimentalEngine() throws Exception {
+        MockCronetBuilderImpl mockBuilderImpl = MockCronetBuilderImpl.withoutNativeSetterSupport();
+        testExperimentalOptionsAllSetImpl(
+                new CronetEngine.Builder(mockBuilderImpl), mockBuilderImpl);
+    }
+
+    private static void testExperimentalOptionsAllSetImpl(
+            CronetEngine.Builder builder, MockCronetBuilderImpl mockBuilderImpl) throws Exception {
         QuicOptions quicOptions =
                 QuicOptions.builder()
                         .addAllowedQuicHost("quicHost1.com")
@@ -550,7 +563,7 @@
                                 toTelephoneKeyboardSequence("badPathErr"))
                         .build();
 
-        mBuilder.setDnsOptions(dnsOptions)
+        builder.setDnsOptions(dnsOptions)
                 .setConnectionMigrationOptions(connectionMigrationOptions)
                 .setQuicOptions(quicOptions)
                 .build();
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
index 017610f5..52c475d 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
@@ -25,7 +25,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.metrics.UmaRecorderHolder;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.net.CronetTestRule.OnlyRunNativeCronet;
 import org.chromium.net.MetricsTestUtil.TestExecutor;
@@ -162,7 +161,6 @@
     @Test
     @SmallTest
     @OnlyRunNativeCronet
-    @DisabledTest(message = "crbug.com/796260")
     public void testQuicDisabled() throws Exception {
         ExperimentalCronetEngine.Builder cronetEngineBuilder =
                 new ExperimentalCronetEngine.Builder(getContext());
@@ -370,7 +368,6 @@
     @Test
     @SmallTest
     @OnlyRunNativeCronet
-    @DisabledTest(message = "crbug.com/796260")
     public void testQuicDisabledWithParams() throws Exception {
         ExperimentalCronetEngine.Builder cronetEngineBuilder =
                 new ExperimentalCronetEngine.Builder(getContext());
diff --git a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
index 6d9c7fbe..d6a9181 100644
--- a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
+++ b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
@@ -94,9 +94,11 @@
         getCronetEngineBuilderImpl(builder).setMockCertVerifierForTesting(mockCertVerifier);
     }
 
-    public static CronetEngineBuilderImpl getCronetEngineBuilderImpl(
+    static CronetEngineBuilderImpl getCronetEngineBuilderImpl(
             ExperimentalCronetEngine.Builder builder) {
-        return (CronetEngineBuilderImpl) builder.getBuilderDelegate();
+        return (CronetEngineBuilderImpl) ((ExperimentalOptionsTranslatingCronetEngineBuilder)
+                                                  builder.getBuilderDelegate())
+                .getDelegate();
     }
 
     /**
diff --git a/components/exo/wayland/test/integration/buffer_checker_test.cc b/components/exo/wayland/test/integration/buffer_checker_test.cc
index 3e8985c7..2195e0c28 100644
--- a/components/exo/wayland/test/integration/buffer_checker_test.cc
+++ b/components/exo/wayland/test/integration/buffer_checker_test.cc
@@ -456,9 +456,9 @@
     drm_names.push_back(DrmCodeToString(format));
     buffer_names.push_back(DrmCodeToBufferFormatString(format));
   }
-  LOG(ERROR) << "zwp_linux_dmabuf_v1 reported supported DRM formats: "
+  LOG(INFO) << "zwp_linux_dmabuf_v1 reported supported DRM formats: "
              << base::JoinString(drm_names, ", ");
-  LOG(ERROR) << "zwp_linux_dmabuf_v1 reported supported gfx::BufferFormats: "
+  LOG(INFO) << "zwp_linux_dmabuf_v1 reported supported gfx::BufferFormats: "
              << base::JoinString(buffer_names, ", ");
 }
 
diff --git a/components/gcm_driver/features.cc b/components/gcm_driver/features.cc
index b59ca1e..639e798 100644
--- a/components/gcm_driver/features.cc
+++ b/components/gcm_driver/features.cc
@@ -21,11 +21,11 @@
 
 BASE_FEATURE(kGCMIncludeAccountTokensInCheckinRequest,
              "GCMIncludeAccountTokensInCheckinRequest",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kGCMReportAccountTokenChanges,
              "GCMReportAccountTokenChanges",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 const char kParamNameTokenInvalidationPeriodDays[] =
     "token_invalidation_period";
diff --git a/components/gcm_driver/gcm_account_mapper_unittest.cc b/components/gcm_driver/gcm_account_mapper_unittest.cc
index 250ddd3..04c5240 100644
--- a/components/gcm_driver/gcm_account_mapper_unittest.cc
+++ b/components/gcm_driver/gcm_account_mapper_unittest.cc
@@ -51,32 +51,6 @@
   account_token.access_token = account_id.ToString() + "_token";
   return account_token;
 }
-
-void VerifyMappings(const GCMAccountMapper::AccountMappings& expected_mappings,
-                    const GCMAccountMapper::AccountMappings& actual_mappings,
-                    const std::string& verification_info) {
-  EXPECT_EQ(expected_mappings.size(), actual_mappings.size())
-      << "Verification Info: " << verification_info;
-  auto expected_iter = expected_mappings.begin();
-  auto actual_iter = actual_mappings.begin();
-  for (; expected_iter != expected_mappings.end() &&
-             actual_iter != actual_mappings.end();
-       ++expected_iter, ++actual_iter) {
-    EXPECT_EQ(expected_iter->email, actual_iter->email)
-        << "Verification Info: " << verification_info
-        << "; Account ID of expected: " << expected_iter->account_id;
-    EXPECT_EQ(expected_iter->account_id, actual_iter->account_id)
-        << "Verification Info: " << verification_info;
-    EXPECT_EQ(expected_iter->status, actual_iter->status)
-        << "Verification Info: " << verification_info
-        << "; Account ID of expected: " << expected_iter->account_id;
-    EXPECT_EQ(expected_iter->status_change_timestamp,
-              actual_iter->status_change_timestamp)
-        << "Verification Info: " << verification_info
-        << "; Account ID of expected: " << expected_iter->account_id;
-  }
-}
-
 class CustomFakeGCMDriver : public FakeGCMDriver {
  public:
   enum LastMessageAction {
@@ -404,168 +378,6 @@
   EXPECT_EQ(kAccountId2, mappings[1].account_id);
 }
 
-// Tests the part where a new account is added with a token, to the point when
-// GCM message is sent.
-TEST_F(GCMAccountMapperTest, AddMappingToMessageSent) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  EXPECT_EQ(1UL, mappings.size());
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(kAccountId, iter->account_id);
-  EXPECT_EQ("acc_id@gmail.com", iter->email);
-  EXPECT_EQ("acc_id_token", iter->access_token);
-  EXPECT_EQ(AccountMapping::NEW, iter->status);
-  EXPECT_EQ(base::Time(), iter->status_change_timestamp);
-
-  EXPECT_TRUE(!gcm_driver().last_message_id().empty());
-}
-
-// Tests the part where GCM message is successfully queued.
-TEST_F(GCMAccountMapperTest, AddMappingMessageQueued) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-
-  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
-  EXPECT_EQ(account_token.account_id,
-            gcm_driver().last_account_mapping().account_id);
-  EXPECT_EQ(account_token.access_token,
-            gcm_driver().last_account_mapping().access_token);
-  EXPECT_EQ(AccountMapping::ADDING, gcm_driver().last_account_mapping().status);
-  EXPECT_EQ(clock()->Now(),
-            gcm_driver().last_account_mapping().status_change_timestamp);
-  EXPECT_EQ(gcm_driver().last_message_id(),
-            gcm_driver().last_account_mapping().last_message_id);
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(account_token.email, iter->email);
-  EXPECT_EQ(account_token.account_id, iter->account_id);
-  EXPECT_EQ(account_token.access_token, iter->access_token);
-  EXPECT_EQ(AccountMapping::ADDING, iter->status);
-  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
-  EXPECT_EQ(gcm_driver().last_message_id(), iter->last_message_id);
-}
-
-// Tests status change from ADDING to MAPPED (Message is acknowledged).
-TEST_F(GCMAccountMapperTest, AddMappingMessageAcknowledged) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
-
-  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
-  EXPECT_EQ(account_token.account_id,
-            gcm_driver().last_account_mapping().account_id);
-  EXPECT_EQ(account_token.access_token,
-            gcm_driver().last_account_mapping().access_token);
-  EXPECT_EQ(AccountMapping::MAPPED, gcm_driver().last_account_mapping().status);
-  EXPECT_EQ(clock()->Now(),
-            gcm_driver().last_account_mapping().status_change_timestamp);
-  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(account_token.email, iter->email);
-  EXPECT_EQ(account_token.account_id, iter->account_id);
-  EXPECT_EQ(account_token.access_token, iter->access_token);
-  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
-  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
-  EXPECT_TRUE(iter->last_message_id.empty());
-}
-
-// Tests status change form ADDING to MAPPED (When message was acknowledged,
-// after Chrome was restarted).
-TEST_F(GCMAccountMapperTest, AddMappingMessageAckedAfterRestart) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-
-  Restart();
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(gcm_driver().last_account_mapping());
-  Initialize(stored_mappings);
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
-
-  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
-  EXPECT_EQ(account_token.account_id,
-            gcm_driver().last_account_mapping().account_id);
-  EXPECT_EQ(account_token.access_token,
-            gcm_driver().last_account_mapping().access_token);
-  EXPECT_EQ(AccountMapping::MAPPED, gcm_driver().last_account_mapping().status);
-  EXPECT_EQ(clock()->Now(),
-            gcm_driver().last_account_mapping().status_change_timestamp);
-  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(account_token.email, iter->email);
-  EXPECT_EQ(account_token.account_id, iter->account_id);
-  EXPECT_EQ(account_token.access_token, iter->access_token);
-  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
-  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
-  EXPECT_TRUE(iter->last_message_id.empty());
-}
-
-// Tests a case when ADD message times out for a new account.
-TEST_F(GCMAccountMapperTest, AddMappingMessageSendErrorForNewAccount) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-
-  clock()->SetNow(base::Time::Now());
-  std::string old_message_id = gcm_driver().last_message_id();
-  gcm_driver().MessageSendError(old_message_id);
-
-  // No new message is sent because of the send error, as the token is stale.
-  // Because the account was new, the entry should be deleted.
-  EXPECT_EQ(old_message_id, gcm_driver().last_message_id());
-  EXPECT_EQ(account_token.account_id, gcm_driver().last_removed_account_id());
-  EXPECT_TRUE(GetAccounts().empty());
-}
-
 /// Tests a case when ADD message times out for a MAPPED account.
 TEST_F(GCMAccountMapperTest, AddMappingMessageSendErrorForMappedAccount) {
   // Start with one account that is mapped.
@@ -597,102 +409,6 @@
   EXPECT_TRUE(iter->last_message_id.empty());
 }
 
-// Tests that a missing token for an account will trigger removing of that
-// account. This test goes only until the message is passed to GCM.
-TEST_F(GCMAccountMapperTest, RemoveMappingToMessageSent) {
-  // Start with one account that is mapped.
-  AccountMapping mapping = MakeAccountMapping(
-      kAccountId, AccountMapping::MAPPED, base::Time::Now(), std::string());
-
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(mapping);
-  Initialize(stored_mappings);
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-  clock()->SetNow(base::Time::Now());
-
-  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
-
-  EXPECT_EQ(mapping.account_id, gcm_driver().last_account_mapping().account_id);
-  EXPECT_EQ(mapping.email, gcm_driver().last_account_mapping().email);
-  EXPECT_EQ(AccountMapping::REMOVING,
-            gcm_driver().last_account_mapping().status);
-  EXPECT_EQ(clock()->Now(),
-            gcm_driver().last_account_mapping().status_change_timestamp);
-  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(mapping.email, iter->email);
-  EXPECT_EQ(mapping.account_id, iter->account_id);
-  EXPECT_EQ(mapping.access_token, iter->access_token);
-  EXPECT_EQ(AccountMapping::REMOVING, iter->status);
-  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
-  EXPECT_TRUE(iter->last_message_id.empty());
-}
-
-// Tests that a missing token for an account will trigger removing of that
-// account. This test goes until the message is queued by GCM.
-TEST_F(GCMAccountMapperTest, RemoveMappingMessageQueued) {
-  // Start with one account that is mapped.
-  AccountMapping mapping = MakeAccountMapping(
-      kAccountId, AccountMapping::MAPPED, base::Time::Now(), std::string());
-
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(mapping);
-  Initialize(stored_mappings);
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-  clock()->SetNow(base::Time::Now());
-  base::Time status_change_timestamp = clock()->Now();
-
-  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-
-  EXPECT_EQ(mapping.account_id, gcm_driver().last_account_mapping().account_id);
-  EXPECT_EQ(mapping.email, gcm_driver().last_account_mapping().email);
-  EXPECT_EQ(AccountMapping::REMOVING,
-            gcm_driver().last_account_mapping().status);
-  EXPECT_EQ(status_change_timestamp,
-            gcm_driver().last_account_mapping().status_change_timestamp);
-  EXPECT_TRUE(!gcm_driver().last_account_mapping().last_message_id.empty());
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(mapping.email, iter->email);
-  EXPECT_EQ(mapping.account_id, iter->account_id);
-  EXPECT_EQ(mapping.access_token, iter->access_token);
-  EXPECT_EQ(AccountMapping::REMOVING, iter->status);
-  EXPECT_EQ(status_change_timestamp, iter->status_change_timestamp);
-  EXPECT_EQ(gcm_driver().last_account_mapping().last_message_id,
-            iter->last_message_id);
-}
-
-// Tests that a missing token for an account will trigger removing of that
-// account. This test goes until the message is acknowledged by GCM.
-// This is a complete success scenario for account removal, and it end with
-// account mapping being completely gone.
-TEST_F(GCMAccountMapperTest, RemoveMappingMessageAcknowledged) {
-  // Start with one account that is mapped.
-  AccountMapping mapping = MakeAccountMapping(
-      kAccountId, AccountMapping::MAPPED, base::Time::Now(), std::string());
-
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(mapping);
-  Initialize(stored_mappings);
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-  clock()->SetNow(base::Time::Now());
-
-  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
-
-  EXPECT_EQ(mapping.account_id, gcm_driver().last_removed_account_id());
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  EXPECT_TRUE(mappings.empty());
-}
-
 // Tests that account removing proceeds, when a removing message is acked after
 // Chrome was restarted.
 TEST_F(GCMAccountMapperTest, RemoveMappingMessageAckedAfterRestart) {
@@ -752,187 +468,6 @@
   EXPECT_TRUE(iter->last_message_id.empty());
 }
 
-// Tests that, if a new token arrives when the adding message is in progress
-// no new message is sent and account mapper still waits for the first one to
-// complete.
-TEST_F(GCMAccountMapperTest, TokenIsRefreshedWhenAdding) {
-  Initialize(GCMAccountMapper::AccountMappings());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  clock()->SetNow(base::Time::Now());
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-  DCHECK_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-  DCHECK_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
-
-  // Providing another token and clearing status.
-  gcm_driver().Clear();
-  mapper()->SetAccountTokens(account_tokens);
-  DCHECK_EQ(CustomFakeGCMDriver::NONE, gcm_driver().last_action());
-}
-
-// Tests that, if a new token arrives when a removing message is in progress
-// a new adding message is sent and while account mapping status is changed to
-// mapped. If the original Removing message arrives it is discarded.
-TEST_F(GCMAccountMapperTest, TokenIsRefreshedWhenRemoving) {
-  // Start with one account that is mapped.
-  AccountMapping mapping = MakeAccountMapping(
-      kAccountId, AccountMapping::MAPPED, base::Time::Now(), std::string());
-
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(mapping);
-  Initialize(stored_mappings);
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-  clock()->SetNow(base::Time::Now());
-
-  // Remove the token to trigger a remove message to be sent
-  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
-  EXPECT_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-  EXPECT_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
-
-  std::string remove_message_id = gcm_driver().last_message_id();
-  gcm_driver().Clear();
-
-  // The account mapping for acc_id is now in status REMOVING.
-  // Adding the token for that account.
-  clock()->SetNow(base::Time::Now());
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo(kAccountId);
-  account_tokens.push_back(account_token);
-  mapper()->SetAccountTokens(account_tokens);
-  DCHECK_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
-  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
-  EXPECT_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
-
-  std::string add_message_id = gcm_driver().last_message_id();
-
-  // A remove message confirmation arrives now, but should be ignored.
-  gcm_driver().AcknowledgeSend(remove_message_id);
-
-  GCMAccountMapper::AccountMappings mappings = GetAccounts();
-  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
-  EXPECT_EQ(mapping.email, iter->email);
-  EXPECT_EQ(mapping.account_id, iter->account_id);
-  EXPECT_FALSE(iter->access_token.empty());
-  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
-  // Status change timestamp is set to very long time ago, to make sure the next
-  // round of mapping picks it up.
-  EXPECT_EQ(base::Time(), iter->status_change_timestamp);
-  EXPECT_EQ(add_message_id, iter->last_message_id);
-}
-
-// Tests adding/removing works for multiple accounts, after a restart and when
-// tokens are periodically delierverd.
-TEST_F(GCMAccountMapperTest, MultipleAccountMappings) {
-  clock()->SetNow(base::Time::Now());
-  base::Time half_hour_ago = clock()->Now() - base::Minutes(30);
-  GCMAccountMapper::AccountMappings stored_mappings;
-  stored_mappings.push_back(MakeAccountMapping(
-      kAccountId, AccountMapping::ADDING, half_hour_ago, "acc_id_msg"));
-  stored_mappings.push_back(MakeAccountMapping(
-      kAccountId1, AccountMapping::MAPPED, half_hour_ago, "acc_id_1_msg"));
-  stored_mappings.push_back(MakeAccountMapping(
-      kAccountId2, AccountMapping::REMOVING, half_hour_ago, "acc_id_2_msg"));
-
-  Initialize(stored_mappings);
-  gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
-  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
-
-  GCMAccountMapper::AccountMappings expected_mappings(stored_mappings);
-
-  // Finish messages after a restart.
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().AcknowledgeSend(expected_mappings[0].last_message_id);
-  expected_mappings[0].status_change_timestamp = clock()->Now();
-  expected_mappings[0].status = AccountMapping::MAPPED;
-  expected_mappings[0].last_message_id.clear();
-
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().AcknowledgeSend(expected_mappings[1].last_message_id);
-  expected_mappings[1].status_change_timestamp = clock()->Now();
-  expected_mappings[1].status = AccountMapping::MAPPED;
-  expected_mappings[1].last_message_id.clear();
-
-  // Upon success last element is removed.
-  clock()->SetNow(base::Time::Now());
-  gcm_driver().AcknowledgeSend(expected_mappings[2].last_message_id);
-  expected_mappings.pop_back();
-
-  VerifyMappings(expected_mappings, GetAccounts(), "Step 1, After restart");
-
-  // One of accounts gets removed.
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  account_tokens.push_back(MakeAccountTokenInfo(kAccountId));
-
-  // Advance a day to make sure existing mappings will be reported.
-  clock()->SetNow(clock()->Now() + base::Days(1));
-  mapper()->SetAccountTokens(account_tokens);
-
-  expected_mappings[0].status = AccountMapping::MAPPED;
-  expected_mappings[1].status = AccountMapping::REMOVING;
-  expected_mappings[1].status_change_timestamp = clock()->Now();
-
-  gcm_driver().CompleteSendAllMessages();
-
-  VerifyMappings(
-      expected_mappings, GetAccounts(), "Step 2, One account is being removed");
-
-  clock()->SetNow(clock()->Now() + base::Seconds(5));
-  gcm_driver().AcknowledgeSendAllMessages();
-
-  expected_mappings[0].status_change_timestamp = clock()->Now();
-  expected_mappings.pop_back();
-
-  VerifyMappings(
-      expected_mappings, GetAccounts(), "Step 3, Removing completed");
-
-  account_tokens.clear();
-  account_tokens.push_back(MakeAccountTokenInfo(kAccountId));
-  account_tokens.push_back(MakeAccountTokenInfo(kAccountId3));
-  account_tokens.push_back(MakeAccountTokenInfo(kAccountId4));
-
-  // Advance a day to make sure existing mappings will be reported.
-  clock()->SetNow(clock()->Now() + base::Days(1));
-  mapper()->SetAccountTokens(account_tokens);
-
-  // Mapping from acc_id_0 still in position 0
-  expected_mappings.push_back(MakeAccountMapping(
-      kAccountId3, AccountMapping::NEW, base::Time(), std::string()));
-  expected_mappings.push_back(MakeAccountMapping(
-      kAccountId4, AccountMapping::NEW, base::Time(), std::string()));
-
-  VerifyMappings(expected_mappings, GetAccounts(), "Step 4, Two new accounts");
-
-  clock()->SetNow(clock()->Now() + base::Seconds(1));
-  gcm_driver().CompleteSendAllMessages();
-
-  expected_mappings[1].status = AccountMapping::ADDING;
-  expected_mappings[1].status_change_timestamp = clock()->Now();
-  expected_mappings[2].status = AccountMapping::ADDING;
-  expected_mappings[2].status_change_timestamp = clock()->Now();
-
-  VerifyMappings(
-      expected_mappings, GetAccounts(), "Step 5, Two accounts being added");
-
-  clock()->SetNow(clock()->Now() + base::Seconds(5));
-  gcm_driver().AcknowledgeSendAllMessages();
-
-  expected_mappings[0].status_change_timestamp = clock()->Now();
-  expected_mappings[1].status_change_timestamp = clock()->Now();
-  expected_mappings[1].status = AccountMapping::MAPPED;
-  expected_mappings[2].status_change_timestamp = clock()->Now();
-  expected_mappings[2].status = AccountMapping::MAPPED;
-
-  VerifyMappings(
-      expected_mappings, GetAccounts(), "Step 6, Three mapped accounts");
-}
-
 TEST_F(GCMAccountMapperTest, DispatchMessageSentToGaiaID) {
   Initialize(GCMAccountMapper::AccountMappings());
   gcm_driver().AddAppHandler(kGCMAccountMapperAppId, mapper());
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
index 3923325..82df70a 100644
--- a/components/gcm_driver/gcm_client_impl_unittest.cc
+++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -1258,45 +1258,6 @@
 }
 
 // This test only checks that periodic checkin happens.
-TEST_F(GCMClientImplCheckinTest, CheckinWithAccounts) {
-  std::map<std::string, std::string> settings;
-  settings["checkin_interval"] = base::NumberToString(kSettingsCheckinInterval);
-  settings["checkin_url"] = "http://alternative.url/checkin";
-  settings["gcm_hostname"] = "alternative.gcm.host";
-  settings["gcm_secure_port"] = "7777";
-  settings["gcm_registration_url"] = "http://alternative.url/registration";
-  ASSERT_NO_FATAL_FAILURE(
-      CompleteCheckin(kDeviceAndroidId, kDeviceSecurityToken,
-                      GServicesSettings::CalculateDigest(settings), settings));
-
-  std::vector<GCMClient::AccountTokenInfo> account_tokens;
-  account_tokens.push_back(MakeAccountToken("test_user1@gmail.com", "token1"));
-  account_tokens.push_back(MakeAccountToken("test_user2@gmail.com", "token2"));
-  gcm_client()->SetAccountTokens(account_tokens);
-
-  EXPECT_TRUE(device_checkin_info().last_checkin_accounts.empty());
-  EXPECT_TRUE(device_checkin_info().accounts_set);
-  EXPECT_EQ(MakeEmailToTokenMap(account_tokens),
-            device_checkin_info().account_tokens);
-
-  PumpLoopUntilIdle();
-  ASSERT_NO_FATAL_FAILURE(
-      CompleteCheckin(kDeviceAndroidId, kDeviceSecurityToken,
-                      GServicesSettings::CalculateDigest(settings), settings));
-
-  std::set<std::string> accounts;
-  accounts.insert("test_user1@gmail.com");
-  accounts.insert("test_user2@gmail.com");
-  EXPECT_EQ(accounts, device_checkin_info().last_checkin_accounts);
-  EXPECT_TRUE(device_checkin_info().accounts_set);
-  EXPECT_EQ(MakeEmailToTokenMap(account_tokens),
-            device_checkin_info().account_tokens);
-
-  // Make sure the checkin request has the account info.
-  EXPECT_EQ(checkin_request().request_info_.account_tokens.size(), 2u);
-}
-
-// This test only checks that periodic checkin happens.
 TEST_F(GCMClientImplCheckinTest, CheckinWithAccountsEmptyWithFeature) {
   scoped_feature_list().InitAndDisableFeature(
       features::kGCMIncludeAccountTokensInCheckinRequest);
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 7bc80a0d6..e838eee3 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -203,7 +203,7 @@
     std::vector<autofill::Suggestion>* suggestions) {
   bool has_no_fillable_suggestions = base::ranges::none_of(
       *suggestions,
-      [](int id) {
+      [](autofill::Suggestion::FrontendId id) {
         return id == autofill::POPUP_ITEM_ID_USERNAME_ENTRY ||
                id == autofill::POPUP_ITEM_ID_PASSWORD_ENTRY ||
                id == autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_USERNAME_ENTRY ||
@@ -217,7 +217,9 @@
 
   bool has_webauthn_credential = base::ranges::any_of(
       *suggestions,
-      [](int id) { return id == autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL; },
+      [](autofill::Suggestion::FrontendId id) {
+        return id == autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL;
+      },
       &autofill::Suggestion::frontend_id);
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -386,7 +388,7 @@
 
 void PasswordAutofillManager::DidSelectSuggestion(
     const std::u16string& value,
-    int frontend_id,
+    autofill::Suggestion::FrontendId frontend_id,
     const autofill::Suggestion::BackendId& backend_id) {
   ClearPreviewedForm();
   if (frontend_id == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
@@ -431,7 +433,7 @@
     const autofill::Suggestion& suggestion,
     int position) {
   using metrics_util::PasswordDropdownSelectedOption;
-  switch (suggestion.frontend_id) {
+  switch (suggestion.frontend_id.as_popup_item_id()) {
     case autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY:
       password_client_->GeneratePassword(PasswordGenerationType::kAutomatic);
       metrics_util::LogPasswordDropdownItemSelected(
@@ -462,8 +464,7 @@
       break;
     case autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN:
     case autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE:
-      OnUnlockItemAccepted(
-          static_cast<autofill::PopupItemId>(suggestion.frontend_id));
+      OnUnlockItemAccepted(suggestion.frontend_id.as_popup_item_id());
       metrics_util::LogPasswordDropdownItemSelected(
           suggestion.frontend_id ==
                   autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN
@@ -545,14 +546,15 @@
 
 bool PasswordAutofillManager::GetDeletionConfirmationText(
     const std::u16string& value,
-    int frontend_id,
+    autofill::Suggestion::FrontendId frontend_id,
     std::u16string* title,
     std::u16string* body) {
   return false;
 }
 
-bool PasswordAutofillManager::RemoveSuggestion(const std::u16string& value,
-                                               int frontend_id) {
+bool PasswordAutofillManager::RemoveSuggestion(
+    const std::u16string& value,
+    autofill::Suggestion::FrontendId frontend_id) {
   // Password suggestions cannot be deleted this way.
   // See http://crbug.com/329038#c15
   return false;
@@ -623,8 +625,9 @@
   if (!autofill_client_ ||
       !HasLoadingSuggestion(
           autofill_client_->GetPopupSuggestions(),
-          autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN))
+          autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)) {
     return;
+  }
   metrics_util::LogPasswordsCountFromAccountStoreAfterUnlock(
       /*account_store_passwords_count=*/0);
   UpdatePopup({CreateAccountStorageEmptyEntry()});
@@ -788,13 +791,15 @@
   metrics_util::PasswordDropdownState dropdown_state =
       metrics_util::PasswordDropdownState::kStandard;
   for (const auto& suggestion : suggestions) {
-    switch (suggestion.frontend_id) {
+    switch (suggestion.frontend_id.as_popup_item_id()) {
       case autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY:
         // TODO(crbug.com/1062709): Revisit metrics for the "opt in and
         // generate" button.
       case autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE:
         dropdown_state = metrics_util::PasswordDropdownState::kStandardGenerate;
         break;
+      default:
+        break;
     }
   }
   metrics_util::LogPasswordDropdownShown(dropdown_state,
@@ -833,8 +838,9 @@
   autofill_client_->UpdatePopup(suggestions, autofill::PopupType::kPasswords);
 }
 
-bool PasswordAutofillManager::FillSuggestion(const std::u16string& username,
-                                             int item_id) {
+bool PasswordAutofillManager::FillSuggestion(
+    const std::u16string& username,
+    autofill::Suggestion::FrontendId item_id) {
   autofill::PasswordAndMetadata password_and_meta_data;
   if (fill_data_ &&
       GetPasswordAndMetadataForUsername(username, item_id, *fill_data_,
@@ -850,8 +856,9 @@
   return false;
 }
 
-bool PasswordAutofillManager::PreviewSuggestion(const std::u16string& username,
-                                                int item_id) {
+bool PasswordAutofillManager::PreviewSuggestion(
+    const std::u16string& username,
+    autofill::Suggestion::FrontendId item_id) {
   if (item_id == autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL) {
     password_manager_driver_->PreviewSuggestion(username, /*password=*/u"");
     return true;
@@ -873,7 +880,7 @@
 
 bool PasswordAutofillManager::GetPasswordAndMetadataForUsername(
     const std::u16string& current_username,
-    int item_id,
+    autofill::Suggestion::FrontendId item_id,
     const autofill::PasswordFormFillData& fill_data,
     autofill::PasswordAndMetadata* password_and_meta_data) {
   // TODO(dubroy): When password access requires some kind of authentication
@@ -950,7 +957,7 @@
 
 void PasswordAutofillManager::OnBiometricReauthCompleted(
     const std::u16string& value,
-    int frontend_id,
+    autofill::Suggestion::FrontendId frontend_id,
     bool auth_succeeded) {
   authenticator_.reset();
   base::UmaHistogramBoolean(
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h
index 9e6afd40..21d0608 100644
--- a/components/password_manager/core/browser/password_autofill_manager.h
+++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -56,15 +56,16 @@
   void OnPopupSuppressed() override;
   void DidSelectSuggestion(
       const std::u16string& value,
-      int frontend_id,
+      autofill::Suggestion::FrontendId frontend_id,
       const autofill::Suggestion::BackendId& backend_id) override;
   void DidAcceptSuggestion(const autofill::Suggestion& suggestion,
                            int position) override;
   bool GetDeletionConfirmationText(const std::u16string& value,
-                                   int frontend_id,
+                                   autofill::Suggestion::FrontendId frontend_id,
                                    std::u16string* title,
                                    std::u16string* body) override;
-  bool RemoveSuggestion(const std::u16string& value, int frontend_id) override;
+  bool RemoveSuggestion(const std::u16string& value,
+                        autofill::Suggestion::FrontendId frontend_id) override;
   void ClearPreviewedForm() override;
   autofill::PopupType GetPopupType() const override;
   absl::variant<autofill::AutofillDriver*, PasswordManagerDriver*> GetDriver()
@@ -152,12 +153,14 @@
   // Attempts to find and fill the suggestions with the user name |username| and
   // the |item_id| indicating the store (account-stored or local). Returns true
   // if it was successful.
-  bool FillSuggestion(const std::u16string& username, int item_id);
+  bool FillSuggestion(const std::u16string& username,
+                      autofill::Suggestion::FrontendId item_id);
 
   // Attempts to find and preview the suggestions with the user name |username|
   // and the |item_id| indicating the store (account-stored or local). Returns
   // true if it was successful.
-  bool PreviewSuggestion(const std::u16string& username, int item_id);
+  bool PreviewSuggestion(const std::u16string& username,
+                         autofill::Suggestion::FrontendId item_id);
 
   // If one of the login mappings in |fill_data| matches |current_username| and
   // |item_id| (indicating whether a credential is stored in account or
@@ -168,7 +171,7 @@
   // Otherwise, returns false and leaves |password_and_meta_data| untouched.
   bool GetPasswordAndMetadataForUsername(
       const std::u16string& current_username,
-      int item_id,
+      autofill::Suggestion::FrontendId item_id,
       const autofill::PasswordFormFillData& fill_data,
       autofill::PasswordAndMetadata* password_and_meta_data);
 
@@ -196,7 +199,7 @@
   // Called when the biometric reauth that guards password filling completes.
   // |frontend_id| identifies the suggestion that was selected for filling.
   void OnBiometricReauthCompleted(const std::u16string& username_value,
-                                  int frontend_id,
+                                  autofill::Suggestion::FrontendId frontend_id,
                                   bool auth_succeded);
 
   // Cancels an ongoing biometric re-authentication. Usually, because
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 81e7106e..6a9d87e 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -228,7 +228,10 @@
               HideAutofillPopup,
               (autofill::PopupHidingReason),
               (override));
-  MOCK_METHOD(void, ExecuteCommand, (int), (override));
+  MOCK_METHOD(void,
+              ExecuteCommand,
+              (autofill::Suggestion::FrontendId),
+              (override));
 };
 
 base::CancelableTaskTracker::TaskId
@@ -463,14 +466,14 @@
         gfx::RectF());
     ASSERT_GE(open_args.suggestions.size(), 1u);
     EXPECT_THAT(open_args.suggestions,
-                SuggestionVectorIdsAre(ElementsAre(
+                SuggestionVectorIdsAre(
                     is_suggestion_on_password_field
                         ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
                         : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                     autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
     EXPECT_TRUE(
         AreImagesEqual(open_args.suggestions[0].custom_icon, kTestFavicon));
 
@@ -534,7 +537,7 @@
     ASSERT_GE(open_args.suggestions.size(), 2u);
     EXPECT_THAT(
         open_args.suggestions,
-        SuggestionVectorIdsAre(ElementsAre(
+        SuggestionVectorIdsAre(
             is_suggestion_on_password_field
                 ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
                 : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
@@ -544,7 +547,7 @@
 #if !BUILDFLAG(IS_ANDROID)
             autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-            autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+            autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
     EXPECT_TRUE(
         AreImagesEqual(open_args.suggestions[0].custom_icon, kTestFavicon));
     EXPECT_TRUE(
@@ -583,13 +586,13 @@
       base::i18n::RIGHT_TO_LEFT, std::u16string(),
       autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                   autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -609,8 +612,8 @@
       base::i18n::RIGHT_TO_LEFT, std::u16string(),
       autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
-                  autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)));
+              SuggestionVectorIdsAre(
+                  autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -629,13 +632,13 @@
       base::i18n::RIGHT_TO_LEFT, std::u16string(),
       autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                   autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_FALSE(open_args.autoselect_first_suggestion);
 }
 
@@ -653,10 +656,10 @@
   std::vector<autofill::Suggestion> suggestions;
   EXPECT_CALL(
       autofill_client,
-      UpdatePopup(SuggestionVectorIdsAre(ElementsAre(
+      UpdatePopup(SuggestionVectorIdsAre(
                       autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                       autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
-                      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)),
+                      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN),
                   PopupType::kPasswords))
       .WillOnce(testing::SaveArg<0>(&suggestions));
   EXPECT_CALL(client, TriggerReauthForPrimaryAccount);
@@ -690,11 +693,11 @@
   EXPECT_CALL(
       autofill_client,
       UpdatePopup(
-          SuggestionVectorIdsAre(ElementsAre(
+          SuggestionVectorIdsAre(
               autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
               autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
               autofill::
-                  POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE)),
+                  POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE),
           PopupType::kPasswords))
       .WillOnce(testing::SaveArg<0>(&suggestions));
   EXPECT_CALL(client, TriggerReauthForPrimaryAccount);
@@ -767,10 +770,10 @@
     EXPECT_CALL(
         autofill_client,
         UpdatePopup(
-            SuggestionVectorIdsAre(ElementsAre(
+            SuggestionVectorIdsAre(
                 autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                 autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
-                autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)),
+                autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN),
             PopupType::kPasswords))
         .WillOnce(testing::SaveArg<0>(&suggestions));
   });
@@ -820,11 +823,11 @@
     EXPECT_CALL(
         autofill_client,
         UpdatePopup(
-            SuggestionVectorIdsAre(ElementsAre(
+            SuggestionVectorIdsAre(
                 autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                 autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
                 autofill::
-                    POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE)),
+                    POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE),
             PopupType::kPasswords))
         .WillOnce(testing::SaveArg<0>(&suggestions));
   });
@@ -937,8 +940,8 @@
               HideAutofillPopup(autofill::PopupHidingReason::kStaleData));
   EXPECT_CALL(
       autofill_client,
-      UpdatePopup(SuggestionVectorIdsAre(ElementsAre(
-                      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY)),
+      UpdatePopup(SuggestionVectorIdsAre(
+                      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY),
                   PopupType::kPasswords));
 
   password_autofill_manager_->DeleteFillData();
@@ -974,13 +977,13 @@
               HideAutofillPopup(autofill::PopupHidingReason::kStaleData));
   EXPECT_CALL(
       autofill_client,
-      UpdatePopup(SuggestionVectorIdsAre(ElementsAre(
+      UpdatePopup(SuggestionVectorIdsAre(
                       autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY,
                       autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                       autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                      autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)),
+                      autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY),
                   PopupType::kPasswords));
 
   password_autofill_manager_->DeleteFillData();
@@ -1340,7 +1343,8 @@
   EXPECT_CALL(*client.mock_driver(),
               PreviewSuggestion(std::u16string(), test_password_));
   password_autofill_manager_->DidSelectSuggestion(
-      no_username_string, 0 /*not used*/, Suggestion::BackendId() /*not used*/);
+      no_username_string, Suggestion::FrontendId() /*not used*/,
+      Suggestion::BackendId() /*not used*/);
   testing::Mock::VerifyAndClearExpectations(client.mock_driver());
 
   // Check that fill of the empty username works.
@@ -1597,10 +1601,9 @@
   EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _));
   password_autofill_manager_->OnAddPasswordFillData(data);
 
-  auto opt_in_and_generate_id = static_cast<int>(
-      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE);
-  auto regular_generate_id =
-      static_cast<int>(autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY);
+  auto opt_in_and_generate_id =
+      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE;
+  auto regular_generate_id = autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY;
   autofill::AutofillClient::PopupOpenArgs open_args;
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
@@ -1666,14 +1669,14 @@
         gfx::RectF());
     ASSERT_GE(open_args.suggestions.size(), 1u);
     EXPECT_THAT(open_args.suggestions,
-                SuggestionVectorIdsAre(ElementsAre(
+                SuggestionVectorIdsAre(
                     is_suggestion_on_password_field
                         ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
                         : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                     autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
 
     // Suggestions should always be filled if the authenticator is not available
     // or it cannot be used.
@@ -1727,14 +1730,14 @@
         gfx::RectF());
     ASSERT_GE(open_args.suggestions.size(), 1u);
     EXPECT_THAT(open_args.suggestions,
-                SuggestionVectorIdsAre(ElementsAre(
+                SuggestionVectorIdsAre(
                     is_suggestion_on_password_field
                         ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
                         : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                     autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
 
     // The suggestion should be filled if the authentication is successful.
     EXPECT_CALL(*client.mock_driver(),
@@ -1798,14 +1801,14 @@
         gfx::RectF());
     ASSERT_GE(open_args.suggestions.size(), 1u);
     EXPECT_THAT(open_args.suggestions,
-                SuggestionVectorIdsAre(ElementsAre(
+                SuggestionVectorIdsAre(
                     is_suggestion_on_password_field
                         ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
                         : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                     autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                    autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
 
     // The suggestion should not be filled if the authentication fails.
     EXPECT_CALL(*client.mock_driver(),
@@ -1864,12 +1867,12 @@
       gfx::RectF());
   ASSERT_GE(open_args.suggestions.size(), 1u);
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_CALL(*client.mock_driver(),
               FillSuggestion(test_username_, test_password_))
       .Times(0);
@@ -1915,12 +1918,12 @@
       gfx::RectF());
   ASSERT_GE(open_args.suggestions.size(), 1u);
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_CALL(*client.mock_driver(),
               FillSuggestion(test_username_, test_password_))
       .Times(0);
@@ -1967,12 +1970,12 @@
       gfx::RectF());
   ASSERT_GE(open_args.suggestions.size(), 1u);
   EXPECT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_CALL(*client.mock_driver(),
               FillSuggestion(test_username_, test_password_))
       .Times(0);
@@ -2108,14 +2111,14 @@
       autofill::ShowPasswordSuggestionsOptions::ACCEPTS_WEBAUTHN_CREDENTIALS,
       element_bounds);
   ASSERT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL,
                   autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
 #if !BUILDFLAG(IS_ANDROID)
                   autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE,
                   autofill::POPUP_ITEM_ID_SEPARATOR,
 #endif  // !BUILDFLAG(IS_ANDROID)
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_EQ(open_args.suggestions[0].GetPayload<Suggestion::BackendId>(),
             Suggestion::BackendId(kIdBase64));
   EXPECT_EQ(open_args.suggestions[0].frontend_id,
@@ -2174,11 +2177,11 @@
       autofill::ShowPasswordSuggestionsOptions::ACCEPTS_WEBAUTHN_CREDENTIALS,
       element_bounds);
   ASSERT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
                   autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE,
                   autofill::POPUP_ITEM_ID_SEPARATOR,
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
 
   // Check that the button shows the correct text.
   EXPECT_EQ(open_args.suggestions[1].main_text.value,
@@ -2223,11 +2226,11 @@
       autofill::ShowPasswordSuggestionsOptions::ACCEPTS_WEBAUTHN_CREDENTIALS,
       element_bounds);
   ASSERT_THAT(open_args.suggestions,
-              SuggestionVectorIdsAre(ElementsAre(
+              SuggestionVectorIdsAre(
                   autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL,
                   autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE,
                   autofill::POPUP_ITEM_ID_SEPARATOR,
-                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+                  autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
   EXPECT_TRUE(
       AreImagesEqual(open_args.suggestions[0].custom_icon, kTestFavicon));
 }
@@ -2260,8 +2263,8 @@
       element_bounds);
   ASSERT_THAT(
       open_args.suggestions,
-      SuggestionVectorIdsAre(ElementsAre(
-          autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE)));
+      SuggestionVectorIdsAre(
+          autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE));
 
   // Check that the button shows the correct text.
   EXPECT_EQ(open_args.suggestions[0].main_text.value,
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index eb37ad004..4532979 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -281,7 +281,10 @@
               (const std::u16string&, const std::u16string&),
               (override));
   MOCK_METHOD(bool, IsContextSecure, (), (const, override));
-  MOCK_METHOD(void, ExecuteCommand, (int), (override));
+  MOCK_METHOD(void,
+              ExecuteCommand,
+              (autofill::Suggestion::FrontendId),
+              (override));
   MOCK_METHOD(autofill::LogManager*, GetLogManager, (), (const, override));
   MOCK_METHOD(const autofill::AutofillAblationStudy&,
               GetAblationStudy,
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.cc b/components/password_manager/core/browser/sync/password_model_type_controller.cc
index 7393ff6..a0c55cf 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -11,7 +11,6 @@
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "components/password_manager/core/browser/password_manager_features_util.h"
-#include "components/password_manager/core/browser/password_store_interface.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
@@ -43,7 +42,6 @@
         delegate_for_full_sync_mode,
     std::unique_ptr<syncer::ModelTypeControllerDelegate>
         delegate_for_transport_mode,
-    scoped_refptr<PasswordStoreInterface> account_password_store_for_cleanup,
     PrefService* pref_service,
     signin::IdentityManager* identity_manager,
     syncer::SyncService* sync_service)
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.h b/components/password_manager/core/browser/sync/password_model_type_controller.h
index eb59a8d3..f4da25090 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.h
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.h
@@ -24,20 +24,16 @@
 
 namespace password_manager {
 
-class PasswordStoreInterface;
-
 // A class that manages the startup and shutdown of password sync.
 class PasswordModelTypeController : public syncer::ModelTypeController,
                                     public syncer::SyncServiceObserver,
                                     public signin::IdentityManager::Observer {
  public:
-  // TODO(crbug.com/1425033): Remove account_password_store_for_cleanup param.
   PasswordModelTypeController(
       std::unique_ptr<syncer::ModelTypeControllerDelegate>
           delegate_for_full_sync_mode,
       std::unique_ptr<syncer::ModelTypeControllerDelegate>
           delegate_for_transport_mode,
-      scoped_refptr<PasswordStoreInterface> account_password_store_for_cleanup,
       PrefService* pref_service,
       signin::IdentityManager* identity_manager,
       syncer::SyncService* sync_service);
diff --git a/components/privacy_sandbox_strings.grdp b/components/privacy_sandbox_strings.grdp
index abbc5cd..be84523 100644
--- a/components/privacy_sandbox_strings.grdp
+++ b/components/privacy_sandbox_strings.grdp
@@ -223,7 +223,7 @@
     When on, a list of topics appears here based on your recent browsing history
   </message>
   <message name="IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY" desc="A description that appear beneath the 'Your topics' title. This setting could be on but no topics appear in the list. This text explains why." formatter_data="android_java">
-    It can take up to a week for a list of topics to appear here based on your recent browsing history
+    No topics to show right now
   </message>
   <message name="IDS_SETTINGS_TOPICS_PAGE_BLOCK_TOPIC" desc="A button associated with each of the user's topics. If the user clicks 'Block', that topic will get moved to the 'Topics you blocked' page.">
     Block
diff --git a/components/privacy_sandbox_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY.png.sha1 b/components/privacy_sandbox_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY.png.sha1
index 87d7ed2b..74618a3 100644
--- a/components/privacy_sandbox_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY.png.sha1
+++ b/components/privacy_sandbox_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_CURRENT_TOPICS_DESCRIPTION_EMPTY.png.sha1
@@ -1 +1 @@
-24374a5a183420869e0c9931cbbd242ed468a28c
\ No newline at end of file
+5661056e43e51321c461ece4f8293a406049536e
\ No newline at end of file
diff --git a/components/services/screen_ai/public/cpp/screen_ai_install_state.cc b/components/services/screen_ai/public/cpp/screen_ai_install_state.cc
index 06c3009..93e90323 100644
--- a/components/services/screen_ai/public/cpp/screen_ai_install_state.cc
+++ b/components/services/screen_ai/public/cpp/screen_ai_install_state.cc
@@ -156,6 +156,10 @@
 }
 
 bool ScreenAIInstallState::IsComponentAvailable() {
+  // Make sure the library becomes available only when it's needed.
+  CHECK(get_component_binary_path().empty() ||
+        features::IsScreenAIServiceNeeded());
+
   return !get_component_binary_path().empty();
 }
 
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 6d1930b..e1da889 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -223,8 +223,8 @@
   // Indicates the the user wants Sync-the-Feature to run. It should get invoked
   // early in the Sync setup flow, after the user has pressed "turn on Sync" but
   // before they have actually confirmed the settings.
-  // TODO(crbug.com/1291953): Remove this API, as SyncService can internally
-  // determine whether or not it is the case.
+  // TODO(crbug.com/1219990): Remove this API once the internal sync-requested
+  // bit is fully removed and rollback/killswitch safe.
   virtual void SetSyncFeatureRequested() = 0;
 
   // Returns the SyncUserSettings, which encapsulate all the user-configurable
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc
index d36965b..c95bed6 100644
--- a/components/sync/protocol/proto_value_conversions_unittest.cc
+++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -55,7 +55,7 @@
     specifics.mutable_##Key();                                      \
     base::Value value = EntitySpecificsToValue(specifics);          \
     ASSERT_TRUE(value.is_dict());                                   \
-    EXPECT_EQ(1, static_cast<int>(value.DictSize()));               \
+    EXPECT_EQ(1u, value.GetDict().size());                          \
   }
 
 // We'd also like to check if we changed any field in our messages. However,
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc
index ea7da24..203ae5325 100644
--- a/content/browser/attribution_reporting/attribution_src_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -34,6 +34,7 @@
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -1143,14 +1144,89 @@
   EXPECT_EQ(data_host->source_data().size(), 1u);
 }
 
+// Tests to verify that cross app web is not enabled when base::Feature is
+// enabled but runtime feature is disabled (without
+// `features::kPrivacySandboxAdsAPIsOverride` override).
+class AttributionSrcCrossAppWebRuntimeDisabledBrowserTest
+    : public AttributionSrcBrowserTest {
+ public:
+  AttributionSrcCrossAppWebRuntimeDisabledBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{network::features::
+                                  kAttributionReportingCrossAppWeb},
+        /*disabled_features=*/{});
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Verify that the Attribution-Reporting-Support header setting is gated by the
+// runtime feature.
+IN_PROC_BROWSER_TEST_F(AttributionSrcCrossAppWebRuntimeDisabledBrowserTest,
+                       Img_SupportHeaderNotSet) {
+  // Create a separate server as we cannot register a `ControllableHttpResponse`
+  // after the server starts.
+  auto https_server = std::make_unique<net::EmbeddedTestServer>(
+      net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+  net::test_server::RegisterDefaultHandlers(https_server.get());
+  https_server->ServeFilesFromSourceDirectory(
+      "content/test/data/attribution_reporting");
+  https_server->ServeFilesFromSourceDirectory("content/test/data");
+
+  auto register_response1 =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server.get(), "/register_source1");
+  auto register_response2 =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server.get(), "/register_source2");
+  ASSERT_TRUE(https_server->Start());
+
+  GURL page_url =
+      https_server->GetURL("b.test", "/page_with_impression_creator.html");
+  ASSERT_TRUE(NavigateToURL(web_contents(), page_url));
+
+  GURL register_url = https_server->GetURL("d.test", "/register_source1");
+  ASSERT_TRUE(ExecJs(web_contents(),
+                     JsReplace("createAttributionSrcImg($1);", register_url)));
+
+  register_response1->WaitForRequest();
+  ASSERT_EQ(register_response1->http_request()->headers.at(
+                "Attribution-Reporting-Eligible"),
+            "event-source, trigger");
+  ASSERT_FALSE(base::Contains(register_response1->http_request()->headers,
+                              "Attribution-Reporting-Support"));
+
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
+  http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+  http_response->AddCustomHeader("Location", "/register_source2");
+  register_response1->Send(http_response->ToResponseString());
+  register_response1->Done();
+
+  // Ensure that redirect requests also don't contain the
+  // Attribution-Reporting-Support header.
+  register_response2->WaitForRequest();
+  ASSERT_EQ(register_response2->http_request()->headers.at(
+                "Attribution-Reporting-Eligible"),
+            "event-source, trigger");
+  ASSERT_FALSE(base::Contains(register_response2->http_request()->headers,
+                              "Attribution-Reporting-Support"));
+}
+
 class AttributionSrcCrossAppWebEnabledBrowserTest
     : public AttributionSrcBrowserTest {
  public:
-  AttributionSrcCrossAppWebEnabledBrowserTest() = default;
+  AttributionSrcCrossAppWebEnabledBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{network::features::
+                                  kAttributionReportingCrossAppWeb,
+                              features::kPrivacySandboxAdsAPIsOverride},
+        /*disabled_features=*/{});
+  }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list{
-      network::features::kAttributionReportingCrossAppWeb};
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(AttributionSrcCrossAppWebEnabledBrowserTest,
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc
index e2e325b..119535c 100644
--- a/content/browser/attribution_reporting/attributions_browsertest.cc
+++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -1186,14 +1186,91 @@
   }
 }
 
+// Tests to verify that cross app web is not enabled when base::Feature is
+// enabled but runtime feature is disabled (without
+// `features::kPrivacySandboxAdsAPIsOverride` override).
+class AttributionsCrossAppWebRuntimeDisabledBrowserTest
+    : public AttributionsBrowserTest {
+ public:
+  AttributionsCrossAppWebRuntimeDisabledBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{network::features::
+                                  kAttributionReportingCrossAppWeb},
+        /*disabled_features=*/{});
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// TODO(crbug.com/1442871): Update this test to ensure that
+// Attribution-Reporting-Support header is not set when runtime feature status
+// is plumbed to the browser process.
+IN_PROC_BROWSER_TEST_F(AttributionsCrossAppWebRuntimeDisabledBrowserTest,
+                       AttributionEligibleNavigation_SupportHeaderSet) {
+  auto register_response1 =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server(), "/register_source_redirect");
+  auto register_response2 =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server(), "/register_source_redirect2");
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL impression_url = https_server()->GetURL(
+      "a.test", "/attribution_reporting/page_with_impression_creator.html");
+  EXPECT_TRUE(NavigateToURL(web_contents(), impression_url));
+
+  GURL register_source_url =
+      https_server()->GetURL("d.test", "/register_source_redirect");
+
+  // Don't use `CreateAndClickSource()` as we need to observe navigation
+  // redirects prior to the navigation finishing.
+  EXPECT_TRUE(ExecJs(web_contents(), JsReplace(R"(
+    createAttributionSrcAnchor({id: 'link',
+                        url: $1,
+                        attributionsrc: '',
+                        target: $2});)",
+                                               register_source_url, "_top")));
+  EXPECT_TRUE(ExecJs(web_contents(), "simulateClick('link');"));
+
+  // Verify the navigation redirects contain the eligibility header.
+  register_response1->WaitForRequest();
+  ASSERT_EQ(register_response1->http_request()->headers.at(
+                "Attribution-Reporting-Eligible"),
+            "navigation-source");
+  ASSERT_EQ(register_response1->http_request()->headers.at(
+                "Attribution-Reporting-Support"),
+            "web");
+
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
+  http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+  http_response->AddCustomHeader("Location", "/register_source_redirect2");
+  register_response1->Send(http_response->ToResponseString());
+  register_response1->Done();
+
+  // Ensure that redirect requests also contain the header.
+  register_response2->WaitForRequest();
+  EXPECT_EQ(register_response2->http_request()->headers.at(
+                "Attribution-Reporting-Eligible"),
+            "navigation-source");
+  EXPECT_EQ(register_response2->http_request()->headers.at(
+                "Attribution-Reporting-Support"),
+            "web");
+}
+
 class AttributionsCrossAppWebEnabledBrowserTest
     : public AttributionsBrowserTest {
  public:
-  AttributionsCrossAppWebEnabledBrowserTest() = default;
+  AttributionsCrossAppWebEnabledBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{network::features::
+                                  kAttributionReportingCrossAppWeb,
+                              features::kPrivacySandboxAdsAPIsOverride},
+        /*disabled_features=*/{});
+  }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_{
-      network::features::kAttributionReportingCrossAppWeb};
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(AttributionsCrossAppWebEnabledBrowserTest,
diff --git a/content/browser/fenced_frame/fenced_frame_reporter.cc b/content/browser/fenced_frame/fenced_frame_reporter.cc
index cc31a38..016cba5 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter.cc
+++ b/content/browser/fenced_frame/fenced_frame_reporter.cc
@@ -378,6 +378,16 @@
             : network::mojom::AttributionReportingEligibility::kEventSource;
 
     request->attribution_reporting_support = AttributionManager::GetSupport();
+
+    // TODO(crbug.com/1442871): Populate whether cross app web runtime feature
+    // is enabled. The runtime feature can only be fully accessed from the
+    // renderer and therefore needs to be plumbed to the browser process.
+    // Currently this is set to true so that Attribution-Reporting-Support
+    // header is set whenever the base::Feature
+    // `network::features::kAttributionReportingCrossAppWeb` is enabled.
+    request->attribution_reporting_runtime_features = {
+        .cross_app_web_enabled = true,
+    };
   }
 
   // Create and configure `SimpleURLLoader` instance.
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 43da4ad..ea885f9 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -85,6 +85,7 @@
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/constants.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/request_destination.h"
@@ -334,6 +335,16 @@
           ? network::mojom::AttributionReportingEligibility::kNavigationSource
           : network::mojom::AttributionReportingEligibility::kUnset;
 
+  // TODO(crbug.com/1442871): Populate whether cross app web runtime feature is
+  // enabled. The runtime feature can only be fully accessed from the renderer
+  // and therefore needs to be plumbed to the browser process. Currently this is
+  // set to true so that Attribution-Reporting-Support header is set whenever
+  // the base::Feature `network::features::kAttributionReportingCrossAppWeb` is
+  // enabled.
+  new_request->attribution_reporting_runtime_features = {
+      .cross_app_web_enabled = true,
+  };
+
   return new_request;
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 977007b0..88f7397 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -184,18 +184,8 @@
 // resizes the top level widget.
 // d) When auto-resize is enabled for the nested main frame and the renderer
 // resizes the nested widget.
-// See https://crbug.com/726743 and https://crbug.com/1050635.
-// TODO(crbug.com/1315346): Flaky on Android and Linux.
-// TODO(crbug.com/1341838): Flaky on Mac (Sheriff 2022-07-04)
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
-#define MAYBE_VisualPropertiesPropagation_VisibleViewportSize \
-  DISABLED_VisualPropertiesPropagation_VisibleViewportSize
-#else
-#define MAYBE_VisualPropertiesPropagation_VisibleViewportSize \
-  VisualPropertiesPropagation_VisibleViewportSize
-#endif
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameBrowserTest,
-                       MAYBE_VisualPropertiesPropagation_VisibleViewportSize) {
+                       VisualPropertiesPropagation_VisibleViewportSize) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -228,8 +218,16 @@
   ASSERT_NE(nested_root_rwh->GetProcess(), nested_child_rwh->GetProcess());
 
   const gfx::Size initial_size = root_view->GetVisibleViewportSize();
-  const gfx::Size nested_initial_size =
-      nested_root_view->GetVisibleViewportSize();
+  ASSERT_FALSE(initial_size.IsEmpty());
+
+  gfx::Size nested_initial_size = nested_root_view->GetVisibleViewportSize();
+  while (nested_initial_size.IsEmpty()) {
+    // CrossProcessFrameConnector for `nested_child_rwh` must receive a
+    // SetRectInParentView() IPC before it has a viewport size. Run tasks until
+    // that IPC arrives.
+    base::RunLoop().RunUntilIdle();
+    nested_initial_size = nested_root_view->GetVisibleViewportSize();
+  }
   ASSERT_NE(initial_size, nested_initial_size);
 
   // We should see the top level widget's size in the visible_viewport_size
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index e008d0ad..80675b4 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -645,7 +645,7 @@
 
   EXPECT_TRUE(NavigateToURL(shell(), kWebUIUrl));
 
-  EXPECT_TRUE(content::ExecuteScript(shell(), kJSCodeForAppendingFrame));
+  EXPECT_TRUE(content::ExecJs(shell(), kJSCodeForAppendingFrame));
 }
 
 // Test that creation of new RenderFrameHost objects sends the correct object
@@ -1476,7 +1476,7 @@
   // present when the cross-site navigation later commits.
   // Note: the javascript function executed will not do the link click but
   // schedule it for afterwards. Since the BeforeUnload event is synchronous,
-  // clicking on the link right away would cause the ExecuteScript to never
+  // clicking on the link right away would cause the ExecJs to never
   // return.
   SetShouldProceedOnBeforeUnload(shell(), false, false);
   AppModalDialogWaiter dialog_waiter(shell());
@@ -3878,7 +3878,8 @@
   base::ScopedClosureRunner fullscreen_block =
       web_contents->ForSecurityDropFullscreen();
 
-  EXPECT_TRUE(ExecuteScript(main_frame, "document.body.requestFullscreen();"));
+  EXPECT_TRUE(ExecJs(main_frame, "document.body.requestFullscreen();",
+                     EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
 
   std::u16string title = title_watcher.WaitAndGetTitle();
   ASSERT_EQ(title, u"onfullscreenerror");
diff --git a/content/public/test/text_input_test_utils.cc b/content/public/test/text_input_test_utils.cc
index 344cb7a..bf7ee0c 100644
--- a/content/public/test/text_input_test_utils.cc
+++ b/content/public/test/text_input_test_utils.cc
@@ -247,6 +247,13 @@
   return !!state ? state->type : ui::TEXT_INPUT_TYPE_NONE;
 }
 
+const ui::mojom::TextInputState* GetTextInputStateFromWebContents(
+    WebContents* web_contents) {
+  return static_cast<WebContentsImpl*>(web_contents)
+      ->GetTextInputManager()
+      ->GetTextInputState();
+}
+
 bool GetTextInputTypeForView(WebContents* web_contents,
                              RenderWidgetHostView* view,
                              ui::TextInputType* type) {
@@ -300,6 +307,11 @@
       text, ime_text_spans, replacement_range, selection_start, selection_end);
 }
 
+void SendTextInputStateChangedToWidget(RenderWidgetHost* rwh,
+                                       ui::mojom::TextInputStatePtr state) {
+  RenderWidgetHostImpl::From(rwh)->TextInputStateChanged(std::move(state));
+}
+
 bool DestroyRenderWidgetHost(int32_t process_id,
                              int32_t local_root_routing_id) {
   RenderFrameHostImpl* rfh =
diff --git a/content/public/test/text_input_test_utils.h b/content/public/test/text_input_test_utils.h
index e9af4e4..612ab5a3 100644
--- a/content/public/test/text_input_test_utils.h
+++ b/content/public/test/text_input_test_utils.h
@@ -46,6 +46,9 @@
 // |web_contents|.
 ui::TextInputType GetTextInputTypeFromWebContents(WebContents* web_contents);
 
+const ui::mojom::TextInputState* GetTextInputStateFromWebContents(
+    WebContents* web_contents);
+
 // This method returns true if |view| is registered in the TextInputManager that
 // is owned by |web_contents|. If that is the case, the value of |type| will be
 // the |TextInputState.type| corresponding to the |view|. Returns false if
@@ -90,6 +93,11 @@
     int selection_start,
     int selection_end);
 
+// Triggers the TextInputStateChanged event on the RenderWidget corresponding to
+// |rwh|.
+void SendTextInputStateChangedToWidget(RenderWidgetHost* rwh,
+                                       ui::mojom::TextInputStatePtr state);
+
 // Immediately destroys the RenderWidgetHost corresponding to the local root
 // which is identified by the given process ID and RenderFrameHost routing ID.
 bool DestroyRenderWidgetHost(int32_t process_id, int32_t local_root_routing_id);
diff --git a/extensions/browser/browser_context_keyed_api_factory.h b/extensions/browser/browser_context_keyed_api_factory.h
index 889ed6c..ca37b4e7 100644
--- a/extensions/browser/browser_context_keyed_api_factory.h
+++ b/extensions/browser/browser_context_keyed_api_factory.h
@@ -34,17 +34,11 @@
   static const bool kServiceRedirectedInIncognito = false;
   static const bool kServiceHasOwnInstanceInIncognito = false;
 
-  // The next two flags allows to force the selection for the System and Guest
-  // Profiles for Keyed Service creation. Values can be overridden in subclasses
-  // by redefining the variables and setting a different value.
-  //
-  // Part of experiment to remove System Profile selection by default with
-  // `kSystemProfileSelectionDefaultNone`. By default do not force the value (do
-  // not create extension services) for the System Profile.
-  // If this value is set to true, the System Profile `ProfileSelection` will
-  // bypass the experiment and be enforced with the value of the Regular
-  // Profile.
-  static const bool kForceSelectionForSystemProfile = false;
+  // This value forces the System profile to set its `ProfileSelection` with the
+  // same value set for the Regular Profile.
+  // If the value is false, then `ProfileSelection::kNone` will be used, and the
+  // service will not be created for the System profile.
+  static const bool kServiceIsCreatedForSystemProfile = false;
   // This value forces the Guest profile to set its `ProfileSelection` with the
   // same value set for the Regular Profile.
   // If the value is false, then `ProfileSelection::kNone` will be used, and the
@@ -164,18 +158,18 @@
     if (T::kServiceRedirectedInIncognito) {
       return ExtensionsBrowserClient::Get()->GetRedirectedContextInIncognito(
           context, T::kServiceIsCreatedInGuestMode,
-          T::kForceSelectionForSystemProfile);
+          T::kServiceIsCreatedForSystemProfile);
     }
 
     if (T::kServiceHasOwnInstanceInIncognito) {
       return ExtensionsBrowserClient::Get()->GetContextForRegularAndIncognito(
           context, T::kServiceIsCreatedInGuestMode,
-          T::kForceSelectionForSystemProfile);
+          T::kServiceIsCreatedForSystemProfile);
     }
 
     return ExtensionsBrowserClient::Get()->GetRegularProfile(
         context, T::kServiceIsCreatedInGuestMode,
-        T::kForceSelectionForSystemProfile);
+        T::kServiceIsCreatedForSystemProfile);
   }
 
   bool ServiceIsCreatedWithBrowserContext() const override {
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 95cec35..de61251 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -147,13 +147,10 @@
   virtual content::BrowserContext* GetOriginalContext(
       content::BrowserContext* context) = 0;
 
-  // The below methods include a test for the experiment
-  // `kSystemProfileSelectionDefaultNone` and will include a similar experiment
-  // for Guest Profile, these two experiment can be bypassed by setting the
-  // force_* to true. The naming of the functions follows the logic of
-  // `ProfileSelections` predefined experimental builders.
-  // - `force_guest_profile`: to force Guest Profile selection in experiment.
-  // - `force_system_profile`: to force System Profile selection in experiment.
+  // The below methods include parameters to enforce the value given to Regular
+  // Profile type for Guest/System Profile types. Guest and System Profiles are
+  // defaulted to return no profile (which leads to no service constructed in
+  // terms of KeyedServices).
   //
   // Returns the Original Profile for Regular Profile and redirects Incognito
   // to the Original Profile.
diff --git a/extensions/browser/guest_view/app_view/app_view_apitest.cc b/extensions/browser/guest_view/app_view/app_view_apitest.cc
index 56ce362d..553a3aa 100644
--- a/extensions/browser/guest_view/app_view/app_view_apitest.cc
+++ b/extensions/browser/guest_view/app_view/app_view_apitest.cc
@@ -121,7 +121,7 @@
 
     ExtensionTestMessageListener done_listener("TEST_PASSED");
     done_listener.set_failure_message("TEST_FAILED");
-    ASSERT_TRUE(content::ExecuteScript(
+    ASSERT_TRUE(content::ExecJs(
         embedder_web_contents_.get(),
         base::StringPrintf("runTest('%s', '%s')", test_name.c_str(),
                            app_embedded->id().c_str())))
diff --git a/extensions/browser/guest_view/web_view/web_view_apitest.cc b/extensions/browser/guest_view/web_view/web_view_apitest.cc
index 157e42e..bd66963 100644
--- a/extensions/browser/guest_view/web_view/web_view_apitest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_apitest.cc
@@ -260,16 +260,16 @@
   if (ad_hoc_framework) {
     ExtensionTestMessageListener done_listener("TEST_PASSED");
     done_listener.set_failure_message("TEST_FAILED");
-    ASSERT_TRUE(content::ExecuteScript(
-        embedder_web_contents_.get(),
-        base::StringPrintf("runTest('%s')", test_name.c_str())))
+    ASSERT_TRUE(
+        content::ExecJs(embedder_web_contents_.get(),
+                        base::StringPrintf("runTest('%s')", test_name.c_str())))
         << "Unable to start test.";
     ASSERT_TRUE(done_listener.WaitUntilSatisfied());
   } else {
     ResultCatcher catcher;
-    ASSERT_TRUE(content::ExecuteScript(
-        embedder_web_contents_.get(),
-        base::StringPrintf("runTest('%s')", test_name.c_str())))
+    ASSERT_TRUE(
+        content::ExecJs(embedder_web_contents_.get(),
+                        base::StringPrintf("runTest('%s')", test_name.c_str())))
         << "Unable to start test.";
     ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
   }
@@ -333,10 +333,9 @@
 }
 
 void WebViewAPITest::SendMessageToEmbedder(const std::string& message) {
-  EXPECT_TRUE(
-      content::ExecuteScript(
-          GetEmbedderWebContents(),
-          base::StringPrintf("onAppCommand('%s');", message.c_str())));
+  EXPECT_TRUE(content::ExecJs(
+      GetEmbedderWebContents(),
+      base::StringPrintf("onAppCommand('%s');", message.c_str())));
 }
 
 content::WebContents* WebViewAPITest::GetEmbedderWebContents() {
@@ -790,8 +789,8 @@
   // Run the test and wait until the guest is available and has finished
   // loading.
   ExtensionTestMessageListener guest_loaded_listener("guest-loaded");
-  EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_.get(),
-                                     "runTest('testRemoveWebviewOnExit')"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents_.get(),
+                              "runTest('testRemoveWebviewOnExit')"));
 
   auto* guest_view = GetGuestViewManager()->WaitForSingleGuestViewCreated();
   EXPECT_TRUE(guest_view);
@@ -799,8 +798,8 @@
   ASSERT_TRUE(guest_loaded_listener.WaitUntilSatisfied());
 
   // Tell the embedder to kill the guest.
-  EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_.get(),
-                                     "removeWebviewOnExitDoCrash()"));
+  EXPECT_TRUE(content::ExecJs(embedder_web_contents_.get(),
+                              "removeWebviewOnExitDoCrash()"));
 
   // Wait until the guest is destroyed.
   GetGuestViewManager()->WaitForLastGuestDeleted();
diff --git a/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc b/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
index b27f7685..85cb5cf 100644
--- a/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
@@ -78,7 +78,7 @@
   void RunTest(const std::string& test_name) {
     ExtensionTestMessageListener test_run_listener("TEST_PASSED");
     test_run_listener.set_failure_message("TEST_FAILED");
-    EXPECT_TRUE(content::ExecuteScript(
+    EXPECT_TRUE(content::ExecJs(
         embedder_web_contents_.get(),
         base::StringPrintf("runTest('%s');", test_name.c_str())));
     ASSERT_TRUE(test_run_listener.WaitUntilSatisfied());
diff --git a/extensions/common/api/offscreen.idl b/extensions/common/api/offscreen.idl
index b797a99b..f9ae4672 100644
--- a/extensions/common/api/offscreen.idl
+++ b/extensions/common/api/offscreen.idl
@@ -25,7 +25,7 @@
     // media (e.g. <code>getUserMedia()</code>).
     USER_MEDIA,
     // The offscreen document needs to interact with media streams from display
-    // media (e.g. <code>getDisplayMedia()</code>).
+    // media (e.g. <code>getDisplayMedia()</code).
     DISPLAY_MEDIA,
     // The offscreen document needs to use WebRTC APIs.
     WEB_RTC,
diff --git a/google_apis/classroom/classroom_api_course_work_response_types.cc b/google_apis/classroom/classroom_api_course_work_response_types.cc
index cc539cb..ff8708c 100644
--- a/google_apis/classroom/classroom_api_course_work_response_types.cc
+++ b/google_apis/classroom/classroom_api_course_work_response_types.cc
@@ -50,17 +50,17 @@
 }
 
 base::TimeDelta GetCourseWorkItemDueTime(
-    const base::Value& raw_course_work_item) {
+    const base::Value::Dict& raw_course_work_item) {
   const auto* const time =
-      raw_course_work_item.FindDictPath(kApiResponseCourseWorkItemDueTimeKey);
+      raw_course_work_item.FindDict(kApiResponseCourseWorkItemDueTimeKey);
   if (!time) {
     return base::TimeDelta();
   }
 
-  const auto hours = time->FindIntKey(kDueTimeHoursComponent);
-  const auto minutes = time->FindIntKey(kDueTimeMinutesComponent);
-  const auto seconds = time->FindIntKey(kDueTimeSecondsComponent);
-  const auto nanos = time->FindIntKey(kDueTimeNanosComponent);
+  const auto hours = time->FindInt(kDueTimeHoursComponent);
+  const auto minutes = time->FindInt(kDueTimeMinutesComponent);
+  const auto seconds = time->FindInt(kDueTimeSecondsComponent);
+  const auto nanos = time->FindInt(kDueTimeNanosComponent);
 
   return base::Hours(hours.value_or(0)) + base::Minutes(minutes.value_or(0)) +
          base::Seconds(seconds.value_or(0)) +
@@ -68,16 +68,16 @@
 }
 
 absl::optional<CourseWorkItem::DueDateTime> GetCourseWorkItemDueDateTime(
-    const base::Value& raw_course_work_item) {
+    const base::Value::Dict& raw_course_work_item) {
   const auto* const date =
-      raw_course_work_item.FindDictPath(kApiResponseCourseWorkItemDueDateKey);
+      raw_course_work_item.FindDict(kApiResponseCourseWorkItemDueDateKey);
   if (!date) {
     return absl::nullopt;
   }
 
-  const auto year = date->FindIntKey(kDueDateYearComponent);
-  const auto month = date->FindIntKey(kDueDateMonthComponent);
-  const auto day = date->FindIntKey(kDueDateDayComponent);
+  const auto year = date->FindInt(kDueDateYearComponent);
+  const auto month = date->FindInt(kDueDateMonthComponent);
+  const auto day = date->FindInt(kDueDateDayComponent);
 
   if (!year.has_value() && !month.has_value() && !day.has_value()) {
     return absl::nullopt;
@@ -116,11 +116,12 @@
 bool CourseWorkItem::ConvertCourseWorkItem(const base::Value* input,
                                            CourseWorkItem* output) {
   base::JSONValueConverter<CourseWorkItem> converter;
-  if (!converter.Convert(*input, output)) {
+  const base::Value::Dict* dict = input->GetIfDict();
+  if (!dict || !converter.Convert(*dict, output)) {
     return false;
   }
 
-  output->due_date_time_ = GetCourseWorkItemDueDateTime(*input);
+  output->due_date_time_ = GetCourseWorkItemDueDateTime(*dict);
   return true;
 }
 
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 2764adf..b3e49f1 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -382,8 +382,8 @@
 
   void DiscoverAdapters();
 
-  int32_t GetPreferredAdapterIndex(WGPUPowerPreference power_preference,
-                                   bool force_fallback) const;
+  WGPUAdapter CreatePreferredAdapter(WGPUPowerPreference power_preference,
+                                     bool force_fallback) const;
 
   // Decide if a device feature is exposed to render process.
   bool IsFeatureExposed(WGPUAdapter adapter, WGPUFeatureName feature) const;
@@ -430,6 +430,8 @@
   // calls that were requested and queued before the isolation key was ready.
   void OnGetIsolationKey(const std::string& isolation_key);
 
+  bool use_blocklist() const;
+
   scoped_refptr<SharedContextState> shared_context_state_;
   const GrContextType gr_context_type_;
 
@@ -439,7 +441,6 @@
   std::unique_ptr<dawn::platform::Platform> dawn_platform_;
   std::unique_ptr<DawnInstance> dawn_instance_;
   std::unique_ptr<DawnServiceMemoryTransferService> memory_transfer_service_;
-  std::vector<dawn::native::Adapter> dawn_adapters_;
 
   bool enable_unsafe_webgpu_ = false;
   WebGPUAdapterName use_webgpu_adapter_ = WebGPUAdapterName::kDefault;
@@ -1245,27 +1246,16 @@
 #endif  // BUILDFLAG(IS_LINUX)
   }
 
-  int32_t requested_adapter_index = GetPreferredAdapterIndex(
-      options->powerPreference, force_fallback_adapter);
+  WGPUAdapter adapter =
+      CreatePreferredAdapter(options->powerPreference, force_fallback_adapter);
 
-  if (requested_adapter_index < 0) {
+  if (adapter == nullptr) {
     // There are no adapters to return since webgpu is not supported here
     callback(WGPURequestAdapterStatus_Unavailable, nullptr,
              "No available adapters.", userdata);
     return;
   }
-
-  // Currently we treat the index of the adapter in
-  // dawn_adapters_ as the id of the adapter in the server side.
-  DCHECK_LT(static_cast<size_t>(requested_adapter_index),
-            dawn_adapters_.size());
-  const dawn::native::Adapter& adapter =
-      dawn_adapters_[requested_adapter_index];
-
-  // Callback takes ownership of the reference. Add a ref to pass to the
-  // callback.
-  dawn::native::GetProcs().adapterReference(adapter.Get());
-  callback(WGPURequestAdapterStatus_Success, adapter.Get(), nullptr, userdata);
+  callback(WGPURequestAdapterStatus_Success, adapter, nullptr, userdata);
 }
 
 bool WebGPUDecoderImpl::AdapterHasFeatureImpl(WGPUAdapter adapter,
@@ -1510,13 +1500,15 @@
       base::Unretained(this), adapter, std::move(desc), callback, userdata);
 }
 
-void WebGPUDecoderImpl::DiscoverAdapters() {
+bool WebGPUDecoderImpl::use_blocklist() const {
   // Enable the blocklist unless --enable-unsafe-webgpu or
   // --disable-dawn-features=adapter_blocklist
-  const bool use_blocklist =
-      !(enable_unsafe_webgpu_ ||
-        base::Contains(require_disabled_toggles_, "adapter_blocklist"));
-  dawn_instance_->EnableAdapterBlocklist(use_blocklist);
+  return !(enable_unsafe_webgpu_ ||
+           base::Contains(require_disabled_toggles_, "adapter_blocklist"));
+}
+
+void WebGPUDecoderImpl::DiscoverAdapters() {
+  dawn_instance_->EnableAdapterBlocklist(use_blocklist());
 
 #if BUILDFLAG(IS_WIN)
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
@@ -1551,15 +1543,20 @@
   // compatibility with ANGLE. Other adapters will not be compatible.
   dawn_instance_->DiscoverDefaultAdapters();
 #endif  // BUILDFLAG(IS_WIN)
+}
 
-  std::vector<dawn::native::Adapter> adapters = dawn_instance_->GetAdapters();
-  for (dawn::native::Adapter& adapter : adapters) {
+WGPUAdapter WebGPUDecoderImpl::CreatePreferredAdapter(
+    WGPUPowerPreference power_preference,
+    bool force_fallback) const {
+  // Build the list of available adapters.
+  std::vector<dawn::native::Adapter> adapters;
+  for (dawn::native::Adapter& adapter : dawn_instance_->GetAdapters()) {
     adapter.SetUseTieredLimits(tiered_adapter_limits_);
 
     WGPUAdapterProperties adapterProperties = {};
     adapter.GetProperties(&adapterProperties);
 
-    if (use_blocklist && IsWebGPUAdapterBlocklisted(adapterProperties)) {
+    if (use_blocklist() && IsWebGPUAdapterBlocklisted(adapterProperties)) {
       continue;
     }
 
@@ -1577,19 +1574,16 @@
 
     if (use_webgpu_adapter_ == WebGPUAdapterName::kCompat) {
       if (adapterProperties.backendType == WGPUBackendType_OpenGLES) {
-        dawn_adapters_.push_back(adapter);
+        adapters.push_back(adapter);
       }
     } else if (adapterProperties.backendType != WGPUBackendType_Null &&
                adapterProperties.backendType != WGPUBackendType_OpenGL &&
                adapterProperties.backendType != WGPUBackendType_D3D11) {
-      dawn_adapters_.push_back(adapter);
+      adapters.push_back(adapter);
     }
   }
-}
 
-int32_t WebGPUDecoderImpl::GetPreferredAdapterIndex(
-    WGPUPowerPreference power_preference,
-    bool force_fallback) const {
+  // Set the preferred adapter type based on flags.
   WGPUAdapterType preferred_adapter_type;
   if (use_webgpu_adapter_ == WebGPUAdapterName::kSwiftShader) {
     // When it is using SwiftShader, it is using CPU, so ignore webgpu power
@@ -1627,8 +1621,9 @@
   int32_t cpu_adapter_index = -1;
   int32_t unknown_adapter_index = -1;
 
-  for (int32_t i = 0; i < static_cast<int32_t>(dawn_adapters_.size()); ++i) {
-    const dawn::native::Adapter& adapter = dawn_adapters_[i];
+  // Find the index of the preferred adapter.
+  for (int32_t i = 0; i < static_cast<int32_t>(adapters.size()); ++i) {
+    const dawn::native::Adapter& adapter = adapters[i];
     WGPUAdapterProperties adapterProperties = {};
     adapter.GetProperties(&adapterProperties);
 
@@ -1639,7 +1634,9 @@
     }
 
     if (adapterProperties.adapterType == preferred_adapter_type) {
-      return i;
+      WGPUAdapter cAdapter = adapters[i].Get();
+      dawn::native::GetProcs().adapterReference(cAdapter);
+      return cAdapter;
     }
     switch (adapterProperties.adapterType) {
       case WGPUAdapterType_DiscreteGPU:
@@ -1664,26 +1661,34 @@
   if (integrated_gpu_adapter_index >= 0 &&
       use_webgpu_power_preference_ !=
           WebGPUPowerPreference::kForceHighPerformance) {
-    return integrated_gpu_adapter_index;
+    WGPUAdapter adapter = adapters[integrated_gpu_adapter_index].Get();
+    dawn::native::GetProcs().adapterReference(adapter);
+    return adapter;
   }
   if (discrete_gpu_adapter_index >= 0 &&
       use_webgpu_power_preference_ != WebGPUPowerPreference::kForceLowPower) {
-    return discrete_gpu_adapter_index;
+    WGPUAdapter adapter = adapters[discrete_gpu_adapter_index].Get();
+    dawn::native::GetProcs().adapterReference(adapter);
+    return adapter;
   }
   if (use_webgpu_power_preference_ == WebGPUPowerPreference::kForceLowPower ||
       use_webgpu_power_preference_ ==
           WebGPUPowerPreference::kForceHighPerformance) {
     // If we cannot find the forced adapter type, early return here instead of
     // returning any other adapter.
-    return -1;
+    return nullptr;
   }
   if (cpu_adapter_index >= 0) {
-    return cpu_adapter_index;
+    WGPUAdapter adapter = adapters[cpu_adapter_index].Get();
+    dawn::native::GetProcs().adapterReference(adapter);
+    return adapter;
   }
   if (unknown_adapter_index >= 0) {
-    return unknown_adapter_index;
+    WGPUAdapter adapter = adapters[unknown_adapter_index].Get();
+    dawn::native::GetProcs().adapterReference(adapter);
+    return adapter;
   }
-  return -1;
+  return nullptr;
 }
 
 const char* WebGPUDecoderImpl::GetCommandName(unsigned int command_id) const {
diff --git a/infra/config/generated/builders/ci/ios16-sdk-device/properties.json b/infra/config/generated/builders/ci/ios16-sdk-device/properties.json
index 264b8cc0..b06e439 100644
--- a/infra/config/generated/builders/ci/ios16-sdk-device/properties.json
+++ b/infra/config/generated/builders/ci/ios16-sdk-device/properties.json
@@ -54,5 +54,5 @@
   },
   "builder_group": "chromium.fyi",
   "recipe": "chromium",
-  "xcode_build_version": "14c18"
+  "xcode_build_version": "14e222b"
 }
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index b4a5d9c..278045ea 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -33977,8 +33977,8 @@
       priority: 35
       execution_timeout_secs: 36000
       caches {
-        name: "xcode_ios_14c18"
-        path: "xcode_ios_14c18.app"
+        name: "xcode_ios_14e222b"
+        path: "xcode_ios_14e222b.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 89bceeb..8b968a42 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -2492,6 +2492,7 @@
             short_name = "dev",
         ),
     ],
+    xcode = xcode.x14betabots,
 )
 
 fyi_ios_builder(
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 0a83cb0..5fd53a5 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2021,6 +2021,9 @@
       <message name="IDS_IOS_TRACKING_PRICE_EMAIL_NOTIFICATIONS_DETAILS" desc="Subtitle that describes to which email address price tracking notifications would be sent.">
         Send to <ph name="USER_EMAIL">$1<ex>janedoe@google.com</ex></ph>
       </message>
+      <message name="IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE" desc="Title for Lockdown Mode.">
+        Lockdown Mode
+      </message>
       <message name="IDS_IOS_PRIVACY_SAFE_BROWSING_ENHANCED_PROTECTION_SUMMARY" desc="Summary for Privacy Safe Browsing enhanced protection mode.">
         Faster, proactive protection against dangerous websites, downloads, and extensions. Warns you about password breaches. Requires browsing data to be sent to Google.
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE.png.sha1
new file mode 100644
index 0000000..a2f93d8
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE.png.sha1
@@ -0,0 +1 @@
+8f4903390a0632b0523f46cb08e6f57a8ad2c2b1
\ No newline at end of file
diff --git a/ios/chrome/browser/sync/sync_setup_service.cc b/ios/chrome/browser/sync/sync_setup_service.cc
index 1c43cba0..4e75ea7 100644
--- a/ios/chrome/browser/sync/sync_setup_service.cc
+++ b/ios/chrome/browser/sync/sync_setup_service.cc
@@ -88,11 +88,6 @@
       sync_all, sync_service_->GetUserSettings()->GetSelectedTypes());
 }
 
-bool SyncSetupService::IsSyncRequested() const {
-  return !sync_service_->HasDisableReason(
-      syncer::SyncService::DISABLE_REASON_USER_CHOICE);
-}
-
 bool SyncSetupService::CanSyncFeatureStart() const {
   return sync_service_->CanSyncFeatureStart();
 }
diff --git a/ios/chrome/browser/sync/sync_setup_service.h b/ios/chrome/browser/sync/sync_setup_service.h
index b8abb3ef..f4bf9be5 100644
--- a/ios/chrome/browser/sync/sync_setup_service.h
+++ b/ios/chrome/browser/sync/sync_setup_service.h
@@ -29,11 +29,6 @@
 
   ~SyncSetupService() override;
 
-  // Returns whether the user wants Sync to run.
-  // TODO(crbug.com/1219990): Remove this function once all calling sites,
-  // including downstream ones, are cleaned up.
-  virtual bool IsSyncRequested() const;
-
   // Returns whether Sync-the-transport can start the Sync feature.
   virtual bool CanSyncFeatureStart() const;
 
diff --git a/ios/chrome/browser/sync/sync_setup_service_mock.h b/ios/chrome/browser/sync/sync_setup_service_mock.h
index ebe3a2da..9654bce 100644
--- a/ios/chrome/browser/sync/sync_setup_service_mock.h
+++ b/ios/chrome/browser/sync/sync_setup_service_mock.h
@@ -24,7 +24,6 @@
   ~SyncSetupServiceMock() override;
   MOCK_METHOD(bool, IsEncryptEverythingEnabled, (), (const override));
   MOCK_METHOD(bool, CanSyncFeatureStart, (), (const override));
-  MOCK_METHOD(bool, IsSyncRequested, (), (const override));
   MOCK_METHOD(bool, IsSyncEverythingEnabled, (), (const override));
   MOCK_METHOD(bool,
               IsDataTypePreferred,
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_mediator_unittest.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_mediator_unittest.mm
index f2469dd..0304491 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_mediator_unittest.mm
@@ -509,7 +509,6 @@
   EXPECT_TRUE(completion_called);
   EXPECT_TRUE(authentication_service()->HasPrimaryIdentity(
       signin::ConsentLevel::kSignin));
-  EXPECT_FALSE(sync_setup_service_mock_->IsSyncRequested());
 }
 
 // Tests the following scenario:
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
index 07f2fa3..b17dc39c 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -138,7 +138,7 @@
   void DidFillOrPreviewField(const std::u16string& autofilled_value,
                              const std::u16string& profile_full_name) override;
   bool IsContextSecure() const override;
-  void ExecuteCommand(int id) override;
+  void ExecuteCommand(Suggestion::FrontendId id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
   LogManager* GetLogManager() const override;
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 207a8aa9..f28829a6 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -490,7 +490,7 @@
   return IsContextSecureForWebState(web_state_);
 }
 
-void ChromeAutofillClientIOS::ExecuteCommand(int id) {
+void ChromeAutofillClientIOS::ExecuteCommand(Suggestion::FrontendId id) {
   NOTIMPLEMENTED();
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 6633a4f..7716eea 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -114,6 +114,7 @@
     "//components/sync/base",
     "//components/sync/driver",
     "//components/undo",
+    "//components/url_formatter",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/flags:system_flags",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
index a6d1f0e..842b7659 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
@@ -225,6 +225,9 @@
 NSArray<NSNumber*>* CreateBookmarkPath(bookmarks::BookmarkModel* model,
                                        int64_t folder_id);
 
+// Converts NSString entered by the user to a GURL.
+GURL ConvertUserDataToGURL(NSString* urlString);
+
 }  // namespace bookmark_utils_ios
 
 #endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UTILS_IOS_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
index e2c9b70..e4a34f1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
@@ -34,6 +34,7 @@
 #import "components/sync/base/user_selectable_type.h"
 #import "components/sync/driver/sync_service.h"
 #import "components/sync/driver/sync_user_settings.h"
+#import "components/url_formatter/url_fixer.h"
 #import "ios/chrome/browser/bookmarks/bookmarks_utils.h"
 #import "ios/chrome/browser/flags/system_flags.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
@@ -742,4 +743,13 @@
   return [[bookmarkPath reverseObjectEnumerator] allObjects];
 }
 
+GURL ConvertUserDataToGURL(NSString* urlString) {
+  if (urlString) {
+    return url_formatter::FixupURL(base::SysNSStringToUTF8(urlString),
+                                   std::string());
+  } else {
+    return GURL();
+  }
+}
+
 }  // namespace bookmark_utils_ios
diff --git a/ios/chrome/browser/ui/bookmarks/editor/BUILD.gn b/ios/chrome/browser/ui/bookmarks/editor/BUILD.gn
index 14f43dc92..602ee14 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/editor/BUILD.gn
@@ -24,12 +24,14 @@
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/ui/table_view",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui/bookmarks:core",
     "//ios/chrome/browser/ui/bookmarks:utils",
     "//ios/chrome/browser/ui/bookmarks/folder_chooser",
     "//ios/chrome/browser/ui/bookmarks/folder_editor",
+    "//ios/third_party/material_components_ios",
     "//ui/base",
     "//url",
   ]
@@ -49,13 +51,11 @@
     "//base:i18n",
     "//components/bookmarks/browser",
     "//components/strings",
-    "//components/url_formatter",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/flags:system_flags",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
-    "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/symbols:icons",
     "//ios/chrome/browser/shared/ui/symbols/resources:cloud_slash",
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.mm b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.mm
index 4fad9522..e858d9e 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.mm
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.h"
 
+#import <MaterialComponents/MaterialSnackbar.h>
+
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
 #import "ios/chrome/browser/bookmarks/account_bookmark_model_factory.h"
@@ -11,6 +13,7 @@
 #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
 #import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller.h"
 #import "ios/chrome/browser/sync/sync_service_factory.h"
 #import "ios/chrome/browser/sync/sync_setup_service_factory.h"
@@ -79,7 +82,6 @@
   _viewController =
       [[BookmarksEditorViewController alloc] initWithBrowser:self.browser];
   _viewController.delegate = self;
-  _viewController.snackbarCommandsHandler = _snackbarCommandsHandler;
   ChromeBrowserState* browserState =
       self.browser->GetBrowserState()->GetOriginalChromeBrowserState();
   bookmarks::BookmarkModel* profileBookmarkModel =
@@ -95,7 +97,8 @@
                   syncSetupService:SyncSetupServiceFactory::GetForBrowserState(
                                        browserState)
                        syncService:SyncServiceFactory::GetForBrowserState(
-                                       browserState)];
+                                       browserState)
+                      browserState:browserState];
   _mediator.consumer = _viewController;
   _mediator.delegate = self;
   _viewController.mutator = _mediator;
@@ -118,7 +121,6 @@
   _mediator.consumer = nil;
   _mediator = nil;
   _viewController.delegate = nil;
-  _viewController.snackbarCommandsHandler = nil;
   _viewController.mutator = nil;
   _viewController = nil;
   _snackbarCommandsHandler = nil;
@@ -163,10 +165,6 @@
   [self.delegate bookmarksEditorCoordinatorShouldStop:self];
 }
 
-- (void)bookmarkEditorWillCommitTitleOrURLChange:
-    (BookmarksEditorViewController*)controller {
-  [self.delegate bookmarkEditorWillCommitTitleOrURLChange:self];
-}
 #pragma mark - UIAdaptivePresentationControllerDelegate
 
 - (void)presentationControllerDidAttemptToDismiss:
@@ -244,6 +242,15 @@
   [_folderChooserCoordinator setSelectedFolder:newParent];
 }
 
+- (void)showSnackbarMessage:(MDCSnackbarMessage*)message {
+  [_snackbarCommandsHandler showSnackbarMessage:message];
+}
+
+- (void)bookmarkEditorWillCommitTitleOrURLChange:
+    (BookmarksEditorMediator*)mediator {
+  [self.delegate bookmarkEditorWillCommitTitleOrURLChange:self];
+}
+
 #pragma mark - BookmarksFolderChooserCoordinatorDelegate
 
 - (void)bookmarksFolderChooserCoordinatorDidConfirm:
@@ -256,7 +263,7 @@
   _folderChooserCoordinator.delegate = nil;
   _folderChooserCoordinator = nil;
 
-  [_mediator changeFolder:folder];
+  [_mediator manuallyChangeFolder:folder];
 }
 
 - (void)bookmarksFolderChooserCoordinatorDidCancel:
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.h b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.h
index a518cbf..ac7ab4e 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.h
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.h
@@ -11,6 +11,7 @@
 
 @protocol BookmarksEditorConsumer;
 @protocol BookmarksEditorMediatorDelegate;
+class ChromeBrowserState;
 class PrefService;
 class SyncSetupService;
 
@@ -50,6 +51,7 @@
                            prefs:(PrefService*)prefs
                 syncSetupService:(SyncSetupService*)syncSetupService
                      syncService:(syncer::SyncService*)syncService
+                    browserState:(ChromeBrowserState*)browserState
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
@@ -57,9 +59,12 @@
 // Disconnects the mediator.
 - (void)disconnect;
 
-// Changes `self.folder` and updates the UI accordingly.
+// Changes `self.folder`, updates the UI accordingly.
 // The change is not committed until the user taps the Save button.
-- (void)changeFolder:(const bookmarks::BookmarkNode*)folder;
+// Save this folder as last used by user in preferences
+// kIosBookmarkLastUsedFolderReceivingBookmarks and
+// kIosBookmarkLastUsedStorageReceivingBookmarks on Save.
+- (void)manuallyChangeFolder:(const bookmarks::BookmarkNode*)folder;
 
 @end
 
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.mm b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.mm
index 6a19a068..314a49a 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.mm
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator.mm
@@ -33,8 +33,13 @@
   std::unique_ptr<BookmarkModelBridge> _bookmarkModelBridgeObserver;
   std::unique_ptr<SyncObserverBridge> _syncObserverModelBridge;
   SyncSetupService* _syncSetupService;
+  ChromeBrowserState* _browserState;
+  // Whether the user manually changed the folder. In which case it must be
+  // saved as last used folder on "save".
+  BOOL _manuallyChangedTheFolder;
 }
 // Flag to ignore bookmark model changes notifications.
+// Property used in BookmarksEditorMutator
 @property(nonatomic, assign) BOOL ignoresBookmarkModelChanges;
 
 @end
@@ -50,7 +55,8 @@
                     bookmarkNode:(const bookmarks::BookmarkNode*)bookmarkNode
                            prefs:(PrefService*)prefs
                 syncSetupService:(SyncSetupService*)syncSetupService
-                     syncService:(syncer::SyncService*)syncService {
+                     syncService:(syncer::SyncService*)syncService
+                    browserState:(ChromeBrowserState*)browserState {
   self = [super init];
   if (self) {
     DCHECK(profileBookmarkModel);
@@ -75,6 +81,7 @@
         new BookmarkModelBridge(self, self.bookmarkModel));
     _syncObserverModelBridge.reset(new SyncObserverBridge(self, syncService));
     _syncSetupService = syncSetupService;
+    _browserState = browserState;
   }
   return self;
 }
@@ -87,6 +94,14 @@
   _prefs = nullptr;
   _bookmarkModelBridgeObserver = nullptr;
   _syncObserverModelBridge = nullptr;
+  _browserState = nullptr;
+}
+
+#pragma mark - Public
+
+- (void)manuallyChangeFolder:(const bookmarks::BookmarkNode*)folder {
+  _manuallyChangedTheFolder = YES;
+  [self changeFolder:folder];
 }
 
 #pragma mark - Properties
@@ -111,15 +126,13 @@
   NOTREACHED_NORETURN();
 }
 
+#pragma mark - Private
+
+// Change the folder of this editor and update the view.
 - (void)changeFolder:(const bookmarks::BookmarkNode*)folder {
   DCHECK(folder);
   DCHECK(folder->is_folder());
   [self setFolder:folder];
-  bookmarks::StorageType type = bookmark_utils_ios::GetBookmarkModelType(
-      folder, _profileBookmarkModel.get(), _accountBookmarkModel.get());
-  // TODO:(crbug.com/1411901): Update the last used default folder on save only.
-  SetLastUsedBookmarkFolder(_prefs, folder, type);
-
   [self.consumer updateFolderLabel];
 }
 
@@ -131,7 +144,7 @@
 
 - (void)bookmarkModel:(bookmarks::BookmarkModel*)model
         didChangeNode:(const bookmarks::BookmarkNode*)bookmarkNode {
-  if (_ignoresBookmarkModelChanges) {
+  if (self.ignoresBookmarkModelChanges) {
     return;
   }
 
@@ -142,7 +155,7 @@
 
 - (void)bookmarkModel:(bookmarks::BookmarkModel*)model
     didChangeChildrenForNode:(const bookmarks::BookmarkNode*)bookmarkNode {
-  if (_ignoresBookmarkModelChanges) {
+  if (self.ignoresBookmarkModelChanges) {
     return;
   }
 
@@ -153,7 +166,7 @@
           didMoveNode:(const bookmarks::BookmarkNode*)bookmarkNode
            fromParent:(const bookmarks::BookmarkNode*)oldParent
              toParent:(const bookmarks::BookmarkNode*)newParent {
-  if (_ignoresBookmarkModelChanges) {
+  if (self.ignoresBookmarkModelChanges) {
     return;
   }
 
@@ -165,7 +178,7 @@
 - (void)bookmarkModel:(bookmarks::BookmarkModel*)model
         didDeleteNode:(const bookmarks::BookmarkNode*)node
            fromFolder:(const bookmarks::BookmarkNode*)folder {
-  if (_ignoresBookmarkModelChanges) {
+  if (self.ignoresBookmarkModelChanges) {
     return;
   }
 
@@ -178,7 +191,7 @@
 }
 
 - (void)bookmarkModelRemovedAllNodes:(bookmarks::BookmarkModel*)model {
-  CHECK(!_ignoresBookmarkModelChanges);
+  CHECK(!self.ignoresBookmarkModelChanges);
   self.bookmark = nullptr;
   self.folder = nullptr;
   [self.delegate bookmarkEditorMediatorWantsDismissal:self];
@@ -186,8 +199,53 @@
 
 #pragma mark - BookmarksEditorMutator
 
-- (BOOL*)ignoresBookmarkModelChangesPointer {
-  return &_ignoresBookmarkModelChanges;
+- (void)commitBookmarkChangesWithURLString:(NSString*)URLString
+                                      name:(NSString*)name {
+  // To stop getting recursive events from committed bookmark editing changes
+  // ignore bookmark model updates notifications.
+  base::AutoReset<BOOL> autoReset(&self->_ignoresBookmarkModelChanges, YES);
+
+  GURL url = bookmark_utils_ios::ConvertUserDataToGURL(URLString);
+  // If the URL was not valid, the `save` message shouldn't have been sent.
+  DCHECK(url.is_valid());
+
+  // Tell delegate if bookmark name or title has been changed.
+  if ([self bookmark] &&
+      ([self bookmark]->GetTitle() != base::SysNSStringToUTF16(name) ||
+       [self bookmark]->url() != url)) {
+    [self.delegate bookmarkEditorWillCommitTitleOrURLChange:self];
+  }
+
+  [self.delegate showSnackbarMessage:
+                     bookmark_utils_ios::CreateOrUpdateBookmarkWithUndoToast(
+                         [self bookmark], name, url, [self folder],
+                         [self bookmarkModel], _browserState)];
+  if (_manuallyChangedTheFolder) {
+    bookmarks::StorageType type = bookmark_utils_ios::GetBookmarkModelType(
+        _folder, _profileBookmarkModel.get(), _accountBookmarkModel.get());
+    SetLastUsedBookmarkFolder(_prefs, _folder, type);
+  }
+}
+
+- (void)deleteBookmark {
+  if (!(self.bookmark && self.bookmarkModel->loaded())) {
+    return;
+  }
+  // To stop getting recursive events from committed bookmark editing changes
+  // ignore bookmark model updates notifications.
+  base::AutoReset<BOOL> autoReset(&self->_ignoresBookmarkModelChanges, YES);
+
+  // When launched from the star button, removing the current bookmark
+  // removes all matching nodes.
+  std::vector<const bookmarks::BookmarkNode*> nodesVector;
+  [self bookmarkModel]->GetNodesByURL([self bookmark]->url(), &nodesVector);
+  std::set<const bookmarks::BookmarkNode*> nodes(nodesVector.begin(),
+                                                 nodesVector.end());
+
+  [self.delegate
+      showSnackbarMessage:bookmark_utils_ios::DeleteBookmarksWithUndoToast(
+                              nodes, {[self bookmarkModel]}, _browserState)];
+  [self setBookmark:nil];
 }
 
 #pragma mark - SyncObserverModelBridge
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator_delegate.h b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator_delegate.h
index 477ed3af..e58993e 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator_delegate.h
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mediator_delegate.h
@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 
 @class BookmarksEditorMediator;
+@class MDCSnackbarMessage;
 
 // Delegate allowing the bookmarks editor mediator to update the coordinator if
 // needed.
@@ -18,6 +19,13 @@
 
 // Change the folder in the folder selector.
 - (void)bookmarkDidMoveToParent:(const bookmarks::BookmarkNode*)newParent;
+
+// Display the message in a snackbar
+- (void)showSnackbarMessage:(MDCSnackbarMessage*)message;
+
+// Called when the controller is going to commit the title or URL change.
+- (void)bookmarkEditorWillCommitTitleOrURLChange:
+    (BookmarksEditorMediator*)mediator;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_EDITOR_BOOKMARKS_EDITOR_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mutator.h b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mutator.h
index f39216e0..f99f39d 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mutator.h
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_mutator.h
@@ -16,6 +16,12 @@
 // model.
 @protocol BookmarksEditorMutator <NSObject>
 
+// Save the bookmark being edited.
+- (void)commitBookmarkChangesWithURLString:(NSString*)URL name:(NSString*)name;
+
+// Delete the bookmark being edited.
+- (void)deleteBookmark;
+
 // TODO(crbug.com/1404311): Remove those accessor and setters.
 // We temporarily use them to facilitate code migration.
 - (const bookmarks::BookmarkNode*)bookmark;
@@ -23,7 +29,6 @@
 - (bookmarks::BookmarkModel*)bookmarkModel;
 - (const bookmarks::BookmarkNode*)folder;
 - (BOOL)ignoresBookmarkModelChanges;
-- (BOOL*)ignoresBookmarkModelChangesPointer;
 - (BOOL)shouldDisplayCloudSlashSymbolForParentFolder;
 
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.h b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.h
index 49d03f75..256a749 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.h
@@ -13,8 +13,6 @@
 
 @protocol BookmarksEditorMutator;
 class Browser;
-@protocol SnackbarCommands;
-
 // View controller for editing bookmarks. Allows editing of the title, URL and
 // the parent folder of the bookmark.
 //
@@ -25,8 +23,6 @@
     : ChromeTableViewController <BookmarksEditorConsumer, KeyCommandActions>
 
 @property(nonatomic, weak) id<BookmarksEditorViewControllerDelegate> delegate;
-// Snackbar commands handler.
-@property(nonatomic, weak) id<SnackbarCommands> snackbarCommandsHandler;
 // Cancel button item in navigation bar.
 @property(nonatomic, strong, readonly) UIBarButtonItem* cancelItem;
 // Mutator for the presented bookmark.
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.mm
index 2148dda..48bc44b9 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.mm
@@ -16,11 +16,9 @@
 #import "base/metrics/user_metrics_action.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/bookmarks/browser/bookmark_model.h"
-#import "components/url_formatter/url_fixer.h"
 #import "ios/chrome/browser/flags/system_flags.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
 #import "ios/chrome/browser/shared/ui/symbols/chrome_icon.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_header_footer_item.h"
 #import "ios/chrome/browser/shared/ui/table_view/chrome_table_view_styler.h"
@@ -50,15 +48,6 @@
 using bookmarks::BookmarkNode;
 
 namespace {
-// Converts NSString entered by the user to a GURL.
-GURL ConvertUserDataToGURL(NSString* urlString) {
-  if (urlString) {
-    return url_formatter::FixupURL(base::SysNSStringToUTF8(urlString),
-                                   std::string());
-  } else {
-    return GURL();
-  }
-}
 
 typedef NS_ENUM(NSInteger, SectionIdentifier) {
   SectionIdentifierInfo = kSectionIdentifierEnumZero,
@@ -81,8 +70,6 @@
 
 @property(nonatomic, assign) Browser* browser;
 
-@property(nonatomic, assign) ChromeBrowserState* browserState;
-
 // Done button item in navigation bar.
 @property(nonatomic, strong) UIBarButtonItem* doneItem;
 
@@ -94,10 +81,6 @@
 // YES if the URL item is displaying a valid URL.
 @property(nonatomic, assign) BOOL displayingValidURL;
 
-// Reports the changes to the delegate, that has the responsibility to save the
-// bookmark.
-- (void)commitBookmarkChanges;
-
 // The Save button is disabled if the form values are deemed non-valid. This
 // method updates the state of the Save button accordingly.
 - (void)updateSaveButtonState;
@@ -117,7 +100,6 @@
 @synthesize delegate = _delegate;
 @synthesize displayingValidURL = _displayingValidURL;
 @synthesize browser = _browser;
-@synthesize browserState = _browserState;
 @synthesize cancelItem = _cancelItem;
 @synthesize doneItem = _doneItem;
 @synthesize nameItem = _nameItem;
@@ -134,7 +116,6 @@
     // Browser may be OTR, which is why the original browser state is being
     // explicitly requested.
     _browser = browser;
-    _browserState = browser->GetBrowserState()->GetOriginalChromeBrowserState();
   }
   return self;
 }
@@ -214,7 +195,8 @@
 #pragma mark - Private
 
 - (BOOL)inputURLIsValid {
-  return ConvertUserDataToGURL([self inputURLString]).is_valid();
+  return bookmark_utils_ios::ConvertUserDataToGURL([self inputURLString])
+      .is_valid();
 }
 
 // Retrieves input URL string from UI.
@@ -227,32 +209,6 @@
   return self.nameItem.text;
 }
 
-- (void)commitBookmarkChanges {
-  // To stop getting recursive events from committed bookmark editing changes
-  // ignore bookmark model updates notifications.
-  base::AutoReset<BOOL> autoReset(
-      [self.mutator ignoresBookmarkModelChangesPointer], YES);
-
-  GURL url = ConvertUserDataToGURL([self inputURLString]);
-  // If the URL was not valid, the `save` message shouldn't have been sent.
-  DCHECK([self inputURLIsValid]);
-
-  // Tell delegate if bookmark name or title has been changed.
-  if ([self.mutator bookmark] &&
-      ([self.mutator bookmark]->GetTitle() !=
-           base::SysNSStringToUTF16([self inputBookmarkName]) ||
-       [self.mutator bookmark]->url() != url)) {
-    [self.delegate bookmarkEditorWillCommitTitleOrURLChange:self];
-  }
-
-  [self.snackbarCommandsHandler
-      showSnackbarMessage:
-          bookmark_utils_ios::CreateOrUpdateBookmarkWithUndoToast(
-              [self.mutator bookmark], [self inputBookmarkName], url,
-              [self.mutator folder], [self.mutator bookmarkModel],
-              self.browserState)];
-}
-
 - (void)dismissBookmarkEditorView {
   [self.view endEditing:YES];
 
@@ -366,25 +322,7 @@
 - (void)deleteBookmark {
   base::RecordAction(
       base::UserMetricsAction("MobileBookmarksEditorDeletedBookmark"));
-  if ([self.mutator bookmark] && [self.mutator bookmarkModel]->loaded()) {
-    // To stop getting recursive events from committed bookmark editing changes
-    // ignore bookmark model updates notifications.
-    base::AutoReset<BOOL> autoReset(
-        [self.mutator ignoresBookmarkModelChangesPointer], YES);
-
-    // When launched from the star button, removing the current bookmark
-    // removes all matching nodes.
-    std::vector<const BookmarkNode*> nodesVector;
-    [self.mutator bookmarkModel]->GetNodesByURL([self.mutator bookmark]->url(),
-                                                &nodesVector);
-    std::set<const BookmarkNode*> nodes(nodesVector.begin(), nodesVector.end());
-
-    [self.snackbarCommandsHandler
-        showSnackbarMessage:bookmark_utils_ios::DeleteBookmarksWithUndoToast(
-                                nodes, {[self.mutator bookmarkModel]},
-                                self.browserState)];
-    [self.mutator setBookmark:nil];
-  }
+  [self.mutator deleteBookmark];
   [self.delegate bookmarkEditorWantsDismissal:self];
 }
 
@@ -401,7 +339,8 @@
 
 - (void)save {
   base::RecordAction(base::UserMetricsAction("MobileBookmarksEditorSaved"));
-  [self commitBookmarkChanges];
+  [self.mutator commitBookmarkChangesWithURLString:[self inputURLString]
+                                              name:[self inputBookmarkName]];
   [self dismissBookmarkEditorView];
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_delegate.h b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_delegate.h
index eb36a928..dec0a9b 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_delegate.h
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_delegate.h
@@ -14,10 +14,6 @@
 // Called when the controller should be dismissed.
 - (void)bookmarkEditorWantsDismissal:(BookmarksEditorViewController*)controller;
 
-// Called when the controller is going to commit the title or URL change.
-- (void)bookmarkEditorWillCommitTitleOrURLChange:
-    (BookmarksEditorViewController*)controller;
-
 // Called when the user wants to select a folder to move the bookmark into.
 - (void)moveBookmark;
 
diff --git a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_unittest.mm b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_unittest.mm
index 64025ea2..5ffe209 100644
--- a/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller_unittest.mm
@@ -63,7 +63,8 @@
                       bookmarkNode:bookmark
                              prefs:nullptr
                   syncSetupService:nullptr
-                       syncService:nullptr];
+                       syncService:nullptr
+                      browserState:nullptr];
   controller.mutator = mediator;
   [controller updateSync];
 }
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 0825742..c5c8d6c 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -2553,7 +2553,7 @@
     willUpdateSnapshotForWebState:(web::WebState*)webState {
   DCHECK(webState);
 
-  if (self.isNTPActiveForCurrentWebState) {
+  if ([self isNTPActiveForCurrentWebState]) {
     [_NTPCoordinator willUpdateSnapshot];
   }
   OverscrollActionsTabHelper::FromWebState(webState)->Clear();
@@ -2624,14 +2624,7 @@
 #pragma mark - WebNavigationNTPDelegate
 
 - (BOOL)isNTPActiveForCurrentWebState {
-  web::WebState* currentWebState =
-      self.browser->GetWebStateList()->GetActiveWebState();
-  if (currentWebState) {
-    NewTabPageTabHelper* NTPHelper =
-        NewTabPageTabHelper::FromWebState(currentWebState);
-    return NTPHelper && NTPHelper->IsActive();
-  }
-  return NO;
+  return [_NTPCoordinator isNTPActiveForCurrentWebState];
 }
 
 - (void)reloadNTPForWebState:(web::WebState*)webState {
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 6d07d26..e678159 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -1019,7 +1019,8 @@
   self.primaryToolbarHeightConstraint.constant =
       [self primaryToolbarHeightWithInset];
 
-  if (self.isNTPActiveForCurrentWebState && self.webUsageEnabled) {
+  if (self.ntpCoordinator.isNTPActiveForCurrentWebState &&
+      self.webUsageEnabled) {
     self.ntpCoordinator.viewController.view.frame =
         [self ntpFrameForWebState:self.currentWebState];
   }
@@ -1914,19 +1915,6 @@
   _lastTapTime = CACurrentMediaTime();
 }
 
-#pragma mark - Private Methods: Reading List
-
-// TODO(crbug.com/1345210) Remove `isNTPActiveForCurrentWebState` method from
-// BVC
-- (BOOL)isNTPActiveForCurrentWebState {
-  if (self.currentWebState) {
-    NewTabPageTabHelper* NTPHelper =
-        NewTabPageTabHelper::FromWebState(self.currentWebState);
-    return NTPHelper && NTPHelper->IsActive();
-  }
-  return NO;
-}
-
 #pragma mark - ** Protocol Implementations and Helpers **
 
 #pragma mark - ThumbStripSupporting
@@ -2082,7 +2070,7 @@
 
   // Stop scrolling in the current web state when transitioning.
   if (self.currentWebState) {
-    if (self.isNTPActiveForCurrentWebState) {
+    if (self.ntpCoordinator.isNTPActiveForCurrentWebState) {
       [self.ntpCoordinator stopScrolling];
     } else {
       CRWWebViewScrollViewProxy* scrollProxy =
@@ -2207,7 +2195,7 @@
   DCHECK(bubblePresenter == _bubblePresenter);
 
   // If NTP exists, check if it is scrolled to top.
-  if (self.isNTPActiveForCurrentWebState) {
+  if (self.ntpCoordinator.isNTPActiveForCurrentWebState) {
     return [self.ntpCoordinator isScrolledToTop];
   }
 
@@ -2558,7 +2546,7 @@
 #pragma mark - OmniboxFocusDelegate (Public)
 
 - (void)omniboxDidBecomeFirstResponder {
-  if (self.isNTPActiveForCurrentWebState) {
+  if (self.ntpCoordinator.isNTPActiveForCurrentWebState) {
     [self.ntpCoordinator locationBarDidBecomeFirstResponder];
   }
   [_sideSwipeController setEnabled:NO];
@@ -2805,7 +2793,8 @@
     [self.contentArea addSubview:toolbarSnapshot];
     newPage.frame = self.view.bounds;
   } else {
-    if (self.isNTPActiveForCurrentWebState && self.webUsageEnabled) {
+    if (self.ntpCoordinator.isNTPActiveForCurrentWebState &&
+        self.webUsageEnabled) {
       newPage.frame = [self ntpFrameForWebState:self.currentWebState];
     } else {
       newPage.frame = self.contentArea.bounds;
@@ -3017,8 +3006,8 @@
 #pragma mark - LogoAnimationControllerOwnerOwner (Public)
 
 - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner {
-  if (self.isNTPActiveForCurrentWebState) {
-    NewTabPageCoordinator* coordinator = self.ntpCoordinator;
+  NewTabPageCoordinator* coordinator = self.ntpCoordinator;
+  if (coordinator.isNTPActiveForCurrentWebState) {
     if ([coordinator logoAnimationControllerOwner]) {
       // If NTP coordinator is showing a GLIF view (e.g. the NTP when there is
       // no doodle), use that GLIFControllerOwner.
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 42d775e9..256c7e8 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -23,7 +23,6 @@
   deps = [
     ":constants",
     ":location_bar_model_delegate",
-    "resources:location_bar_connection_offline",
     "//base",
     "//components/feature_engagement/public",
     "//components/omnibox/browser",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_steady_view_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_steady_view_mediator.mm
index 88401a7..49a6f99 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_steady_view_mediator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_steady_view_mediator.mm
@@ -254,8 +254,7 @@
 
 // Returns a location icon for offline pages.
 - (UIImage*)imageForOfflinePage {
-  return [[UIImage imageNamed:@"location_bar_connection_offline"]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  return GetLocationBarOfflineIcon();
 }
 
 // The status text associated with the current location icon.
diff --git a/ios/chrome/browser/ui/location_bar/resources/BUILD.gn b/ios/chrome/browser/ui/location_bar/resources/BUILD.gn
deleted file mode 100644
index 0fd390c..0000000
--- a/ios/chrome/browser/ui/location_bar/resources/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ios/asset_catalog.gni")
-
-imageset("location_bar_connection_offline") {
-  sources = [
-    "location_bar_connection_offline.imageset/Contents.json",
-    "location_bar_connection_offline.imageset/location_bar_connection_offline@2x.png",
-    "location_bar_connection_offline.imageset/location_bar_connection_offline@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/Contents.json b/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/Contents.json
deleted file mode 100644
index 252126b..0000000
--- a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/Contents.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "location_bar_connection_offline@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "location_bar_connection_offline@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@2x.png b/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@2x.png
deleted file mode 100644
index 25ec2b69..0000000
--- a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@3x.png b/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@3x.png
deleted file mode 100644
index e99a27a..0000000
--- a/ios/chrome/browser/ui/location_bar/resources/location_bar_connection_offline.imageset/location_bar_connection_offline@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
index c4d20b7..7da6c5ce 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
@@ -102,6 +102,9 @@
 // stops the NTP.
 - (void)stopIfNeeded;
 
+// Checks if NTP is active for the current webState.
+- (BOOL)isNTPActiveForCurrentWebState;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 1cf7585..624f963 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -415,11 +415,19 @@
       return;
     }
   }
-
   // No active NTPs were found.
   [self stop];
 }
 
+- (BOOL)isNTPActiveForCurrentWebState {
+  if (!self.webState) {
+    return NO;
+  }
+  NewTabPageTabHelper* NTPHelper =
+      NewTabPageTabHelper::FromWebState(self.webState);
+  return NTPHelper && NTPHelper->IsActive();
+}
+
 - (void)stopScrolling {
   if (!self.contentSuggestionsCoordinator) {
     return;
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index 777bb988..5bb1e5f 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -126,7 +126,6 @@
     ":omnibox_popup_shared",
     ":omnibox_suggestion_icon_util",
     ":omnibox_util",
-    "resources:omnibox_clear_icon",
     "//base",
     "//components/favicon/ios",
     "//components/feature_engagement/public",
@@ -159,6 +158,7 @@
     "//ios/chrome/browser/shared/model/browser_state",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/public/features",
+    "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/ui/default_promo",
     "//ios/chrome/browser/ui/fullscreen",
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h
index 36c8b27..130b25e 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h
@@ -35,7 +35,7 @@
 
 #if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
 // Returns the branded Google icon.
-UIImage* GetBrandedGoogleIcon();
+UIImage* GetBrandedGoogleIconForOmnibox();
 #endif  // BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
 
 #endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_SUGGESTION_ICON_UTIL_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm
index 9d989b0..44be8468 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm
@@ -74,8 +74,8 @@
 }
 
 #if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
-UIImage* GetBrandedGoogleIcon() {
-  return MakeSymbolMulticolor(
+UIImage* GetBrandedGoogleIconForOmnibox() {
+  return MakeSymbolMonochrome(
       CustomSymbolWithPointSize(kGoogleIconSymbol, kSymbolSize));
 }
 #endif  // BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.h b/ios/chrome/browser/ui/omnibox/omnibox_util.h
index 78c529a8..c3b9f16b 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.h
@@ -38,4 +38,7 @@
 UIImage* GetLocationBarSecurityIconForSecurityState(
     security_state::SecurityLevel security_level);
 
+// Returns the icon for an offline page.
+UIImage* GetLocationBarOfflineIcon();
+
 #endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_UTIL_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
index 3058ee3..423130d1 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -114,3 +114,8 @@
       GetLocationBarSecurityIconTypeForSecurityState(security_level);
   return GetLocationBarSecurityIcon(iconType);
 }
+
+UIImage* GetLocationBarOfflineIcon() {
+  return DefaultSymbolTemplateWithPointSize(kDownloadPromptFillSymbol,
+                                            kSymbolLocationBarPointSize);
+}
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index 60df9e83..f534b9b 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -14,6 +14,7 @@
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/default_browser/utils.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_constants.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_container_view.h"
@@ -35,7 +36,8 @@
 
 namespace {
 
-const CGFloat kClearButtonSize = 28.0f;
+const CGFloat kClearButtonInset = 4.0f;
+const CGFloat kClearButtonImageSize = 17.0f;
 
 }  // namespace
 
@@ -580,9 +582,16 @@
   [self.textField setClearButtonMode:UITextFieldViewModeNever];
   [self.textField setRightViewMode:UITextFieldViewModeAlways];
 
+  UIButtonConfiguration* conf =
+      [UIButtonConfiguration plainButtonConfiguration];
+  conf.image = [self clearButtonIcon];
+  conf.contentInsets =
+      NSDirectionalEdgeInsetsMake(kClearButtonInset, kClearButtonInset,
+                                  kClearButtonInset, kClearButtonInset);
+
   UIButton* clearButton = [UIButton buttonWithType:UIButtonTypeSystem];
-  clearButton.frame = CGRectMake(0, 0, kClearButtonSize, kClearButtonSize);
-  [clearButton setImage:[self clearButtonIcon] forState:UIControlStateNormal];
+  clearButton.configuration = conf;
+
   [clearButton addTarget:self
                   action:@selector(clearButtonPressed)
         forControlEvents:UIControlEventTouchUpInside];
@@ -604,10 +613,8 @@
 }
 
 - (UIImage*)clearButtonIcon {
-  UIImage* image = [[UIImage imageNamed:@"omnibox_clear_icon"]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-
-  return image;
+  return DefaultSymbolWithPointSize(kXMarkCircleFillSymbol,
+                                    kClearButtonImageSize);
 }
 
 - (void)clearButtonPressed {
diff --git a/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm b/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm
index 1000be6..d9b61a58 100644
--- a/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm
@@ -53,7 +53,7 @@
 #if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
   if (self.suggestionIconType == OmniboxSuggestionIconType::kFallbackAnswer &&
       self.defaultSearchEngineIsGoogle) {
-    return GetBrandedGoogleIcon();
+    return GetBrandedGoogleIconForOmnibox();
   }
 #endif  // BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
   return GetOmniboxSuggestionIcon(self.suggestionIconType);
diff --git a/ios/chrome/browser/ui/omnibox/resources/BUILD.gn b/ios/chrome/browser/ui/omnibox/resources/BUILD.gn
deleted file mode 100644
index 44c6eb0..0000000
--- a/ios/chrome/browser/ui/omnibox/resources/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ios/asset_catalog.gni")
-
-imageset("omnibox_clear_icon") {
-  sources = [
-    "omnibox_clear_icon.imageset/Contents.json",
-    "omnibox_clear_icon.imageset/omnibox_clear_icon.png",
-    "omnibox_clear_icon.imageset/omnibox_clear_icon@2x.png",
-    "omnibox_clear_icon.imageset/omnibox_clear_icon@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/Contents.json b/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/Contents.json
deleted file mode 100644
index 0cf51af..0000000
--- a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "omnibox_clear_icon.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "omnibox_clear_icon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "omnibox_clear_icon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon.png b/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon.png
deleted file mode 100644
index e044741..0000000
--- a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@2x.png b/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@2x.png
deleted file mode 100644
index 200a810..0000000
--- a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@3x.png b/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@3x.png
deleted file mode 100644
index f25b1da..0000000
--- a/ios/chrome/browser/ui/omnibox/resources/omnibox_clear_icon.imageset/omnibox_clear_icon@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_consumer.h b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_consumer.h
index 3c7c54e..919a425 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_consumer.h
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_consumer.h
@@ -12,9 +12,10 @@
 // Suggestions consumer for the passwords bottom sheet.
 @protocol PasswordSuggestionBottomSheetConsumer
 
-// Sends the list of suggestions to be presented to the user on the bottom
-// sheet.
-- (void)setSuggestions:(NSArray<FormSuggestion*>*)suggestions;
+// Sends the list of suggestions to be presented to the user on the bottom sheet
+// and the current page's domain.
+- (void)setSuggestions:(NSArray<FormSuggestion*>*)suggestions
+             andDomain:(NSString*)domain;
 
 // Request to dismiss the bottom sheet.
 - (void)dismiss;
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
index 37b2df74..0403a14 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
@@ -8,6 +8,7 @@
 #import "base/strings/sys_string_conversions.h"
 #import "components/autofill/ios/form_util/form_activity_params.h"
 #import "components/password_manager/core/browser/password_store_interface.h"
+#import "components/password_manager/core/browser/password_ui_utils.h"
 #import "components/password_manager/core/browser/ui/credential_ui_entry.h"
 #import "components/password_manager/ios/password_manager_java_script_feature.h"
 #import "components/password_manager/ios/shared_password_controller.h"
@@ -209,7 +210,13 @@
 - (void)setConsumer:(id<PasswordSuggestionBottomSheetConsumer>)consumer {
   _consumer = consumer;
   if ([self hasSuggestions]) {
-    [consumer setSuggestions:self.suggestions];
+    NSString* domain = @"";
+    if (!_URL.is_empty()) {
+      url::Origin origin = url::Origin::Create(_URL);
+      domain =
+          base::SysUTF8ToNSString(password_manager::GetShownOrigin(origin));
+    }
+    [consumer setSuggestions:self.suggestions andDomain:domain];
   } else {
     [consumer dismiss];
   }
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
index c1c67645..bbd2277b 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
@@ -266,7 +266,8 @@
   CreateMediatorWithSuggestions();
   EXPECT_TRUE(mediator_);
 
-  OCMExpect([consumer_ setSuggestions:[OCMArg isNotNil]]);
+  OCMExpect([consumer_ setSuggestions:[OCMArg isNotNil]
+                            andDomain:[OCMArg isNotNil]]);
   [mediator_ setConsumer:consumer_];
   EXPECT_OCMOCK_VERIFY(consumer_);
 }
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
index e14d976..48daf35 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
@@ -84,6 +84,10 @@
   // The property is defined by PasswordSuggestionBottomSheetConsumer protocol.
   NSArray<FormSuggestion*>* _suggestions;
 
+  // The current's page domain. This is used for the password bottom sheet
+  // description label.
+  NSString* _domain;
+
   // The password controller handler used to open the password manager.
   id<PasswordSuggestionBottomSheetHandler> _handler;
 }
@@ -159,8 +163,10 @@
 
 #pragma mark - PasswordSuggestionBottomSheetConsumer
 
-- (void)setSuggestions:(NSArray<FormSuggestion*>*)suggestions {
+- (void)setSuggestions:(NSArray<FormSuggestion*>*)suggestions
+             andDomain:(NSString*)domain {
   _suggestions = suggestions;
+  _domain = domain;
 }
 
 - (void)dismiss {
@@ -239,7 +245,7 @@
   // and URL.
   cell.titleLabel.text = [self suggestionAtRow:indexPath.row];
   cell.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
-  cell.URLLabel.text = [self descriptionAtRow:indexPath.row];
+  cell.URLLabel.text = _domain;
   cell.URLLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
   cell.URLLabel.hidden = NO;
 
@@ -349,17 +355,6 @@
   return username;
 }
 
-// Returns the display description at a given row in the table view.
-- (NSString*)descriptionAtRow:(NSInteger)row {
-  FormSuggestion* formSuggestion = [_suggestions objectAtIndex:row];
-  GURL URL(base::SysNSStringToUTF8(formSuggestion.displayDescription));
-  if (!URL.is_empty()) {
-    return base::SysUTF8ToNSString(
-        password_manager::GetShownOrigin(url::Origin::Create(URL)));
-  }
-  return formSuggestion.displayDescription;
-}
-
 // Creates the password bottom sheet's table view, initially at minimized
 // height.
 - (UITableView*)createTableView {
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
index e5013c4..df9a593 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
@@ -207,6 +207,11 @@
 
 // Open tools menu and verify elements are accessible.
 - (void)testAccessibilityOnToolsMenu {
+  if (@available(iOS 16.3, *)) {
+    // TODO(crbug.com/1443713): Re-enable when fixed on iOS16.3+.
+    EARL_GREY_TEST_SKIPPED(@"Test broken on iOS 16.3+");
+  }
+
   [ChromeEarlGreyUI openToolsMenu];
   [ChromeEarlGrey verifyAccessibilityForCurrentScreen];
   // Close Tools menu.
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn
index 3aa91e9..ea1b2b5 100644
--- a/ios/chrome/browser/ui/reading_list/BUILD.gn
+++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -231,6 +231,7 @@
     "//components/reading_list/features:flags",
     "//components/signin/public/base",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/table_view:constants",
     "//ios/chrome/browser/signin:fake_system_identity",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index 031a78ca..0f780dc 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -17,6 +17,7 @@
 #import "base/strings/sys_string_conversions.h"
 #import "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/shared/ui/table_view/table_view_constants.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_app_interface.h"
@@ -452,11 +453,12 @@
   }
 
   // Test the presence of the omnibox offline chip.
+  UIImage* symbol =
+      DefaultSymbolTemplateWithPointSize(kDownloadPromptFillSymbol, 10);
+
   [[EarlGrey selectElementWithMatcher:
                  grey_allOf(chrome_test_util::PageSecurityInfoIndicator(),
-                            chrome_test_util::ImageViewWithImageNamed(
-                                @"location_bar_connection_offline"),
-                            nil)]
+                            chrome_test_util::ImageViewWithImage(symbol), nil)]
       assertWithMatcher:online ? grey_nil() : grey_notNil()];
 }
 
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm
index dad86189..470267e 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm
@@ -798,7 +798,9 @@
           controller());
   [password_details editButtonPressed];
   [password_details tableView:password_details.tableView
-      didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:0]];
+      didSelectRowAtIndexPath:[NSIndexPath
+                                  indexPathForRow:NumberOfItemsInSection(0) - 1
+                                        inSection:0]];
   EXPECT_TRUE(handler().deletionCalled);
   EXPECT_TRUE(handler().deletionCalledOnCompromisedPassword);
 }
diff --git a/ios/chrome/browser/ui/settings/privacy/BUILD.gn b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
index 74a1c3f..fd055cb7 100644
--- a/ios/chrome/browser/ui/settings/privacy/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
@@ -64,6 +64,7 @@
     "//ios/chrome/browser/ui/settings/sync/utils",
     "//ios/chrome/browser/ui/settings/utils",
     "//ios/chrome/browser/url:constants",
+    "//ios/chrome/browser/web:feature_flags",
     "//ios/chrome/common:string_util",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/reauthentication",
@@ -149,6 +150,7 @@
     "//ios/chrome/browser/sync:test_support",
     "//ios/chrome/browser/ui/settings/privacy:privacy_ui",
     "//ios/chrome/browser/ui/settings/utils",
+    "//ios/chrome/browser/web:feature_flags",
     "//ios/chrome/test:test_support",
     "//ios/components/security_interstitials/https_only_mode:feature",
     "//ios/web/public/test",
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_constants.h b/ios/chrome/browser/ui/settings/privacy/privacy_constants.h
index 5d86bfa..837ff9a 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_constants.h
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_constants.h
@@ -10,6 +10,9 @@
 // The accessibility identifier of the Privacy setting table view.
 extern NSString* const kPrivacyTableViewId;
 
+// The accessibility identifier of the Privacy Lockdown Mode cell.
+extern NSString* const kPrivacyLockdownModeCellId;
+
 // The accessibility identifier of the Privacy Safe Browsing setting table view.
 extern NSString* const kPrivacySafeBrowsingTableViewId;
 
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_constants.mm b/ios/chrome/browser/ui/settings/privacy/privacy_constants.mm
index 3f4f245..c93fb130 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_constants.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_constants.mm
@@ -10,6 +10,8 @@
 
 NSString* const kPrivacyTableViewId = @"kPrivacyTableViewId";
 
+NSString* const kPrivacyLockdownModeCellId = @"kPrivacyLockdownModeCellId";
+
 NSString* const kPrivacySafeBrowsingTableViewId =
     @"kPrivacySafeBrowsingTableViewId";
 
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
index e73f7de..8a84de90 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
@@ -16,7 +16,6 @@
 #import "components/prefs/ios/pref_observer_bridge.h"
 #import "components/prefs/pref_change_registrar.h"
 #import "components/prefs/pref_service.h"
-#import "components/safe_browsing/core/common/features.h"
 #import "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #import "components/strings/grit/components_strings.h"
 #import "components/sync/driver/sync_service.h"
@@ -46,6 +45,7 @@
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h"
 #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
+#import "ios/chrome/browser/web/features.h"
 #import "ios/chrome/common/string_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/reauthentication/reauthentication_protocol.h"
@@ -69,6 +69,7 @@
   SectionIdentifierWebServices,
   SectionIdentifierIncognitoAuth,
   SectionIdentifierIncognitoInterstitial,
+  SectionIdentifierLockdownMode,
 };
 
 typedef NS_ENUM(NSInteger, ItemType) {
@@ -82,6 +83,7 @@
   ItemTypeHTTPSOnlyMode,
   ItemTypeIncognitoInterstitial,
   ItemTypeIncognitoInterstitialDisabled,
+  ItemTypeLockdownMode,
 };
 
 // Only used in this class to openn the Sync and Google services settings.
@@ -204,6 +206,7 @@
   TableViewModel* model = self.tableViewModel;
   [model addSectionWithIdentifier:SectionIdentifierPrivacyContent];
   [model addSectionWithIdentifier:SectionIdentifierSafeBrowsing];
+  [model addSectionWithIdentifier:SectionIdentifierLockdownMode];
 
   if (base::FeatureList::IsEnabled(
           security_interstitials::features::kHttpsOnlyMode)) {
@@ -223,13 +226,20 @@
   // Privacy Safe Browsing item.
   [model addItem:[self safeBrowsingDetailItem]
       toSectionWithIdentifier:SectionIdentifierSafeBrowsing];
-  [model setFooter:[self showPrivacyFooterItem]
-      forSectionWithIdentifier:SectionIdentifierIncognitoInterstitial];
+
+  // Lockdown Mode item.
+  if (web::IsBrowserLockdownModeEnabled()) {
+    [model addItem:[self lockdownModeDetailItem]
+        toSectionWithIdentifier:SectionIdentifierLockdownMode];
+  }
 
   // Web Services item.
   [model addItem:[self handoffDetailItem]
       toSectionWithIdentifier:SectionIdentifierWebServices];
 
+  [model setFooter:[self showPrivacyFooterItem]
+      forSectionWithIdentifier:SectionIdentifierIncognitoInterstitial];
+
   // Incognito reauth item is added. If Incognito mode is disabled, or device
   // authentication is not supported, a disabled version is shown instead with
   // relevant information as a popover.
@@ -358,6 +368,19 @@
   return _safeBrowsingDetailItem;
 }
 
+- (TableViewItem*)lockdownModeDetailItem {
+  NSString* detailText =
+      _browserState->GetPrefs()->GetBoolean(prefs::kBrowserLockdownModeEnabled)
+          ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
+          : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
+  TableViewDetailIconItem* lockdownModeDetailItem =
+      [self detailItemWithType:ItemTypeLockdownMode
+                          titleId:IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE
+                       detailText:detailText
+          accessibilityIdentifier:kPrivacyLockdownModeCellId];
+  return lockdownModeDetailItem;
+}
+
 - (TableViewSwitchItem*)incognitoReauthItem {
   if (_incognitoReauthItem) {
     return _incognitoReauthItem;
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
index 8d0cd54..d832378f 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
@@ -33,6 +33,7 @@
 #import "ios/chrome/browser/shared/ui/table_view/chrome_table_view_controller_test.h"
 #import "ios/chrome/browser/sync/mock_sync_service_utils.h"
 #import "ios/chrome/browser/sync/sync_service_factory.h"
+#import "ios/chrome/browser/web/features.h"
 #import "ios/chrome/grit/ios_chromium_strings.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
@@ -90,6 +91,9 @@
         policy::policy_prefs::kIncognitoModeAvailability,
         std::make_unique<base::Value>(
             static_cast<int>(GetParam().incognitoModeAvailability)));
+
+    // TODO(crbug.com/1443624): Remove when feature is enabled by default.
+    feature_list_.InitAndEnableFeature(web::kEnableBrowserLockdownMode);
   }
 
   void TearDown() override {
@@ -136,6 +140,7 @@
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
   std::unique_ptr<Browser> browser_;
   NSString* initialValueForSpdyProxyEnabled_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // Tests PrivacyTableViewController is set up with all appropriate items
@@ -150,6 +155,11 @@
           security_interstitials::features::kHttpsOnlyMode)) {
     expectedNumberOfSections++;
   }
+
+  if (base::FeatureList::IsEnabled(web::kEnableBrowserLockdownMode)) {
+    expectedNumberOfSections++;
+  }
+
   // IncognitoInterstitial section.
   expectedNumberOfSections++;
   EXPECT_EQ(expectedNumberOfSections, NumberOfSections());
@@ -166,7 +176,16 @@
   EXPECT_EQ(1, NumberOfItemsInSection(currentSection));
   CheckTextCellTextAndDetailText(
       l10n_util::GetNSString(IDS_IOS_PRIVACY_SAFE_BROWSING_TITLE),
-      SafeBrowsingDetailText(), 1, 0);
+      SafeBrowsingDetailText(), currentSection, 0);
+
+  // Lockdown Mode section.
+  if (base::FeatureList::IsEnabled(web::kEnableBrowserLockdownMode)) {
+    currentSection++;
+    EXPECT_EQ(1, NumberOfItemsInSection(currentSection));
+    CheckTextCellTextAndDetailText(
+        l10n_util::GetNSString(IDS_IOS_PRIVACY_LOCKDOWN_MODE_TITLE),
+        l10n_util::GetNSString(IDS_IOS_SETTING_OFF), currentSection, 0);
+  }
 
   // HTTPS-Only Mode section.
   if (base::FeatureList::IsEnabled(
@@ -237,6 +256,11 @@
           security_interstitials::features::kHttpsOnlyMode)) {
     expectedNumberOfSections++;
   }
+
+  if (base::FeatureList::IsEnabled(web::kEnableBrowserLockdownMode)) {
+    expectedNumberOfSections++;
+  }
+
   // IncognitoInterstitial section.
   expectedNumberOfSections++;
   EXPECT_EQ(expectedNumberOfSections, NumberOfSections());
@@ -262,6 +286,11 @@
           security_interstitials::features::kHttpsOnlyMode)) {
     expectedNumberOfSections++;
   }
+
+  if (base::FeatureList::IsEnabled(web::kEnableBrowserLockdownMode)) {
+    expectedNumberOfSections++;
+  }
+
   // IncognitoInterstitial section.
   expectedNumberOfSections++;
   EXPECT_EQ(expectedNumberOfSections, NumberOfSections());
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller+private.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller+private.h
index 5487b5d7..07d59b03 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller+private.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller+private.h
@@ -14,7 +14,6 @@
 @property(nonatomic, readonly) NSMutableArray<TabSwitcherItem*>* items;
 @property(nonatomic, readonly) NSUInteger selectedIndex;
 @property(nonatomic, readonly) UICollectionView* collectionView;
-@property(nonatomic, assign, getter=isViewAppeared) BOOL viewAppeared;
 
 @end
 
diff --git a/ios/chrome/browser/web/restore_egtest.mm b/ios/chrome/browser/web/restore_egtest.mm
index 730e98a..03e27ec 100644
--- a/ios/chrome/browser/web/restore_egtest.mm
+++ b/ios/chrome/browser/web/restore_egtest.mm
@@ -379,22 +379,3 @@
 }
 
 @end
-
-// Test using synthesize restore.
-@interface RestoreWithLegacyTestCase : RestoreWithCacheTestCase
-@end
-
-@implementation RestoreWithLegacyTestCase
-
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config = [super appConfigurationForTestCase];
-  config.features_disabled.push_back(web::features::kSynthesizedRestoreSession);
-  config.features_disabled.push_back(web::kRestoreSessionFromCache);
-  return config;
-}
-
-// This is currently needed to prevent this test case from being ignored.
-- (void)testEmpty {
-}
-
-@end
diff --git a/ios/chrome/browser/web/visible_url_egtest.mm b/ios/chrome/browser/web/visible_url_egtest.mm
index 187ae49..74a94cd 100644
--- a/ios/chrome/browser/web/visible_url_egtest.mm
+++ b/ios/chrome/browser/web/visible_url_egtest.mm
@@ -494,23 +494,3 @@
 }
 
 @end
-
-// Test using legacy restore.
-@interface VisibleURLWithWithLegacyRestoreTestCase
-    : VisibleURLWithCachedRestoreTestCase
-@end
-
-@implementation VisibleURLWithWithLegacyRestoreTestCase
-
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config = [super appConfigurationForTestCase];
-  config.features_disabled.push_back(web::features::kSynthesizedRestoreSession);
-  config.features_disabled.push_back(web::kRestoreSessionFromCache);
-  return config;
-}
-
-// This is currently needed to prevent this test case from being ignored.
-- (void)testEmpty {
-}
-
-@end
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 583461f..1f887bc2 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/c++/c++.gni")
 import("//ios/build/chrome_build.gni")
 import("//ios/build/config.gni")
 import("//ios/chrome/features.gni")
@@ -9,6 +10,13 @@
 import("//testing/test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
+declare_args() {
+  # Controls whether to build the Swift - C++ interop tests.
+  # TODO(crbug.com/1444308): the Swift - C++ interop miscompiles when using
+  # a custom libc++. Re-enable those tests when the interop is fixed.
+  ios_enable_swift_interop_tests = !use_custom_libcxx
+}
+
 # All tests needs to be listed in that target to be built as part of
 # "gn_all" target (i.e. by the bots).
 group("all_tests") {
@@ -16,10 +24,13 @@
   deps = [
     ":all_fuzzer_tests",
     ":ios_chrome_unittests",
-    "//ios/chrome/test/swift_interop:ios_swift_interop_xcuitests",
     "//ios/chrome/test/xcuitest:ios_chrome_device_check_xcuitests_module",
     "//ios/chrome/test/xcuitest:ios_chrome_xcuitests",
   ]
+
+  if (ios_enable_swift_interop_tests) {
+    deps += [ "//ios/chrome/test/swift_interop:ios_swift_interop_xcuitests" ]
+  }
 }
 
 group("all_fuzzer_tests") {
diff --git a/ios/web/content/js_messaging/content_web_frame.mm b/ios/web/content/js_messaging/content_web_frame.mm
index 9a9e355..9326295 100644
--- a/ios/web/content/js_messaging/content_web_frame.mm
+++ b/ios/web/content/js_messaging/content_web_frame.mm
@@ -4,6 +4,10 @@
 
 #import "ios/web/content/js_messaging/content_web_frame.h"
 
+#import "base/json/json_writer.h"
+#import "base/strings/string_util.h"
+#import "base/strings/stringprintf.h"
+#import "base/strings/utf_string_conversions.h"
 #import "content/public/browser/render_frame_host.h"
 #import "ios/web/content/web_state/content_web_state.h"
 
@@ -13,6 +17,34 @@
 
 namespace web {
 
+namespace {
+
+void WebToContentJavaScriptCallbackAdapter(
+    base::OnceCallback<void(const base::Value*)> web_callback,
+    base::Value value) {
+  std::move(web_callback).Run(&value);
+}
+
+void WebWithErrorToContentJavaScriptCallbackAdapter(
+    WebFrame::ExecuteJavaScriptCallbackWithError web_callback,
+    base::Value value) {
+  std::move(web_callback).Run(&value, /*error=*/nil);
+}
+
+std::u16string CreateFunctionCallWithParameters(
+    const std::string& name,
+    const std::vector<base::Value>& parameters) {
+  std::vector<std::string> parameter_strings(parameters.size());
+  for (size_t i = 0; i < parameters.size(); ++i) {
+    base::JSONWriter::Write(parameters[i], &parameter_strings[i]);
+  }
+  std::string joined_paramters = base::JoinString(parameter_strings, ",");
+  return base::UTF8ToUTF16(base::StringPrintf("__gCrWeb.%s(%s)", name.c_str(),
+                                              joined_paramters.c_str()));
+}
+
+}  // namespace
+
 ContentWebFrame::ContentWebFrame(const std::string& web_frame_id,
                                  content::RenderFrameHost* render_frame_host,
                                  ContentWebState* content_web_state)
@@ -20,6 +52,7 @@
       content_web_state_(content_web_state),
       render_frame_host_(render_frame_host) {
   content_web_state->AddObserver(this);
+  render_frame_host_->AllowInjectingJavaScript();
 }
 
 ContentWebFrame::~ContentWebFrame() {
@@ -52,8 +85,7 @@
 bool ContentWebFrame::CallJavaScriptFunction(
     const std::string& name,
     const std::vector<base::Value>& parameters) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters));
 }
 
 bool ContentWebFrame::CallJavaScriptFunction(
@@ -61,16 +93,17 @@
     const std::vector<base::Value>& parameters,
     base::OnceCallback<void(const base::Value*)> callback,
     base::TimeDelta timeout) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  // TODO(crbug.com/1423527): Handle timeouts.
+  return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters),
+                           std::move(callback));
 }
 
 bool ContentWebFrame::CallJavaScriptFunctionInContentWorld(
     const std::string& name,
     const std::vector<base::Value>& parameters,
     JavaScriptContentWorld* content_world) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  // TODO(crbug.com/1423527): Handle injecting into an isolated world.
+  return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters));
 }
 
 bool ContentWebFrame::CallJavaScriptFunctionInContentWorld(
@@ -79,27 +112,34 @@
     JavaScriptContentWorld* content_world,
     base::OnceCallback<void(const base::Value*)> callback,
     base::TimeDelta timeout) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  // TODO(crbug.com/1423527): Handle timeouts and injecting into an isolated
+  // world.
+  return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters),
+                           std::move(callback));
 }
 
 bool ContentWebFrame::ExecuteJavaScript(const std::u16string& script) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  render_frame_host_->ExecuteJavaScript(
+      script, content::RenderFrameHost::JavaScriptResultCallback());
+  return true;
 }
 
 bool ContentWebFrame::ExecuteJavaScript(
     const std::u16string& script,
     base::OnceCallback<void(const base::Value*)> callback) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  render_frame_host_->ExecuteJavaScript(
+      script, base::BindOnce(&WebToContentJavaScriptCallbackAdapter,
+                             std::move(callback)));
+  return true;
 }
 
 bool ContentWebFrame::ExecuteJavaScript(
     const std::u16string& script,
     ExecuteJavaScriptCallbackWithError callback) {
-  // TODO(crbug.com/1423527): Implement this.
-  return false;
+  render_frame_host_->ExecuteJavaScript(
+      script, base::BindOnce(&WebWithErrorToContentJavaScriptCallbackAdapter,
+                             std::move(callback)));
+  return true;
 }
 
 void ContentWebFrame::DetachFromWebState() {
diff --git a/ios/web/content/js_messaging/content_web_frames_manager.h b/ios/web/content/js_messaging/content_web_frames_manager.h
index c257e46..d650b030 100644
--- a/ios/web/content/js_messaging/content_web_frames_manager.h
+++ b/ios/web/content/js_messaging/content_web_frames_manager.h
@@ -46,11 +46,19 @@
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void PrimaryPageChanged(content::Page& page) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
 
  private:
-  // List of pointers to all web frames.
+  // Return the WebFrame* corresponding to the given content id.
+  WebFrame* WebFrameForContentId(content::GlobalRenderFrameHostId content_id);
+
+  // Map of ids to owning pointers for all WebFrames.
   std::map<std::string, std::unique_ptr<WebFrame>> web_frames_;
 
+  // Set of RenderFrameHosts that have finished loading content.
+  std::set<content::GlobalRenderFrameHostId> available_frame_hosts_;
+
   // Map from content's id scheme to web's id scheme.
   std::map<content::GlobalRenderFrameHostId, std::string>
       content_to_web_id_map_;
diff --git a/ios/web/content/js_messaging/content_web_frames_manager.mm b/ios/web/content/js_messaging/content_web_frames_manager.mm
index 9c836ef..eaa7d55 100644
--- a/ios/web/content/js_messaging/content_web_frames_manager.mm
+++ b/ios/web/content/js_messaging/content_web_frames_manager.mm
@@ -8,6 +8,7 @@
 
 #import "base/ios/device_util.h"
 #import "components/js_injection/browser/js_communication_host.h"
+#import "content/public/browser/navigation_handle.h"
 #import "content/public/browser/page.h"
 #import "content/public/browser/web_contents.h"
 #import "ios/web/content/js_messaging/content_web_frame.h"
@@ -44,8 +45,8 @@
 
 std::set<WebFrame*> ContentWebFramesManager::GetAllWebFrames() {
   std::set<WebFrame*> frames;
-  for (const auto& it : web_frames_) {
-    frames.insert(it.second.get());
+  for (const auto& it : available_frame_hosts_) {
+    frames.insert(WebFrameForContentId(it));
   }
   return frames;
 }
@@ -76,13 +77,8 @@
   std::string web_frame_id = ios::device_util::GetRandomId();
   auto web_frame = std::make_unique<ContentWebFrame>(
       web_frame_id, render_frame_host, content_web_state_);
-  WebFrame* new_frame = web_frame.get();
   web_frames_[web_frame_id] = std::move(web_frame);
   content_to_web_id_map_[render_frame_host->GetGlobalId()] = web_frame_id;
-
-  for (auto& observer : observers_) {
-    observer.WebFrameBecameAvailable(this, new_frame);
-  }
 }
 
 void ContentWebFramesManager::RenderFrameDeleted(
@@ -92,8 +88,11 @@
   auto web_id_it = content_to_web_id_map_.find(content_id);
   DCHECK(web_id_it != content_to_web_id_map_.end());
 
-  for (auto& observer : observers_) {
-    observer.WebFrameBecameUnavailable(this, web_id_it->second);
+  if (available_frame_hosts_.count(content_id)) {
+    for (auto& observer : observers_) {
+      observer.WebFrameBecameUnavailable(this, web_id_it->second);
+    }
+    available_frame_hosts_.erase(content_id);
   }
 
   if (main_frame_content_id_ == content_id) {
@@ -108,4 +107,44 @@
   main_frame_content_id_ = page.GetMainDocument().GetGlobalId();
 }
 
+void ContentWebFramesManager::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  content::RenderFrameHost* render_frame_host =
+      navigation_handle->GetRenderFrameHost();
+
+  // Some navigations (e.g., downloads, 204 responses) do not have a
+  // RenderFrameHost.
+  if (!render_frame_host) {
+    return;
+  }
+
+  content::GlobalRenderFrameHostId content_id =
+      render_frame_host->GetGlobalId();
+  if (available_frame_hosts_.count(content_id)) {
+    return;
+  }
+
+  available_frame_hosts_.insert(content_id);
+
+  // Notify observers here rather than in `RenderFrameCreated`, to
+  // ensure that frames are no longer in a speculative lifecycle
+  // phase where JavaScript injection is not yet allowed. crbug.com/1183639
+  // tracks delaying `RenderFrameCreated` until frames are past the
+  // speculative state, which is not intended to be exposed to embedders.
+  WebFrame* web_frame = WebFrameForContentId(content_id);
+  for (auto& observer : observers_) {
+    observer.WebFrameBecameAvailable(this, web_frame);
+  }
+}
+
+WebFrame* ContentWebFramesManager::WebFrameForContentId(
+    content::GlobalRenderFrameHostId content_id) {
+  auto web_id_it = content_to_web_id_map_.find(content_id);
+  DCHECK(web_id_it != content_to_web_id_map_.end());
+  auto web_frame_it = web_frames_.find(web_id_it->second);
+  DCHECK(web_frame_it != web_frames_.end());
+
+  return web_frame_it->second.get();
+}
+
 }  // namespace web
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
index 147b8eb..3d663d0 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -327,7 +327,7 @@
   std::vector<autofill::Suggestion> filtered_suggestions;
   base::ranges::copy_if(suggestions, std::back_inserter(filtered_suggestions),
                         [](const autofill::Suggestion& suggestion) {
-                          return suggestion.frontend_id > 0;
+                          return suggestion.frontend_id.as_int() > 0;
                         });
   [_autofillAgent showAutofillPopup:filtered_suggestions
                       popupDelegate:delegate];
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
index a695b45..fc3edfb 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -131,7 +131,7 @@
   void DidFillOrPreviewField(const std::u16string& autofilled_value,
                              const std::u16string& profile_full_name) override;
   bool IsContextSecure() const override;
-  void ExecuteCommand(int id) override;
+  void ExecuteCommand(Suggestion::FrontendId id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
   bool IsLastQueriedField(FieldGlobalId field_id) override;
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
index 82ef1aef..8045495a 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -360,7 +360,7 @@
   return IsContextSecureForWebState(web_state_);
 }
 
-void WebViewAutofillClientIOS::ExecuteCommand(int id) {
+void WebViewAutofillClientIOS::ExecuteCommand(Suggestion::FrontendId id) {
   NOTIMPLEMENTED();
 }
 
diff --git a/net/nqe/socket_watcher.cc b/net/nqe/socket_watcher.cc
index fbb4bca2..e0bb766 100644
--- a/net/nqe/socket_watcher.cc
+++ b/net/nqe/socket_watcher.cc
@@ -57,6 +57,7 @@
       updated_rtt_observation_callback_(updated_rtt_observation_callback),
       should_notify_rtt_callback_(should_notify_rtt_callback),
       rtt_notifications_minimum_interval_(min_notification_interval),
+      allow_rtt_private_address_(allow_rtt_private_address),
       run_rtt_callback_(allow_rtt_private_address ||
                         address.IsPubliclyRoutable()),
       tick_clock_(tick_clock),
@@ -97,8 +98,11 @@
   // tcp_socket_posix may sometimes report RTT as 1 microsecond when the RTT was
   // actually invalid. See:
   // https://cs.chromium.org/chromium/src/net/socket/tcp_socket_posix.cc?rcl=7ad660e34f2a996e381a85b2a515263003b0c171&l=106.
-  if (rtt <= base::Microseconds(1))
+  // Connections to private address eg localhost because they typically have
+  // small rtt.
+  if (!allow_rtt_private_address_ && rtt <= base::Microseconds(1)) {
     return;
+  }
 
   if (!first_quic_rtt_notification_received_ &&
       protocol_ == SocketPerformanceWatcherFactory::PROTOCOL_QUIC) {
diff --git a/net/nqe/socket_watcher.h b/net/nqe/socket_watcher.h
index c9970aa6..195502f 100644
--- a/net/nqe/socket_watcher.h
+++ b/net/nqe/socket_watcher.h
@@ -91,6 +91,10 @@
   // Minimum interval betweeen consecutive incoming notifications.
   const base::TimeDelta rtt_notifications_minimum_interval_;
 
+  // True if socket watchers constructed by this factory can use the RTT from
+  // the sockets that are connected to the private addresses.
+  const bool allow_rtt_private_address_;
+
   // True if the RTT observations from this socket can be notified using
   // |updated_rtt_observation_callback_|.
   const bool run_rtt_callback_;
diff --git a/services/network/attribution/attribution_request_helper.cc b/services/network/attribution/attribution_request_helper.cc
index 8557abe..de8c5b1 100644
--- a/services/network/attribution/attribution_request_helper.cc
+++ b/services/network/attribution/attribution_request_helper.cc
@@ -26,6 +26,7 @@
 #include "services/network/attribution/attribution_verification_mediator.h"
 #include "services/network/attribution/attribution_verification_mediator_metrics_recorder.h"
 #include "services/network/attribution/boringssl_verification_cryptographer.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/attribution_utils.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
@@ -308,7 +309,12 @@
                                           eligibility_header,
                                           /*overwrite=*/true);
 
-  if (base::FeatureList::IsEnabled(
+  // Note that it's important that the network process check both the
+  // base::Feature (which is set from the browser, so trustworthy) and the
+  // runtime feature (which can be spoofed in a compromised renderer, so is
+  // best-effort).
+  if (request.attribution_reporting_runtime_features.cross_app_web_enabled &&
+      base::FeatureList::IsEnabled(
           features::kAttributionReportingCrossAppWeb)) {
     url_request.SetExtraRequestHeaderByName(
         "Attribution-Reporting-Support",
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index 03c4945..713a21e 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -312,27 +312,28 @@
 }
 
 # This component is separate from `:cpp_base` to avoid a circular dependency as
-# its needed by :trigger_verification_traits.
-component("trigger_verification") {
+# its needed by :attribution_traits.
+component("attribution") {
   sources = [
+    "attribution_reporting_runtime_features.h",
     "trigger_verification.cc",
     "trigger_verification.h",
   ]
   deps = [ "//base" ]
-  defines = [ "IS_NETWORK_CPP_TRIGGER_VERIFICATION_IMPL" ]
+  defines = [ "IS_NETWORK_CPP_ATTRIBUTION_IMPL" ]
 }
 
 # This component is separate from
 # //services/network/public/mojom:url_loader_base to use the same typemap for
 # both Blink and non-Blink bindings.
-component("trigger_verification_traits") {
+component("attribution_traits") {
   sources = [
     "attribution_mojom_traits.cc",
     "attribution_mojom_traits.h",
     "trigger_verification.h",
   ]
   deps = [
-    ":trigger_verification",
+    ":attribution",
     "//base",
     "//services/network/public/mojom:mojom_attribution_shared",
   ]
@@ -428,6 +429,8 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   public_deps = [
+    ":attribution",
+    ":attribution_traits",
     ":cookies_mojom_support",
     ":crash_keys",
     ":cross_origin_embedder_policy",
@@ -436,7 +439,6 @@
     ":proxy_config_mojom_support",
     ":schemeful_site_mojom_support",
     ":structured_headers_mojom_support",
-    ":trigger_verification",
     "//services/network/public/mojom:url_loader_base",
     "//url/ipc:url_ipc",
     "//url/mojom:url_mojom_gurl",
@@ -502,8 +504,8 @@
   ]
 
   public_deps = [
+    ":attribution",
     ":cpp",
-    ":trigger_verification",
     "//base",
     "//base/test:test_support",
     "//testing/gmock",
diff --git a/services/network/public/cpp/attribution_mojom_traits.h b/services/network/public/cpp/attribution_mojom_traits.h
index 49089a6c..ff82c59 100644
--- a/services/network/public/cpp/attribution_mojom_traits.h
+++ b/services/network/public/cpp/attribution_mojom_traits.h
@@ -7,6 +7,7 @@
 
 #include "base/component_export.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/trigger_verification.h"
 #include "services/network/public/mojom/attribution.mojom-shared.h"
 
@@ -30,6 +31,23 @@
                    network::TriggerVerification* out);
 };
 
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_ATTRIBUTION_MOJOM_TRAITS)
+    StructTraits<network::mojom::AttributionReportingRuntimeFeaturesDataView,
+                 network::AttributionReportingRuntimeFeatures> {
+  static bool cross_app_web_enabled(
+      const network::AttributionReportingRuntimeFeatures& runtime_features) {
+    return runtime_features.cross_app_web_enabled;
+  }
+
+  static bool Read(
+      network::mojom::AttributionReportingRuntimeFeaturesDataView data,
+      network::AttributionReportingRuntimeFeatures* out) {
+    out->cross_app_web_enabled = data.cross_app_web_enabled();
+    return true;
+  }
+};
+
 }  // namespace mojo
 
 #endif  // SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_MOJOM_TRAITS_H_
diff --git a/services/network/public/cpp/attribution_reporting_runtime_features.h b/services/network/public/cpp/attribution_reporting_runtime_features.h
new file mode 100644
index 0000000..c8cbade
--- /dev/null
+++ b/services/network/public/cpp/attribution_reporting_runtime_features.h
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_REPORTING_RUNTIME_FEATURES_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_REPORTING_RUNTIME_FEATURES_H_
+
+#include "base/component_export.h"
+
+namespace network {
+
+// This corresponds to network::mojom::AttributionReportingRuntimeFeatures.
+// See the comments there.
+struct COMPONENT_EXPORT(NETWORK_CPP_ATTRIBUTION)
+    AttributionReportingRuntimeFeatures {
+  bool cross_app_web_enabled = false;
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_REPORTING_RUNTIME_FEATURES_H_
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 5ac88d0..ee82c5c1 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -20,6 +20,7 @@
 #include "net/http/http_request_headers.h"
 #include "net/log/net_log_source.h"
 #include "net/url_request/referrer_policy.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/optional_trust_token_params.h"
 #include "services/network/public/cpp/resource_request_body.h"
 #include "services/network/public/mojom/accept_ch_frame_observer.mojom.h"
@@ -198,6 +199,8 @@
       network::mojom::AttributionSupport::kWeb;
   mojom::AttributionReportingEligibility attribution_reporting_eligibility =
       mojom::AttributionReportingEligibility::kUnset;
+  network::AttributionReportingRuntimeFeatures
+      attribution_reporting_runtime_features;
 };
 
 // This does not accept |kDefault| referrer policy.
diff --git a/services/network/public/cpp/trigger_verification.h b/services/network/public/cpp/trigger_verification.h
index a035fd3f..9292453 100644
--- a/services/network/public/cpp/trigger_verification.h
+++ b/services/network/public/cpp/trigger_verification.h
@@ -13,7 +13,7 @@
 
 namespace network {
 
-class COMPONENT_EXPORT(NETWORK_CPP_TRIGGER_VERIFICATION) TriggerVerification {
+class COMPONENT_EXPORT(NETWORK_CPP_ATTRIBUTION) TriggerVerification {
  public:
   // Creates a TriggerVerification instance if the `aggregatable_report_id` is a
   // valid id and `token` is not empty.
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index cccbc1f..6459844 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -185,7 +185,9 @@
           &out->devtools_accepted_stream_types) ||
       !data.ReadNetLogCreateInfo(&out->net_log_create_info) ||
       !data.ReadNetLogReferenceInfo(&out->net_log_reference_info) ||
-      !data.ReadNavigationRedirectChain(&out->navigation_redirect_chain)) {
+      !data.ReadNavigationRedirectChain(&out->navigation_redirect_chain) ||
+      !data.ReadAttributionReportingRuntimeFeatures(
+          &out->attribution_reporting_runtime_features)) {
     // Note that data.ReadTrustTokenParams is temporarily handled below.
     return false;
   }
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 266602284..f4ad62d0 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -20,6 +20,7 @@
 #include "mojo/public/cpp/bindings/union_traits.h"
 #include "net/base/request_priority.h"
 #include "net/url_request/referrer_policy.h"
+#include "services/network/public/cpp/attribution_mojom_traits.h"
 #include "services/network/public/cpp/cookie_manager_shared_mojom_traits.h"
 #include "services/network/public/cpp/data_element.h"
 #include "services/network/public/cpp/network_isolation_key_mojom_traits.h"
@@ -385,6 +386,11 @@
   attribution_reporting_eligibility(const network::ResourceRequest& request) {
     return request.attribution_reporting_eligibility;
   }
+  static const network::AttributionReportingRuntimeFeatures&
+  attribution_reporting_runtime_features(
+      const network::ResourceRequest& request) {
+    return request.attribution_reporting_runtime_features;
+  }
 
   static bool Read(network::mojom::URLRequestDataView data,
                    network::ResourceRequest* out);
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index ac028e47..7c23274 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -378,11 +378,14 @@
           cpp = "::network::TriggerVerification"
           move_only = true
         },
+        {
+          mojom = "network.mojom.AttributionReportingRuntimeFeatures"
+          cpp = "::network::AttributionReportingRuntimeFeatures"
+        },
       ]
       traits_headers =
           [ "//services/network/public/cpp/attribution_mojom_traits.h" ]
-      traits_deps =
-          [ "//services/network/public/cpp:trigger_verification_traits" ]
+      traits_deps = [ "//services/network/public/cpp:attribution_traits" ]
     },
   ]
 
diff --git a/services/network/public/mojom/attribution.mojom b/services/network/public/mojom/attribution.mojom
index a3cbce1..231522a2 100644
--- a/services/network/public/mojom/attribution.mojom
+++ b/services/network/public/mojom/attribution.mojom
@@ -41,3 +41,9 @@
   // The header contains `event-source, trigger`.
   kEventSourceOrTrigger,
 };
+
+// Wraps whether Attribution Reporting API related runtime features are
+// enabled.
+struct AttributionReportingRuntimeFeatures {
+  bool cross_app_web_enabled;
+};
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom
index 708c86d4..7b684ab 100644
--- a/services/network/public/mojom/url_request.mojom
+++ b/services/network/public/mojom/url_request.mojom
@@ -509,6 +509,13 @@
   // the request is made.
   AttributionReportingEligibility attribution_reporting_eligibility =
     AttributionReportingEligibility.kUnset;
+
+  // Indicates whether Attribution Reporting API related runtime features are
+  // enabled.
+  //
+  // TODO(https://crbug.com/1443602): Get rid of this with proper OT
+  // infrastructure support in the network service.
+  AttributionReportingRuntimeFeatures attribution_reporting_runtime_features;
 };
 
 // URLRequestBody represents body (i.e. upload data) of a HTTP request.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5e405b01..149c99d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -12788,24 +12788,6 @@
             ]
         }
     ],
-    "SystemProfileSelectionDefaultNone": [
-        {
-            "platforms": [
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SystemProfileSelectionDefaultNone"
-                    ]
-                }
-            ]
-        }
-    ],
     "TabAudioMuting": [
         {
             "platforms": [
@@ -14342,28 +14324,6 @@
             ]
         }
     ],
-    "WebAuthFlowInBrowserTab": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledWithNewTab",
-                    "params": {
-                        "browser_tab_mode": "new_tab"
-                    },
-                    "enable_features": [
-                        "WebAuthFlowInBrowserTab"
-                    ]
-                }
-            ]
-        }
-    ],
     "WebContentsCaptureHiDPI": [
         {
             "platforms": [
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index f5b9ba0e..290ecbc7 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 3132b83a1a1c82df959e000057de27e1b8ff692d
+Revision: b19ec98accca194511616f789c0a448c2b9d40e7
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/absl/container/btree_test.cc b/third_party/abseil-cpp/absl/container/btree_test.cc
index 15335c8ca..72f446b 100644
--- a/third_party/abseil-cpp/absl/container/btree_test.cc
+++ b/third_party/abseil-cpp/absl/container/btree_test.cc
@@ -1233,8 +1233,10 @@
   }
 
   template <typename Btree>
-  constexpr static bool UsesGenerations() {
-    return Btree::params_type::kEnableGenerations;
+  constexpr static bool FieldTypeEqualsSlotType() {
+    return std::is_same<
+        typename btree_node<typename Btree::params_type>::field_type,
+        typename btree_node<typename Btree::params_type>::slot_type>::value;
   }
 };
 
@@ -1463,7 +1465,7 @@
   using Base = typename SizedBtreeSet::btree_set_container;
 
  public:
-  SizedBtreeSet() {}
+  SizedBtreeSet() = default;
   using Base::Base;
 };
 
@@ -1509,10 +1511,9 @@
   EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
   EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(
-        BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
-        // When we have generations, there is one fewer slot.
-        BtreeNodePeer::UsesGenerations<absl::btree_set<int32_t>>() ? 60 : 61);
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              // When we have generations, there is one fewer slot.
+              BtreeGenerationsEnabled() ? 60 : 61);
   }
 
   // Test key insertion/deletion in random order.
@@ -1568,10 +1569,9 @@
   EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
   EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(
-        BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
-        // When we have generations, there is one fewer slot.
-        BtreeNodePeer::UsesGenerations<absl::btree_set<int32_t>>() ? 60 : 61);
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              // When we have generations, there is one fewer slot.
+              BtreeGenerationsEnabled() ? 60 : 61);
   }
 
   // Test key insertion/deletion in random order.
@@ -3226,7 +3226,7 @@
 #ifndef _MSC_VER
 // This test crashes on MSVC.
 TEST(Btree, InvalidIteratorUse) {
-  if (!BtreeNodePeer::UsesGenerations<absl::btree_set<int>>())
+  if (!BtreeGenerationsEnabled())
     GTEST_SKIP() << "Generation validation for iterators is disabled.";
 
   // Invalid memory use can trigger heap-use-after-free in ASan or invalidated
@@ -3569,6 +3569,41 @@
   EXPECT_DEATH(std::cout << *ptr, "heap-use-after-free");
 }
 
+template<typename Set>
+void TestBasicFunctionality(Set set) {
+  using value_type = typename Set::value_type;
+  for (int i = 0; i < 100; ++i) { set.insert(value_type(i)); }
+  for (int i = 50; i < 100; ++i) { set.erase(value_type(i)); }
+  auto it = set.begin();
+  for (int i = 0; i < 50; ++i, ++it) {
+    ASSERT_EQ(set.find(value_type(i)), it) << i;
+  }
+}
+
+template<size_t align>
+struct alignas(align) OveralignedKey {
+  explicit OveralignedKey(int i) : key(i) {}
+  bool operator<(const OveralignedKey &other) const { return key < other.key; }
+  int key = 0;
+};
+
+TEST(Btree, OveralignedKey) {
+  // Test basic functionality with both even and odd numbers of slots per node.
+  // The goal here is to detect cases where alignment may be incorrect.
+  TestBasicFunctionality(
+      SizedBtreeSet<OveralignedKey<16>, /*TargetValuesPerNode=*/8>());
+  TestBasicFunctionality(
+      SizedBtreeSet<OveralignedKey<16>, /*TargetValuesPerNode=*/9>());
+}
+
+TEST(Btree, FieldTypeEqualsSlotType) {
+  // This breaks if we try to do layout_type::Pointer<slot_type> because
+  // slot_type is the same as field_type.
+  using set_type = absl::btree_set<uint8_t>;
+  static_assert(BtreeNodePeer::FieldTypeEqualsSlotType<set_type>(), "");
+  TestBasicFunctionality(set_type());
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/third_party/abseil-cpp/absl/container/fixed_array.h b/third_party/abseil-cpp/absl/container/fixed_array.h
index efc40a5..e99137a 100644
--- a/third_party/abseil-cpp/absl/container/fixed_array.h
+++ b/third_party/abseil-cpp/absl/container/fixed_array.h
@@ -200,18 +200,22 @@
   //
   // Returns a const T* pointer to elements of the `FixedArray`. This pointer
   // can be used to access (but not modify) the contained elements.
-  const_pointer data() const { return AsValueType(storage_.begin()); }
+  const_pointer data() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return AsValueType(storage_.begin());
+  }
 
   // Overload of FixedArray::data() to return a T* pointer to elements of the
   // fixed array. This pointer can be used to access and modify the contained
   // elements.
-  pointer data() { return AsValueType(storage_.begin()); }
+  pointer data() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return AsValueType(storage_.begin());
+  }
 
   // FixedArray::operator[]
   //
   // Returns a reference the ith element of the fixed array.
   // REQUIRES: 0 <= i < size()
-  reference operator[](size_type i) {
+  reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
@@ -219,7 +223,7 @@
   // Overload of FixedArray::operator()[] to return a const reference to the
   // ith element of the fixed array.
   // REQUIRES: 0 <= i < size()
-  const_reference operator[](size_type i) const {
+  const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
@@ -228,7 +232,7 @@
   //
   // Bounds-checked access.  Returns a reference to the ith element of the fixed
   // array, or throws std::out_of_range
-  reference at(size_type i) {
+  reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
     }
@@ -237,7 +241,7 @@
 
   // Overload of FixedArray::at() to return a const reference to the ith element
   // of the fixed array.
-  const_reference at(size_type i) const {
+  const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
     }
@@ -247,14 +251,14 @@
   // FixedArray::front()
   //
   // Returns a reference to the first element of the fixed array.
-  reference front() {
+  reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[0];
   }
 
   // Overload of FixedArray::front() to return a reference to the first element
   // of a fixed array of const values.
-  const_reference front() const {
+  const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[0];
   }
@@ -262,14 +266,14 @@
   // FixedArray::back()
   //
   // Returns a reference to the last element of the fixed array.
-  reference back() {
+  reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[size() - 1];
   }
 
   // Overload of FixedArray::back() to return a reference to the last element
   // of a fixed array of const values.
-  const_reference back() const {
+  const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[size() - 1];
   }
@@ -277,62 +281,74 @@
   // FixedArray::begin()
   //
   // Returns an iterator to the beginning of the fixed array.
-  iterator begin() { return data(); }
+  iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
 
   // Overload of FixedArray::begin() to return a const iterator to the
   // beginning of the fixed array.
-  const_iterator begin() const { return data(); }
+  const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
 
   // FixedArray::cbegin()
   //
   // Returns a const iterator to the beginning of the fixed array.
-  const_iterator cbegin() const { return begin(); }
+  const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return begin();
+  }
 
   // FixedArray::end()
   //
   // Returns an iterator to the end of the fixed array.
-  iterator end() { return data() + size(); }
+  iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data() + size(); }
 
   // Overload of FixedArray::end() to return a const iterator to the end of the
   // fixed array.
-  const_iterator end() const { return data() + size(); }
+  const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return data() + size();
+  }
 
   // FixedArray::cend()
   //
   // Returns a const iterator to the end of the fixed array.
-  const_iterator cend() const { return end(); }
+  const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
 
   // FixedArray::rbegin()
   //
   // Returns a reverse iterator from the end of the fixed array.
-  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return reverse_iterator(end());
+  }
 
   // Overload of FixedArray::rbegin() to return a const reverse iterator from
   // the end of the fixed array.
-  const_reverse_iterator rbegin() const {
+  const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_reverse_iterator(end());
   }
 
   // FixedArray::crbegin()
   //
   // Returns a const reverse iterator from the end of the fixed array.
-  const_reverse_iterator crbegin() const { return rbegin(); }
+  const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return rbegin();
+  }
 
   // FixedArray::rend()
   //
   // Returns a reverse iterator from the beginning of the fixed array.
-  reverse_iterator rend() { return reverse_iterator(begin()); }
+  reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return reverse_iterator(begin());
+  }
 
   // Overload of FixedArray::rend() for returning a const reverse iterator
   // from the beginning of the fixed array.
-  const_reverse_iterator rend() const {
+  const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_reverse_iterator(begin());
   }
 
   // FixedArray::crend()
   //
   // Returns a reverse iterator from the beginning of the fixed array.
-  const_reverse_iterator crend() const { return rend(); }
+  const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return rend();
+  }
 
   // FixedArray::fill()
   //
diff --git a/third_party/abseil-cpp/absl/container/flat_hash_set.h b/third_party/abseil-cpp/absl/container/flat_hash_set.h
index f5376f99..17bbf1a4 100644
--- a/third_party/abseil-cpp/absl/container/flat_hash_set.h
+++ b/third_party/abseil-cpp/absl/container/flat_hash_set.h
@@ -343,7 +343,7 @@
   // for the past-the-end iterator, which is invalidated.
   //
   // `swap()` requires that the flat hash set's hashing and key equivalence
-  // functions be Swappable, and are exchaged using unqualified calls to
+  // functions be Swappable, and are exchanged using unqualified calls to
   // non-member `swap()`. If the set's allocator has
   // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
   // set to `true`, the allocators are also exchanged using an unqualified call
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector.h b/third_party/abseil-cpp/absl/container/inlined_vector.h
index 3e807fd..04e2c385 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector.h
+++ b/third_party/abseil-cpp/absl/container/inlined_vector.h
@@ -341,7 +341,7 @@
   // can be used to access and modify the contained elements.
   //
   // NOTE: only elements within [`data()`, `data() + size()`) are valid.
-  pointer data() noexcept {
+  pointer data() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
                                      : storage_.GetInlinedData();
   }
@@ -351,7 +351,7 @@
   // modify the contained elements.
   //
   // NOTE: only elements within [`data()`, `data() + size()`) are valid.
-  const_pointer data() const noexcept {
+  const_pointer data() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
                                      : storage_.GetInlinedData();
   }
@@ -359,14 +359,14 @@
   // `InlinedVector::operator[](...)`
   //
   // Returns a `reference` to the `i`th element of the inlined vector.
-  reference operator[](size_type i) {
+  reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
 
   // Overload of `InlinedVector::operator[](...)` that returns a
   // `const_reference` to the `i`th element of the inlined vector.
-  const_reference operator[](size_type i) const {
+  const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(i < size());
     return data()[i];
   }
@@ -377,7 +377,7 @@
   //
   // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
   // in both debug and non-debug builds, `std::out_of_range` will be thrown.
-  reference at(size_type i) {
+  reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type)` failed bounds check");
@@ -390,7 +390,7 @@
   //
   // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
   // in both debug and non-debug builds, `std::out_of_range` will be thrown.
-  const_reference at(size_type i) const {
+  const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange(
           "`InlinedVector::at(size_type) const` failed bounds check");
@@ -401,14 +401,14 @@
   // `InlinedVector::front()`
   //
   // Returns a `reference` to the first element of the inlined vector.
-  reference front() {
+  reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[0];
   }
 
   // Overload of `InlinedVector::front()` that returns a `const_reference` to
   // the first element of the inlined vector.
-  const_reference front() const {
+  const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[0];
   }
@@ -416,14 +416,14 @@
   // `InlinedVector::back()`
   //
   // Returns a `reference` to the last element of the inlined vector.
-  reference back() {
+  reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[size() - 1];
   }
 
   // Overload of `InlinedVector::back()` that returns a `const_reference` to the
   // last element of the inlined vector.
-  const_reference back() const {
+  const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(!empty());
     return data()[size() - 1];
   }
@@ -431,63 +431,82 @@
   // `InlinedVector::begin()`
   //
   // Returns an `iterator` to the beginning of the inlined vector.
-  iterator begin() noexcept { return data(); }
+  iterator begin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
 
   // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
   // the beginning of the inlined vector.
-  const_iterator begin() const noexcept { return data(); }
+  const_iterator begin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return data();
+  }
 
   // `InlinedVector::end()`
   //
   // Returns an `iterator` to the end of the inlined vector.
-  iterator end() noexcept { return data() + size(); }
+  iterator end() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return data() + size();
+  }
 
   // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
   // end of the inlined vector.
-  const_iterator end() const noexcept { return data() + size(); }
+  const_iterator end() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return data() + size();
+  }
 
   // `InlinedVector::cbegin()`
   //
   // Returns a `const_iterator` to the beginning of the inlined vector.
-  const_iterator cbegin() const noexcept { return begin(); }
+  const_iterator cbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return begin();
+  }
 
   // `InlinedVector::cend()`
   //
   // Returns a `const_iterator` to the end of the inlined vector.
-  const_iterator cend() const noexcept { return end(); }
+  const_iterator cend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return end();
+  }
 
   // `InlinedVector::rbegin()`
   //
   // Returns a `reverse_iterator` from the end of the inlined vector.
-  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+  reverse_iterator rbegin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return reverse_iterator(end());
+  }
 
   // Overload of `InlinedVector::rbegin()` that returns a
   // `const_reverse_iterator` from the end of the inlined vector.
-  const_reverse_iterator rbegin() const noexcept {
+  const_reverse_iterator rbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_reverse_iterator(end());
   }
 
   // `InlinedVector::rend()`
   //
   // Returns a `reverse_iterator` from the beginning of the inlined vector.
-  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+  reverse_iterator rend() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return reverse_iterator(begin());
+  }
 
   // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
   // from the beginning of the inlined vector.
-  const_reverse_iterator rend() const noexcept {
+  const_reverse_iterator rend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_reverse_iterator(begin());
   }
 
   // `InlinedVector::crbegin()`
   //
   // Returns a `const_reverse_iterator` from the end of the inlined vector.
-  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+  const_reverse_iterator crbegin() const noexcept
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return rbegin();
+  }
 
   // `InlinedVector::crend()`
   //
   // Returns a `const_reverse_iterator` from the beginning of the inlined
   // vector.
-  const_reverse_iterator crend() const noexcept { return rend(); }
+  const_reverse_iterator crend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return rend();
+  }
 
   // `InlinedVector::get_allocator()`
   //
@@ -597,20 +616,23 @@
   //
   // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
   // inserted element.
-  iterator insert(const_iterator pos, const_reference v) {
+  iterator insert(const_iterator pos,
+                  const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(pos, v);
   }
 
   // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
   // move semantics, returning an `iterator` to the newly inserted element.
-  iterator insert(const_iterator pos, value_type&& v) {
+  iterator insert(const_iterator pos,
+                  value_type&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(pos, std::move(v));
   }
 
   // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
   // of `v` starting at `pos`, returning an `iterator` pointing to the first of
   // the newly inserted elements.
-  iterator insert(const_iterator pos, size_type n, const_reference v) {
+  iterator insert(const_iterator pos, size_type n,
+                  const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(pos >= begin());
     ABSL_HARDENING_ASSERT(pos <= end());
 
@@ -638,7 +660,8 @@
   // Overload of `InlinedVector::insert(...)` that inserts copies of the
   // elements of `list` starting at `pos`, returning an `iterator` pointing to
   // the first of the newly inserted elements.
-  iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
+  iterator insert(const_iterator pos, std::initializer_list<value_type> list)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert(pos, list.begin(), list.end());
   }
 
@@ -650,7 +673,7 @@
   template <typename ForwardIterator,
             EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
   iterator insert(const_iterator pos, ForwardIterator first,
-                  ForwardIterator last) {
+                  ForwardIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(pos >= begin());
     ABSL_HARDENING_ASSERT(pos <= end());
 
@@ -670,7 +693,8 @@
   // NOTE: this overload is for iterators that are "input" category.
   template <typename InputIterator,
             DisableIfAtLeastForwardIterator<InputIterator> = 0>
-  iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
+  iterator insert(const_iterator pos, InputIterator first,
+                  InputIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(pos >= begin());
     ABSL_HARDENING_ASSERT(pos <= end());
 
@@ -687,7 +711,8 @@
   // Constructs and inserts an element using `args...` in the inlined vector at
   // `pos`, returning an `iterator` pointing to the newly emplaced element.
   template <typename... Args>
-  iterator emplace(const_iterator pos, Args&&... args) {
+  iterator emplace(const_iterator pos,
+                   Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(pos >= begin());
     ABSL_HARDENING_ASSERT(pos <= end());
 
@@ -715,7 +740,7 @@
   // Constructs and inserts an element using `args...` in the inlined vector at
   // `end()`, returning a `reference` to the newly emplaced element.
   template <typename... Args>
-  reference emplace_back(Args&&... args) {
+  reference emplace_back(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return storage_.EmplaceBack(std::forward<Args>(args)...);
   }
 
@@ -746,7 +771,7 @@
   // erased element was located.
   //
   // NOTE: may return `end()`, which is not dereferenceable.
-  iterator erase(const_iterator pos) {
+  iterator erase(const_iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(pos >= begin());
     ABSL_HARDENING_ASSERT(pos < end());
 
@@ -758,7 +783,8 @@
   // erased element was located.
   //
   // NOTE: may return `end()`, which is not dereferenceable.
-  iterator erase(const_iterator from, const_iterator to) {
+  iterator erase(const_iterator from,
+                 const_iterator to) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(from >= begin());
     ABSL_HARDENING_ASSERT(from <= to);
     ABSL_HARDENING_ASSERT(to <= end());
@@ -816,8 +842,8 @@
 
   void MoveAssignment(MemcpyPolicy, InlinedVector&& other) {
     // Assumption check: we shouldn't be told to use memcpy to implement move
-    // asignment unless we have trivially destructible elements and an allocator
-    // that does nothing fancy.
+    // assignment unless we have trivially destructible elements and an
+    // allocator that does nothing fancy.
     static_assert(absl::is_trivially_destructible<value_type>::value, "");
     static_assert(std::is_same<A, std::allocator<value_type>>::value, "");
 
diff --git a/third_party/abseil-cpp/absl/container/internal/btree.h b/third_party/abseil-cpp/absl/container/internal/btree.h
index 6071247c..569faa0 100644
--- a/third_party/abseil-cpp/absl/container/internal/btree.h
+++ b/third_party/abseil-cpp/absl/container/internal/btree.h
@@ -86,6 +86,12 @@
 #define ABSL_BTREE_ENABLE_GENERATIONS
 #endif
 
+#ifdef ABSL_BTREE_ENABLE_GENERATIONS
+constexpr bool BtreeGenerationsEnabled() { return true; }
+#else
+constexpr bool BtreeGenerationsEnabled() { return false; }
+#endif
+
 template <typename Compare, typename T, typename U>
 using compare_result_t = absl::result_of_t<const Compare(const T &, const U &)>;
 
@@ -378,12 +384,6 @@
       std::is_same<key_compare, StringBtreeDefaultGreater>::value;
   static constexpr bool kIsKeyCompareTransparent =
       IsTransparent<original_key_compare>::value || kIsKeyCompareStringAdapted;
-  static constexpr bool kEnableGenerations =
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
-      true;
-#else
-      false;
-#endif
 
   // A type which indicates if we have a key-compare-to functor or a plain old
   // key-compare functor.
@@ -589,7 +589,7 @@
   constexpr static size_type SizeWithNSlots(size_type n) {
     return layout_type(
                /*parent*/ 1,
-               /*generation*/ params_type::kEnableGenerations ? 1 : 0,
+               /*generation*/ BtreeGenerationsEnabled() ? 1 : 0,
                /*position, start, finish, max_count*/ 4,
                /*slots*/ n,
                /*children*/ 0)
@@ -629,23 +629,22 @@
   // has this value.
   constexpr static field_type kInternalNodeMaxCount = 0;
 
+  constexpr static layout_type Layout(const size_type slot_count,
+                                      const size_type child_count) {
+    return layout_type(
+        /*parent*/ 1,
+        /*generation*/ BtreeGenerationsEnabled() ? 1 : 0,
+        /*position, start, finish, max_count*/ 4,
+        /*slots*/ slot_count,
+        /*children*/ child_count);
+  }
   // Leaves can have less than kNodeSlots values.
   constexpr static layout_type LeafLayout(
       const size_type slot_count = kNodeSlots) {
-    return layout_type(
-        /*parent*/ 1,
-        /*generation*/ params_type::kEnableGenerations ? 1 : 0,
-        /*position, start, finish, max_count*/ 4,
-        /*slots*/ slot_count,
-        /*children*/ 0);
+    return Layout(slot_count, 0);
   }
   constexpr static layout_type InternalLayout() {
-    return layout_type(
-        /*parent*/ 1,
-        /*generation*/ params_type::kEnableGenerations ? 1 : 0,
-        /*position, start, finish, max_count*/ 4,
-        /*slots*/ kNodeSlots,
-        /*children*/ kNodeSlots + 1);
+    return Layout(kNodeSlots, kNodeSlots + 1);
   }
   constexpr static size_type LeafSize(const size_type slot_count = kNodeSlots) {
     return LeafLayout(slot_count).AllocSize();
@@ -729,7 +728,7 @@
 
   // Gets the root node's generation integer, which is the one used by the tree.
   uint32_t *get_root_generation() const {
-    assert(params_type::kEnableGenerations);
+    assert(BtreeGenerationsEnabled());
     const btree_node *curr = this;
     for (; !curr->is_root(); curr = curr->parent()) continue;
     return const_cast<uint32_t *>(&curr->GetField<1>()[0]);
@@ -737,16 +736,16 @@
 
   // Returns the generation for iterator validation.
   uint32_t generation() const {
-    return params_type::kEnableGenerations ? *get_root_generation() : 0;
+    return BtreeGenerationsEnabled() ? *get_root_generation() : 0;
   }
   // Updates generation. Should only be called on a root node or during node
   // initialization.
   void set_generation(uint32_t generation) {
-    if (params_type::kEnableGenerations) GetField<1>()[0] = generation;
+    if (BtreeGenerationsEnabled()) GetField<1>()[0] = generation;
   }
   // Updates the generation. We do this whenever the node is mutated.
   void next_generation() {
-    if (params_type::kEnableGenerations) ++*get_root_generation();
+    if (BtreeGenerationsEnabled()) ++*get_root_generation();
   }
 
   // Getters for the key/value at position i in the node.
@@ -1543,7 +1542,8 @@
 
   // Insert a range of values into the btree.
   template <typename InputIterator>
-  void insert_iterator_multi(InputIterator b, InputIterator e);
+  void insert_iterator_multi(InputIterator b,
+                             InputIterator e);
 
   // Erase the specified iterator from the btree. The iterator must be valid
   // (i.e. not equal to end()).  Return an iterator pointing to the node after
diff --git a/third_party/abseil-cpp/absl/container/internal/btree_container.h b/third_party/abseil-cpp/absl/container/internal/btree_container.h
index 2bff11d..a68ce44 100644
--- a/third_party/abseil-cpp/absl/container/internal/btree_container.h
+++ b/third_party/abseil-cpp/absl/container/internal/btree_container.h
@@ -95,18 +95,36 @@
       std::is_nothrow_move_assignable<Tree>::value) = default;
 
   // Iterator routines.
-  iterator begin() { return tree_.begin(); }
-  const_iterator begin() const { return tree_.begin(); }
-  const_iterator cbegin() const { return tree_.begin(); }
-  iterator end() { return tree_.end(); }
-  const_iterator end() const { return tree_.end(); }
-  const_iterator cend() const { return tree_.end(); }
-  reverse_iterator rbegin() { return tree_.rbegin(); }
-  const_reverse_iterator rbegin() const { return tree_.rbegin(); }
-  const_reverse_iterator crbegin() const { return tree_.rbegin(); }
-  reverse_iterator rend() { return tree_.rend(); }
-  const_reverse_iterator rend() const { return tree_.rend(); }
-  const_reverse_iterator crend() const { return tree_.rend(); }
+  iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.begin(); }
+  const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.begin();
+  }
+  const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.begin();
+  }
+  iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.end(); }
+  const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.end();
+  }
+  const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.end();
+  }
+  reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.rbegin();
+  }
+  const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.rbegin();
+  }
+  const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.rbegin();
+  }
+  reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.rend(); }
+  const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.rend();
+  }
+  const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.rend();
+  }
 
   // Lookup routines.
   template <typename K = key_type>
@@ -115,11 +133,12 @@
     return equal_range.second - equal_range.first;
   }
   template <typename K = key_type>
-  iterator find(const key_arg<K> &key) {
+  iterator find(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.find(key);
   }
   template <typename K = key_type>
-  const_iterator find(const key_arg<K> &key) const {
+  const_iterator find(const key_arg<K> &key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.find(key);
   }
   template <typename K = key_type>
@@ -127,28 +146,31 @@
     return find(key) != end();
   }
   template <typename K = key_type>
-  iterator lower_bound(const key_arg<K> &key) {
+  iterator lower_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.lower_bound(key);
   }
   template <typename K = key_type>
-  const_iterator lower_bound(const key_arg<K> &key) const {
+  const_iterator lower_bound(const key_arg<K> &key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.lower_bound(key);
   }
   template <typename K = key_type>
-  iterator upper_bound(const key_arg<K> &key) {
+  iterator upper_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.upper_bound(key);
   }
   template <typename K = key_type>
-  const_iterator upper_bound(const key_arg<K> &key) const {
+  const_iterator upper_bound(const key_arg<K> &key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.upper_bound(key);
   }
   template <typename K = key_type>
-  std::pair<iterator, iterator> equal_range(const key_arg<K> &key) {
+  std::pair<iterator, iterator> equal_range(const key_arg<K> &key)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.equal_range(key);
   }
   template <typename K = key_type>
   std::pair<const_iterator, const_iterator> equal_range(
-      const key_arg<K> &key) const {
+      const key_arg<K> &key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.equal_range(key);
   }
 
@@ -158,9 +180,14 @@
   // Erase the specified iterator from the btree. The iterator must be valid
   // (i.e. not equal to end()).  Return an iterator pointing to the node after
   // the one that was erased (or end() if none exists).
-  iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); }
-  iterator erase(iterator iter) { return tree_.erase(iter); }
-  iterator erase(const_iterator first, const_iterator last) {
+  iterator erase(const_iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.erase(iterator(iter));
+  }
+  iterator erase(iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return tree_.erase(iter);
+  }
+  iterator erase(const_iterator first,
+                 const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return tree_.erase_range(iterator(first), iterator(last)).second;
   }
   template <typename K = key_type>
@@ -170,8 +197,8 @@
   }
 
   // Extract routines.
-  extract_and_get_next_return_type extract_and_get_next(
-      const_iterator position) {
+  extract_and_get_next_return_type extract_and_get_next(const_iterator position)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     // Use Construct instead of Transfer because the rebalancing code will
     // destroy the slot later.
     // Note: we rely on erase() taking place after Construct().
@@ -298,32 +325,38 @@
       : btree_set_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
-  std::pair<iterator, bool> insert(const value_type &v) {
+  std::pair<iterator, bool> insert(const value_type &v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_.insert_unique(params_type::key(v), v);
   }
-  std::pair<iterator, bool> insert(value_type &&v) {
+  std::pair<iterator, bool> insert(value_type &&v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_.insert_unique(params_type::key(v), std::move(v));
   }
   template <typename... Args>
-  std::pair<iterator, bool> emplace(Args &&... args) {
+  std::pair<iterator, bool> emplace(Args &&...args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     // Use a node handle to manage a temp slot.
     auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
                                                    std::forward<Args>(args)...);
     auto *slot = CommonAccess::GetSlot(node);
     return this->tree_.insert_unique(params_type::key(slot), slot);
   }
-  iterator insert(const_iterator hint, const value_type &v) {
+  iterator insert(const_iterator hint,
+                  const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_
         .insert_hint_unique(iterator(hint), params_type::key(v), v)
         .first;
   }
-  iterator insert(const_iterator hint, value_type &&v) {
+  iterator insert(const_iterator hint,
+                  value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_
         .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
         .first;
   }
   template <typename... Args>
-  iterator emplace_hint(const_iterator hint, Args &&... args) {
+  iterator emplace_hint(const_iterator hint,
+                        Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     // Use a node handle to manage a temp slot.
     auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
                                                    std::forward<Args>(args)...);
@@ -339,7 +372,7 @@
   void insert(std::initializer_list<init_type> init) {
     this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
   }
-  insert_return_type insert(node_type &&node) {
+  insert_return_type insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (!node) return {this->end(), false, node_type()};
     std::pair<iterator, bool> res =
         this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)),
@@ -351,7 +384,8 @@
       return {res.first, false, std::move(node)};
     }
   }
-  iterator insert(const_iterator hint, node_type &&node) {
+  iterator insert(const_iterator hint,
+                  node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (!node) return this->end();
     std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
         iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
@@ -434,37 +468,43 @@
   // Note: the nullptr template arguments and extra `const M&` overloads allow
   // for supporting bitfield arguments.
   template <typename K = key_type, class M>
-  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k,
-                                             const M &obj) {
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, const M &obj)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(k, obj);
   }
   template <typename K = key_type, class M, K * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) {
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(std::forward<K>(k), obj);
   }
   template <typename K = key_type, class M, M * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) {
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(k, std::forward<M>(obj));
   }
   template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) {
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
   }
   template <typename K = key_type, class M>
   iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
-                            const M &obj) {
+                            const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_hint_impl(hint, k, obj);
   }
   template <typename K = key_type, class M, K * = nullptr>
-  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, const M &obj) {
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k,
+                            const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
   }
   template <typename K = key_type, class M, M * = nullptr>
-  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, M &&obj) {
+  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
+                            M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
   }
   template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
-  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, M &&obj) {
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k,
+                            M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_hint_impl(hint, std::forward<K>(k),
                                       std::forward<M>(obj));
   }
@@ -472,44 +512,48 @@
   template <typename K = key_type, typename... Args,
             typename absl::enable_if_t<
                 !std::is_convertible<K, const_iterator>::value, int> = 0>
-  std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&... args) {
+  std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&...args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_impl(k, std::forward<Args>(args)...);
   }
   template <typename K = key_type, typename... Args,
             typename absl::enable_if_t<
                 !std::is_convertible<K, const_iterator>::value, int> = 0>
-  std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&... args) {
+  std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&...args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
   }
   template <typename K = key_type, typename... Args>
   iterator try_emplace(const_iterator hint, const key_arg<K> &k,
-                       Args &&... args) {
+                       Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
   }
   template <typename K = key_type, typename... Args>
-  iterator try_emplace(const_iterator hint, key_arg<K> &&k, Args &&... args) {
+  iterator try_emplace(const_iterator hint, key_arg<K> &&k,
+                       Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_hint_impl(hint, std::forward<K>(k),
                                  std::forward<Args>(args)...);
   }
 
   template <typename K = key_type>
-  mapped_type &operator[](const key_arg<K> &k) {
+  mapped_type &operator[](const key_arg<K> &k) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace(k).first->second;
   }
   template <typename K = key_type>
-  mapped_type &operator[](key_arg<K> &&k) {
+  mapped_type &operator[](key_arg<K> &&k) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace(std::forward<K>(k)).first->second;
   }
 
   template <typename K = key_type>
-  mapped_type &at(const key_arg<K> &key) {
+  mapped_type &at(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = this->find(key);
     if (it == this->end())
       base_internal::ThrowStdOutOfRange("absl::btree_map::at");
     return it->second;
   }
   template <typename K = key_type>
-  const mapped_type &at(const key_arg<K> &key) const {
+  const mapped_type &at(const key_arg<K> &key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = this->find(key);
     if (it == this->end())
       base_internal::ThrowStdOutOfRange("absl::btree_map::at");
@@ -600,14 +644,18 @@
       : btree_multiset_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
-  iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
-  iterator insert(value_type &&v) {
+  iterator insert(const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return this->tree_.insert_multi(v);
+  }
+  iterator insert(value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_.insert_multi(std::move(v));
   }
-  iterator insert(const_iterator hint, const value_type &v) {
+  iterator insert(const_iterator hint,
+                  const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_.insert_hint_multi(iterator(hint), v);
   }
-  iterator insert(const_iterator hint, value_type &&v) {
+  iterator insert(const_iterator hint,
+                  value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
   }
   template <typename InputIterator>
@@ -618,21 +666,22 @@
     this->tree_.insert_iterator_multi(init.begin(), init.end());
   }
   template <typename... Args>
-  iterator emplace(Args &&... args) {
+  iterator emplace(Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     // Use a node handle to manage a temp slot.
     auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
                                                    std::forward<Args>(args)...);
     return this->tree_.insert_multi(CommonAccess::GetSlot(node));
   }
   template <typename... Args>
-  iterator emplace_hint(const_iterator hint, Args &&... args) {
+  iterator emplace_hint(const_iterator hint,
+                        Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     // Use a node handle to manage a temp slot.
     auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
                                                    std::forward<Args>(args)...);
     return this->tree_.insert_hint_multi(iterator(hint),
                                          CommonAccess::GetSlot(node));
   }
-  iterator insert(node_type &&node) {
+  iterator insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (!node) return this->end();
     iterator res =
         this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)),
@@ -640,7 +689,8 @@
     CommonAccess::Destroy(&node);
     return res;
   }
-  iterator insert(const_iterator hint, node_type &&node) {
+  iterator insert(const_iterator hint,
+                  node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (!node) return this->end();
     iterator res = this->tree_.insert_hint_multi(
         iterator(hint),
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h b/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h
index c7df2ef..2d5a8710 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h
@@ -71,43 +71,51 @@
   //   m.insert_or_assign(n, n);
   template <class K = key_type, class V = mapped_type, K* = nullptr,
             V* = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
   }
 
   template <class K = key_type, class V = mapped_type, K* = nullptr>
-  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(std::forward<K>(k), v);
   }
 
   template <class K = key_type, class V = mapped_type, V* = nullptr>
-  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(k, std::forward<V>(v));
   }
 
   template <class K = key_type, class V = mapped_type>
-  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign_impl(k, v);
   }
 
   template <class K = key_type, class V = mapped_type, K* = nullptr,
             V* = nullptr>
-  iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k,
+                            V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
   }
 
   template <class K = key_type, class V = mapped_type, K* = nullptr>
-  iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) {
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k,
+                            const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign(std::forward<K>(k), v).first;
   }
 
   template <class K = key_type, class V = mapped_type, V* = nullptr>
-  iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) {
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k,
+                            V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign(k, std::forward<V>(v)).first;
   }
 
   template <class K = key_type, class V = mapped_type>
-  iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v) {
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k,
+                            const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert_or_assign(k, v).first;
   }
 
@@ -118,29 +126,33 @@
             typename std::enable_if<
                 !std::is_convertible<K, const_iterator>::value, int>::type = 0,
             K* = nullptr>
-  std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) {
+  std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
   }
 
   template <class K = key_type, class... Args,
             typename std::enable_if<
                 !std::is_convertible<K, const_iterator>::value, int>::type = 0>
-  std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args) {
+  std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace_impl(k, std::forward<Args>(args)...);
   }
 
   template <class K = key_type, class... Args, K* = nullptr>
-  iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
+  iterator try_emplace(const_iterator, key_arg<K>&& k,
+                       Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
   }
 
   template <class K = key_type, class... Args>
-  iterator try_emplace(const_iterator, const key_arg<K>& k, Args&&... args) {
+  iterator try_emplace(const_iterator, const key_arg<K>& k,
+                       Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return try_emplace(k, std::forward<Args>(args)...).first;
   }
 
   template <class K = key_type, class P = Policy>
-  MappedReference<P> at(const key_arg<K>& key) {
+  MappedReference<P> at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = this->find(key);
     if (it == this->end()) {
       base_internal::ThrowStdOutOfRange(
@@ -150,7 +162,8 @@
   }
 
   template <class K = key_type, class P = Policy>
-  MappedConstReference<P> at(const key_arg<K>& key) const {
+  MappedConstReference<P> at(const key_arg<K>& key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = this->find(key);
     if (it == this->end()) {
       base_internal::ThrowStdOutOfRange(
@@ -160,18 +173,21 @@
   }
 
   template <class K = key_type, class P = Policy, K* = nullptr>
-  MappedReference<P> operator[](key_arg<K>&& key) {
+  MappedReference<P> operator[](key_arg<K>&& key)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return Policy::value(&*try_emplace(std::forward<K>(key)).first);
   }
 
   template <class K = key_type, class P = Policy>
-  MappedReference<P> operator[](const key_arg<K>& key) {
+  MappedReference<P> operator[](const key_arg<K>& key)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return Policy::value(&*try_emplace(key).first);
   }
 
  private:
   template <class K, class V>
-  std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v) {
+  std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto res = this->find_or_prepare_insert(k);
     if (res.second)
       this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
@@ -181,7 +197,8 @@
   }
 
   template <class K = key_type, class... Args>
-  std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args) {
+  std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto res = this->find_or_prepare_insert(k);
     if (res.second)
       this->emplace_at(res.first, std::piecewise_construct,
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
index 93d3680..df7ff79 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -1828,19 +1828,25 @@
     infoz().Unregister();
   }
 
-  iterator begin() {
+  iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = iterator_at(0);
     it.skip_empty_or_deleted();
     return it;
   }
-  iterator end() { return iterator(common().generation_ptr()); }
+  iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return iterator(common().generation_ptr());
+  }
 
-  const_iterator begin() const {
+  const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_cast<raw_hash_set*>(this)->begin();
   }
-  const_iterator end() const { return iterator(common().generation_ptr()); }
-  const_iterator cbegin() const { return begin(); }
-  const_iterator cend() const { return end(); }
+  const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return iterator(common().generation_ptr());
+  }
+  const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+    return begin();
+  }
+  const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
 
   bool empty() const { return !size(); }
   size_t size() const { return common().size_; }
@@ -1887,7 +1893,7 @@
   template <class T, RequiresInsertable<T> = 0, class T2 = T,
             typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
             T* = nullptr>
-  std::pair<iterator, bool> insert(T&& value) {
+  std::pair<iterator, bool> insert(T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(std::forward<T>(value));
   }
 
@@ -1905,7 +1911,8 @@
   template <
       class T, RequiresInsertable<const T&> = 0,
       typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
-  std::pair<iterator, bool> insert(const T& value) {
+  std::pair<iterator, bool> insert(const T& value)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(value);
   }
 
@@ -1914,7 +1921,8 @@
   //
   //   flat_hash_map<std::string, int> s;
   //   s.insert({"abc", 42});
-  std::pair<iterator, bool> insert(init_type&& value) {
+  std::pair<iterator, bool> insert(init_type&& value)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(std::move(value));
   }
 
@@ -1923,18 +1931,20 @@
   template <class T, RequiresInsertable<T> = 0, class T2 = T,
             typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
             T* = nullptr>
-  iterator insert(const_iterator, T&& value) {
+  iterator insert(const_iterator, T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert(std::forward<T>(value)).first;
   }
 
   template <
       class T, RequiresInsertable<const T&> = 0,
       typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
-  iterator insert(const_iterator, const T& value) {
+  iterator insert(const_iterator,
+                  const T& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert(value).first;
   }
 
-  iterator insert(const_iterator, init_type&& value) {
+  iterator insert(const_iterator,
+                  init_type&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return insert(std::move(value)).first;
   }
 
@@ -1952,7 +1962,7 @@
     insert(ilist.begin(), ilist.end());
   }
 
-  insert_return_type insert(node_type&& node) {
+  insert_return_type insert(node_type&& node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     if (!node) return {end(), false, node_type()};
     const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
     auto res = PolicyTraits::apply(
@@ -1966,7 +1976,8 @@
     }
   }
 
-  iterator insert(const_iterator, node_type&& node) {
+  iterator insert(const_iterator,
+                  node_type&& node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto res = insert(std::move(node));
     node = std::move(res.node);
     return res.position;
@@ -1983,7 +1994,8 @@
   //   m.emplace("abc", "xyz");
   template <class... Args, typename std::enable_if<
                                IsDecomposable<Args...>::value, int>::type = 0>
-  std::pair<iterator, bool> emplace(Args&&... args) {
+  std::pair<iterator, bool> emplace(Args&&... args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return PolicyTraits::apply(EmplaceDecomposable{*this},
                                std::forward<Args>(args)...);
   }
@@ -1993,7 +2005,8 @@
   // destroys.
   template <class... Args, typename std::enable_if<
                                !IsDecomposable<Args...>::value, int>::type = 0>
-  std::pair<iterator, bool> emplace(Args&&... args) {
+  std::pair<iterator, bool> emplace(Args&&... args)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     alignas(slot_type) unsigned char raw[sizeof(slot_type)];
     slot_type* slot = reinterpret_cast<slot_type*>(&raw);
 
@@ -2003,7 +2016,8 @@
   }
 
   template <class... Args>
-  iterator emplace_hint(const_iterator, Args&&... args) {
+  iterator emplace_hint(const_iterator,
+                        Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return emplace(std::forward<Args>(args)...).first;
   }
 
@@ -2053,7 +2067,8 @@
   };
 
   template <class K = key_type, class F>
-  iterator lazy_emplace(const key_arg<K>& key, F&& f) {
+  iterator lazy_emplace(const key_arg<K>& key,
+                        F&& f) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto res = find_or_prepare_insert(key);
     if (res.second) {
       slot_type* slot = slot_array() + res.first;
@@ -2103,7 +2118,8 @@
     erase_meta_only(it);
   }
 
-  iterator erase(const_iterator first, const_iterator last) {
+  iterator erase(const_iterator first,
+                 const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     while (first != last) {
       erase(first++);
     }
@@ -2232,7 +2248,8 @@
   // 2. The type of the key argument doesn't have to be key_type. This is so
   // called heterogeneous key support.
   template <class K = key_type>
-  iterator find(const key_arg<K>& key, size_t hash) {
+  iterator find(const key_arg<K>& key,
+                size_t hash) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto seq = probe(common(), hash);
     slot_type* slot_ptr = slot_array();
     const ctrl_t* ctrl = control();
@@ -2250,17 +2267,19 @@
     }
   }
   template <class K = key_type>
-  iterator find(const key_arg<K>& key) {
+  iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     prefetch_heap_block();
     return find(key, hash_ref()(key));
   }
 
   template <class K = key_type>
-  const_iterator find(const key_arg<K>& key, size_t hash) const {
+  const_iterator find(const key_arg<K>& key,
+                      size_t hash) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return const_cast<raw_hash_set*>(this)->find(key, hash);
   }
   template <class K = key_type>
-  const_iterator find(const key_arg<K>& key) const {
+  const_iterator find(const key_arg<K>& key) const
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     prefetch_heap_block();
     return find(key, hash_ref()(key));
   }
@@ -2271,14 +2290,15 @@
   }
 
   template <class K = key_type>
-  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key)
+      ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = find(key);
     if (it != end()) return {it, std::next(it)};
     return {it, it};
   }
   template <class K = key_type>
   std::pair<const_iterator, const_iterator> equal_range(
-      const key_arg<K>& key) const {
+      const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     auto it = find(key);
     if (it != end()) return {it, std::next(it)};
     return {it, it};
@@ -2606,10 +2626,10 @@
            "constructed value does not match the lookup key");
   }
 
-  iterator iterator_at(size_t i) {
+  iterator iterator_at(size_t i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return {control() + i, slot_array() + i, common().generation_ptr()};
   }
-  const_iterator iterator_at(size_t i) const {
+  const_iterator iterator_at(size_t i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return {control() + i, slot_array() + i, common().generation_ptr()};
   }
 
diff --git a/third_party/abseil-cpp/absl/container/node_hash_map.h b/third_party/abseil-cpp/absl/container/node_hash_map.h
index 6868e63..dc8d7d9a 100644
--- a/third_party/abseil-cpp/absl/container/node_hash_map.h
+++ b/third_party/abseil-cpp/absl/container/node_hash_map.h
@@ -404,7 +404,7 @@
   // for the past-the-end iterator, which is invalidated.
   //
   // `swap()` requires that the node hash map's hashing and key equivalence
-  // functions be Swappable, and are exchaged using unqualified calls to
+  // functions be Swappable, and are exchanged using unqualified calls to
   // non-member `swap()`. If the map's allocator has
   // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
   // set to `true`, the allocators are also exchanged using an unqualified call
diff --git a/third_party/abseil-cpp/absl/crc/internal/crc.h b/third_party/abseil-cpp/absl/crc/internal/crc.h
index 08afba3..e683c25 100644
--- a/third_party/abseil-cpp/absl/crc/internal/crc.h
+++ b/third_party/abseil-cpp/absl/crc/internal/crc.h
@@ -68,7 +68,7 @@
   // any reduction of error-detection ability in the outer CRC.
   // Unscramble() performs the inverse transformation.
   // It is strongly recommended that CRCs be scrambled before storage or
-  // transmission, and unscrambled at the other end before futher manipulation.
+  // transmission, and unscrambled at the other end before further manipulation.
   virtual void Scramble(uint32_t* crc) const = 0;
   virtual void Unscramble(uint32_t* crc) const = 0;
 
diff --git a/third_party/abseil-cpp/absl/crc/internal/crc_cord_state.h b/third_party/abseil-cpp/absl/crc/internal/crc_cord_state.h
index cbcff053..fbbb8c0 100644
--- a/third_party/abseil-cpp/absl/crc/internal/crc_cord_state.h
+++ b/third_party/abseil-cpp/absl/crc/internal/crc_cord_state.h
@@ -109,7 +109,7 @@
   // Returns true if the chunked CRC32C cached is normalized.
   bool IsNormalized() const { return rep().removed_prefix.length == 0; }
 
-  // Normalizes the chunked CRC32C checksum cache by substracting any removed
+  // Normalizes the chunked CRC32C checksum cache by subtracting any removed
   // prefix from the chunks.
   void Normalize();
 
diff --git a/third_party/abseil-cpp/absl/crc/internal/crc_internal.h b/third_party/abseil-cpp/absl/crc/internal/crc_internal.h
index 97083423..7d77bdf5 100644
--- a/third_party/abseil-cpp/absl/crc/internal/crc_internal.h
+++ b/third_party/abseil-cpp/absl/crc/internal/crc_internal.h
@@ -60,7 +60,7 @@
 constexpr uint64_t kScrambleLo = (static_cast<uint64_t>(0xf9ce6030U) << 32) |
                                  static_cast<uint64_t>(0x2e76e41bU);
 
-class CRCImpl : public CRC {  // Implemention of the abstract class CRC
+class CRCImpl : public CRC {  // Implementation of the abstract class CRC
  public:
   using Uint32By256 = uint32_t[256];
 
diff --git a/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc b/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
index e482b37a..ef521d2 100644
--- a/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
+++ b/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
@@ -515,7 +515,7 @@
       }
 
       for (size_t i = 1; i < bs; i++) {
-        // Prefetch data for next itterations.
+        // Prefetch data for next iterations.
         for (size_t j = 0; j < num_crc_streams; j++) {
           PrefetchToLocalCache(
               reinterpret_cast<const char*>(crc_streams[j] + kPrefetchHorizon));
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
index 86063da..e89dbae8 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -49,6 +49,7 @@
         ":debugging_internal",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
         "//absl/base:raw_logging_internal",
     ],
 )
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn
index 1d0ba6e5..2c61d53 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.gn
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn
@@ -24,6 +24,7 @@
     ":debugging_internal",
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/base:dynamic_annotations",
     "//third_party/abseil-cpp/absl/base:raw_logging_internal",
   ]
 }
diff --git a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
index 8f29cc0..ef6b496 100644
--- a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
@@ -41,6 +41,7 @@
     absl::debugging_internal
     absl::config
     absl::core_headers
+    absl::dynamic_annotations
     absl::raw_logging_internal
   PUBLIC
 )
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag.h b/third_party/abseil-cpp/absl/flags/commandlineflag.h
index f2fa089..c30aa60 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag.h
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag.h
@@ -186,7 +186,7 @@
   // command line.
   virtual bool IsSpecifiedOnCommandLine() const = 0;
 
-  // Validates supplied value usign validator or parseflag routine
+  // Validates supplied value using validator or parseflag routine
   virtual bool ValidateInputValue(absl::string_view value) const = 0;
 
   // Checks that flags default value can be converted to string and back to the
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.cc b/third_party/abseil-cpp/absl/flags/internal/flag.cc
index 8da820e..65d0e58 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/flag.cc
@@ -238,7 +238,7 @@
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kValueAndInitBit:
     case FlagValueStorageKind::kOneWordAtomic: {
-      // Load the current value to avoid setting 'init' bit manualy.
+      // Load the current value to avoid setting 'init' bit manually.
       int64_t one_word_val = OneWordValue().load(std::memory_order_acquire);
       std::memcpy(&one_word_val, src, Sizeof(op_));
       OneWordValue().store(one_word_val, std::memory_order_release);
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.h b/third_party/abseil-cpp/absl/flags/internal/flag.h
index d7edb8c..b41f9a69 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag.h
+++ b/third_party/abseil-cpp/absl/flags/internal/flag.h
@@ -223,12 +223,12 @@
 // first overload if possible. If help message is evaluatable on constexpr
 // context We'll be able to make FixedCharArray out of it and we'll choose first
 // overload. In this case the help message expression is immediately evaluated
-// and is used to construct the absl::Flag. No additionl code is generated by
+// and is used to construct the absl::Flag. No additional code is generated by
 // ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the
 // consideration, in which case the second overload will be used. The second
 // overload does not attempt to evaluate the help message expression
-// immediately and instead delays the evaluation by returing the function
-// pointer (&T::NonConst) genering the help message when necessary. This is
+// immediately and instead delays the evaluation by returning the function
+// pointer (&T::NonConst) generating the help message when necessary. This is
 // evaluatable in constexpr context, but the cost is an extra function being
 // generated in the ABSL_FLAG code.
 template <typename Gen, size_t N>
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag_msvc.inc b/third_party/abseil-cpp/absl/flags/internal/flag_msvc.inc
index c31bd27..614d09f 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag_msvc.inc
+++ b/third_party/abseil-cpp/absl/flags/internal/flag_msvc.inc
@@ -29,7 +29,7 @@
 // second level of protection is a global Mutex, so if two threads attempt to
 // construct the flag concurrently only one wins.
 //
-// This solution is based on a recomendation here:
+// This solution is based on a recommendation here:
 // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html?childToView=648454#comment-648454
 
 namespace flags_internal {
diff --git a/third_party/abseil-cpp/absl/functional/function_ref_test.cc b/third_party/abseil-cpp/absl/functional/function_ref_test.cc
index f91e15e..c61117eb 100644
--- a/third_party/abseil-cpp/absl/functional/function_ref_test.cc
+++ b/third_party/abseil-cpp/absl/functional/function_ref_test.cc
@@ -257,7 +257,7 @@
       "Reference types should be preserved");
 
   // Make sure the address of an object received by reference is the same as the
-  // addess of the object passed by the caller.
+  // address of the object passed by the caller.
   {
     LargeTrivial obj;
     auto test = [&obj](LargeTrivial& input) { ASSERT_EQ(&input, &obj); };
diff --git a/third_party/abseil-cpp/absl/random/internal/uniform_helper.h b/third_party/abseil-cpp/absl/random/internal/uniform_helper.h
index e68b82e..db737e1 100644
--- a/third_party/abseil-cpp/absl/random/internal/uniform_helper.h
+++ b/third_party/abseil-cpp/absl/random/internal/uniform_helper.h
@@ -217,7 +217,7 @@
 // UniformDistributionWrapper is used as the underlying distribution type
 // by the absl::Uniform template function. It selects the proper Abseil
 // uniform distribution and provides constructor overloads that match the
-// expected parameter order as well as adjusting distribtuion bounds based
+// expected parameter order as well as adjusting distribution bounds based
 // on the tag.
 template <typename NumType>
 struct UniformDistributionWrapper : public UniformDistribution<NumType> {
diff --git a/third_party/abseil-cpp/absl/status/statusor.h b/third_party/abseil-cpp/absl/status/statusor.h
index beedd79..935366d 100644
--- a/third_party/abseil-cpp/absl/status/statusor.h
+++ b/third_party/abseil-cpp/absl/status/statusor.h
@@ -146,7 +146,7 @@
 //
 //   absl::StatusOr<int> i = GetCount();
 //   if (i.ok()) {
-//     updated_total += *i
+//     updated_total += *i;
 //   }
 //
 // NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will
@@ -612,6 +612,21 @@
     return this->data_;
   }
 
+  // StatusOr<T>::AssignStatus()
+  //
+  // Sets the status of `absl::StatusOr<T>` to the given non-ok status value.
+  //
+  // NOTE: We recommend using the constructor and `operator=` where possible.
+  // This method is intended for use in generic programming, to enable setting
+  // the status of a `StatusOr<T>` when `T` may be `Status`. In that case, the
+  // constructor and `operator=` would assign into the inner value of type
+  // `Status`, rather than status of the `StatusOr` (b/280392796).
+  //
+  // REQUIRES: !Status(std::forward<U>(v)).ok(). This requirement is DCHECKed.
+  // In optimized builds, passing absl::OkStatus() here will have the effect
+  // of passing absl::StatusCode::kInternal as a fallback.
+  using internal_statusor::StatusOrData<T>::AssignStatus;
+
  private:
   using internal_statusor::StatusOrData<T>::Assign;
   template <typename U>
diff --git a/third_party/abseil-cpp/absl/status/statusor_test.cc b/third_party/abseil-cpp/absl/status/statusor_test.cc
index 2902154..e65f5d2 100644
--- a/third_party/abseil-cpp/absl/status/statusor_test.cc
+++ b/third_party/abseil-cpp/absl/status/statusor_test.cc
@@ -1844,4 +1844,37 @@
   }
 }
 
+TEST(StatusOr, StatusAssignmentFromStatusError) {
+  absl::StatusOr<absl::Status> statusor;
+  statusor.AssignStatus(absl::CancelledError());
+
+  EXPECT_FALSE(statusor.ok());
+  EXPECT_EQ(statusor.status(), absl::CancelledError());
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(StatusOr, StatusAssignmentFromStatusOk) {
+  EXPECT_DEBUG_DEATH(
+      {
+        absl::StatusOr<absl::Status> statusor;
+        // This will DCHECK.
+        statusor.AssignStatus(absl::OkStatus());
+        // In optimized mode, we are actually going to get error::INTERNAL for
+        // status here, rather than crashing, so check that.
+        EXPECT_FALSE(statusor.ok());
+        EXPECT_EQ(statusor.status().code(), absl::StatusCode::kInternal);
+      },
+      "An OK status is not a valid constructor argument to StatusOr<T>");
+}
+#endif
+
+TEST(StatusOr, StatusAssignmentFromTypeConvertibleToStatus) {
+  CustomType<MyType, kConvToStatus> v;
+  absl::StatusOr<MyType> statusor;
+  statusor.AssignStatus(v);
+
+  EXPECT_FALSE(statusor.ok());
+  EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+}
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc b/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc
index 20a5579..db7d4fe 100644
--- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc
@@ -42,7 +42,8 @@
 
 }  // namespace
 
-void Consume(CordRep* rep, ConsumeFn consume_fn) {
+void Consume(CordRep* rep,
+             FunctionRef<void(CordRep*, size_t, size_t)> consume_fn) {
   size_t offset = 0;
   size_t length = rep->length;
 
@@ -53,8 +54,9 @@
   consume_fn(rep, offset, length);
 }
 
-void ReverseConsume(CordRep* rep, ConsumeFn consume_fn) {
-  return Consume(rep, std::move(consume_fn));
+void ReverseConsume(CordRep* rep,
+                    FunctionRef<void(CordRep*, size_t, size_t)> consume_fn) {
+  return Consume(rep, consume_fn);
 }
 
 }  // namespace cord_internal
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.h b/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.h
index d46fca2..bece1874 100644
--- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.h
+++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.h
@@ -24,11 +24,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace cord_internal {
 
-// Functor for the Consume() and ReverseConsume() functions:
-//   void ConsumeFunc(CordRep* rep, size_t offset, size_t length);
-// See the Consume() and ReverseConsume() function comments for documentation.
-using ConsumeFn = FunctionRef<void(CordRep*, size_t, size_t)>;
-
 // Consume() and ReverseConsume() consume CONCAT based trees and invoke the
 // provided functor with the contained nodes in the proper forward or reverse
 // order, which is used to convert CONCAT trees into other tree or cord data.
@@ -40,8 +35,10 @@
 // violations, we can not 100% guarantee that all code respects 'new format'
 // settings and flags, so we need to be able to parse old data on the fly until
 // all old code is deprecated / no longer the default format.
-void Consume(CordRep* rep, ConsumeFn consume_fn);
-void ReverseConsume(CordRep* rep, ConsumeFn consume_fn);
+void Consume(CordRep* rep,
+             FunctionRef<void(CordRep*, size_t, size_t)> consume_fn);
+void ReverseConsume(CordRep* rep,
+                    FunctionRef<void(CordRep*, size_t, size_t)> consume_fn);
 
 }  // namespace cord_internal
 ABSL_NAMESPACE_END
diff --git a/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h b/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h
index 6035ca4..e50468b 100644
--- a/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h
+++ b/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h
@@ -13,7 +13,7 @@
 // limitations under the License.
 //
 
-// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type
+// The file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type
 // trait metafunction to assist in working with the _GLIBCXX_DEBUG debug
 // wrappers of STL containers.
 //
diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
index a0cd433..5074044 100644
--- a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
@@ -238,6 +238,7 @@
     size = "large",
     srcs = ["mutex_test.cc"],
     copts = ABSL_TEST_COPTS,
+    flaky = 1,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     shard_count = 25,
     deps = [
@@ -300,6 +301,7 @@
     size = "small",
     srcs = ["notification_test.cc"],
     copts = ABSL_TEST_COPTS,
+    flaky = 1,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     tags = ["no_test_lexan"],
     deps = [
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/futex_waiter.cc b/third_party/abseil-cpp/absl/synchronization/internal/futex_waiter.cc
index 7c07fbe..87eb3b23c 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/futex_waiter.cc
+++ b/third_party/abseil-cpp/absl/synchronization/internal/futex_waiter.cc
@@ -63,7 +63,6 @@
   // Note that, since the thread ticker is just reset, we don't need to check
   // whether the thread is idle on the very first pass of the loop.
   bool first_pass = true;
-
   while (true) {
     int32_t x = futex_.load(std::memory_order_relaxed);
     while (x != 0) {
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index 29c049d..8bbcae8 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -273,7 +273,7 @@
   // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`.
   //
   // These methods may be used (along with the complementary `Reader*()`
-  // methods) to distingish simple exclusive `Mutex` usage (`Lock()`,
+  // methods) to distinguish simple exclusive `Mutex` usage (`Lock()`,
   // etc.) from reader/writer lock usage.
   void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
 
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex_method_pointer_test.cc b/third_party/abseil-cpp/absl/synchronization/mutex_method_pointer_test.cc
index 1ec801a..f4c82d2 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex_method_pointer_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex_method_pointer_test.cc
@@ -26,8 +26,8 @@
 
 #ifdef _MSC_VER
 // These tests verify expectations about sizes of MSVC pointers to methods.
-// Pointers to methods are distinguished by whether their class hierachies
-// contain single inheritance, multiple inheritance, or virtual inheritence.
+// Pointers to methods are distinguished by whether their class hierarchies
+// contain single inheritance, multiple inheritance, or virtual inheritance.
 
 // Declare classes of the various MSVC inheritance types.
 class __single_inheritance SingleInheritance{};
diff --git a/third_party/abseil-cpp/absl/time/civil_time_test.cc b/third_party/abseil-cpp/absl/time/civil_time_test.cc
index 0ebd97ad..ec435ac7 100644
--- a/third_party/abseil-cpp/absl/time/civil_time_test.cc
+++ b/third_party/abseil-cpp/absl/time/civil_time_test.cc
@@ -1228,7 +1228,7 @@
   EXPECT_EQ(0, day_floor.hour());  // 09:09:09 is floored
   EXPECT_EQ(absl::CivilDay(2015, 1, 2), day_floor);
 
-  // Unspecified fields default to their minium value
+  // Unspecified fields default to their minimum value
   absl::CivilDay day_default(2015);  // Defaults to Jan 1
   EXPECT_EQ(absl::CivilDay(2015, 1, 1), day_default);
 
diff --git a/third_party/abseil-cpp/absl/time/time.cc b/third_party/abseil-cpp/absl/time/time.cc
index 7256a69..a11e8e9b 100644
--- a/third_party/abseil-cpp/absl/time/time.cc
+++ b/third_party/abseil-cpp/absl/time/time.cc
@@ -137,7 +137,7 @@
 }
 
 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
-// necessary. If sec is min/max, then consult cs+tz to check for overlow.
+// necessary. If sec is min/max, then consult cs+tz to check for overflow.
 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
                           const cctz::civil_second& cs,
                           const cctz::time_zone& tz,
diff --git a/third_party/abseil-cpp/absl/types/any.h b/third_party/abseil-cpp/absl/types/any.h
index 204da26..61f071f 100644
--- a/third_party/abseil-cpp/absl/types/any.h
+++ b/third_party/abseil-cpp/absl/types/any.h
@@ -53,6 +53,7 @@
 #ifndef ABSL_TYPES_ANY_H_
 #define ABSL_TYPES_ANY_H_
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/utility/utility.h"
 
@@ -288,7 +289,7 @@
       typename T, typename... Args, typename VT = absl::decay_t<T>,
       absl::enable_if_t<std::is_copy_constructible<VT>::value &&
                         std::is_constructible<VT, Args...>::value>* = nullptr>
-  VT& emplace(Args&&... args) {
+  VT& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     reset();  // NOTE: reset() is required here even in the world of exceptions.
     Obj<VT>* const object_ptr =
         new Obj<VT>(in_place, std::forward<Args>(args)...);
@@ -312,7 +313,8 @@
       absl::enable_if_t<std::is_copy_constructible<VT>::value &&
                         std::is_constructible<VT, std::initializer_list<U>&,
                                               Args...>::value>* = nullptr>
-  VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
+  VT& emplace(std::initializer_list<U> ilist,
+              Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     reset();  // NOTE: reset() is required here even in the world of exceptions.
     Obj<VT>* const object_ptr =
         new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
diff --git a/third_party/abseil-cpp/absl/types/optional.h b/third_party/abseil-cpp/absl/types/optional.h
index e42ab4d0..0a8080d 100644
--- a/third_party/abseil-cpp/absl/types/optional.h
+++ b/third_party/abseil-cpp/absl/types/optional.h
@@ -357,7 +357,7 @@
   template <typename... Args,
             typename = typename std::enable_if<
                 std::is_constructible<T, Args&&...>::value>::type>
-  T& emplace(Args&&... args) {
+  T& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     this->destruct();
     this->construct(std::forward<Args>(args)...);
     return reference();
@@ -377,7 +377,8 @@
   template <typename U, typename... Args,
             typename = typename std::enable_if<std::is_constructible<
                 T, std::initializer_list<U>&, Args&&...>::value>::type>
-  T& emplace(std::initializer_list<U> il, Args&&... args) {
+  T& emplace(std::initializer_list<U> il,
+             Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
     this->destruct();
     this->construct(il, std::forward<Args>(args)...);
     return reference();
@@ -414,11 +415,11 @@
   // `optional` is empty, behavior is undefined.
   //
   // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
-  const T* operator->() const {
+  const T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(this->engaged_);
     return std::addressof(this->data_);
   }
-  T* operator->() {
+  T* operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(this->engaged_);
     return std::addressof(this->data_);
   }
@@ -427,17 +428,17 @@
   //
   // Accesses the underlying `T` value of an `optional`. If the `optional` is
   // empty, behavior is undefined.
-  constexpr const T& operator*() const& {
+  constexpr const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return ABSL_HARDENING_ASSERT(this->engaged_), reference();
   }
-  T& operator*() & {
+  T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(this->engaged_);
     return reference();
   }
-  constexpr const T&& operator*() const && {
+  constexpr const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return ABSL_HARDENING_ASSERT(this->engaged_), absl::move(reference());
   }
-  T&& operator*() && {
+  T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
     ABSL_HARDENING_ASSERT(this->engaged_);
     return std::move(reference());
   }
@@ -472,23 +473,24 @@
   // and lvalue/rvalue-ness of the `optional` is preserved to the view of
   // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional`
   // is empty.
-  constexpr const T& value() const & {
+  constexpr const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return static_cast<bool>(*this)
                ? reference()
                : (optional_internal::throw_bad_optional_access(), reference());
   }
-  T& value() & {
+  T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return static_cast<bool>(*this)
                ? reference()
                : (optional_internal::throw_bad_optional_access(), reference());
   }
-  T&& value() && {  // NOLINT(build/c++11)
+  T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND {  // NOLINT(build/c++11)
     return std::move(
         static_cast<bool>(*this)
             ? reference()
             : (optional_internal::throw_bad_optional_access(), reference()));
   }
-  constexpr const T&& value() const && {  // NOLINT(build/c++11)
+  constexpr const T&& value()
+      const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {  // NOLINT(build/c++11)
     return absl::move(
         static_cast<bool>(*this)
             ? reference()
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc
index 7353441f..287fb75 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -77,13 +77,13 @@
     case CSSPrimitiveValue::UnitType::kViewportHeight:
     case CSSPrimitiveValue::UnitType::kViewportMin:
     case CSSPrimitiveValue::UnitType::kViewportMax:
-      return kCalcLength;
     case CSSPrimitiveValue::UnitType::kRexs:
     case CSSPrimitiveValue::UnitType::kRchs:
     case CSSPrimitiveValue::UnitType::kRics:
     case CSSPrimitiveValue::UnitType::kRlhs:
-      return RuntimeEnabledFeatures::CSSNewRootFontUnitsEnabled() ? kCalcLength
-                                                                  : kCalcOther;
+    case CSSPrimitiveValue::UnitType::kIcs:
+    case CSSPrimitiveValue::UnitType::kLhs:
+      return kCalcLength;
     case CSSPrimitiveValue::UnitType::kViewportInlineSize:
     case CSSPrimitiveValue::UnitType::kViewportBlockSize:
     case CSSPrimitiveValue::UnitType::kSmallViewportWidth:
@@ -113,12 +113,6 @@
     case CSSPrimitiveValue::UnitType::kContainerMin:
     case CSSPrimitiveValue::UnitType::kContainerMax:
       return kCalcLength;
-    case CSSPrimitiveValue::UnitType::kIcs:
-      return RuntimeEnabledFeatures::CSSIcUnitEnabled() ? kCalcLength
-                                                        : kCalcOther;
-    case CSSPrimitiveValue::UnitType::kLhs:
-      return RuntimeEnabledFeatures::CSSLhUnitEnabled() ? kCalcLength
-                                                        : kCalcOther;
     case CSSPrimitiveValue::UnitType::kDegrees:
     case CSSPrimitiveValue::UnitType::kGradians:
     case CSSPrimitiveValue::UnitType::kRadians:
diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h
index 3c375f64..19398212 100644
--- a/third_party/blink/renderer/core/css/css_variable_data.h
+++ b/third_party/blink/renderer/core/css/css_variable_data.h
@@ -128,12 +128,12 @@
                               bool& has_line_height_units);
 
   // The maximum number of bytes for a CSS variable (including text
-  // that comes from var() substitution).
+  // that comes from var() substitution). This matches Firefox.
   //
   // If you change this, length_ below may need updates.
   //
   // https://drafts.csswg.org/css-variables/#long-variables
-  static const size_t kMaxVariableBytes = 1048576;
+  static const size_t kMaxVariableBytes = 2097152;
 
  private:
   CSSVariableData()
@@ -159,16 +159,16 @@
   // balloon in size on Windows:
   // https://randomascii.wordpress.com/2010/06/06/bit-field-packing-with-visual-c/
 
-  // Enough for storing up to 1MB (and then some), cf. kMaxSubstitutionBytes.
-  // The remaining 5 bits are kept in reserve for future use.
-  const unsigned length_ : 21;
+  // Enough for storing up to 2MB (and then some), cf. kMaxSubstitutionBytes.
+  // The remaining 4 bits are kept in reserve for future use.
+  const unsigned length_ : 22;
   const unsigned is_animation_tainted_ : 1;       // bool.
   const unsigned needs_variable_resolution_ : 1;  // bool.
   const unsigned is_8bit_ : 1;                    // bool.
   unsigned has_font_units_ : 1;                   // bool.
   unsigned has_root_font_units_ : 1;              // bool.
   unsigned has_line_height_units_ : 1;            // bool.
-  const unsigned unused_ : 5;
+  const unsigned unused_ : 4;
 
   // The actual character data is stored after this.
 };
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index e168a45..d4fc41e 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -1143,14 +1143,12 @@
       case CSSPrimitiveValue::UnitType::kViewportHeight:
       case CSSPrimitiveValue::UnitType::kViewportMin:
       case CSSPrimitiveValue::UnitType::kViewportMax:
-        break;
+      case CSSPrimitiveValue::UnitType::kIcs:
+      case CSSPrimitiveValue::UnitType::kLhs:
       case CSSPrimitiveValue::UnitType::kRexs:
       case CSSPrimitiveValue::UnitType::kRchs:
       case CSSPrimitiveValue::UnitType::kRics:
       case CSSPrimitiveValue::UnitType::kRlhs:
-        if (!RuntimeEnabledFeatures::CSSNewRootFontUnitsEnabled()) {
-          return nullptr;
-        }
         break;
       case CSSPrimitiveValue::UnitType::kViewportInlineSize:
       case CSSPrimitiveValue::UnitType::kViewportBlockSize:
@@ -1183,16 +1181,6 @@
       case CSSPrimitiveValue::UnitType::kContainerMin:
       case CSSPrimitiveValue::UnitType::kContainerMax:
         break;
-      case CSSPrimitiveValue::UnitType::kIcs:
-        if (!RuntimeEnabledFeatures::CSSIcUnitEnabled()) {
-          return nullptr;
-        }
-        break;
-      case CSSPrimitiveValue::UnitType::kLhs:
-        if (!RuntimeEnabledFeatures::CSSLhUnitEnabled()) {
-          return nullptr;
-        }
-        break;
       default:
         return nullptr;
     }
diff --git a/third_party/blink/renderer/core/frame/DEPS b/third_party/blink/renderer/core/frame/DEPS
index 7fd2cf3..651c875 100644
--- a/third_party/blink/renderer/core/frame/DEPS
+++ b/third_party/blink/renderer/core/frame/DEPS
@@ -4,6 +4,7 @@
   ],
   "attribution_src_loader(\.cc|\.h|_test\.cc)": [
     "+components/attribution_reporting",
+    "+services/network/public/cpp/attribution_reporting_runtime_features.h",
     "+services/network/public/cpp/attribution_utils.h",
     "+services/network/public/cpp/trigger_verification.h",
   ],
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
index 75d52a3..8ebceff1 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -26,6 +26,7 @@
 #include "components/attribution_reporting/trigger_registration_error.mojom-shared.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/shared_remote.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/attribution_utils.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/trigger_verification.h"
@@ -137,11 +138,14 @@
   AtomicString os_trigger;
   uint64_t request_id;
 
-  AttributionHeaders(const HTTPHeaderMap& map, uint64_t request_id)
+  AttributionHeaders(const HTTPHeaderMap& map,
+                     uint64_t request_id,
+                     bool cross_app_web_runtime_enabled)
       : web_source(map.Get(http_names::kAttributionReportingRegisterSource)),
         web_trigger(map.Get(http_names::kAttributionReportingRegisterTrigger)),
         request_id(request_id) {
-    if (base::FeatureList::IsEnabled(
+    if (cross_app_web_runtime_enabled &&
+        base::FeatureList::IsEnabled(
             network::features::kAttributionReportingCrossAppWeb)) {
       os_source = map.Get(http_names::kAttributionReportingRegisterOSSource);
       os_trigger = map.Get(http_names::kAttributionReportingRegisterOSTrigger);
@@ -530,6 +534,15 @@
   return Platform::Current()->GetAttributionReportingSupport();
 }
 
+network::AttributionReportingRuntimeFeatures
+AttributionSrcLoader::GetRuntimeFeatures() const {
+  return network::AttributionReportingRuntimeFeatures{
+      .cross_app_web_enabled =
+          RuntimeEnabledFeatures::AttributionReportingCrossAppWebEnabled(
+              local_frame_->DomWindow()),
+  };
+}
+
 bool AttributionSrcLoader::MaybeRegisterAttributionHeaders(
     const ResourceRequest& request,
     const ResourceResponse& response,
@@ -548,7 +561,10 @@
   }
 
   const uint64_t request_id = request.InspectorId();
-  AttributionHeaders headers(response.HttpHeaderFields(), request_id);
+  AttributionHeaders headers(
+      response.HttpHeaderFields(), request_id,
+      RuntimeEnabledFeatures::AttributionReportingCrossAppWebEnabled(
+          local_frame_->DomWindow()));
 
   // Only handle requests which are attempting to invoke the API.
   if (headers.count() == 0) {
@@ -676,7 +692,10 @@
 void AttributionSrcLoader::ResourceClient::HandleResponseHeaders(
     const ResourceResponse& response,
     uint64_t request_id) {
-  AttributionHeaders headers(response.HttpHeaderFields(), request_id);
+  AttributionHeaders headers(
+      response.HttpHeaderFields(), request_id,
+      RuntimeEnabledFeatures::AttributionReportingCrossAppWebEnabled(
+          loader_->local_frame_->DomWindow()));
   if (headers.count() == 0) {
     return;
   }
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.h b/third_party/blink/renderer/core/frame/attribution_src_loader.h
index 564bb67..5be296d 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.h
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.h
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace network {
+struct AttributionReportingRuntimeFeatures;
 class TriggerVerification;
 }  // namespace network
 
@@ -100,6 +101,8 @@
 
   network::mojom::AttributionSupport GetSupport() const;
 
+  network::AttributionReportingRuntimeFeatures GetRuntimeFeatures() const;
+
  private:
   class ResourceClient;
 
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
index 28c58cf..5abbad6 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
@@ -25,6 +25,7 @@
 #include "third_party/blink/public/mojom/conversions/attribution_data_host.mojom-blink.h"
 #include "third_party/blink/public/mojom/conversions/conversions.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -570,10 +571,45 @@
   }
 }
 
+class AttributionSrcLoaderCrossAppWebRuntimeDisabledTest
+    : public AttributionSrcLoaderTest {
+ public:
+  AttributionSrcLoaderCrossAppWebRuntimeDisabledTest() = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      network::features::kAttributionReportingCrossAppWeb};
+
+ protected:
+  ScopedTestingPlatformSupport<AttributionTestingPlatformSupport> platform_;
+};
+
+TEST_F(AttributionSrcLoaderCrossAppWebRuntimeDisabledTest,
+       OsTriggerNotRegistered) {
+  platform_->attribution_support =
+      network::mojom::AttributionSupport::kWebAndOs;
+
+  KURL test_url = ToKURL("https://example1.com/foo.html");
+
+  ResourceRequest request(test_url);
+  auto* resource = MakeGarbageCollected<MockResource>(test_url);
+  ResourceResponse response(test_url);
+  response.SetHttpStatusCode(200);
+  response.SetHttpHeaderField(
+      http_names::kAttributionReportingRegisterOSTrigger,
+      R"("https://r.test/x")");
+
+  EXPECT_FALSE(attribution_src_loader_->MaybeRegisterAttributionHeaders(
+      request, response, resource));
+}
+
 class AttributionSrcLoaderCrossAppWebEnabledTest
     : public AttributionSrcLoaderTest {
  public:
-  AttributionSrcLoaderCrossAppWebEnabledTest() = default;
+  AttributionSrcLoaderCrossAppWebEnabledTest() {
+    WebRuntimeFeatures::EnableFeatureFromString(
+        /*name=*/"AttributionReportingCrossAppWeb", /*enable=*/true);
+  }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_{
diff --git a/third_party/blink/renderer/core/loader/DEPS b/third_party/blink/renderer/core/loader/DEPS
index 399d917..fe107da 100644
--- a/third_party/blink/renderer/core/loader/DEPS
+++ b/third_party/blink/renderer/core/loader/DEPS
@@ -15,6 +15,9 @@
     "resource_load_observer_for_worker.cc": [
         "+services/network/public/cpp/ip_address_space_util.h",
     ],
+    "frame_fetch_context.cc": [
+        "+services/network/public/cpp/attribution_reporting_runtime_features.h",
+    ],
 }
 include_rules = [
   "+base/containers/flat_map.h",
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 2e87215..8b66309 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -39,6 +39,7 @@
 #include "build/build_config.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "net/http/structured_headers.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/cpp/client_hints.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/web_client_hints_types.mojom-blink.h"
@@ -361,10 +362,12 @@
   if (document_loader_->ForceFetchCacheMode())
     request.SetCacheMode(*document_loader_->ForceFetchCacheMode());
 
-  if (AttributionSrcLoader* attribution_src_loader =
+  if (const AttributionSrcLoader* attribution_src_loader =
           GetFrame()->GetAttributionSrcLoader()) {
     request.SetAttributionReportingSupport(
         attribution_src_loader->GetSupport());
+    request.SetAttributionReportingRuntimeFeatures(
+        attribution_src_loader->GetRuntimeFeatures());
   }
 
   GetLocalFrameClient()->DispatchWillSendRequest(request);
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 13ab906..6e8d525 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -2116,7 +2116,7 @@
   }
 
   if (IsMissingActualFragment()) {
-    // TODO(crbug.com/1442211): Handle clipping correctly when the ancestor
+    // TODO(crbug.com/1418917): Handle clipping correctly when the ancestor
     // fragment is missing. For now, don't apply any clipping in such
     // situations, since we risk overclipping.
     return;
@@ -2181,7 +2181,7 @@
 
   if (NeedsPaintPropertyUpdate()) {
     if (IsMissingActualFragment()) {
-      // TODO(crbug.com/1442211): Handle clipping correctly when the ancestor
+      // TODO(crbug.com/1418917): Handle clipping correctly when the ancestor
       // fragment is missing. For now, don't apply any clipping in such
       // situations, since we risk overclipping.
       return;
@@ -2220,7 +2220,7 @@
 
   if (NeedsPaintPropertyUpdate()) {
     if (IsMissingActualFragment()) {
-      // TODO(crbug.com/1442211): Handle clipping correctly when the ancestor
+      // TODO(crbug.com/1418917): Handle clipping correctly when the ancestor
       // fragment is missing. For now, don't apply any clipping in such
       // situations, since we risk overclipping.
       return;
diff --git a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
index d87d3615..2fdb472 100644
--- a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
@@ -52,7 +52,8 @@
     media::VideoCodecProfile codec,
     absl::optional<uint8_t> level,
     const gfx::Size& size,
-    bool use_native_input)
+    bool use_native_input,
+    bool is_screencast)
     : Encoder(std::move(encoding_task_runner),
               on_encoded_video_cb,
               bits_per_second > 0
@@ -64,6 +65,7 @@
       bitrate_mode_(bitrate_mode),
       size_(size),
       use_native_input_(use_native_input),
+      is_screencast_(is_screencast),
       error_notified_(false),
       num_frames_after_keyframe_(0),
       force_next_frame_to_be_keyframe_(false),
@@ -309,7 +311,9 @@
   const media::VideoEncodeAccelerator::Config config(
       pixel_format, input_visible_size_, codec_, bitrate, absl::nullopt,
       absl::nullopt, level_, false, storage_type,
-      media::VideoEncodeAccelerator::Config::ContentType::kCamera);
+      is_screencast_
+          ? media::VideoEncodeAccelerator::Config::ContentType::kDisplay
+          : media::VideoEncodeAccelerator::Config::ContentType::kCamera);
   if (!video_encoder_ ||
       !video_encoder_->Initialize(config, this,
                                   std::make_unique<media::NullMediaLog>())) {
diff --git a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
index 17f83e0..1837a8f 100644
--- a/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
+++ b/third_party/blink/renderer/modules/mediarecorder/vea_encoder.h
@@ -41,7 +41,8 @@
              media::VideoCodecProfile codec,
              absl::optional<uint8_t> level,
              const gfx::Size& size,
-             bool use_native_input);
+             bool use_native_input,
+             bool is_screencast);
   ~VEAEncoder() override;
 
   // media::VideoEncodeAccelerator::Client implementation.
@@ -88,6 +89,7 @@
   // Attributes for initialization.
   const gfx::Size size_;
   const bool use_native_input_;
+  const bool is_screencast_;
 
   // The underlying VEA to perform encoding on.
   std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_;
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index cb2ec9ac..bec3ee5e 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -797,6 +797,9 @@
 
   DisconnectFromTrack();
 
+  const bool is_screencast =
+      static_cast<const MediaStreamVideoTrack*>(track_->GetPlatformTrack())
+          ->is_screencast();
   std::unique_ptr<Encoder> encoder;
   base::WeakPtr<Encoder> weak_encoder;
   scoped_refptr<base::SequencedTaskRunner> encoding_task_runner;
@@ -828,7 +831,7 @@
             WTF::BindRepeating(&VideoTrackRecorderImpl::OnHardwareEncoderError,
                                weak_factory_.GetWeakPtr())),
         bitrate_mode, bits_per_second, vea_profile, codec_profile.level,
-        input_size, use_import_mode);
+        input_size, use_import_mode, is_screencast);
     weak_encoder = vea_encoder->GetWeakPtr();
     encoder = std::move(vea_encoder);
   } else {
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 89ea1ff..0978209 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2156,6 +2156,7 @@
     "mojo/string16_mojom_traits_test.cc",
     "p2p/filtering_network_manager_test.cc",
     "p2p/ipc_network_manager_test.cc",
+    "p2p/socket_client_impl_test.cc",
     "peerconnection/coalesced_tasks_test.cc",
     "peerconnection/linear_histogram_test.cc",
     "peerconnection/low_precision_timer_test.cc",
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index 0f13b94..e035bff0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -227,6 +227,8 @@
   request->SetAttributionReportingSupport(GetAttributionReportingSupport());
   request->SetAttributionReportingEligibility(
       GetAttributionReportingEligibility());
+  request->SetAttributionReportingRuntimeFeatures(
+      GetAttributionReportingRuntimeFeatures());
 
   return request;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.h b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
index 1dbb1705d..64e045a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
@@ -36,6 +36,7 @@
 #include "net/cookies/site_for_cookies.h"
 #include "net/filter/source_stream.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
 #include "services/network/public/mojom/attribution.mojom-blink.h"
 #include "services/network/public/mojom/chunked_data_pipe_getter.mojom-blink-forward.h"
 #include "services/network/public/mojom/cors.mojom-blink-forward.h"
@@ -579,6 +580,16 @@
     attribution_reporting_eligibility_ = eligibility;
   }
 
+  const network::AttributionReportingRuntimeFeatures&
+  GetAttributionReportingRuntimeFeatures() const {
+    return attribution_reporting_runtime_features_;
+  }
+
+  void SetAttributionReportingRuntimeFeatures(
+      network::AttributionReportingRuntimeFeatures runtime_features) {
+    attribution_reporting_runtime_features_ = runtime_features;
+  }
+
  private:
   const CacheControlHeader& GetCacheControlHeader() const;
 
@@ -706,6 +717,9 @@
   network::mojom::AttributionReportingEligibility
       attribution_reporting_eligibility_ =
           network::mojom::AttributionReportingEligibility::kUnset;
+
+  network::AttributionReportingRuntimeFeatures
+      attribution_reporting_runtime_features_;
 };
 
 class PLATFORM_EXPORT ResourceRequestBody {
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
index 5a0ab80d..15c509f9 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
@@ -408,6 +408,9 @@
 
   dest->attribution_reporting_eligibility =
       src.GetAttributionReportingEligibility();
+
+  dest->attribution_reporting_runtime_features =
+      src.GetAttributionReportingRuntimeFeatures();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/p2p/ipc_socket_factory.cc b/third_party/blink/renderer/platform/p2p/ipc_socket_factory.cc
index 1b21cf0..518594e6 100644
--- a/third_party/blink/renderer/platform/p2p/ipc_socket_factory.cc
+++ b/third_party/blink/renderer/platform/p2p/ipc_socket_factory.cc
@@ -110,7 +110,9 @@
   typedef std::list<InFlightPacketRecord> InFlightPacketList;
 
   // Always takes ownership of client even if initialization fails.
-  bool Init(network::P2PSocketType type,
+  bool Init(P2PSocketDispatcher* dispatcher,
+            const net::NetworkTrafficAnnotationTag& traffic_annotation,
+            network::P2PSocketType type,
             std::unique_ptr<P2PSocketClientImpl> client,
             const rtc::SocketAddress& local_address,
             uint16_t min_port,
@@ -282,12 +284,15 @@
   }
 }
 
-bool IpcPacketSocket::Init(network::P2PSocketType type,
-                           std::unique_ptr<P2PSocketClientImpl> client,
-                           const rtc::SocketAddress& local_address,
-                           uint16_t min_port,
-                           uint16_t max_port,
-                           const rtc::SocketAddress& remote_address) {
+bool IpcPacketSocket::Init(
+    P2PSocketDispatcher* dispatcher,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
+    network::P2PSocketType type,
+    std::unique_ptr<P2PSocketClientImpl> client,
+    const rtc::SocketAddress& local_address,
+    uint16_t min_port,
+    uint16_t max_port,
+    const rtc::SocketAddress& remote_address) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK_EQ(state_, kIsUninitialized);
 
@@ -323,8 +328,12 @@
   // Certificate will be tied to domain name not to IP address.
   network::P2PHostAndIPEndPoint remote_info(remote_address.hostname(),
                                             remote_endpoint);
+  dispatcher->GetP2PSocketManager()->CreateSocket(
+      type, local_endpoint, network::P2PPortRange(min_port, max_port),
+      remote_info, net::MutableNetworkTrafficAnnotationTag(traffic_annotation),
+      client_ptr->CreatePendingRemote(), client_ptr->CreatePendingReceiver());
 
-  client_ptr->Init(type, local_endpoint, min_port, max_port, remote_info, this);
+  client_ptr->Init(this);
 
   return true;
 }
@@ -746,10 +755,10 @@
     uint16_t max_port) {
   auto socket_dispatcher = socket_dispatcher_.Lock();
   DCHECK(socket_dispatcher);
-  auto socket_client = std::make_unique<P2PSocketClientImpl>(
-      socket_dispatcher, traffic_annotation_);
+  auto socket_client = std::make_unique<P2PSocketClientImpl>();
   std::unique_ptr<IpcPacketSocket> socket(new IpcPacketSocket());
-  if (!socket->Init(network::P2P_SOCKET_UDP, std::move(socket_client),
+  if (!socket->Init(socket_dispatcher, traffic_annotation_,
+                    network::P2P_SOCKET_UDP, std::move(socket_client),
                     local_address, min_port, max_port, rtc::SocketAddress())) {
     return nullptr;
   }
@@ -791,12 +800,13 @@
   }
   auto socket_dispatcher = socket_dispatcher_.Lock();
   DCHECK(socket_dispatcher);
-  auto socket_client = std::make_unique<P2PSocketClientImpl>(
-      socket_dispatcher, traffic_annotation_);
+  auto socket_client = std::make_unique<P2PSocketClientImpl>();
   std::unique_ptr<IpcPacketSocket> socket(new IpcPacketSocket());
-  if (!socket->Init(type, std::move(socket_client), local_address, 0, 0,
-                    remote_address))
+  if (!socket->Init(socket_dispatcher, traffic_annotation_, type,
+                    std::move(socket_client), local_address, 0, 0,
+                    remote_address)) {
     return nullptr;
+  }
   return socket.release();
 }
 
diff --git a/third_party/blink/renderer/platform/p2p/socket_client_delegate.h b/third_party/blink/renderer/platform/p2p/socket_client_delegate.h
index bd61486..d669a6c 100644
--- a/third_party/blink/renderer/platform/p2p/socket_client_delegate.h
+++ b/third_party/blink/renderer/platform/p2p/socket_client_delegate.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_P2P_SOCKET_CLIENT_DELEGATE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_P2P_SOCKET_CLIENT_DELEGATE_H_
 
+#include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
 #include "services/network/public/cpp/p2p_socket_type.h"
 
diff --git a/third_party/blink/renderer/platform/p2p/socket_client_impl.cc b/third_party/blink/renderer/platform/p2p/socket_client_impl.cc
index f15273b1..2081448 100644
--- a/third_party/blink/renderer/platform/p2p/socket_client_impl.cc
+++ b/third_party/blink/renderer/platform/p2p/socket_client_impl.cc
@@ -25,14 +25,10 @@
 
 namespace blink {
 
-P2PSocketClientImpl::P2PSocketClientImpl(
-    P2PSocketDispatcher* dispatcher,
-    const net::NetworkTrafficAnnotationTag& traffic_annotation)
-    : dispatcher_(dispatcher),
-      socket_id_(0),
+P2PSocketClientImpl::P2PSocketClientImpl()
+    : socket_id_(0),
       delegate_(nullptr),
       state_(kStateUninitialized),
-      traffic_annotation_(traffic_annotation),
       random_socket_id_(0),
       next_packet_id_(0) {
   crypto::RandBytes(&random_socket_id_, sizeof(random_socket_id_));
@@ -42,13 +38,7 @@
   CHECK(state_ == kStateClosed || state_ == kStateUninitialized);
 }
 
-void P2PSocketClientImpl::Init(
-    network::P2PSocketType type,
-    const net::IPEndPoint& local_address,
-    uint16_t min_port,
-    uint16_t max_port,
-    const network::P2PHostAndIPEndPoint& remote_address,
-    blink::P2PSocketClientDelegate* delegate) {
+void P2PSocketClientImpl::Init(blink::P2PSocketClientDelegate* delegate) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(delegate);
   // |delegate_| is only accessesed on |delegate_message_loop_|.
@@ -56,14 +46,6 @@
 
   DCHECK_EQ(state_, kStateUninitialized);
   state_ = kStateOpening;
-  auto dispatcher = dispatcher_.Lock();
-  CHECK(dispatcher);
-  dispatcher->GetP2PSocketManager()->CreateSocket(
-      type, local_address, network::P2PPortRange(min_port, max_port),
-      remote_address,
-      net::MutableNetworkTrafficAnnotationTag(traffic_annotation_),
-      receiver_.BindNewPipeAndPassRemote(),
-      socket_.BindNewPipeAndPassReceiver());
   receiver_.set_disconnect_handler(WTF::BindOnce(
       &P2PSocketClientImpl::OnConnectionError, WTF::Unretained(this)));
 }
diff --git a/third_party/blink/renderer/platform/p2p/socket_client_impl.h b/third_party/blink/renderer/platform/p2p/socket_client_impl.h
index f12f5cf7..4c5929b 100644
--- a/third_party/blink/renderer/platform/p2p/socket_client_impl.h
+++ b/third_party/blink/renderer/platform/p2p/socket_client_impl.h
@@ -18,6 +18,7 @@
 #include "services/network/public/mojom/p2p.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/cross_thread_persistent.h"
 #include "third_party/blink/renderer/platform/p2p/socket_client.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -29,12 +30,11 @@
 // P2P socket that routes all calls over Mojo.
 //
 // The object is created and runs on the WebRTC worker thread.
-class P2PSocketClientImpl : public blink::P2PSocketClient,
-                            public network::mojom::blink::P2PSocketClient {
+class PLATFORM_EXPORT P2PSocketClientImpl
+    : public blink::P2PSocketClient,
+      public network::mojom::blink::P2PSocketClient {
  public:
-  P2PSocketClientImpl(
-      P2PSocketDispatcher* dispatcher,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation);
+  P2PSocketClientImpl();
   P2PSocketClientImpl(const P2PSocketClientImpl&) = delete;
   P2PSocketClientImpl& operator=(const P2PSocketClientImpl&) = delete;
   ~P2PSocketClientImpl() override;
@@ -42,12 +42,7 @@
   // Initialize socket of the specified |type| and connected to the
   // specified |address|. |address| matters only when |type| is set to
   // P2P_SOCKET_TCP_CLIENT.
-  virtual void Init(network::P2PSocketType type,
-                    const net::IPEndPoint& local_address,
-                    uint16_t min_port,
-                    uint16_t max_port,
-                    const network::P2PHostAndIPEndPoint& remote_address,
-                    blink::P2PSocketClientDelegate* delegate);
+  virtual void Init(blink::P2PSocketClientDelegate* delegate);
 
   // Send the |data| to the |address| using Differentiated Services Code Point
   // |dscp|. Return value is the unique packet_id for this packet.
@@ -66,6 +61,15 @@
 
   void SetDelegate(blink::P2PSocketClientDelegate* delegate) override;
 
+  mojo::PendingReceiver<network::mojom::blink::P2PSocket>
+  CreatePendingReceiver() {
+    return socket_.BindNewPipeAndPassReceiver();
+  }
+  mojo::PendingRemote<network::mojom::blink::P2PSocketClient>
+  CreatePendingRemote() {
+    return receiver_.BindNewPipeAndPassRemote();
+  }
+
  private:
   enum State {
     kStateUninitialized,
@@ -92,14 +96,10 @@
 
   void OnConnectionError();
 
-  // `P2PSocketDispatcher` is owned by the main thread, and must be accessed in
-  // a thread-safe way.
-  CrossThreadWeakPersistent<P2PSocketDispatcher> dispatcher_;
   THREAD_CHECKER(thread_checker_);
   int socket_id_;
   blink::P2PSocketClientDelegate* delegate_;
   State state_;
-  const net::NetworkTrafficAnnotationTag traffic_annotation_;
 
   // These two fields are used to identify packets for tracing.
   uint32_t random_socket_id_;
diff --git a/third_party/blink/renderer/platform/p2p/socket_client_impl_test.cc b/third_party/blink/renderer/platform/p2p/socket_client_impl_test.cc
new file mode 100644
index 0000000..96dcb4e4
--- /dev/null
+++ b/third_party/blink/renderer/platform/p2p/socket_client_impl_test.cc
@@ -0,0 +1,144 @@
+#include "third_party/blink/renderer/platform/p2p/socket_client_impl.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "net/base/ip_endpoint.h"
+#include "services/network/public/cpp/p2p_socket_type.h"
+#include "services/network/public/mojom/p2p.mojom-blink-forward.h"
+#include "services/network/public/mojom/p2p.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/p2p/socket_client_delegate.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+namespace {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::WithArgs;
+
+class MockSocketService : public network::mojom::blink::P2PSocket {
+ public:
+  MOCK_METHOD(void,
+              Send,
+              (base::span<const uint8_t>, const network::P2PPacketInfo&),
+              (override));
+  MOCK_METHOD(void,
+              SetOption,
+              (network::P2PSocketOption option, int32_t value),
+              (override));
+};
+
+class MockDelegate : public P2PSocketClientDelegate {
+ public:
+  MOCK_METHOD(void,
+              OnOpen,
+              (const net::IPEndPoint&, const net::IPEndPoint&),
+              (override));
+  MOCK_METHOD(void,
+              OnSendComplete,
+              (const network::P2PSendPacketMetrics&),
+              (override));
+  MOCK_METHOD(void, OnError, (), (override));
+  MOCK_METHOD(void,
+              OnDataReceived,
+              (const net::IPEndPoint&,
+               base::span<const uint8_t>,
+               const base::TimeTicks&),
+              (override));
+};
+
+class SocketClientImplTest : public ::testing::Test {
+ public:
+  SocketClientImplTest() {
+    receiver_.Bind(client_.CreatePendingReceiver());
+    remote_.Bind(client_.CreatePendingRemote());
+    client_.Init(&delegate_);
+  }
+  ~SocketClientImplTest() override { client_.Close(); }
+
+  void Open() {
+    ON_CALL(delegate_, OnOpen).WillByDefault(Return());
+    remote_->SocketCreated(net::IPEndPoint(), net::IPEndPoint());
+    task_environment_.RunUntilIdle();
+  }
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  MockSocketService socket_;
+  mojo::Receiver<network::mojom::blink::P2PSocket> receiver_{&socket_};
+  P2PSocketClientImpl client_;
+  mojo::Remote<network::mojom::blink::P2PSocketClient> remote_;
+  NiceMock<MockDelegate> delegate_;
+};
+
+TEST_F(SocketClientImplTest, OnOpenCalled) {
+  EXPECT_CALL(delegate_, OnOpen);
+  remote_->SocketCreated(net::IPEndPoint(), net::IPEndPoint());
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SocketClientImplTest, OnDataReceivedCalled) {
+  using network::mojom::blink::P2PReceivedPacket;
+  using network::mojom::blink::P2PReceivedPacketPtr;
+  Open();
+  WTF::Vector<P2PReceivedPacketPtr> packets;
+  auto first = base::TimeTicks() + base::Microseconds(1);
+  auto second = base::TimeTicks() + base::Microseconds(2);
+  auto data = WTF::Vector<uint8_t>(1);
+  packets.push_back(P2PReceivedPacket::New(data, net::IPEndPoint(), first));
+  packets.push_back(P2PReceivedPacket::New(data, net::IPEndPoint(), second));
+  InSequence s;
+  EXPECT_CALL(delegate_, OnDataReceived(_, _, first));
+  EXPECT_CALL(delegate_, OnDataReceived(_, _, second));
+  remote_->DataReceived(std::move(packets));
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SocketClientImplTest, OnSendCompleteCalled) {
+  Open();
+  EXPECT_CALL(delegate_, OnSendComplete);
+  remote_->SendComplete(network::P2PSendPacketMetrics());
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SocketClientImplTest, OnConnectionErrorCalled) {
+  Open();
+  EXPECT_CALL(delegate_, OnError);
+  remote_.reset();
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SocketClientImplTest, SendsWithIncreasingPacketId) {
+  Open();
+  network::P2PPacketInfo first_info;
+  InSequence s;
+  EXPECT_CALL(socket_, Send).WillOnce(SaveArg<1>(&first_info));
+  EXPECT_CALL(socket_, Send)
+      .WillOnce(WithArgs<1>([&first_info](const network::P2PPacketInfo& info) {
+        EXPECT_EQ(info.packet_id, first_info.packet_id + 1);
+      }));
+  client_.Send(net::IPEndPoint(), std::vector<uint8_t>(1),
+               rtc::PacketOptions());
+  client_.Send(net::IPEndPoint(), std::vector<uint8_t>(1),
+               rtc::PacketOptions());
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SocketClientImplTest, SetsOption) {
+  Open();
+  InSequence s;
+  EXPECT_CALL(socket_,
+              SetOption(network::P2PSocketOption::P2P_SOCKET_OPT_DSCP, 1));
+  EXPECT_CALL(socket_,
+              SetOption(network::P2PSocketOption::P2P_SOCKET_OPT_RCVBUF, 2));
+  client_.SetOption(network::P2PSocketOption::P2P_SOCKET_OPT_DSCP, 1);
+  client_.SetOption(network::P2PSocketOption::P2P_SOCKET_OPT_RCVBUF, 2);
+  task_environment_.RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index e8058ea..980338f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -880,11 +880,6 @@
       base_feature: "CSSHyphenateLimitChars",
     },
     {
-      name: "CSSIcUnit",
-      status: "stable",
-      base_feature: "none",
-    },
-    {
       // If enabled,
       // image-set values without the `-webkit-` prefix
       // will be parsed.
@@ -907,10 +902,6 @@
       base_feature: "none",
     },
     {
-      name: "CSSLhUnit",
-      status: "stable",
-    },
-    {
       name: "CSSLinearTimingFunction",
       status: "stable"
     },
@@ -970,11 +961,6 @@
       name: "CSSNestingIdent",
     },
     {
-      name: "CSSNewRootFontUnits",
-      status: "stable",
-      base_feature: "none",
-    },
-    {
       name: "CSSObjectViewBox",
       status: "stable",
       base_feature: "none",
@@ -1120,7 +1106,7 @@
     {
       // Support style() queries that evaluate in a boolean context.
       name: "CSSStyleQueriesBoolean",
-      status: "experimental",
+      status: "stable",
     },
     {
       // Merge multiple rulesets into one, for faster matching.
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index e24753d..d52278e0 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -352,9 +352,7 @@
 crbug.com/1081534 [ Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-transformclip.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video.html [ Slow ]
-crbug.com/1081534 [ Debug Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-clipping.html [ Slow ]
-crbug.com/1081534 [ Mac10.15 Release ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-clipping.html [ Slow ]
-crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-image.html [ Slow ]
+crbug.com/1081534 [ Debug Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-image.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-pattern.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-image-over-gradient.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-pattern-over-color.html [ Slow ]
@@ -442,11 +440,10 @@
 crbug.com/866850 [ Mac12 Release ] virtual/gpu/fast/canvas/canvas-blending-image-over-gradient.html [ Slow ]
 crbug.com/866850 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Slow ]
 crbug.com/866850 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-pattern.html [ Slow ]
-crbug.com/866850 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-pattern.html [ Slow ]
+crbug.com/866850 [ Mac10.15 Release ] virtual/gpu/fast/canvas/canvas-blending-image-over-pattern.html [ Slow ]
 crbug.com/866850 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-color.html [ Slow ]
 crbug.com/866850 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-color.html [ Slow ]
 crbug.com/866850 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-gradient.html [ Slow ]
-crbug.com/866850 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-gradient.html [ Slow ]
 crbug.com/866850 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-pattern-over-gradient.html [ Slow ]
 crbug.com/866850 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-image.html [ Slow ]
 crbug.com/866850 [ Debug Mac12 ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-image.html [ Slow ]
@@ -847,7 +844,6 @@
 crbug.com/914981 [ Mac Release ] fast/events/no-fake-mousemove.html [ Slow ]
 
 crbug.com/980804 [ Debug Linux ] virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
-crbug.com/980804 [ Debug Mac12 ] virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 crbug.com/980804 [ Release ] virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 
 crbug.com/983642 [ Debug ] virtual/gpu/fast/canvas/canvas-composite-alpha.html [ Slow ]
@@ -1547,3 +1543,6 @@
 crbug.com/1423483 [ Mac11 Release ] external/wpt/css/css-color/parsing/color-computed-hsl.html [ Slow ]
 crbug.com/1423483 [ Mac12 ] external/wpt/css/css-color/parsing/color-computed-hsl.html [ Slow ]
 crbug.com/1423483 [ Release Win ] external/wpt/css/css-color/parsing/color-computed-hsl.html [ Slow ]
+
+# Slow because of too many cycles of waiting for layout and paint
+crbug.com/1310326 http/tests/misc/transforms-usecounter-3d-scene.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 6c841e72..95b912f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2155,7 +2155,6 @@
 # By about a quarter or less of a pixel.
 crbug.com/997202 [ Mac ] virtual/text-antialias/international/bdo-bidi-width.html [ Failure ]
 
-crbug.com/574283 [ Debug Mac12 ] fast/scroll-behavior/smooth-scroll/ongoing-smooth-scroll-anchors.html [ Crash Failure Pass Timeout ]
 crbug.com/574283 [ Mac11 Release ] fast/scroll-behavior/smooth-scroll/ongoing-smooth-scroll-anchors.html [ Crash Failure Pass Timeout ]
 
 crbug.com/599670 [ Win ] http/tests/devtools/resource-parameters-ipv6.js [ Crash Failure Pass ]
@@ -2923,31 +2922,15 @@
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 [ Mac13 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/background-sync.https.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/pending-beacon/external/wpt/pending-beacon/pending_beacon-sendonhidden.tentative.https.window.html [ Timeout ]
-crbug.com/626703 [ Mac12 ] virtual/prefetch/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/prefetch/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=RelativeUrlForCandidate [ Timeout ]
 crbug.com/626703 external/wpt/css/css-images/image-set/image-set-negative-resolution-rendering-2.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-images/image-set/image-set-negative-resolution-rendering.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-nesting/conditional-rules.html [ Failure ]
 crbug.com/626703 external/wpt/html/semantics/popovers/popover-hide-crash.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-content/quotes-020.html [ Failure ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-overflow/scrollbar-gutter-002.html [ Failure ]
 crbug.com/626703 [ Mac13-arm64 ] external/wpt/css/css-overflow/scrollbar-gutter-002.html [ Failure ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-overflow/scrollbar-gutter-vertical-lr-002.html [ Failure ]
 crbug.com/626703 [ Mac13-arm64 ] external/wpt/css/css-overflow/scrollbar-gutter-vertical-lr-002.html [ Failure ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-overflow/scrollbar-gutter-vertical-rl-002.html [ Failure ]
 crbug.com/626703 [ Mac13-arm64 ] external/wpt/css/css-overflow/scrollbar-gutter-vertical-rl-002.html [ Failure ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/css/css-tables/crashtests/textarea-intrinsic-size-crash.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
-crbug.com/626703 [ Mac13-arm64 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/html/semantics/links/hyperlink-auditing/headers.optional.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] external/wpt/service-workers/cache-storage/crashtests/cache-response-clone.https.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] virtual/keepalive-in-browser-migration/external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] virtual/pending-beacon/external/wpt/pending-beacon/pending_post_beacon-cors.tentative.https.window.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-color/color-mix-currentcolor-003.html [ Failure ]
-crbug.com/626703 [ Linux ] virtual/prefetch/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-cascade/import-conditional-002.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Timeout ]
@@ -4624,7 +4607,7 @@
 
 # Sheriff 2020-0-21
 
-crbug.com/1122582 external/wpt/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html [ Failure Pass ]
+crbug.com/1122582 [ Debug Mac12 ] external/wpt/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html [ Failure Pass ]
 
 
 # Sheriff 2020-09-22
@@ -4912,7 +4895,6 @@
 crbug.com/1208173 [ Mac ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-render-surfaces-with-rotation.html [ Failure ]
 crbug.com/1208173 [ Mac ] virtual/scalefactor200/external/wpt/css/filter-effects/backdrop-filter-basic-opacity-2.html [ Failure ]
 crbug.com/1208173 [ Mac10.14 Release ] virtual/scalefactor200/external/wpt/css/filter-effects/css-filters-animation-opacity.html [ Failure ]
-crbug.com/1208173 [ Mac11-arm64 Release ] virtual/scalefactor200/external/wpt/css/filter-effects/css-filters-animation-opacity.html [ Failure ]
 
 # Fix to unblock wpt-importer
 
@@ -5288,7 +5270,6 @@
 
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-011.html [ Crash Failure Pass ]
 crbug.com/1249176 [ Mac12-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-011.html [ Crash Failure Pass ]
-crbug.com/1249176 [ Mac12-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-018.html [ Failure Pass ]
 crbug.com/1249176 [ Mac12-arm64 ] http/tests/security/cross-origin-shared-worker-allowed.html [ Crash Pass ]
 
 # Sheriff 2021-09-16
@@ -5597,7 +5578,10 @@
 crbug.com/1309633 [ Mac ] external/wpt/FileAPI/url/url-lifetime.html [ Failure ]
 
 # Sheriff 2022-03-24
-crbug.com/1309756 http/tests/images/force-reload.html [ Crash Failure Pass Timeout ]
+crbug.com/1309756 [ Debug Mac ] http/tests/images/force-reload.html [ Crash Failure Pass Timeout ]
+crbug.com/1309756 [ Mac11-arm64 Release ] http/tests/images/force-reload.html [ Crash Failure Pass Timeout ]
+crbug.com/1309756 [ Mac12-arm64 Release ] http/tests/images/force-reload.html [ Crash Failure Pass Timeout ]
+crbug.com/1309756 [ Release Win ] http/tests/images/force-reload.html [ Crash Failure Pass Timeout ]
 crbug.com/1309756 [ Mac11-arm64 ] http/tests/images/force-reload-image-document.html [ Crash Failure Pass Timeout ]
 
 # Sheriff 2022-03-25
@@ -6666,7 +6650,7 @@
 crbug.com/1428795 [ Linux ] external/wpt/dom/events/Event-dispatch-on-disabled-elements.html [ Failure Pass ]
 
 # Sheriff 2023-04-05
-crbug.com/1430215 external/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html [ Failure Pass ]
+crbug.com/1430215 [ Release Win11 ] external/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html [ Failure Pass ]
 crbug.com/1430986 http/tests/inspector-protocol/tracing/page-load-metrics.js [ Failure Pass Timeout ]
 
 # Sheriff 2023-04-06
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index d76bbde..160f2fc 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -169,7 +169,7 @@
     "bases": ["wpt_internal/attribution-reporting"],
     "exclusive_tests": "ALL",
     "args": ["--attribution-reporting-debug-mode",
-             "--enable-features=AttributionReportingCrossAppWeb,AttributionReportingReportVerification",
+             "--enable-features=AttributionReportingCrossAppWeb,AttributionReportingReportVerification,PrivacySandboxAdsAPIsOverride",
              "--additional-private-state-token-key-commitments={\"https://web-platform.test:8444\":{\"PrivateStateTokenV3VOPRF\":{\"protocol_version\":\"PrivateStateTokenV3VOPRF\",\"id\":1,\"batchsize\":1,\"keys\":{\"0\":{\"Y\":\"AAAAAASqh8oivosFN46xxx7zIK10bh07Younm5hZ90HgglQqOFUC8l2/VSlsOlReOHJ2CrfJ6CG1adnTkKJhZ0BtbSPWBwviQtdl64MWJc7sSg9HPvWfTjDigX5ihbzihG8V8aA=\",\"expiry\":\"253402300799000000\"}}}}}"],
     "expires": "Jul 1, 2023"
   },
@@ -178,7 +178,7 @@
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/inspector-protocol/attribution-reporting/os"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=AttributionReportingCrossAppWeb"],
+    "args": ["--enable-features=AttributionReportingCrossAppWeb,PrivacySandboxAdsAPIsOverride"],
     "expires": "Jul 1, 2023"
   },
   {
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html
index 69e8433..1242ebbf 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators-2.https.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/utils.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators.sub.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators.sub.https.html
index 74e7932..c35ccde 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/different-initiators.sub.https.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<meta name="timeout" content="long">
 <meta name="variant" content="?cross-site-1">
 <meta name="variant" content="?cross-site-2">
 <meta name="variant" content="?same-site">
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/app-manifest-view-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/app-manifest-view-a11y-test.js
index 5ee82a32..bdaac6e5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/app-manifest-view-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/app-manifest-view-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
 
   TestRunner.addResult('Tests accessibility of AppManifestView on application panel.');
   const manifest = `{
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/application-tree-outline.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/application-tree-outline.js
index b749e6db..47318d5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/application-tree-outline.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/application-tree-outline.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
 
   TestRunner.addResult('Tests accessibility of Tree outline sidepane in Application Panel.');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/clear-storage-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/clear-storage-a11y-test.js
index c61e3d4..b28d55ef 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/clear-storage-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/clear-storage-a11y-test.js
@@ -1,10 +1,12 @@
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+import {TestRunner} from 'test_runner';
+import {ApplicationTestRunner} from 'application_test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
 (async function() {
   TestRunner.addResult('Tests accessibility in the Storage view using the axe-core linter.');
-  await TestRunner.loadTestModule('application_test_runner');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await ApplicationTestRunner.resetState();
   await TestRunner.showPanel('resources');
   await UI.viewManager.showView('resources');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/service-worker-view-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/service-worker-view-a11y-test.js
index 4da820d0..132d4a12 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/service-worker-view-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/service-worker-view-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ApplicationTestRunner} from 'application_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility of ServiceWorkersView on application panel.');
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('application_test_runner');
   await ApplicationTestRunner.resetState();
 
   await TestRunner.showPanel('resources');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/websql-console-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/websql-console-a11y-test.js
index e04b7cc..615f590 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/websql-console-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/application-panel/websql-console-a11y-test.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ApplicationTestRunner} from 'application_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests accessibility of WebSQL console in application panel.`);
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner');
+  await TestRunner.loadLegacyModule('console');
   // Note: every test that uses a storage API must manually clean-up state from previous tests.
   await ApplicationTestRunner.resetState();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/basic-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/basic-a11y-test.js
index 3066405..5c36a52 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/basic-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/basic-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
   const locationsToTest =
     [
       // elements
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/changes/changes-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/changes/changes-a11y-test.js
index acce8ed..dd05f1d9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/changes/changes-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/changes/changes-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Changes drawer.');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.loadLegacyModule('changes');
 
   const diff = [
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/console-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/console-a11y-test.js
index 0ac4fce..213c34f8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/console-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/console-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
   TestRunner.addResult(
       'Tests accessibility in the console using the axe-core linter.');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/dom-breakpoints-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/dom-breakpoints-a11y-test.js
index d9a80fff..705584fe 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/dom-breakpoints-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/dom-breakpoints-a11y-test.js
@@ -1,12 +1,14 @@
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
 (async function() {
   TestRunner.addResult(
       'Tests accessibility in DOM breakpoints using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('elements_test_runner');
   await TestRunner.showPanel('elements');
   UI.panels.elements.sidebarPaneView.tabbedPane().selectTab('elements.domBreakpoints', true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js
index a7c7645..dcaa89f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/event-listeners-a11y-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
     // axe-core issue #1444 -- role="tree" requires children with role="treeitem",
     // but it is reasonable to have trees with no leaves.
@@ -15,8 +19,6 @@
     TestRunner.addResult(
         'Tests accessibility in DOM eventlistener pane using axe-core linter.');
 
-    await TestRunner.loadTestModule('axe_core_test_runner');
-    await TestRunner.loadTestModule('sources_test_runner');
     const view = 'elements.eventListeners';
     const widget = await UI.viewManager.view(view).widget();
     await UI.viewManager.showView(view);
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/main-tool-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/main-tool-test.js
index b90b592..b1e3b29 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/main-tool-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/elements/main-tool-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   // axe-core issue #1444 -- role="tree" requires children with role="treeitem",
   // but it is reasonable to have trees with no leaves.
@@ -11,8 +15,6 @@
     },
   };
   const DEFAULT_RULESET = {};
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('elements_test_runner');
   const tests = [
     testElementsDomTree,
     testElementsDomBreadcrumbs,
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/layers/layers-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/layers/layers-a11y-test.js
index a34987f..901bb8c71 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/layers/layers-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/layers/layers-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {LayersTestRunner} from 'layers_test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests accessibility in the layers view using the axe-core linter.`);
-  await TestRunner.loadTestModule('layers_test_runner');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.loadHTML(`
       <div id="a" style="transform: translateZ(0px); background-color:blue; width:100px; height:100px;">
           <div style="width:50px; height:50px; background-color:red;"></div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/lighthouse-start-view-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/lighthouse-start-view-a11y-test.js
index f0714fe..7b951206 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/lighthouse-start-view-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/lighthouse-start-view-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the lighthouse start view using the axe-core linter.\n');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.showPanel('lighthouse');
 
   const widget = await UI.viewManager.view('lighthouse').widget();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/memory/heap-profiler-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/memory/heap-profiler-a11y-test.js
index a61c987..74e42e0a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/memory/heap-profiler-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/memory/heap-profiler-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {HeapProfilerTestRunner} from 'heap_profiler_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in heap profiler using the axe-core linter.');
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('heap_profiler_test_runner');
   await TestRunner.showPanel('heap_profiler');
   await TestRunner.evaluateInPagePromise(`
       class MyTestClass {
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/network/network-condition-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/network/network-condition-a11y-test.js
index ab0128a..f3fff1f7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/network/network-condition-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/network/network-condition-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in Network conditions view using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
   const view = 'network.config';
   await UI.viewManager.showView(view);
   const widget = await UI.viewManager.view(view).widget();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/landing-page-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/landing-page-a11y-test.js
index cdf1a3d..8517b4b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/landing-page-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/landing-page-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in Performance landing page using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
   const view = 'timeline';
   await UI.viewManager.showView(view);
   const widget = await UI.viewManager.view(view).widget();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/main-flamechart-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/main-flamechart-a11y-test.js
index 16df6b3..bf40dec 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/main-flamechart-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/main-flamechart-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - main flamechart.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/network-flamechart-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/network-flamechart-a11y-test.js
index 1ddc0ed..b0a94a104 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/network-flamechart-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/network-flamechart-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - network flamechart.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-right-toolbar-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-right-toolbar-a11y-test.js
index 1cd2b91..f18086e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-right-toolbar-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-right-toolbar-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - panel right toolbar.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-toolbar-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-toolbar-a11y-test.js
index 806facc..a864c17 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-toolbar-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/panel-toolbar-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - panel toolbar.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance-pane-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance-pane-a11y-test.js
index 9c4ebd8..214150c4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance-pane-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance-pane-a11y-test.js
@@ -1,9 +1,11 @@
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('performance_test_runner');
   await TestRunner.showPanel('timeline');
 
   const testData = [
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance_event_log_a11y_test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance_event_log_a11y_test.js
index deb0db3..b994d78 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance_event_log_a11y_test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/performance_event_log_a11y_test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('performance_test_runner');
 
   await TestRunner.showPanel('timeline');
   TestRunner.addResult('Performance panel loaded.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/settings-pane-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/settings-pane-a11y-test.js
index dfba89a2..53c82639 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/settings-pane-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/settings-pane-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - settings pane.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/timeline-overview-container-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/timeline-overview-container-a11y-test.js
index 4284ce1..e9fa4c2f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/timeline-overview-container-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/performance/timeline-overview-container-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {PerformanceTestRunner} from 'performance_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing a11y in performance panel - timeline overview container.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
+  await TestRunner.loadLegacyModule('timeline');
   await TestRunner.showPanel('timeline');
 
   await PerformanceTestRunner.runPerfTraceWithReload();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/quick-open-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/quick-open-a11y-test.js
index 273ecb6..dc2717de 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/quick-open-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/quick-open-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Test accessibility in Quick Open dialog\n');
   await TestRunner.loadLegacyModule('quick_open');
-  await TestRunner.loadTestModule('axe_core_test_runner');
 
   QuickOpen.QuickOpen.show('');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/rendering/basic-rendering-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/rendering/basic-rendering-a11y-test.js
index b42c457c..65a41c6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/rendering/basic-rendering-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/rendering/basic-rendering-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
 
   TestRunner.addResult('Tests accessibility in the rendering view using the axe-core linter.');
   await UI.viewManager.showView('rendering');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js
index f7ea02f..3c6eff2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SecurityTestRunner} from 'security_test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('security_test_runner');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.showPanel('security');
 
   const request1 = new SDK.NetworkRequest(0, 'https://foo.test/', 'https://foo.test', 0, 0, null);
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-overview-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-overview-a11y-test.js
index 493e488..7869131 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-overview-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-overview-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SecurityTestRunner} from 'security_test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('security_test_runner');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.showPanel('security');
 
   const pageVisibleSecurityState = new Security.PageVisibleSecurityState(
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/blackbox-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/blackbox-a11y-test.js
index d8e0fb3..4d62236 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/blackbox-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/blackbox-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in IgnoreList view using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await UI.viewManager.showView('blackbox');
   const ignoreListWidget = await UI.viewManager.view('blackbox').widget();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/emulated-device-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/emulated-device-a11y-test.js
index ad44abd..4e580ffe 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/emulated-device-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/emulated-device-a11y-test.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+
 (async function() {
   TestRunner.addResult('Test error message in the settings tool Emulated Device pane');
   await UI.viewManager.showView('devices');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/locations-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/locations-a11y-test.js
index fcebbc1..56d0943 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/locations-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/locations-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the settings tool locations pane using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await UI.viewManager.showView('emulation-locations');
   const locationsWidget = await UI.viewManager.view('emulation-locations').widget();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/menu-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/menu-a11y-test.js
index 9139d45d..6243962 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/menu-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/menu-a11y-test.js
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult(
       'Tests accessibility in the settings menu using the axe-core linter.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.loadLegacyModule('settings');
 
   await UI.actionRegistry.action('settings.show').execute();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/shortcuts-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/shortcuts-a11y-test.js
index 5176c154..add9594 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/shortcuts-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/shortcuts-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the settings tool shortcuts pane using the axe-core linter.');
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.loadLegacyModule('settings');
 
   async function testShortcuts() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/workspace-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/workspace-a11y-test.js
index 53b6d330..774e1937 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/workspace-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/settings/workspace-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('bindings_test_runner');
 
   TestRunner.addResult(
       'Tests accessibility in the settings workspace view using the axe-core linter.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt
index bb05b12..4c17d8e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt
@@ -1,6 +1,6 @@
 Testing accessibility in the call stack sidebar pane.
 Set timer for test function.
-Call stack pane content: Show ignore-listed framesNot pausedSome call frames have warnings(anonymous)test.js:21callWithAsyncStacktest.js:14call1wrapper.js:1setTimeout (async)scheduleTestFunctionVM:3(anonymous)VM:1Show more
+Call stack pane content: Show ignore-listed framesNot pausedSome call frames have warnings(anonymous)test.js:23callWithAsyncStacktest.js:16call1wrapper.js:1setTimeout (async)scheduleTestFunctionVM:3(anonymous)VM:1Show more
 Running the axe-core linter on the call stack sidebar pane.
 aXe violations: []
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
index 2654c01..5c88fd56 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.showPanel('sources');
 
   TestRunner.addResult('Testing accessibility in the call stack sidebar pane.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/dom-breakpoints-pane-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/dom-breakpoints-pane-a11y-test.js
index 6f266278..cbf1866 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/dom-breakpoints-pane-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/dom-breakpoints-pane-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('elements_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.showPanel('elements');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise(
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/event-listener-breakpoints-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/event-listener-breakpoints-a11y-test.js
index f7d19c3..de4bf1e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/event-listener-breakpoints-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/event-listener-breakpoints-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function () {
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.showPanel('sources');
   await TestRunner.loadLegacyModule('browser_debugger');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test-expected.txt
index 016cd8e..e2ce51e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test-expected.txt
@@ -3,7 +3,7 @@
 
 ======== touchstart ========
 == Raw
-[expanded] WindowRemoveToggle Passiveglobal-listeners-sidebar-a11y-test.js:13
+[expanded] WindowRemoveToggle Passiveglobal-listeners-sidebar-a11y-test.js:15
     useCapture: false
     passive: true
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test.js
index c1cc0c8..e828065 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/global-listeners-sidebar-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('elements_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise('../sources/debugger-breakpoints/resources/dom-breakpoints.html');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js
index ee90535..1084d373 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await UI.viewManager.showView('sources.scopeChain');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-contentscripts-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-contentscripts-a11y-test.js
index 05b5998..60863b3c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-contentscripts-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-contentscripts-a11y-test.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SDKTestRunner} from 'sdk_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Sources panel Navigator pane Contentscripts tab using axe-core.');
 
@@ -13,9 +18,6 @@
     },
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('sdk_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
 
   await UI.viewManager.showView('sources');
   await setup();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js
index fc21ade..a48f1b0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-filesystem-a11y-test.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Sources panel Navigator pane FileSystem tab using axe-core.');
 
@@ -13,9 +18,6 @@
     },
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('bindings_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
 
   await UI.viewManager.showView('sources');
   await setup();
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-network-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-network-a11y-test.js
index 6dd44d8..683f5980 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-network-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-network-a11y-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Sources panel Navigator pane Network tab using axe-core.');
 
@@ -13,8 +17,6 @@
     },
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
 
   await UI.viewManager.showView('sources');
   await testA11yForView(NO_REQUIRED_CHILDREN_RULESET);
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-overrides-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-overrides-a11y-test.js
index d2f6dba8..e8a9788 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-overrides-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-overrides-a11y-test.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Sources panel Navigator pane Overrides tab using axe-core.');
 
@@ -13,9 +18,6 @@
     },
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('bindings_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
 
   await UI.viewManager.showView('sources');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-snippets-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-snippets-a11y-test.js
index 56585302..7aead43 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-snippets-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/source-navigator-snippets-a11y-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the Sources panel Navigator pane Snippets tab using axe-core.');
 
@@ -13,8 +17,6 @@
     },
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadLegacyModule('snippets');
 
   await UI.viewManager.showView('sources');
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/sources-editor-pane-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/sources-editor-pane-a11y-test.js
index 9477602..d286c65f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/sources-editor-pane-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/sources-editor-pane-a11y-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests accessibility in the editor pane in sources panel using the axe-core linter.');
 
@@ -19,8 +23,6 @@
     }
   };
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
 
   await UI.viewManager.showView('sources');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/threads-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/threads-a11y-test.js
index a755e455..a553acb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/threads-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/threads-a11y-test.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult('Testing accessibility in the threads sidebar pane.');
 
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await SourcesTestRunner.startDebuggerTestPromise(/* quiet */ true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/watch-expression-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/watch-expression-a11y-test.js
index 308c0ab..d218c95 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/watch-expression-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/watch-expression-a11y-test.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
-  await TestRunner.loadTestModule('elements_test_runner');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise('../sources/debugger-breakpoints/resources/dom-breakpoints.html');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/xhr-breakpoints-sidebar-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/xhr-breakpoints-sidebar-a11y-test.js
index 22d71f3..076e11dd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/xhr-breakpoints-sidebar-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/xhr-breakpoints-sidebar-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
   await TestRunner.showPanel('sources');
   await TestRunner.loadLegacyModule('browser_debugger');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/web-audio-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/web-audio-a11y-test.js
index ff3fe65..fcb2095 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/web-audio-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/web-audio-a11y-test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {AxeCoreTestRunner} from 'axe_core_test_runner';
+
 (async function() {
-  await TestRunner.loadTestModule('axe_core_test_runner');
   TestRunner.addResult(
       'Tests accessibility in the web audio tool using the axe-core linter.');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-KeyframeEffect-crash.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-KeyframeEffect-crash.js
index 694539c..405363a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-KeyframeEffect-crash.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-KeyframeEffect-crash.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that animations can be created with KeyframeEffect without crashing.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
       <div id="node" style="background-color: red; height: 100px"></div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-after-navigation.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-after-navigation.js
index a83868b..ed3bf73 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-after-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-after-navigation.js
@@ -2,13 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that animation view works post navigation.\n`);
 
   // This loads the animations view on the existing page, which is
   // somewhere below http://127.0.0.1:8000/. By loading the animations view,
   // we'll start the InspectorAnimationAgent.
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await UI.viewManager.showView('animations');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-empty-web-animations.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-empty-web-animations.js
index 1f69a1c..5eab034 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-empty-web-animations.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-empty-web-animations.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the empty web animations do not show up in animation timeline.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
       <div id="node" style="background-color: red; height: 100px"></div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-animations.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-animations.js
index f30c0b0..5611047 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-animations.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-animations.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests the matching performed in AnimationModel of groups composed of animations, which are applied through a variety of selectors.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.loadLegacyModule('animation');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-transitions.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-transitions.js
index 684f6b2..db39184d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-transitions.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching-transitions.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests the matching performed in AnimationModel of groups composed of transitions, which are applied through a variety of selectors.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.loadLegacyModule('animation');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching.js
index b03a12d..5b389e86 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-group-matching.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the matching of groups in AnimationModel.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.loadLegacyModule('animation');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-timeline.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-timeline.js
index 1926b7f..b11b55c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-timeline.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-timeline.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the display of animations on the animation timeline.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
       <style>
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-transition-setTiming-crash.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-transition-setTiming-crash.js
index bb50366c..079e6a09 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-transition-setTiming-crash.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-transition-setTiming-crash.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`This test passes if it does not crash.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
       <style>
diff --git a/third_party/blink/web_tests/http/tests/devtools/animation/animation-web-anim-negative-start-time.js b/third_party/blink/web_tests/http/tests/devtools/animation/animation-web-anim-negative-start-time.js
index 29da9e5..4f22c3f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/animation/animation-web-anim-negative-start-time.js
+++ b/third_party/blink/web_tests/http/tests/devtools/animation/animation-web-anim-negative-start-time.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that animation with negative start delay gets added.\n`);
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('elements');
   await TestRunner.loadHTML(`
       <div id="node" style="background-color: red; height: 100px"></div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/tsconfig.json b/third_party/blink/web_tests/http/tests/devtools/tsconfig.json
new file mode 100644
index 0000000..a5ed517
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/tsconfig.json
@@ -0,0 +1,41 @@
+{
+  "extends": "../../../../../devtools-frontend/src/config/typescript/tsconfig.base.json",
+  "compilerOptions": {
+    "lib": [
+      "esnext",
+      "dom",
+      "dom.iterable",
+      "Webworker",
+      "Webworker.Iterable"
+    ],
+    "rootDirs": ["../../../../../devtools-frontend/src/front_end", "./"],
+    "outDir": "ignored-for-vscode",
+    "baseUrl": "../../../../../devtools-frontend/src/front_end",
+    "paths": {
+      "test_runner": ["./legacy_test_runner/test_runner/test_runner.js"],
+      "accessibility_test_runner": ["./legacy_test_runner/accessibility_test_runner/accessibility_test_runner.js"],
+      "application_test_runner": ["./legacy_test_runner/application_test_runner/application_test_runner.js"],
+      "axe_core_test_runner": ["./legacy_test_runner/axe_core_test_runner/axe_core_test_runner.js"],
+      "bindings_test_runner": ["./legacy_test_runner/bindings_test_runner/bindings_test_runner.js"],
+      "console_test_runner": ["./legacy_test_runner/console_test_runner/console_test_runner.js"],
+      "coverage_test_runner": ["./legacy_test_runner/coverage_test_runner/coverage_test_runner.js"],
+      "cpu_profiler_test_runner": ["./legacy_test_runner/cpu_profiler_test_runner/cpu_profiler_test_runner.js"],
+      "data_grid_test_runner": ["./legacy_test_runner/data_grid_test_runner/data_grid_test_runner.js"],
+      "device_mode_test_runner": ["./legacy_test_runner/device_mode_test_runner/device_mode_test_runner.js"],
+      "elements_test_runner": ["./legacy_test_runner/elements_test_runner/elements_test_runner.js"],
+      "extensions_test_runner": ["./legacy_test_runner/extensions_test_runner/extensions_test_runner.js"],
+      "heap_profiler_test_runner": ["./legacy_test_runner/heap_profiler_test_runner/heap_profiler_test_runner.js"],
+      "layers_test_runner": ["./legacy_test_runner/layers_test_runner/layers_test_runner.js"],
+      "network_test_runner": ["./legacy_test_runner/network_test_runner/network_test_runner.js"],
+      "performance_test_runner": ["./legacy_test_runner/performance_test_runner/performance_test_runner.js"],
+      "sdk_test_runner": ["./legacy_test_runner/sdk_test_runner/sdk_test_runner.js"],
+      "security_test_runner": ["./legacy_test_runner/security_test_runner/security_test_runner.js"],
+      "sources_test_runner": ["./legacy_test_runner/sources_test_runner/sources_test_runner.js"],
+      "devtools/*": ["./*"]
+    }
+  },
+  "include": [
+    "../../../../../devtools-frontend/src/front_end",
+    "./"
+  ]
+}
diff --git a/third_party/jacoco/3pp/3pp.pb b/third_party/jacoco/3pp/3pp.pb
index 287bca7..c7ecc1a0 100644
--- a/third_party/jacoco/3pp/3pp.pb
+++ b/third_party/jacoco/3pp/3pp.pb
@@ -1,11 +1,22 @@
 create {
   source {
-    url {
-      download_url: "https://repo1.maven.org/maven2/org/jacoco/jacoco/0.8.8/jacoco-0.8.8.zip"
-      version: "0.8.8"
-      extension: ".zip"
+    git {
+      repo: "https://github.com/jacoco/jacoco.git"
+      tag_pattern: "v%s"
+      version_restriction {
+        op: EQ
+        val: "0.8.3"
+      }
     }
-    unpack_archive: true
+    patch_dir: "patches"
+    patch_version: "chromium.1"
+  }
+  build {
+    install: "install.py"
+    tool: "chromium/third_party/maven"
+    # TODO(crbug.com/1412466): jacoco 0.8.3 can't use the latest chromium jdk (17).
+    # This may be changed to chromium normal jdk when jacoco is upgraded to newer versions.
+    external_dep: "chromium/third_party/jdk@2@11.0.15+10.cr0"
   }
 }
 
diff --git a/third_party/jacoco/3pp/install.py b/third_party/jacoco/3pp/install.py
new file mode 100755
index 0000000..4f8bb54
--- /dev/null
+++ b/third_party/jacoco/3pp/install.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import glob
+import os
+import shutil
+import subprocess
+import sys
+
+
+_JACOCO_BUILD_SUB_DIR = 'org.jacoco.build'
+
+
+def install(output_prefix, deps_prefix):
+
+  # Set up JAVA_HOME and PATH for the mvn command to find the JDK.
+  env = os.environ.copy()
+  env['JAVA_HOME'] = os.path.join(deps_prefix, 'current')
+  java_home_bin = os.path.join(deps_prefix, 'current', 'bin')
+  env['PATH'] = '%s:%s' % (env.get('PATH', ''), java_home_bin)
+
+  # Building Jacoco following instructions from:
+  # https://www.jacoco.org/jacoco/trunk/doc/build.html
+
+  # Change working dir to jacoco build dir.
+  os.chdir(os.path.join(os.getcwd(), _JACOCO_BUILD_SUB_DIR))
+
+  # Build Jacoco.
+  subprocess.run(['mvn', 'clean', 'verify', '-DskipTests'], env=env, check=True)
+
+  # Find build ouput and move lib dir to output.
+  build_output_dir = os.path.join(os.getcwd(), '..', 'jacoco', 'target')
+  file_pattern = os.path.join(build_output_dir, 'jacoco-%s.*.zip' % env['_3PP_VERSION'])
+  for item in glob.glob(file_pattern):
+    shutil.unpack_archive(item, build_output_dir)
+    break
+
+  os.makedirs(output_prefix, exist_ok=True)
+  shutil.move(os.path.join(build_output_dir, 'lib'), output_prefix)
+
+
+if __name__ == '__main__':
+  install(sys.argv[1], sys.argv[2])
+
diff --git a/third_party/jacoco/3pp/install.sh b/third_party/jacoco/3pp/install.sh
deleted file mode 100755
index c48ac0d..0000000
--- a/third_party/jacoco/3pp/install.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-# Copyright 2023 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-set -e
-set -x
-set -o pipefail
-
-PREFIX="$1"
-
-cp -R "lib" "$PREFIX"
\ No newline at end of file
diff --git a/third_party/jacoco/3pp/patches/0001-hardcode-properties.patch b/third_party/jacoco/3pp/patches/0001-hardcode-properties.patch
new file mode 100644
index 0000000..4a2fa32
--- /dev/null
+++ b/third_party/jacoco/3pp/patches/0001-hardcode-properties.patch
@@ -0,0 +1,29 @@
+diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
+index 9020c2fc..7c3d4399 100644
+--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
++++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
+@@ -33,7 +33,10 @@ final class ConfigLoader {
+
+ 	static Properties load(final String resource, final Properties system) {
+ 		final Properties result = new Properties();
+-		loadResource(resource, result);
++		// Local modification: Do not read from resource file because strict mode
++		// doesn't allow this. See crbug.com/1401476. Using hardcoded properties
++		// here.
++		result.setProperty("output", "none");
+ 		loadSystemProperties(system, result);
+ 		substSystemProperties(result, system);
+ 		return result;
+diff --git a/org.jacoco.examples.test/src/test/resources/verify-offline.groovy b/org.jacoco.examples.test/src/test/resources/verify-offline.groovy
+index 0f00234b..2c37184a 100644
+--- a/org.jacoco.examples.test/src/test/resources/verify-offline.groovy
++++ b/org.jacoco.examples.test/src/test/resources/verify-offline.groovy
+@@ -10,7 +10,7 @@
+  *
+  *******************************************************************************/
+ File realBaseDir = new File(basedir, "../../../target/it-offline/build");
+-assert new File(realBaseDir, "target/site/jacoco/index.html").exists();
++// For local modification in ConfigLoader.
+ assert !new File(realBaseDir, "target/site/jacoco-it/index.html").exists();
+ assert new File(realBaseDir, "build.log").getText().contains(":restore-instrumented-classes");
+ return true;
diff --git a/third_party/swift-toolchain/3pp/3pp.pb b/third_party/swift-toolchain/3pp/3pp.pb
index 94e80239..ae9f2bfe 100644
--- a/third_party/swift-toolchain/3pp/3pp.pb
+++ b/third_party/swift-toolchain/3pp/3pp.pb
@@ -17,13 +17,13 @@
   platform_re: "mac-.*"
   source {
     url {
-      download_url: "https://download.swift.org/swift-5.7-release/xcode/swift-5.7-RELEASE/swift-5.7-RELEASE-osx.pkg"
-      version: "5.7-release"
+      download_url: "https://download.swift.org/swift-5.8-release/xcode/swift-5.8-RELEASE/swift-5.8-RELEASE-osx.pkg"
+      version: "5.8-release"
     }
   }
   build {
     install: "install-mac.sh"
-    install: "swift-5.7-RELEASE-osx"
+    install: "swift-5.8-RELEASE-osx"
   }
 }
 
diff --git a/third_party/swift-toolchain/OWNERS b/third_party/swift-toolchain/OWNERS
index 57ad6d05..40a68c7 100644
--- a/third_party/swift-toolchain/OWNERS
+++ b/third_party/swift-toolchain/OWNERS
@@ -1,2 +1 @@
-pinkerton@chromium.org
 rohitrao@chromium.org
diff --git a/third_party/swift-toolchain/README.chromium b/third_party/swift-toolchain/README.chromium
index 502199e..04a8750 100644
--- a/third_party/swift-toolchain/README.chromium
+++ b/third_party/swift-toolchain/README.chromium
@@ -1,8 +1,8 @@
 Name: Swift toolchain
 Short Name: swift-toolchain
 URL: https://www.swift.org/download/
-Version: 5.7
-Date: 2022 September 12
+Version: 5.8
+Date: 2023 March 30
 License: Apache 2.0
 License File: LICENSE
 Security Critical: no
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 29597d3..c673c8d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5158,6 +5158,11 @@
   <int value="8" label="Bottom right"/>
 </enum>
 
+<enum name="AsmJsInstantiateResult">
+  <int value="0" label="asm.js instantiation succeeded"/>
+  <int value="1" label="asm.js instantiation failed"/>
+</enum>
+
 <enum name="AssignedLabelSource">
   <int value="0" label="Id"/>
   <int value="1" label="Name"/>
@@ -64121,6 +64126,7 @@
   <int value="904811479" label="query-tiles-enable-trending"/>
   <int value="907051864" label="UseMultiPlaneFormatForHardwareVideo:disabled"/>
   <int value="907056713" label="DetectFormSubmissionOnFormClear:enabled"/>
+  <int value="907696422" label="SafetyHub:disabled"/>
   <int value="908302031"
       label="OmniboxUIExperimentElideSuggestionUrlAfterHost:enabled"/>
   <int value="908370794" label="UserActivityPredictionMlService:enabled"/>
@@ -65338,6 +65344,7 @@
   <int value="1577205328"
       label="DataReductionProxyEnabledWithNetworkService:enabled"/>
   <int value="1577544798" label="StartSurfaceWithAccessibility:disabled"/>
+  <int value="1577651674" label="SafetyHub:enabled"/>
   <int value="1579084737" label="TemporaryUnexpireFlagsM80:disabled"/>
   <int value="1579461102" label="MemoryCoordinator:disabled"/>
   <int value="1580340993" label="EnableTabMuting:enabled"/>
@@ -94469,6 +94476,10 @@
   <int value="13" label="Restricted notice flow completed"/>
   <int value="14"
       label="Restricted notice not shown due to full notice acknowledged"/>
+  <int value="15"
+      label="User is waiting for graduation and notice flow is not completed"/>
+  <int value="16"
+      label="User is waiting for graduation and notice flow is completed"/>
 </enum>
 
 <enum name="SettingsPrivacySandboxStartupStates">
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index 3a8fde7..ba0b1e20 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -4195,27 +4195,6 @@
       label="Used super pages in the configurable pool. Only recorded for
              64-bit with process uptime 24H+."/>
   <suffix
-      name="PartitionAlloc.AddressSpace.PkeyPoolLargestAvailableReservation"
-      label="Longest free chunk in the pkey pool. Only recorded on
-             pkey-supported platforms."/>
-  <suffix
-      name="PartitionAlloc.AddressSpace.PkeyPoolLargestAvailableReservation.After1H"
-      label="Longest free chunk in the pkey pool. Only recorded on
-             pkey-supported platforms with process uptime [1,24)H."/>
-  <suffix
-      name="PartitionAlloc.AddressSpace.PkeyPoolLargestAvailableReservation.After24H"
-      label="Longest free chunk in the pkey pool. Only recorded on
-             pkey-supported platforms with process uptime 24H+."/>
-  <suffix name="PartitionAlloc.AddressSpace.PkeyPoolUsage"
-      label="Used super pages in the pkey pool. Only recorded on
-             pkey-supported platforms."/>
-  <suffix name="PartitionAlloc.AddressSpace.PkeyPoolUsage.After1H"
-      label="Used super pages in the pkey pool. Only recorded on
-             pkey-supported platforms with process uptime [1,24)H."/>
-  <suffix name="PartitionAlloc.AddressSpace.PkeyPoolUsage.After24H"
-      label="Used super pages in the pkey pool. Only recorded on
-             pkey-supported platforms with process uptime 24H+."/>
-  <suffix
       name="PartitionAlloc.AddressSpace.RegularPoolLargestAvailableReservation"
       label="Longest free chunk in the regular pool. Only recorded for
              64-bit."/>
@@ -4235,6 +4214,27 @@
   <suffix name="PartitionAlloc.AddressSpace.RegularPoolUsage.After24H"
       label="Used super pages in the regular pool. Only recorded when process
              uptime is 24H+."/>
+  <suffix
+      name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolLargestAvailableReservation"
+      label="Longest free chunk in the thread isolated pool. Only recorded on
+             supported platforms."/>
+  <suffix
+      name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolLargestAvailableReservation.After1H"
+      label="Longest free chunk in the thread isolated pool. Only recorded on
+             supported platforms with process uptime [1,24)H."/>
+  <suffix
+      name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolLargestAvailableReservation.After24H"
+      label="Longest free chunk in the thread isolated pool. Only recorded on
+             supported platforms with process uptime 24H+."/>
+  <suffix name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolUsage"
+      label="Used super pages in the thread isolated pool. Only recorded on
+             supported platforms."/>
+  <suffix name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolUsage.After1H"
+      label="Used super pages in the thread isolated pool. Only recorded on
+             supported platforms with process uptime [1,24)H."/>
+  <suffix name="PartitionAlloc.AddressSpace.ThreadIsolatedPoolUsage.After24H"
+      label="Used super pages in the thread isolated pool. Only recorded on
+             supported platforms with process uptime 24H+."/>
   <suffix name="PartitionAlloc.AllocatedObjects"
       label="Only counting objects allocated using Partition allocator."/>
   <suffix name="PartitionAlloc.CommittedSize.ArrayBuffer"
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 05557c6..68c700a 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -1277,7 +1277,7 @@
 </histogram>
 
 <histogram name="Sync.Startup.TimeDeferred2" units="ms"
-    expires_after="2023-06-16">
+    expires_after="2024-05-10">
   <owner>mastiz@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <component>Services&gt;Sync</component>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index d734cb3..7b48867 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -40,6 +40,22 @@
   <summary>Array buffer sizes for which V8 failed to allocate memory.</summary>
 </histogram>
 
+<histogram name="V8.AsmjsInstantiateResult" enum="AsmJsInstantiateResult"
+    expires_after="2024-06-06">
+  <owner>ahaas@chromium.org</owner>
+  <owner>ecmziegler@chromium.org</owner>
+  <owner>wasm-v8@google.com</owner>
+  <summary>
+    Counter of succeeded and failed asm.js instantiations with the asm.js
+    pipeline. Success means that the asm.js pipeline is used to execute the
+    asm.js module. Failure means that the asm.js module gets executed with the
+    normal JavaScript pipeline. Reasons for failed instantiations can be that
+    the asm.js module gets instantiated with an invalid memory type like a
+    WebAssembly memory. Recorded after each attempt to instantiate asm.js module
+    with the asm.js pipeline.
+  </summary>
+</histogram>
+
 <histogram name="V8.CodeCacheRejectReason" enum="V8CodeCacheRejectReason"
     expires_after="M77">
   <owner>yangguo@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 45196f6..28a5cd86 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "3c46a5b0f822637b5840ab8a108523623e20b8ea",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/0b3824020e3b444cb05de5020ded5102fc259507/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/6c650e1ad49593538b1bff04070cce56b8f036f9/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "336a42cb9ec3c417e13a97816271fec10cdf67e5",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "1d8180921422595a6d099a574d0d7c68c32dbde1",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/0b3824020e3b444cb05de5020ded5102fc259507/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6c650e1ad49593538b1bff04070cce56b8f036f9/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index ea541405..87852fa 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -276,8 +276,18 @@
              "ReadAnythingWithScreen2x",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// This feature can be used as an emergency kill switch to disable Screen AI
+// main content extraction service in case of security or other issues.
+// Please talk to components/services/screen_ai/OWNERS if any changes to this
+// feature or its functionality is needed.
+BASE_FEATURE(kEmergencyDisableScreenAIMainContentExtraction,
+             "EmergencyDisableScreenAIMainContentExtraction",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsReadAnythingWithScreen2xEnabled() {
-  return base::FeatureList::IsEnabled(::features::kReadAnythingWithScreen2x);
+  return base::FeatureList::IsEnabled(::features::kReadAnythingWithScreen2x) &&
+         !base::FeatureList::IsEnabled(
+             ::features::kEmergencyDisableScreenAIMainContentExtraction);
 }
 
 bool IsScreenAIServiceNeeded() {
@@ -295,10 +305,20 @@
   return base::FeatureList::IsEnabled(::features::kScreenAIDebugMode);
 }
 
+// This feature can be used as an emergency kill switch to disable Screen AI
+// OCR service in case of security or other issues.
+// Please talk to components/services/screen_ai/OWNERS if any changes to this
+// feature or its functionality is needed.
+BASE_FEATURE(kEmergencyDisableScreenAIOCR,
+             "EmergencyDisableScreenAIOCR",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kPdfOcr, "PdfOcr", base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsPdfOcrEnabled() {
-  return base::FeatureList::IsEnabled(::features::kPdfOcr);
+  return base::FeatureList::IsEnabled(::features::kPdfOcr) &&
+         !base::FeatureList::IsEnabled(
+             ::features::kEmergencyDisableScreenAIOCR);
 }
 
 BASE_FEATURE(kLayoutExtraction,
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 530ea5a..78987e3a 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -224,8 +224,8 @@
 // distills web pages using an ML model.
 AX_BASE_EXPORT bool IsReadAnythingWithScreen2xEnabled();
 
-// Returns true if Screen AI Service is needed as either
-// ScreenAIVisualAnnotations or ReadAnythingWithScreen2x are enabled.
+// Returns true if Screen AI Service is needed as any of the features relying on
+// it are enabled.
 AX_BASE_EXPORT bool IsScreenAIServiceNeeded();
 
 // If enabled, ScreenAI library writes some debug data in /tmp.
diff --git a/ui/base/pointer/touch_editing_controller.h b/ui/base/pointer/touch_editing_controller.h
index aa094bee..5777e9c3 100644
--- a/ui/base/pointer/touch_editing_controller.h
+++ b/ui/base/pointer/touch_editing_controller.h
@@ -90,6 +90,12 @@
   // Gets the NativeView hosting the client.
   virtual gfx::NativeView GetNativeView() const = 0;
 
+  // Checks whether the client is currently in a selection dragging state, i.e.
+  // whether it is currently handling scroll gestures to adjust the cursor or
+  // selection. If so, selection changes will notify the controller to update
+  // the quick menu and touch selection magnifier without showing touch handles.
+  virtual bool IsSelectionDragging() const = 0;
+
   // Converts a point to/from screen coordinates from/to client view.
   virtual void ConvertPointToScreen(gfx::Point* point) = 0;
   virtual void ConvertPointFromScreen(gfx::Point* point) = 0;
diff --git a/ui/file_manager/file_manager/containers/nudge_container.ts b/ui/file_manager/file_manager/containers/nudge_container.ts
index 97776c2b..1f74c30 100644
--- a/ui/file_manager/file_manager/containers/nudge_container.ts
+++ b/ui/file_manager/file_manager/containers/nudge_container.ts
@@ -196,11 +196,24 @@
     }
     window.addEventListener(
         'resize', this.throttledRepositionCallback_.bind(this), config);
-    document.addEventListener('keydown', e => this.handleKeyDown_(e), config);
-    document.addEventListener(
-        'pointerdown', e => this.handlePointerDown_(e), config);
-    anchor.addEventListener(
-        'blur', (_: Event) => this.closeNudge(this.currentNudgeType_), config);
+
+    if (info.dismissText) {
+      // Self dismissable nudge only dismisses if the user clicks on the dismiss
+      // button.
+      this.nudge_.addEventListener(
+          XfNudge.events.DISMISS, () => this.closeNudge(this.currentNudgeType_),
+          config);
+      this.nudge_.dismissText = info.dismissText;
+    } else {
+      // Otherwise the nudge dismisses when user clicks anywhere in the app.
+      document.addEventListener('keydown', e => this.handleKeyDown_(e), config);
+      document.addEventListener(
+          'pointerdown', e => this.handlePointerDown_(e), config);
+      anchor.addEventListener(
+          'blur', (_: Event) => this.closeNudge(this.currentNudgeType_),
+          config);
+      this.nudge_.dismissText = '';
+    }
 
     this.nudge_.anchor = anchor;
     this.nudge_.content = info.content();
@@ -312,6 +325,7 @@
  */
 export enum NudgeType {
   TEST_NUDGE = 'test-nudge',
+  MANUAL_TEST_NUDGE = 'manual-test-nudge',
   TRASH_NUDGE = 'trash-nudge',
   ONE_DRIVE_MOVED_FILE_NUDGE = 'one-drive-moved-file-nudge',
   DRIVE_MOVED_FILE_NUDGE = 'drive-moved-file-nudge',
@@ -336,6 +350,11 @@
   // The date the nudge expires, after this date even if the nudge is invoked it
   // will not appear.
   expiryDate: Date;
+
+  // When the nudge has a dismiss text, the user can dismiss by clicking the
+  // dismiss button. Otherwise the nudge is dismissed when clicking anywhere in
+  // the app/document.
+  dismissText?: string;
 }
 
 /**
@@ -358,6 +377,28 @@
     // Expire this after 4 releases (expires when M112 hits Stable).
     expiryDate: new Date(2023, 4, 6),
   },
+  [NudgeType['MANUAL_TEST_NUDGE']]: {
+    anchor: () => {
+      const children = Array.from(document.querySelectorAll<HTMLElement>(
+          '.tree-item[section-start="my_files"] > .tree-children > .tree-item .entry-name'));
+
+      for (const child of children) {
+        if (child.innerText !== 'Downloads') {
+          continue;
+        }
+
+        return child.parentElement?.querySelector<HTMLSpanElement>(
+                   '.item-icon') ??
+            null;
+      }
+
+      return null;
+    },
+    content: () => str('ONE_DRIVE_MOVED_FILE_NUDGE'),
+    direction: NudgeDirection.TRAILING_DOWNWARD,
+    expiryDate: new Date(2999, 1, 1),
+    dismissText: str('OK_LABEL'),
+  },
   [NudgeType['ONE_DRIVE_MOVED_FILE_NUDGE']]: {
     anchor: () => {
       return document
@@ -370,6 +411,7 @@
     direction: NudgeDirection.TRAILING_DOWNWARD,
     // Expire after 4 releases (expires when M120 hits Stable).
     expiryDate: new Date(2023, 12, 5),
+    dismissText: str('OK_LABEL'),
   },
   [NudgeType['DRIVE_MOVED_FILE_NUDGE']]: {
     anchor: () => {
@@ -383,6 +425,7 @@
     direction: NudgeDirection.TRAILING_DOWNWARD,
     // Expire after 4 releases (expires when M120 hits Stable).
     expiryDate: new Date(2023, 12, 5),
+    dismissText: str('OK_LABEL'),
   },
   [NudgeType['SEARCH_V2_EDUCATION_NUDGE']]: {
     anchor: () => document.querySelector<HTMLSpanElement>('#search-wrapper'),
diff --git a/ui/file_manager/file_manager/containers/nudge_container_unittest.ts b/ui/file_manager/file_manager/containers/nudge_container_unittest.ts
index 518c132..bb52aa44 100644
--- a/ui/file_manager/file_manager/containers/nudge_container_unittest.ts
+++ b/ui/file_manager/file_manager/containers/nudge_container_unittest.ts
@@ -99,7 +99,7 @@
  * The repositions are setup as 0, this indicates the nudge has not been moved
  * to position, i.e. an uninitialised state.
  */
-function waitUntilRepositionsUnitialised() {
+function waitUntilRepositionsUninitialised() {
   return waitUntilRepositions(0);
 }
 
@@ -115,24 +115,28 @@
 /**
  * Tests that a defined nudge without an anchor is not shown.
  */
-export async function testShowWorksOnlyWhenAProperAnchorIsAvailable() {
+export async function testShowWorksOnlyWhenAProperAnchorIsAvailable(
+    done: () => void) {
   // The first showing of nudge should not work as the <div id="test"> is not
   // visible on the DOM.
   nudgeContainer!.showNudge(NudgeType.TEST_NUDGE);
   assertFalse(await nudgeContainer!.checkSeen(NudgeType.TEST_NUDGE));
-  await waitUntilRepositionsUnitialised();
+  await waitUntilRepositionsUninitialised();
 
   // The second showing of the nudge should work as we've appended the <div
   // id="test"> to the DOM.
   await createAndAppendTestDiv();
   nudgeContainer!.showNudge(NudgeType.TEST_NUDGE);
   await waitUntilRepositions(1);
+
+  done();
 }
 
 /**
  * Tests that the enter key dismisses the nudge.
  */
-export async function testEnterKeyHidesNudge() {
+export async function testEnterKeyHidesNudge(done: () => void) {
+  nudgeInfo[NudgeType.TEST_NUDGE].dismissText = '';
   await createAndShowTestNudge();
 
   const keyDownEvent = new KeyboardEvent('keydown', {key: 'Enter'});
@@ -144,13 +148,15 @@
   assertTrue(
       await nudgeContainer!.checkSeen(NudgeType.TEST_NUDGE),
       'check nudge has been seen');
+
+  done();
 }
 
 /**
  * Tests that a <p> element is appended beside the anchor element with the nudge
  * content to enable screen readers to hear the content.
  */
-export async function testAriaDescribedByElementIsAdded() {
+export async function testAriaDescribedByElementIsAdded(done: () => void) {
   await createAndShowTestNudge();
 
   await waitUntil(() => getDescribedByElement() !== null);
@@ -160,13 +166,16 @@
   assertNotEquals(describedByElement, null);
   assertEquals(
       describedByElement!.innerText, nudgeInfo[NudgeType.TEST_NUDGE].content());
+
+  done();
 }
 
 /**
  * Tests that the nudge moves with the element if it gets moved
  * programmatically.
  */
-export async function testNudgeMovesWhenElementIsRepositioned() {
+export async function testNudgeMovesWhenElementIsRepositioned(
+    done: () => void) {
   const testDiv = await createAndAppendTestDiv();
   nudgeContainer!.showNudge(NudgeType.TEST_NUDGE);
   await waitUntilRepositions(1);
@@ -175,17 +184,19 @@
   testDiv.style.left = '200px';
   testDiv.style.top = '200px';
   await waitUntilRepositions(2);
+
+  done();
 }
 
 /**
  * Tests that the nudge is not shown after being shown for the first time.
  */
-export async function testNudgeIsNotShownAfterFirstTime() {
+export async function testNudgeIsNotShownAfterFirstTime(done: () => void) {
   await createAndShowTestNudge();
 
   // Close the nudge which should set the nudge to "seen".
   nudgeContainer!.closeNudge(NudgeType.TEST_NUDGE);
-  await waitUntilRepositionsUnitialised();
+  await waitUntilRepositionsUninitialised();
   assertTrue(
       await nudgeContainer!.checkSeen(NudgeType.TEST_NUDGE),
       'check nudge has been seen');
@@ -193,17 +204,47 @@
   // Assert that showing the nudge again doesn't work as it's already been
   // "seen".
   nudgeContainer!.showNudge(NudgeType.TEST_NUDGE);
-  await waitUntilRepositionsUnitialised();
+  await waitUntilRepositionsUninitialised();
+
+  done();
 }
 
 /**
  * Tests the nudge doesn't show if the expiry period has elapsed.
  */
-export async function testNudgeIsNotShownIfExpiryPeriodElapsed() {
+export async function testNudgeIsNotShownIfExpiryPeriodElapsed(
+    done: () => void) {
   // Update the test nudge timestamp to be 60s before now.
   nudgeInfo[NudgeType.TEST_NUDGE].expiryDate =
       new Date(new Date().getTime() - (60 * 1000));
   await createAndAppendTestDiv();
   nudgeContainer!.showNudge(NudgeType.TEST_NUDGE);
-  await waitUntilRepositionsUnitialised();
+  await waitUntilRepositionsUninitialised();
+
+  done();
+}
+
+/**
+ * Tests the nudge is dismissed by the dismiss button, when it has a
+ * dismissText.
+ */
+export async function testNudgeDismissButton(done: () => void) {
+  nudgeInfo[NudgeType.TEST_NUDGE].dismissText = 'Ok';
+  await createAndShowTestNudge();
+
+  const button = nudgeElement?.shadowRoot!.getElementById('dismiss')!;
+  assertTrue(
+      button.getBoundingClientRect().width > 0,
+      'Dismiss button should be visible');
+
+  // Click and wait it to dismiss.
+  button.click();
+
+  // Reposition to hidden.
+  await waitUntilRepositionsUninitialised();
+  assertTrue(
+      await nudgeContainer!.checkSeen(NudgeType.TEST_NUDGE),
+      'check nudge has been seen');
+
+  done();
 }
diff --git a/ui/file_manager/file_manager/widgets/xf_nudge.html b/ui/file_manager/file_manager/widgets/xf_nudge.html
index 546f0b2..524f8b9 100644
--- a/ui/file_manager/file_manager/widgets/xf_nudge.html
+++ b/ui/file_manager/file_manager/widgets/xf_nudge.html
@@ -41,11 +41,19 @@
   color: var(--cros-button-label-color-primary);
   font: var(--cros-body-2-font);
 }
+
+#dismiss {
+  --focus-shadow-color: var(--cros-sys-inverse_primary);
+  align-self: center;
+  border-radius: 8px;
+  color: var(--cros-button-label-color-primary);
+}
 </style>
 <div aria-hidden="true" id="container">
   <div id="dot"></div>
   <div id="bubble">
     <span class="icon"></span>
     <span id="text"></span>
+    <cr-button id="dismiss" aria-describedby="text" hidden></cr-button>
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/file_manager/file_manager/widgets/xf_nudge.ts b/ui/file_manager/file_manager/widgets/xf_nudge.ts
index 5199bd9..0f7d748 100644
--- a/ui/file_manager/file_manager/widgets/xf_nudge.ts
+++ b/ui/file_manager/file_manager/widgets/xf_nudge.ts
@@ -42,6 +42,11 @@
   private contentSlot_: HTMLElement;
 
   /**
+   * The dismiss button element.
+   */
+  private dismissButton_: HTMLElement;
+
+  /**
    * The direction of the nudge relative to the anchor.
    */
   private direction_: NudgeDirection = NudgeDirection.TOP_STARTWARD;
@@ -52,6 +57,11 @@
   private content_: string = '';
 
   /**
+   * Text used in the dismiss button. When empty the button is hidden.
+   */
+  private dismissText_: string = '';
+
+  /**
    * How many times the nudge has been repositioned, this is reset when the
    * nudge is hidden.
    */
@@ -67,9 +77,23 @@
 
     this.bubble_ = this.shadowRoot!.getElementById('bubble')!;
     this.contentSlot_ = this.shadowRoot!.getElementById('text')!;
+    this.dismissButton_ = this.shadowRoot!.getElementById('dismiss')!;
+    this.dismissButton_.addEventListener(
+        'click', this.dismissClicked_.bind(this));
     this.dot_ = this.shadowRoot!.getElementById('dot')!;
   }
 
+  static get events() {
+    return {
+      DISMISS: 'dismiss',
+    } as const;
+  }
+
+  private dismissClicked_() {
+    this.dispatchEvent(new CustomEvent(
+        XfNudge.events.DISMISS, {bubbles: true, composed: true}));
+  }
+
   /**
    * Show the nudge attached to a provided anchor. Note: This class should not
    * handle any logic on _when_ a nudge should be shown. This should be
@@ -83,6 +107,8 @@
       throw new Error('Attempted to show <xf-nudge> without an anchor');
     }
 
+    this.dismissButton_.innerText = this.dismissText_;
+    this.dismissButton_.toggleAttribute('hidden', this.dismissText_ === '');
     this.contentSlot_.innerText = this.content_;
     this.reposition();
   }
@@ -159,6 +185,17 @@
   }
 
   /**
+   * Sets the text for the dismiss button, when empty hides the button.
+   */
+  set dismissText(text: string) {
+    this.dismissText_ = text;
+  }
+
+  get dismissText() {
+    return this.dismissText_;
+  }
+
+  /**
    * Sets the direction of the nudge to appear relative to the anchor point.
    */
   set direction(direction: NudgeDirection) {
diff --git a/ui/file_manager/file_manager/widgets/xf_nudge_unittest.ts b/ui/file_manager/file_manager/widgets/xf_nudge_unittest.ts
index 2563801..7b97817 100644
--- a/ui/file_manager/file_manager/widgets/xf_nudge_unittest.ts
+++ b/ui/file_manager/file_manager/widgets/xf_nudge_unittest.ts
@@ -4,7 +4,7 @@
 
 import './xf_nudge.js';
 
-import {assertEquals, assertGT, assertLT, assertThrows} from 'chrome://webui-test/chromeos/chai_assert.js';
+import {assertEquals, assertGT, assertLT, assertThrows, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
 
 import {NudgeDirection, XfNudge} from './xf_nudge.js';
 
@@ -107,7 +107,7 @@
 /**
  * Tests that the nudge gets repositioned appopriately if the element moves.
  */
-export async function testNudgeGetsRepositionedCorrectlyIfAnchorChanges() {
+export function testNudgeGetsRepositionedCorrectlyIfAnchorChanges() {
   const nudge = getNudge();
 
   // Insert an anchor and make it position relative to ensure we can position it
@@ -139,3 +139,47 @@
   assertEquals(nudge.dotRect.y, 412, 'dot y-ordinate');
   assertEquals(nudge.dotRect.x, 354, 'dot x-ordinate');
 }
+
+/**
+ * Tests that setting the dismissText displays the dismiss button and setting an
+ * empty text hides the button.
+ */
+export async function testDismissButtonHideAndShow() {
+  const nudge = getNudge();
+
+  // Create an anchor element and insert it before the nudge in the DOM.
+  const anchor = document.createElement('div');
+  anchor.style.width = '100px';
+  anchor.style.height = '100px';
+  anchor.innerText = 'Test anchor';
+  nudge.insertAdjacentElement('beforebegin', anchor);
+
+  // Add the dismiss text and display the nudge.
+  nudge.content = 'Nudge contents';
+  nudge.dismissText = 'Dismiss';
+  nudge.direction = NudgeDirection.BOTTOM_ENDWARD;
+  nudge.anchor = anchor;
+  nudge.show();
+
+  // Check that the button is visible.
+  const dismissButton = nudge.shadowRoot!.getElementById('dismiss')!;
+  assertEquals(
+      dismissButton.innerText, 'Dismiss',
+      'dismiss button should show the dismissText');
+  assertTrue(dismissButton.getBoundingClientRect().width > 0);
+
+  // <xf-nudge> fires its DISMISS event when user clicks on the dismiss button.
+  let clicked = false;
+  nudge.addEventListener(XfNudge.events.DISMISS, () => clicked = true);
+  dismissButton.click();
+  assertTrue(clicked, '<xf-nudge> should fire DISMISS event');
+
+  nudge.hide();
+
+  // Displaying without dismiss text, the button should be hidden.
+  nudge.dismissText = '';
+  nudge.show();
+  assertEquals(
+      dismissButton.innerText, '', 'dismiss button text should be empty');
+  assertEquals(dismissButton.getBoundingClientRect().width, 0);
+}
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 703b4fc..7ea833d9 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -845,12 +845,14 @@
               GetRenderText()->GetUpdatedDisplayOffset().x();
           show_touch_handles_after_scroll_ =
               touch_selection_controller_ != nullptr;
+          // Deactivate touch selection controller when scrolling.
+          DestroyTouchSelection();
         } else {
+          // Create touch selection controller to show a magnifier when
+          // selection dragging.
+          CreateTouchSelectionControllerAndNotifyIt();
           show_touch_handles_after_scroll_ = true;
         }
-        // Deactivate touch selection handles when scrolling or selection
-        // dragging.
-        DestroyTouchSelection();
         event->SetHandled();
       }
       break;
@@ -864,6 +866,7 @@
           drag_start_location_x_ = event->location().x();
           drag_start_display_offset_ =
               GetRenderText()->GetUpdatedDisplayOffset().x();
+          DestroyTouchSelection();
           show_touch_handles_after_scroll_ = true;
         }
         switch (selection_dragging_state_) {
@@ -889,11 +892,11 @@
     case ui::ET_GESTURE_SCROLL_END:
     case ui::ET_SCROLL_FLING_START:
       if (HasFocus()) {
+        selection_dragging_state_ = SelectionDraggingState::kNone;
         if (show_touch_handles_after_scroll_) {
           CreateTouchSelectionControllerAndNotifyIt();
           show_touch_handles_after_scroll_ = false;
         }
-        selection_dragging_state_ = SelectionDraggingState::kNone;
         event->SetHandled();
       }
       break;
@@ -1389,6 +1392,10 @@
   return GetWidget()->GetNativeView();
 }
 
+bool Textfield::IsSelectionDragging() const {
+  return selection_dragging_state_ != SelectionDraggingState::kNone;
+}
+
 void Textfield::ConvertPointToScreen(gfx::Point* point) {
   View::ConvertPointToScreen(this, point);
 }
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 02a4f69..6bae17b 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -389,6 +389,7 @@
                              gfx::SelectionBound* focus) override;
   gfx::Rect GetBounds() override;
   gfx::NativeView GetNativeView() const override;
+  bool IsSelectionDragging() const override;
   void ConvertPointToScreen(gfx::Point* point) override;
   void ConvertPointFromScreen(gfx::Point* point) override;
   void OpenContextMenu(const gfx::Point& anchor) override;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index 23f7461..6080576 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/pickle.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -3738,36 +3737,6 @@
   EXPECT_EQ(range, gfx::Range(kCursorEndPos));
 }
 
-TEST_F(TextfieldTest, ScrollToPlaceCursorShowsTouchHandles) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      /*enabled_features=*/{::features::kTouchTextEditingRedesign},
-      /*disabled_features=*/{});
-
-  InitTextfield();
-  textfield_->SetText(u"Hello string world");
-
-  // Scroll in a horizontal direction to move the cursor.
-  const gfx::Point kScrollStart = views::View::ConvertPointToScreen(
-      textfield_, {GetCursorPositionX(2), GetCursorYForTesting()});
-  const gfx::Point kScrollEnd = views::View::ConvertPointToScreen(
-      textfield_, {GetCursorPositionX(15), GetCursorYForTesting()});
-  event_generator_->GestureScrollSequenceWithCallback(
-      kScrollStart, kScrollEnd, /*duration=*/base::Milliseconds(50),
-      /*steps=*/5,
-      base::BindLambdaForTesting(
-          [&](ui::EventType event_type, const gfx::Vector2dF& offset) {
-            if (event_type != ui::ET_GESTURE_SCROLL_UPDATE) {
-              return;
-            }
-            // Touch handles should be hidden during scroll.
-            EXPECT_FALSE(test_api_->touch_selection_controller());
-          }));
-
-  // Touch handles should be shown after scroll ends.
-  EXPECT_TRUE(test_api_->touch_selection_controller());
-}
-
 TEST_F(TextfieldTest, ScrollToPlaceCursorAdjustsDisplayOffset) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc
index 3bef4fa..a9f9f11 100644
--- a/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/ui/views/touchui/touch_selection_controller_impl.cc
@@ -435,16 +435,26 @@
       ConvertToScreen(client_view_, anchor);
   gfx::SelectionBound screen_bound_focus_clipped =
       ConvertToScreen(client_view_, focus);
-  if (screen_bound_anchor_clipped == selection_bound_1_clipped_ &&
-      screen_bound_focus_clipped == selection_bound_2_clipped_)
+  const bool is_client_selection_dragging = client_view_->IsSelectionDragging();
+  if (is_client_selection_dragging == is_client_selection_dragging_ &&
+      screen_bound_anchor_clipped == selection_bound_1_clipped_ &&
+      screen_bound_focus_clipped == selection_bound_2_clipped_) {
     return;
+  }
 
+  is_client_selection_dragging_ = is_client_selection_dragging;
   selection_bound_1_ = screen_bound_anchor;
   selection_bound_2_ = screen_bound_focus;
   selection_bound_1_clipped_ = screen_bound_anchor_clipped;
   selection_bound_2_clipped_ = screen_bound_focus_clipped;
 
-  if (dragging_handle_) {
+  if (is_client_selection_dragging) {
+    selection_handle_1_->SetWidgetVisible(false);
+    selection_handle_2_->SetWidgetVisible(false);
+    cursor_handle_->SetWidgetVisible(false);
+    UpdateQuickMenu();
+    ShowMagnifier(screen_bound_focus);
+  } else if (dragging_handle_) {
     // We need to reposition only the selection handle that is being dragged.
     // The other handle stays the same. Also, the selection handle being dragged
     // will always be at the end of selection, while the other handle will be at
@@ -485,6 +495,7 @@
       quick_menu_requested_ = true;
     }
     UpdateQuickMenu();
+    HideMagnifier();
   }
 }
 
diff --git a/ui/views/touchui/touch_selection_controller_impl.h b/ui/views/touchui/touch_selection_controller_impl.h
index 69b60eb4..a9e3851 100644
--- a/ui/views/touchui/touch_selection_controller_impl.h
+++ b/ui/views/touchui/touch_selection_controller_impl.h
@@ -158,6 +158,11 @@
   // Selection bounds, clipped to client view's boundaries.
   gfx::SelectionBound selection_bound_1_clipped_;
   gfx::SelectionBound selection_bound_2_clipped_;
+
+  // Used to track whether the client is selection dragging. If the client's
+  // selection dragging state changes, then the handles need to be updated on
+  // the next selection change notification.
+  bool is_client_selection_dragging_ = false;
 };
 
 }  // namespace views
diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index 8e6c069..674aedf 100644
--- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
@@ -796,6 +797,74 @@
   EXPECT_FALSE(ui::TouchSelectionMagnifierRunner::GetInstance()->IsRunning());
 }
 
+// Tests that the magnifier is shown when directly dragging the cursor in the
+// textfield, i.e. when performing a scroll gesture on the textfield rather than
+// on the touch handles.
+TEST_F(TouchSelectionControllerImplTest, MagnifierShownWhenDraggingCursor) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{::features::kTouchTextEditingRedesign},
+      /*disabled_features=*/{});
+
+  CreateTextfield();
+  textfield_->SetText(u"some text in a textfield");
+  ui::test::EventGenerator generator(
+      textfield_->GetWidget()->GetNativeView()->GetRootWindow());
+
+  // Scroll in a horizontal direction over the textfield to move the cursor.
+  // Magnifier should be shown during the dragging movement, then hidden once
+  // dragging ends.
+  const gfx::Point drag_start =
+      GetCursorPosition(gfx::SelectionModel(6, gfx::CURSOR_FORWARD));
+  const gfx::Point drag_end = drag_start + gfx::Vector2d(80, 0);
+  generator.GestureScrollSequenceWithCallback(
+      drag_start, drag_end, /*duration=*/base::Milliseconds(50),
+      /*steps=*/5,
+      base::BindRepeating([](ui::EventType event_type,
+                             const gfx::Vector2dF& offset) {
+        if (event_type == ui::ET_GESTURE_SCROLL_UPDATE) {
+          EXPECT_TRUE(
+              ui::TouchSelectionMagnifierRunner::GetInstance()->IsRunning());
+        }
+      }));
+  EXPECT_FALSE(ui::TouchSelectionMagnifierRunner::GetInstance()->IsRunning());
+}
+
+// Tests that touch handles are correctly shown when directly dragging the
+// cursor in the textfield.
+TEST_F(TouchSelectionControllerImplTest, DraggingCursorShowsHandle) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{::features::kTouchTextEditingRedesign},
+      /*disabled_features=*/{});
+
+  CreateTextfield();
+  textfield_->SetText(u"some text in a textfield");
+  ui::test::EventGenerator generator(
+      textfield_->GetWidget()->GetNativeView()->GetRootWindow());
+
+  // Scroll in a horizontal direction over the textfield to move the cursor.
+  // Touch handles should be hidden during the dragging movement, then the
+  // cursor handle should be shown once dragging ends.
+  const gfx::Point drag_start =
+      GetCursorPosition(gfx::SelectionModel(6, gfx::CURSOR_FORWARD));
+  const gfx::Point drag_end = drag_start + gfx::Vector2d(80, 0);
+  generator.GestureScrollSequenceWithCallback(
+      drag_start, drag_end, /*duration=*/base::Milliseconds(50),
+      /*steps=*/5,
+      base::BindLambdaForTesting(
+          [&](ui::EventType event_type, const gfx::Vector2dF& offset) {
+            if (event_type == ui::ET_GESTURE_SCROLL_UPDATE) {
+              EXPECT_FALSE(IsCursorHandleVisible());
+              EXPECT_FALSE(IsSelectionHandle1Visible());
+              EXPECT_FALSE(IsSelectionHandle2Visible());
+            }
+          }));
+  EXPECT_TRUE(IsCursorHandleVisible());
+  EXPECT_FALSE(IsSelectionHandle1Visible());
+  EXPECT_FALSE(IsSelectionHandle2Visible());
+}
+
 TEST_F(TouchSelectionControllerImplTest, TapOnHandleTogglesMenu) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
@@ -953,6 +1022,7 @@
   }
   gfx::Rect GetBounds() override { return gfx::Rect(bounds_.size()); }
   gfx::NativeView GetNativeView() const override { return window_; }
+  bool IsSelectionDragging() const override { return false; }
   void ConvertPointToScreen(gfx::Point* point) override {
     aura::client::ScreenPositionClient* screen_position_client =
         aura::client::GetScreenPositionClient(window_->GetRootWindow());
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
index 6b17ddc..e57e76d8 100644
--- a/ui/views/window/dialog_client_view.cc
+++ b/ui/views/window/dialog_client_view.cc
@@ -304,15 +304,27 @@
 void DialogClientView::ButtonPressed(ui::DialogButton type,
                                      const ui::Event& event) {
   DialogDelegate* const delegate = GetDialogDelegate();
-  if (delegate && !input_protector_->IsPossiblyUnintendedInteraction(event)) {
-    (type == ui::DIALOG_BUTTON_OK) ? delegate->AcceptDialog()
-                                   : delegate->CancelDialog();
+  if (!delegate || input_protector_->IsPossiblyUnintendedInteraction(event)) {
+    return;
+  }
+
+  DCHECK(type == ui::DIALOG_BUTTON_OK || type == ui::DIALOG_BUTTON_CANCEL);
+  if (type == ui::DIALOG_BUTTON_OK &&
+      !delegate->ShouldIgnoreButtonPressedEventHandling(ok_button_, event)) {
+    delegate->AcceptDialog();
+  }
+
+  if (type == ui::DIALOG_BUTTON_CANCEL &&
+      !delegate->ShouldIgnoreButtonPressedEventHandling(cancel_button_,
+                                                        event)) {
+    delegate->CancelDialog();
   }
 }
 
 int DialogClientView::GetExtraViewSpacing() const {
-  if (!ShouldShow(extra_view_) || !(ok_button_ || cancel_button_))
+  if (!ShouldShow(extra_view_) || !(ok_button_ || cancel_button_)) {
     return 0;
+  }
 
   return LayoutProvider::Get()->GetDistanceMetric(
       views::DISTANCE_RELATED_BUTTON_HORIZONTAL);
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index 159b30ab..806d0b1 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -161,6 +161,12 @@
   return params_.enabled_buttons & button;
 }
 
+bool DialogDelegate::ShouldIgnoreButtonPressedEventHandling(
+    View* button,
+    const ui::Event& event) const {
+  return false;
+}
+
 bool DialogDelegate::Cancel() {
   DCHECK(!already_started_close_);
   if (cancel_callback_)
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index f6a7596..37661f6 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -139,6 +139,11 @@
   // Returns whether the specified dialog button is enabled.
   virtual bool IsDialogButtonEnabled(ui::DialogButton button) const;
 
+  // Returns true if we should ignore key pressed event handling of `button`.
+  virtual bool ShouldIgnoreButtonPressedEventHandling(
+      View* button,
+      const ui::Event& event) const;
+
   // For Dialog boxes, if there is a "Cancel" button or no dialog button at all,
   // this is called when the user presses the "Cancel" button.  This function
   // should return true if the window can be closed after it returns, or false
diff --git a/weblayer/browser/autofill_client_impl.cc b/weblayer/browser/autofill_client_impl.cc
index d9eef41..0faeef2 100644
--- a/weblayer/browser/autofill_client_impl.cc
+++ b/weblayer/browser/autofill_client_impl.cc
@@ -361,7 +361,7 @@
   return false;
 }
 
-void AutofillClientImpl::ExecuteCommand(int id) {
+void AutofillClientImpl::ExecuteCommand(autofill::Suggestion::FrontendId id) {
   NOTREACHED();
 }
 
diff --git a/weblayer/browser/autofill_client_impl.h b/weblayer/browser/autofill_client_impl.h
index 5390a1a..e4764f5d 100644
--- a/weblayer/browser/autofill_client_impl.h
+++ b/weblayer/browser/autofill_client_impl.h
@@ -153,7 +153,7 @@
   void DidFillOrPreviewField(const std::u16string& autofilled_value,
                              const std::u16string& profile_full_name) override;
   bool IsContextSecure() const override;
-  void ExecuteCommand(int id) override;
+  void ExecuteCommand(autofill::Suggestion::FrontendId id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;