diff --git a/DEPS b/DEPS
index dc62341..ab4c073b 100644
--- a/DEPS
+++ b/DEPS
@@ -271,15 +271,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': 'd3cbea4114aabd84958d6ec9662c2f80c405dc59',
+  'skia_revision': '8d7729ee6ac419d2dbf0c1f2bcff3830d342c4ae',
   # 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': 'fbfdd1057d29dd8fdef4dea69a67166ef7efdd76',
+  'v8_revision': 'b35f2a7cb67dc221dd83be16a21fd34fc00f6574',
   # 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': '2db4297ad0fb70cfa1f18ac86b3548448ccf14b0',
+  'angle_revision': '2ae8bdb3a7338cd3ce13a4ce349a689157ae3c87',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -342,7 +342,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'a1cf7a299ecea4633a1ea4c2c40dcd345220820a',
+  'catapult_revision': 'e983ebe3bf3b86444f1c50977bd26f65836d5056',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -350,7 +350,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'e2040405a1dcaf52613c0e8ad9d0fc330b276d43',
+  'devtools_frontend_revision': '206da4afeb2c8446626987c105f42809d66dade6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -386,7 +386,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '318f6acd56c06af7605f1c0a4baf0ad3dbf4db84',
+  'dawn_revision': 'e89b311a5d7f7ca90e0fa14047025a8b9c5192ee',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -916,7 +916,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'ZofHBCltyn83hrR-v-njZxfWNNfAyvw9vo0dfPt3AFYC',
+          'version': 'zkZyJUSFePiq9zoq7iyJ5x7BUomTWa37iQSsaTTON-kC',
       },
     ],
     'condition': 'checkout_android',
@@ -1112,7 +1112,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ad83db0e8a6b33407630af4289153372924ccf6c',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '84ce7a768c7aa98899398747a739e034a157a93d',
       'condition': 'checkout_chromeos',
   },
 
@@ -1532,7 +1532,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5a9d84436fccfcb0eaaad6f8c40c851b12c24420',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '785aac6dabe1216142ec32490a9086cd35db3b2d',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1707,7 +1707,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9618103c4aa25ea342ddad65848ff8bb0c1cee9a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c3fa7c38b2b74cf7b5dd2cc323ccaa8473b50e80',
+    Var('webrtc_git') + '/src.git' + '@' + '485457f0509339b41c2a694e55d0c0ab1eb06255',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1780,7 +1780,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4169a9720b7c7aad9f7478c9c272a68749bca591',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2a1e8c2d41aa15ecfb504a1870d84a42a753ee75',
     'condition': 'checkout_src_internal',
   },
 
@@ -1810,7 +1810,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '6BzZeaAzCL5uhzFEQTKh8G1-hfxdAo6E5xBB1AHLuAkC',
+        'version': 'q17ZIX2CbSTU3GnFjTqgyfkPh8F0QK4g5mTGTpzM9AAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1821,7 +1821,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'VW8OLMUzhVZlvxnnmL-162Mk66yVLTxDMIuFrZc2HjIC',
+        'version': 'Ap_Nmod1IBnYMdDD7eGL74vxSTBBp6JQUFdfSNHPJoAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
index feb38d0..cc36ef6 100644
--- a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
+++ b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
@@ -74,6 +74,9 @@
     private static final long TIMEOUT_SECONDS = 20;
 
     private static final String MODE_REBASELINE = "rebaseline";
+    private static final String NOT_WEBVIEW_EXPOSED_CHROMIUM_PATH =
+            "//android_webview/tools/system_webview_shell/test/data/"
+            + "webexposed/not-webview-exposed.txt";
 
     private WebViewLayoutTestActivity mTestActivity;
     private boolean mRebaseLine;
@@ -245,13 +248,17 @@
         String result = mTestActivity.getTestResult();
         webviewInterfacesMap = buildHashMap(result);
 
+        HashSet<String> missingInterfaces = new HashSet<>();
+        HashMap<String, HashSet<String>> missingInterfaceProperties = new HashMap<>();
+
         // Check that each stable blink interface and its properties are present in webview
         // except the excluded interfaces/properties.
         for (HashMap.Entry<String, HashSet<String>> entry : blinkStableInterfacesMap.entrySet()) {
             String interfaceS = entry.getKey();
             HashSet<String> subsetExcluded = webviewExcludedInterfacesMap.get(interfaceS);
+
             if (subsetExcluded != null && subsetExcluded.isEmpty()) {
-                // Interface is not exposed in WebView at all
+                // Interface is not exposed in WebView.
                 continue;
             }
 
@@ -259,25 +266,44 @@
             HashSet<String> subsetWebView = webviewInterfacesMap.get(interfaceS);
 
             if (subsetWebView == null) {
-                // interface is missing completely
-                missing.append(interfaceS + "\n");
+                // Interface is unexpectedly missing from WebView.
+                missingInterfaces.add(interfaceS);
                 continue;
             }
 
             for (String propertyBlink : subsetBlink) {
-                if (subsetExcluded != null && subsetExcluded.contains(propertyBlink)) continue;
+                if (subsetExcluded != null && subsetExcluded.contains(propertyBlink)) {
+                    // At least one of the properties of this interface is excluded from WebView.
+                    continue;
+                }
                 if (!subsetWebView.contains(propertyBlink)) {
-                    missing.append(interfaceS + "." + propertyBlink + "\n");
+                    // At least one of the properties of this interface is unexpectedly missing from
+                    // WebView.
+                    missingInterfaceProperties.putIfAbsent(interfaceS, new HashSet<>());
+                    missingInterfaceProperties.get(interfaceS).add(propertyBlink);
                 }
             }
         }
 
-        if (missing.length() > 0) {
-            Assert.fail("Android WebView is missing the following declared Blink interfaces: "
-                    + missing.toString()
-                    + ". Interfaces which are intentionally not exposed in WebView need to be"
-                    + " added to not-webview-exposed.txt");
+        StringBuilder errorMessage = new StringBuilder();
+        if (!missingInterfaces.isEmpty()) {
+            errorMessage.append(String.format("\nWebView does not expose the "
+                            + "Blink interfaces below. Add them to\n%s\nto suppress this error.\n",
+                    NOT_WEBVIEW_EXPOSED_CHROMIUM_PATH));
+            missingInterfaces.forEach(
+                    (missingInterface) -> errorMessage.append("\t- " + missingInterface + "\n"));
         }
+        missingInterfaceProperties.forEach((blinkInterface, missingProperties) -> {
+            errorMessage.append(String.format(
+                    "\nAt least one of the properties of the Blink interface \"%s\" "
+                            + "is not exposed in WebView.\nAdd them to the list of properties "
+                            + "not exposed for the \"%s\" interface in\n%s\nto suppress "
+                            + "this error\n",
+                    blinkInterface, blinkInterface, NOT_WEBVIEW_EXPOSED_CHROMIUM_PATH));
+            missingProperties.forEach(
+                    (missingProperty) -> errorMessage.append("\t- " + missingProperty + "\n"));
+        });
+        Assert.assertTrue(errorMessage.toString(), errorMessage.length() == 0);
     }
 
     @Test
@@ -465,7 +491,7 @@
     }
 
     private HashMap<String, HashSet<String>> buildHashMap(String contents) {
-        HashMap<String, HashSet<String>> interfaces = new HashMap<String, HashSet<String>>();
+        HashMap<String, HashSet<String>> interfaces = new HashMap<>();
 
         return buildHashMap(contents, interfaces);
     }
@@ -480,7 +506,7 @@
             if (isInterfaceOrGlobalObject(s)) {
                 subset = interfaces.get(s);
                 if (subset == null) {
-                    subset = new HashSet<String>();
+                    subset = new HashSet<>();
                     interfaces.put(s, subset);
                 }
             } else if (isInterfaceProperty(s) && subset != null) {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 99c9424..c84a038 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1810,6 +1810,10 @@
   return base::FeatureList::IsEnabled(kFuseBox);
 }
 
+bool IsFileManagerFuseBoxDebugEnabled() {
+  return base::FeatureList::IsEnabled(kFuseBoxDebug);
+}
+
 bool IsFileManagerSwaEnabled() {
   return base::FeatureList::IsEnabled(kFilesSWA);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 2223936c..8788383e 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -669,6 +669,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairSubsequentPairingUXEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairSavedDevicesEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerFuseBoxEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerFuseBoxDebugEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerSwaEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFirmwareUpdaterAppEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFloatingWorkspaceEnabled();
diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc
index 0d98a8b..7c4999efb 100644
--- a/ash/display/mouse_cursor_event_filter_unittest.cc
+++ b/ash/display/mouse_cursor_event_filter_unittest.cc
@@ -150,11 +150,10 @@
       display::test::CreateDisplayLayout(display_manager(),
                                          display::DisplayPlacement::RIGHT, 0));
   auto* cursor_manager = Shell::Get()->cursor_manager();
-
   EXPECT_EQ(1.0f, cursor_manager->GetCursor().image_scale_factor());
-  TestIfMouseWarpsAt(gfx::Point(399, 200));
+  GetEventGenerator()->MoveMouseTo(401, 200);
   EXPECT_EQ(2.0f, cursor_manager->GetCursor().image_scale_factor());
-  TestIfMouseWarpsAt(gfx::Point(400, 200));
+  GetEventGenerator()->MoveMouseTo(399, 200);
   EXPECT_EQ(1.0f, cursor_manager->GetCursor().image_scale_factor());
 }
 
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index 78ede94..2dcf021 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -7,7 +7,9 @@
 #include <memory>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/keyboard_shortcut_item.h"
+#include "ash/public/cpp/style/color_provider.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.h"
 #include "ash/shortcut_viewer/strings/grit/shortcut_viewer_strings.h"
@@ -29,16 +31,54 @@
 
 namespace {
 
+// Light mode color:
+constexpr int kIconSize = 16;
+
+constexpr SkColor kShortcutBubbleSeparatorColorLight =
+    SkColorSetARGB(0xFF, 0x1A, 0x73, 0xE8);
+
+// Custom separator view to enable updating OnThemeChanged.
+class KSVSeparatorImageView : public views::ImageView {
+ public:
+  KSVSeparatorImageView() {
+    color_provider_ = ash::ColorProvider::Get();
+    ConfigureImage();
+  }
+
+  KSVSeparatorImageView(const KSVSeparatorImageView&) = delete;
+  KSVSeparatorImageView operator=(const KSVSeparatorImageView&) = delete;
+
+  ~KSVSeparatorImageView() override = default;
+
+  // views::View:
+  void OnThemeChanged() override {
+    ConfigureImage();
+
+    views::ImageView::OnThemeChanged();
+  }
+
+ private:
+  // Configure separator image view depending on color mode.
+  void ConfigureImage() {
+    DCHECK(color_provider_);
+    SkColor kShortcutBubbleSeparatorColor = kShortcutBubbleSeparatorColorLight;
+    if (ash::features::IsDarkLightModeEnabled() &&
+        color_provider_->IsDarkModeEnabled()) {
+      kShortcutBubbleSeparatorColor = color_provider_->GetContentLayerColor(
+          ash::ColorProvider::ContentLayerType::kTextColorSecondary);
+    }
+    SetImage(gfx::CreateVectorIcon(ash::kKsvSeparatorPlusIcon,
+                                   kShortcutBubbleSeparatorColor));
+    SetImageSize(gfx::Size(kIconSize, kIconSize));
+  }
+
+  ash::ColorProvider* color_provider_;  // Not owned.
+};
+
 // Creates the separator view between bubble views of modifiers and key.
 std::unique_ptr<views::View> CreateSeparatorView() {
-  constexpr SkColor kSeparatorColor = SkColorSetARGB(0xFF, 0x1A, 0x73, 0xE8);
-  constexpr int kIconSize = 16;
-
-  std::unique_ptr<views::ImageView> separator_view =
-      std::make_unique<views::ImageView>();
-  separator_view->SetImage(
-      gfx::CreateVectorIcon(ash::kKsvSeparatorPlusIcon, kSeparatorColor));
-  separator_view->SetImageSize(gfx::Size(kIconSize, kIconSize));
+  std::unique_ptr<KSVSeparatorImageView> separator_view =
+      std::make_unique<KSVSeparatorImageView>();
   return separator_view;
 }
 
diff --git a/ash/shortcut_viewer/views/ksv_search_box_view.cc b/ash/shortcut_viewer/views/ksv_search_box_view.cc
index 15927bb..4ef2e81 100644
--- a/ash/shortcut_viewer/views/ksv_search_box_view.cc
+++ b/ash/shortcut_viewer/views/ksv_search_box_view.cc
@@ -4,10 +4,15 @@
 
 #include "ash/shortcut_viewer/views/ksv_search_box_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_color_provider.h"
+#include "ash/public/cpp/style/color_provider.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/search_box/search_box_constants.h"
+#include "ash/search_box/search_box_view_base.h"
 #include "ash/search_box/search_box_view_delegate.h"
 #include "ash/shortcut_viewer/strings/grit/shortcut_viewer_strings.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -25,27 +30,23 @@
 
 // Border corner radius of the search box.
 constexpr int kBorderCornerRadius = 32;
+constexpr int kBorderThichness = 2;
 
 }  // namespace
 
 KSVSearchBoxView::KSVSearchBoxView(ash::SearchBoxViewDelegate* delegate)
     : ash::SearchBoxViewBase(delegate) {
   SetSearchBoxBackgroundCornerRadius(kBorderCornerRadius);
-  UpdateBackgroundColor(
-      ash::AppListColorProvider::Get()->GetSearchBoxBackgroundColor());
+  UpdateBackgroundColor(GetBackgroundColor());
   search_box()->SetBackgroundColor(SK_ColorTRANSPARENT);
-  search_box()->SetColor(
-      ash::AppListColorProvider::Get()->GetSearchBoxTextColor(
-          gfx::kGoogleGrey900));
+  search_box()->SetColor(GetPrimaryTextColor());
   SetPlaceholderTextAttributes();
   const std::u16string search_box_name(
       l10n_util::GetStringUTF16(IDS_KSV_SEARCH_BOX_ACCESSIBILITY_NAME));
   search_box()->SetPlaceholderText(search_box_name);
   search_box()->SetAccessibleName(search_box_name);
-  SetSearchIconImage(gfx::CreateVectorIcon(
-      ash::kKsvSearchBarIcon,
-      ash::AppListColorProvider::Get()->GetSearchBoxIconColor(
-          gfx::kGoogleGrey900)));
+  SetSearchIconImage(
+      gfx::CreateVectorIcon(ash::kKsvSearchBarIcon, GetPrimaryIconColor()));
 }
 
 gfx::Size KSVSearchBoxView::CalculatePreferredSize() const {
@@ -72,6 +73,25 @@
     SetSearchBoxActive(false, event->type());
 }
 
+void KSVSearchBoxView::OnThemeChanged() {
+  ash::SearchBoxViewBase::OnThemeChanged();
+
+  back_button()->SetImage(
+      views::ImageButton::STATE_NORMAL,
+      gfx::CreateVectorIcon(ash::kKsvSearchBackIcon, GetBackButtonColor()));
+  close_button()->SetImage(
+      views::ImageButton::STATE_NORMAL,
+      gfx::CreateVectorIcon(ash::kKsvSearchCloseIcon, GetCloseButtonColor()));
+  search_box()->SetBackgroundColor(SK_ColorTRANSPARENT);
+  search_box()->SetColor(GetPrimaryTextColor());
+  search_box()->set_placeholder_text_color(GetPlaceholderTextColor());
+  SetBorder(views::CreateRoundedRectBorder(
+      kBorderThichness, kBorderCornerRadius, GetBorderColor()));
+  SetSearchIconImage(
+      gfx::CreateVectorIcon(ash::kKsvSearchBarIcon, GetPrimaryIconColor()));
+  UpdateBackgroundColor(GetBackgroundColor());
+}
+
 void KSVSearchBoxView::SetAccessibleValue(const std::u16string& value) {
   accessible_value_ = value;
   NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
@@ -83,19 +103,15 @@
   if (!search_box()->HasFocus() && search_box()->GetText().empty())
     SetSearchBoxActive(false, ui::ET_UNKNOWN);
 
-  constexpr int kBorderThichness = 2;
-  constexpr SkColor kActiveBorderColor = SkColorSetARGB(0x7F, 0x1A, 0x73, 0xE8);
-
-  if (search_box()->HasFocus() || is_search_box_active()) {
+  if (ShouldUseFocusedColors()) {
     SetBorder(views::CreateRoundedRectBorder(
-        kBorderThichness, kBorderCornerRadius, kActiveBorderColor));
-    UpdateBackgroundColor(gfx::kGoogleGrey100);
+        kBorderThichness, kBorderCornerRadius, GetBorderColor()));
+    UpdateBackgroundColor(GetBackgroundColor());
     return;
   }
   SetBorder(views::CreateRoundedRectBorder(
-      kBorderThichness, kBorderCornerRadius, SK_ColorTRANSPARENT));
-  UpdateBackgroundColor(
-      ash::AppListColorProvider::Get()->GetSearchBoxBackgroundColor());
+      kBorderThichness, kBorderCornerRadius, GetBorderColor()));
+  UpdateBackgroundColor(GetBackgroundColor());
 }
 
 void KSVSearchBoxView::SetupCloseButton() {
@@ -103,7 +119,7 @@
   close->SetHasInkDropActionOnClick(true);
   close->SetImage(
       views::ImageButton::STATE_NORMAL,
-      gfx::CreateVectorIcon(ash::kKsvSearchCloseIcon, gfx::kGoogleGrey700));
+      gfx::CreateVectorIcon(ash::kKsvSearchCloseIcon, GetCloseButtonColor()));
   close->SetPreferredSize(gfx::Size(kIconSize, kIconSize));
   close->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
   close->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
@@ -119,7 +135,7 @@
   back->SetHasInkDropActionOnClick(true);
   back->SetImage(
       views::ImageButton::STATE_NORMAL,
-      gfx::CreateVectorIcon(ash::kKsvSearchBackIcon, gfx::kGoogleBlue500));
+      gfx::CreateVectorIcon(ash::kKsvSearchBackIcon, GetBackButtonColor()));
   back->SetPreferredSize(gfx::Size(kIconSize, kIconSize));
   back->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
   back->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
@@ -135,12 +151,67 @@
 }
 
 void KSVSearchBoxView::SetPlaceholderTextAttributes() {
-  search_box()->set_placeholder_text_color(
-      ash::AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor(
-          ash::kZeroQuerySearchboxColor));
+  search_box()->set_placeholder_text_color(GetPlaceholderTextColor());
   search_box()->set_placeholder_text_draw_flags(
       base::i18n::IsRTL() ? gfx::Canvas::TEXT_ALIGN_RIGHT
                           : gfx::Canvas::TEXT_ALIGN_LEFT);
 }
 
+SkColor KSVSearchBoxView::GetBackgroundColor() {
+  constexpr SkColor kBackgroundDarkColor =
+      SkColorSetARGB(0xFF, 0x32, 0x33, 0x34);
+
+  if (ShouldUseDarkThemeColors()) {
+    return kBackgroundDarkColor;
+  }
+
+  return ShouldUseFocusedColors()
+             ? gfx::kGoogleGrey100
+             : ash::AppListColorProvider::Get()->GetSearchBoxBackgroundColor();
+}
+
+SkColor KSVSearchBoxView::GetBackButtonColor() {
+  return ShouldUseDarkThemeColors() ? gfx::kGoogleBlue300 : gfx::kGoogleBlue500;
+}
+
+SkColor KSVSearchBoxView::GetBorderColor() {
+  if (!ShouldUseFocusedColors()) {
+    return SK_ColorTRANSPARENT;
+  }
+
+  constexpr SkColor kActiveBorderLightColor =
+      SkColorSetARGB(0x7F, 0x1A, 0x73, 0xE8);
+  const SkColor kActiveBorderDarkColor =
+      ash::AppListColorProvider::Get()->GetFocusRingColor();
+
+  return ShouldUseDarkThemeColors() ? kActiveBorderDarkColor
+                                    : kActiveBorderLightColor;
+}
+
+SkColor KSVSearchBoxView::GetCloseButtonColor() {
+  return ShouldUseDarkThemeColors() ? gfx::kGoogleGrey400 : gfx::kGoogleGrey700;
+}
+
+SkColor KSVSearchBoxView::GetPlaceholderTextColor() {
+  return ShouldUseDarkThemeColors() ? gfx::kGoogleGrey400
+                                    : ash::kZeroQuerySearchboxColor;
+}
+
+SkColor KSVSearchBoxView::GetPrimaryIconColor() {
+  return ShouldUseDarkThemeColors() ? gfx::kGoogleGrey200 : gfx::kGoogleGrey900;
+}
+
+SkColor KSVSearchBoxView::GetPrimaryTextColor() {
+  return ShouldUseDarkThemeColors() ? gfx::kGoogleGrey200 : gfx::kGoogleGrey900;
+}
+
+bool KSVSearchBoxView::ShouldUseFocusedColors() {
+  return search_box()->HasFocus() || is_search_box_active();
+}
+
+bool KSVSearchBoxView::ShouldUseDarkThemeColors() {
+  return ash::features::IsDarkLightModeEnabled() &&
+         ash::ColorProvider::Get()->IsDarkModeEnabled();
+}
+
 }  // namespace keyboard_shortcut_viewer
diff --git a/ash/shortcut_viewer/views/ksv_search_box_view.h b/ash/shortcut_viewer/views/ksv_search_box_view.h
index 3bd721a..d6884b3 100644
--- a/ash/shortcut_viewer/views/ksv_search_box_view.h
+++ b/ash/shortcut_viewer/views/ksv_search_box_view.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/search_box/search_box_view_base.h"
+#include "third_party/skia/include/core/SkColor.h"
 
 namespace ash {
 class SearchBoxViewDelegate;
@@ -29,6 +30,7 @@
   gfx::Size CalculatePreferredSize() const override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void OnKeyEvent(ui::KeyEvent* event) override;
+  void OnThemeChanged() override;
 
   void SetAccessibleValue(const std::u16string& value);
 
@@ -41,6 +43,17 @@
  private:
   void SetPlaceholderTextAttributes();
 
+  SkColor GetBackgroundColor();
+  SkColor GetBackButtonColor();
+  SkColor GetBorderColor();
+  SkColor GetCloseButtonColor();
+  SkColor GetPlaceholderTextColor();
+  SkColor GetPrimaryIconColor();
+  SkColor GetPrimaryTextColor();
+
+  bool ShouldUseFocusedColors();
+  bool ShouldUseDarkThemeColors();
+
   // Accessibility data value. Used to pronounce the number of search results.
   std::u16string accessible_value_;
 };
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 67d8a2a..a0814d8d 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -85,8 +85,15 @@
   ui::EventTarget* GetTargetAt(const gfx::Point& point_in_screen) override {
     display::Screen* screen = display::Screen::GetScreen();
     display::Display display = screen->GetDisplayNearestPoint(point_in_screen);
+    if (current_display_id_ != display.id()) {
+      Shell::Get()->cursor_manager()->SetDisplay(display);
+      current_display_id_ = display.id();
+    }
     return Shell::GetRootWindowForDisplayId(display.id())->GetHost()->window();
   }
+
+ private:
+  int64_t current_display_id_ = display::kInvalidDisplayId;
 };
 
 }  // namespace
diff --git a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
index 106bf14..e470911 100644
--- a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
+++ b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
@@ -92,7 +92,7 @@
   </iron-a11y-keys>
   <iron-selector id="selector" selected="0" selectable=".color-container"
       selected-item="{{ironSelectedColor_}}">
-    <div id$="[[wallpaperColorId_]]" class="color-container" tabindex="0"
+    <div id$="[[wallpaperColorId_]]" class$="[[getWallpaperColorContainerClass_(backlightColor_)]]" tabindex="0"
         on-click="onWallpaperColorSelected_"
         on-keypress="onWallpaperColorSelected_"
         aria-label="$i18n{wallpaperColor}"
@@ -105,7 +105,7 @@
     </div>
     <div class="divider"></div>
     <template is="dom-repeat" items="[[presetColorIds_]]" as="presetColorId">
-      <div id$="[[presetColorId]]" class="color-container"
+      <div id$="[[presetColorId]]" class$="[[getPresetColorContainerClass_(presetColorId, presetColors_, backlightColor_)]]"
           on-click="onPresetColorSelected_" on-keypress="onPresetColorSelected_"
           aria-label$="[[getPresetColorAriaLabel_(presetColorId)]]"
           aria-selected$="[[getPresetColorAriaSelected_(presetColorId, presetColors_, backlightColor_)]]">
@@ -116,10 +116,10 @@
         </div>
       </div>
     </template>
-    <div id$="[[rainbowColorId_]]" class="color-container" tabindex="0"
+    <div id$="[[rainbowColorId_]]" class$="[[getRainbowColorContainerClass_(backlightColor_)]]" tabindex="0"
         on-click="onRainbowColorSelected_" on-keypress="onRainbowColorSelected_"
         aria-label="$i18n{rainbowColor}"
-        aria-selected$="[[getRainbowColorAriaSelected(backlightColor_)]]">
+        aria-selected$="[[getRainbowColorAriaSelected_(backlightColor_)]]">
       <div class="color-inner-container"
           style$="[[getColorInnerContainerStyle_(rainbowColorId_, presetColors_)]]">
         <paper-ripple class="circle"></paper-ripple>
diff --git a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
index 1d101a4..aae50a7 100644
--- a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
@@ -218,6 +218,30 @@
     return this.i18n(presetColorId);
   }
 
+  private getWallpaperColorContainerClass_(selectedColor: BacklightColor):
+      string {
+    return this.getColorContainerClass_(
+        this.getWallpaperColorAriaSelected_(selectedColor));
+  }
+
+  private getPresetColorContainerClass_(
+      colorId: string, colors: Record<string, ColorInfo>,
+      selectedColor: BacklightColor) {
+    return this.getColorContainerClass_(
+        this.getPresetColorAriaSelected_(colorId, colors, selectedColor));
+  }
+
+  private getRainbowColorContainerClass_(selectedColor: BacklightColor) {
+    return this.getColorContainerClass_(
+        this.getRainbowColorAriaSelected_(selectedColor));
+  }
+
+  private getColorContainerClass_(isSelected: string) {
+    const defaultClassName = 'color-container';
+    return isSelected === 'true' ? `${defaultClassName} tast-selected-color` :
+                                   defaultClassName;
+  }
+
   private getWallpaperColorAriaSelected_(selectedColor: BacklightColor) {
     return (selectedColor === BacklightColor.kWallpaper).toString();
   }
@@ -231,7 +255,7 @@
     return (colors[colorId].enumVal === selectedColor).toString();
   }
 
-  private getRainbowColorAriaSelected(selectedColor: BacklightColor) {
+  private getRainbowColorAriaSelected_(selectedColor: BacklightColor) {
     return (selectedColor === BacklightColor.kRainbow).toString();
   }
 }
diff --git a/ash/webui/shimless_rma/resources/shimless_rma.js b/ash/webui/shimless_rma/resources/shimless_rma.js
index c6e572f..b34c704 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma.js
+++ b/ash/webui/shimless_rma/resources/shimless_rma.js
@@ -101,7 +101,7 @@
   },
   [State.kSelectComponents]: {
     componentIs: 'onboarding-select-components-page',
-    requiresReloadWhenShown: false,
+    requiresReloadWhenShown: true,
     buttonNext: ButtonState.DISABLED,
     buttonCancel: ButtonState.VISIBLE,
     buttonBack: ButtonState.VISIBLE,
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index 3412ed33..6ed8735 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -732,11 +732,8 @@
         CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION));
     EXPECT_EQ(1.0f, cursor_manager->GetCursor().image_scale_factor());
     ASSERT_TRUE(resizer.get());
-    // TODO(crbug.com/990589): Unit tests should be able to simulate mouse input
-    // without having to call |CursorManager::SetDisplay|.
-    cursor_manager->SetDisplay(display1);
     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
-    TestIfMouseWarpsAt(gfx::Point(399, 200));
+    TestIfMouseWarpsAt(gfx::Point(699, 200));
     EXPECT_EQ(2.0f, cursor_manager->GetCursor().image_scale_factor());
     resizer->CompleteDrag();
     EXPECT_EQ(2.0f, cursor_manager->GetCursor().image_scale_factor());
@@ -752,9 +749,6 @@
         CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION));
     EXPECT_EQ(2.0f, cursor_manager->GetCursor().image_scale_factor());
     ASSERT_TRUE(resizer.get());
-    // TODO(crbug.com/990589): Unit tests should be able to simulate mouse input
-    // without having to call |CursorManager::SetDisplay|.
-    cursor_manager->SetDisplay(display0);
     resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0);
     TestIfMouseWarpsAt(gfx::Point(400, 200));
     EXPECT_EQ(1.0f, cursor_manager->GetCursor().image_scale_factor());
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto
index ccc9d07..d8ee813 100644
--- a/base/tracing/protos/chrome_track_event.proto
+++ b/base/tracing/protos/chrome_track_event.proto
@@ -764,6 +764,29 @@
   optional FrameTreeNodeInfo frame_tree_node = 4;
   optional RenderFrameHost render_frame_host = 5;
 
+  enum NavigationType {
+    NAVIGATION_TYPE_UNSPECIFIED = 0;
+    RELOAD = 1;
+    RELOAD_BYPASSING_CACHE = 2;
+    RELOAD_ORIGINAL_REQUEST_URL = 3;
+    RESTORE = 4;
+    RESTORE_WITH_POST = 5;
+    HISTORY_SAME_DOCUMENT = 6;
+    HISTORY_DIFFERENT_DOCUMENT = 7;
+    SAME_DOCUMENT = 8;
+    DIFFERENT_DOCUMENT = 9;
+  }
+  optional NavigationType navigation_type = 6;
+
+  enum FrameType {
+    FRAME_TYPE_UNSPECIFIED = 0;
+    SUBFRAME = 1;
+    PRIMARY_MAIN_FRAME = 2;
+    PRERENDER_MAIN_FRAME = 3;
+    FENCED_FRAME_ROOT = 4;
+  }
+  optional FrameType frame_type = 7;
+
   // Additional untyped debug information associated with this
   // NavigationHandle/Request, populated via TracedProto::AddDebugAnnotations
   // API.
@@ -780,7 +803,7 @@
 
 message ChromeTrackEvent {
   // Extension range for Chrome: 1000-1999
-  // Next ID: 1037
+  // Next ID: 1039
   extend TrackEvent {
     optional ChromeAppState chrome_app_state = 1000;
 
@@ -862,5 +885,7 @@
     optional DeviceThermalState device_thermal_state = 1036;
 
     optional NavigationHandle navigation = 1037;
+
+    optional NavigationHandle navigation_when_created = 1038;
   }
 }
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 30bcd85..842e979 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-8.20220522.3.1
+8.20220523.1.1
diff --git a/build/xcode_binaries.yaml b/build/xcode_binaries.yaml
index 00ef3cb..c819665 100644
--- a/build/xcode_binaries.yaml
+++ b/build/xcode_binaries.yaml
@@ -8,9 +8,9 @@
 # To deploy the newly created cipd package across the fleet, modify
 # mac_toolchain.py to point to the new cipd hash.
 #
-# Note that runhooks extracts the cipd file to build/mac/xcode_binaries -- your
-# build/xcode_binaries you're creating in step 1 above isn't used as part of
-# the Chromium build, build/mac_files/xcode_binaries is. So you need to
+# Note that runhooks extracts the cipd file to build/mac_files/xcode_binaries
+# -- your build/xcode_binaries you're creating in step 1 above isn't used as
+# part of the Chromium build, build/mac_files/xcode_binaries is. So you need to
 # `runhooks` after updating the hash in mac_toolchain.py like everyone else to
 # get the new bits for your local build.
 #
diff --git a/chrome/VERSION b/chrome/VERSION
index 5a07786..22bb9cb 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=104
 MINOR=0
-BUILD=5080
+BUILD=5081
 PATCH=0
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
index a6fa6b11..8f53474 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
@@ -530,8 +530,11 @@
         CustomTabActivity customTabActivity = launchIncognitoCustomTab(intent);
 
         // Ensure that we did indeed create the re-auth controller.
-        IncognitoReauthController controller = customTabActivity.getRootUiCoordinatorForTesting()
-                                                       .getIncognitoReauthControllerForTesting();
-        assertNotNull(controller);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            IncognitoReauthController controller =
+                    customTabActivity.getRootUiCoordinatorForTesting()
+                            .getIncognitoReauthControllerForTesting();
+            assertNotNull(controller);
+        });
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e51e9f4..3351342 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9573,6 +9573,9 @@
         Sync settings
       </message>
       <if expr="chromeos_lacros">
+        <message name="IDS_SYNC_CONFIRMATION_TITLE_LACROS_NON_FORCED" desc="Title of the sync confirmation dialog/screen on lacros when sync is not forced.">
+          Turn on Chrome browser sync?
+        </message>
         <message name="IDS_SYNC_CONFIRMATION_TITLE_LACROS" desc="Title of the sync confirmation dialog/screen on lacros.">
           Chrome browser sync is on
         </message>
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_TITLE_LACROS_NON_FORCED.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_TITLE_LACROS_NON_FORCED.png.sha1
new file mode 100644
index 0000000..1d05dd0b
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_TITLE_LACROS_NON_FORCED.png.sha1
@@ -0,0 +1 @@
+726e2317363b54d1d4bce3f45d083e180bb3bd81
\ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index 678d5ae..619c648 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -698,13 +698,13 @@
         Welcome to Chrome
       </message>
       <message name="IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE" desc="Subtitle of the landing screen in first run experience for the primary profile. The screen promotes Chrome sync.">
-        Access your Chrome browser stuff from <ph name="ACCOUNT_EMAIL">$1<ex>Jane.Doe@gmail.com</ex></ph>
+        Get your Chrome browser stuff from <ph name="ACCOUNT_EMAIL">$1<ex>Jane.Doe@gmail.com</ex></ph>
       </message>
       <message name="IDS_PRIMARY_PROFILE_FIRST_RUN_NEXT_BUTTON_LABEL" desc="Label of the 'next' button of the landing screen in first run experience for the primary profile. The screen promotes Chrome sync.">
         Let's go
       </message>
       <message name="IDS_PRIMARY_PROFILE_FIRST_RUN_SESSION_MANAGED_BY_DESCRIPTION" desc="Disclaimer on the landing screen in first run experience for the primary profile, informing that the session is managed by an administrator.">
-        Your account is managed by <ph name="MANAGER_NAME">$1<ex>example.com</ex></ph>. Your administrator can see and edit this Chrome browser profile and its data. Your data includes bookmarks, history, and passwords.
+        Your account is managed by <ph name="MANAGER_NAME">$1<ex>example.com</ex></ph>. Your administrator can see and edit this Chrome browser profile and its data like bookmarks, history, and passwords.
       </message>
     </if>
 
diff --git a/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SESSION_MANAGED_BY_DESCRIPTION.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SESSION_MANAGED_BY_DESCRIPTION.png.sha1
index a54f825f..21c83f5 100644
--- a/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SESSION_MANAGED_BY_DESCRIPTION.png.sha1
+++ b/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SESSION_MANAGED_BY_DESCRIPTION.png.sha1
@@ -1 +1 @@
-0da5976f4d66c817c3ded826cb4070505364fd1d
\ No newline at end of file
+326bf830998bb6dedf723e17f4a5bb468a1872f1
\ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE.png.sha1
index a54f825f..21c83f5 100644
--- a/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE.png.sha1
+++ b/chrome/app/profiles_strings_grdp/IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE.png.sha1
@@ -1 +1 @@
-0da5976f4d66c817c3ded826cb4070505364fd1d
\ No newline at end of file
+326bf830998bb6dedf723e17f4a5bb468a1872f1
\ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index f1d2c439..8133c7d 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -258,6 +258,7 @@
 
   if (is_chrome_branded) {
     sources += [
+      "google_chrome/assistant.icon",
       "google_chrome/google_calendar.icon",
       "google_chrome/google_g_logo.icon",
       "google_chrome/google_g_logo_monochrome.icon",
@@ -270,10 +271,6 @@
       "google_chrome/google_super_g.icon",
     ]
   }
-
-  if (is_chrome_branded && is_chromeos_ash) {
-    sources += [ "google_chrome/assistant.icon" ]
-  }
 }
 
 source_set("vector_icons") {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ec95945..f278bfa 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4371,6 +4371,7 @@
       "//chrome/app/theme:chrome_unscaled_resources_grit",
       "//chrome/app/vector_icons",
       "//chrome/browser/ash/system_web_apps/types:types",
+      "//chrome/browser/autofill_assistant/password_change/proto:proto",
       "//chrome/browser/cart:mojo_bindings",
       "//chrome/browser/enterprise/signals:utils",
       "//chrome/browser/first_party_sets",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0f98bd2..d018804 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -7909,7 +7909,7 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     {"privacy-guide", flag_descriptions::kPrivacyGuideName,
-     flag_descriptions::kPrivacyGuideDescription, kOsDesktop | kOsAndroid,
+     flag_descriptions::kPrivacyGuideDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kPrivacyGuide)},
 
     {"privacy-guide-2", flag_descriptions::kPrivacyGuide2Name,
@@ -7917,6 +7917,12 @@
      FEATURE_VALUE_TYPE(features::kPrivacyGuide2)},
 
 #if BUILDFLAG(IS_ANDROID)
+    {"privacy-guide-android", flag_descriptions::kPrivacyGuideAndroidName,
+     flag_descriptions::kPrivacyGuideAndroidDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(features::kPrivacyGuideAndroid)},
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
     {"google-mobile-services-passwords",
      flag_descriptions::kUnifiedPasswordManagerAndroidName,
      flag_descriptions::kUnifiedPasswordManagerAndroidDescription, kOsAndroid,
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index b051a1a..8bd6c1a 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -4,6 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 #import <Foundation/Foundation.h>
+#import <objc/runtime.h>
 #include <stddef.h>
 
 #include <string>
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index ce5ec81..3d740ba 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -530,6 +530,124 @@
     "arc/window_predictor/window_predictor.h",
     "arc/window_predictor/window_predictor_utils.cc",
     "arc/window_predictor/window_predictor_utils.h",
+    "assistant/assistant_util.cc",
+    "assistant/assistant_util.h",
+    "attestation/attestation_ca_client.cc",
+    "attestation/attestation_ca_client.h",
+    "attestation/attestation_policy_observer.cc",
+    "attestation/attestation_policy_observer.h",
+    "attestation/certificate_util.cc",
+    "attestation/certificate_util.h",
+    "attestation/enrollment_certificate_uploader.h",
+    "attestation/enrollment_certificate_uploader_impl.cc",
+    "attestation/enrollment_certificate_uploader_impl.h",
+    "attestation/enrollment_id_upload_manager.cc",
+    "attestation/enrollment_id_upload_manager.h",
+    "attestation/machine_certificate_uploader.h",
+    "attestation/machine_certificate_uploader_impl.cc",
+    "attestation/machine_certificate_uploader_impl.h",
+    "attestation/platform_verification_flow.cc",
+    "attestation/platform_verification_flow.h",
+    "attestation/soft_bind_attestation_flow.cc",
+    "attestation/soft_bind_attestation_flow.h",
+    "attestation/tpm_challenge_key.cc",
+    "attestation/tpm_challenge_key.h",
+    "attestation/tpm_challenge_key_result.cc",
+    "attestation/tpm_challenge_key_result.h",
+    "attestation/tpm_challenge_key_subtle.cc",
+    "attestation/tpm_challenge_key_subtle.h",
+    "attestation/tpm_challenge_key_with_timeout.cc",
+    "attestation/tpm_challenge_key_with_timeout.h",
+    "audio/audio_survey_handler.cc",
+    "audio/audio_survey_handler.h",
+    "authpolicy/authpolicy_credentials_manager.cc",
+    "authpolicy/authpolicy_credentials_manager.h",
+    "authpolicy/authpolicy_helper.cc",
+    "authpolicy/authpolicy_helper.h",
+    "authpolicy/data_pipe_utils.cc",
+    "authpolicy/data_pipe_utils.h",
+    "authpolicy/kerberos_files_handler.cc",
+    "authpolicy/kerberos_files_handler.h",
+    "base/file_flusher.cc",
+    "base/file_flusher.h",
+    "base/locale_util.cc",
+    "base/locale_util.h",
+    "bluetooth/debug_logs_manager.cc",
+    "bluetooth/debug_logs_manager.h",
+    "bluetooth/debug_logs_manager_factory.cc",
+    "bluetooth/debug_logs_manager_factory.h",
+    "boot_times_recorder.cc",
+    "boot_times_recorder.h",
+    "borealis/borealis_app_launcher.cc",
+    "borealis/borealis_app_launcher.h",
+    "borealis/borealis_app_launcher_impl.cc",
+    "borealis/borealis_app_launcher_impl.h",
+    "borealis/borealis_app_uninstaller.cc",
+    "borealis/borealis_app_uninstaller.h",
+    "borealis/borealis_capabilities.cc",
+    "borealis/borealis_capabilities.h",
+    "borealis/borealis_context.cc",
+    "borealis/borealis_context.h",
+    "borealis/borealis_context_manager.h",
+    "borealis/borealis_context_manager_impl.cc",
+    "borealis/borealis_context_manager_impl.h",
+    "borealis/borealis_credits.cc",
+    "borealis/borealis_credits.h",
+    "borealis/borealis_disk_manager.h",
+    "borealis/borealis_disk_manager_dispatcher.cc",
+    "borealis/borealis_disk_manager_dispatcher.h",
+    "borealis/borealis_disk_manager_impl.cc",
+    "borealis/borealis_disk_manager_impl.h",
+    "borealis/borealis_engagement_metrics.cc",
+    "borealis/borealis_engagement_metrics.h",
+    "borealis/borealis_features.cc",
+    "borealis/borealis_features.h",
+    "borealis/borealis_features_util.cc",
+    "borealis/borealis_features_util.h",
+    "borealis/borealis_game_mode_controller.cc",
+    "borealis/borealis_game_mode_controller.h",
+    "borealis/borealis_installer.cc",
+    "borealis/borealis_installer.h",
+    "borealis/borealis_installer_impl.cc",
+    "borealis/borealis_installer_impl.h",
+    "borealis/borealis_launch_options.cc",
+    "borealis/borealis_launch_options.h",
+    "borealis/borealis_launch_watcher.cc",
+    "borealis/borealis_launch_watcher.h",
+    "borealis/borealis_metrics.cc",
+    "borealis/borealis_metrics.h",
+    "borealis/borealis_power_controller.cc",
+    "borealis/borealis_power_controller.h",
+    "borealis/borealis_prefs.cc",
+    "borealis/borealis_prefs.h",
+    "borealis/borealis_service.cc",
+    "borealis/borealis_service.h",
+    "borealis/borealis_service_factory.cc",
+    "borealis/borealis_service_factory.h",
+    "borealis/borealis_service_impl.cc",
+    "borealis/borealis_service_impl.h",
+    "borealis/borealis_shutdown_monitor.cc",
+    "borealis/borealis_shutdown_monitor.h",
+    "borealis/borealis_switches.cc",
+    "borealis/borealis_switches.h",
+    "borealis/borealis_task.cc",
+    "borealis/borealis_task.h",
+    "borealis/borealis_util.cc",
+    "borealis/borealis_util.h",
+    "borealis/borealis_window_manager.cc",
+    "borealis/borealis_window_manager.h",
+    "borealis/infra/described.h",
+    "borealis/infra/expected.h",
+    "borealis/infra/state_manager.h",
+    "borealis/infra/transition.h",
+    "browser_accelerator_configuration.cc",
+    "browser_accelerator_configuration.h",
+    "browser_context_keyed_service_factories.cc",
+    "browser_context_keyed_service_factories.h",
+    "bruschetta/bruschetta_service.cc",
+    "bruschetta/bruschetta_service.h",
+    "bruschetta/bruschetta_service_factory.cc",
+    "bruschetta/bruschetta_service_factory.h",
   ]
 
   allow_circular_includes_from = [
@@ -551,6 +669,7 @@
     "//ash/components/arc/session",
     "//ash/components/arc/session:arc_base_enums",
     "//ash/components/arc/session:connection_holder",
+    "//ash/components/attestation",
     "//ash/components/audio",
     "//ash/components/disks",
     "//ash/components/login/auth",
@@ -567,21 +686,30 @@
     "//chrome/browser/extensions",
     "//chrome/browser/image_decoder",
     "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
     "//chrome/browser/web_applications",
     "//chrome/common:buildflags",
     "//chrome/common:constants",
     "//chrome/common/extensions/api",
     "//chrome/services/keymaster/public/mojom",
     "//chrome/services/printing/public/mojom",
+    "//chromeos/ash/components/dbus/authpolicy",
+    "//chromeos/ash/components/dbus/authpolicy:authpolicy_proto",
+    "//chromeos/ash/components/dbus/cicerone",
     "//chromeos/ash/components/dbus/concierge",
     "//chromeos/components/sharesheet:constants",
     "//chromeos/crosapi/mojom",
+    "//chromeos/dbus/attestation",
+    "//chromeos/dbus/attestation:attestation_proto",
     "//chromeos/dbus/common",
+    "//chromeos/dbus/constants",
     "//chromeos/dbus/dlcservice",
     "//chromeos/dbus/power",
     "//chromeos/dbus/resourced",
     "//chromeos/dbus/session_manager",
     "//chromeos/dbus/tpm_manager:tpm_manager_proto",
+    "//chromeos/metrics",
+    "//chromeos/network",
     "//chromeos/services/cros_healthd/public/mojom",
     "//chromeos/ui/base",
     "//components/account_id",
@@ -604,6 +732,7 @@
     "//components/services/app_service/public/cpp:app_types",
     "//components/services/app_service/public/cpp:app_update",
     "//components/services/app_service/public/cpp:icon_types",
+    "//components/services/app_service/public/cpp:instance_update",
     "//components/services/app_service/public/mojom:types_headers",
     "//components/session_manager/core",
     "//components/signin/public/identity_manager",
@@ -625,6 +754,7 @@
     "//mojo/public/cpp/system",
     "//net",
     "//services/data_decoder/public/cpp",
+    "//services/device/public/mojom",
     "//services/media_session/public/mojom",
     "//services/network/public/cpp",
     "//services/network/public/mojom:cookies_mojom",
@@ -668,6 +798,7 @@
     "//ash/components/multidevice/logging",
     "//ash/components/settings",
     "//ash/constants",
+    "//ash/public/mojom",
     "//ash/resources/vector_icons",
     "//ash/services/multidevice_setup/public/cpp:prefs",
     "//ash/services/multidevice_setup/public/mojom",
@@ -679,6 +810,7 @@
     "//chrome/browser:browser_process",
     "//chrome/browser:resources",
     "//chrome/browser/ash/crosapi:browser_util",
+    "//chrome/browser/chromeos:attestation_proto",
     "//chrome/browser/profiles",
     "//chrome/browser/resources:component_extension_resources",
     "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
@@ -688,34 +820,45 @@
     "//chrome/common:chrome_features",
     "//chrome/common:non_code_constants",
     "//chrome/common/net",
+    "//chromeos/ash/components/dbus/cicerone:cicerone_proto",
+    "//chromeos/ash/components/dbus/concierge:concierge_proto",
     "//chromeos/ash/components/dbus/upstart",
     "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser",
     "//chromeos/components/onc",
     "//chromeos/constants",
     "//chromeos/dbus",
+    "//chromeos/dbus:vm_applications_apps_proto",
+    "//chromeos/dbus:vm_launch_proto",
     "//chromeos/dbus/arc",
     "//chromeos/dbus/cdm_factory_daemon",
+    "//chromeos/dbus/cryptohome:attestation_proto",
+    "//chromeos/dbus/dlcservice:dlcservice_proto",
     "//chromeos/dbus/power:power_manager_proto",
     "//chromeos/dbus/session_manager",
     "//chromeos/dbus/tpm_manager",
     "//chromeos/dbus/userdataauth",
     "//chromeos/dbus/virtual_file_provider",
     "//chromeos/network",
+    "//chromeos/services/assistant/public/cpp",
     "//chromeos/services/cros_healthd/public/cpp",
     "//chromeos/system",
     "//chromeos/ui/vector_icons",
     "//components/app_constants",
     "//components/arc/common:arc_intent_helper_constants",
     "//components/consent_auditor",
+    "//components/content_settings/core/common",
     "//components/crx_file",
     "//components/device_event_log",
     "//components/embedder_support:browser_util",
+    "//components/guest_os",
+    "//components/guest_os:prefs",
     "//components/language/core/browser",
     "//components/language/core/common",
     "//components/live_caption:constants",
     "//components/metrics",
     "//components/onc",
     "//components/ownership",
+    "//components/permissions",
     "//components/pref_registry",
     "//components/services/app_service/public/cpp:intents",
     "//components/services/app_service/public/cpp:types",
@@ -725,10 +868,13 @@
     "//components/strings:components_strings",
     "//components/sync/base",
     "//components/sync/driver",
+    "//components/translate/core/browser",
     "//components/version_info",
+    "//components/version_info:channel",
     "//components/webapps/browser",
     "//components/webapps/browser:constants",
     "//content/public/common",
+    "//dbus",
     "//extensions/browser/api/file_handlers",
     "//extensions/browser/api/runtime",
     "//extensions/browser/api/virtual_keyboard_private",
@@ -754,6 +900,7 @@
     "//third_party/blink/public/mojom:mojom_platform",
     "//third_party/icu",
     "//third_party/re2",
+    "//third_party/securemessage/proto",
     "//ui/accessibility",
     "//ui/accessibility:ax_enums_mojo",
     "//ui/base:features",
diff --git a/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc b/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
index 28e6523..40bbee0 100644
--- a/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
@@ -316,8 +316,6 @@
   principal_expander_ = std::make_unique<VariableExpander>(substitutions);
 
   // Connect to a signal that indicates when Kerberos files change.
-  // TODO(https://crbug.com/963824): Make sure no code inside this constructor
-  // causes the daemon to start.
   KerberosClient::Get()->ConnectToKerberosFileChangedSignal(
       base::BindRepeating(&KerberosCredentialsManager::OnKerberosFilesChanged,
                           weak_factory_.GetWeakPtr()));
@@ -821,9 +819,8 @@
     VLOG(1) << "No or empty KerberosAccounts policy";
     NotifyRequiresLoginPassword(false);
 
-    // https://crbug.com/963824: The active principal is empty if there are no
-    // accounts, so no need to remove accounts. It would just start up the
-    // daemon unnecessarily.
+    // The active principal is empty if there are no accounts, so no need to
+    // remove accounts. It would just start up the daemon unnecessarily.
     if (!GetActivePrincipalName().empty())
       RemoveAllManagedAccountsExcept({});
     return;
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
index d250343..6d2f34d 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
@@ -57,9 +57,9 @@
   }
   if (base::IsStringASCII(scheme) &&
       (ProfileIOData::IsHandledProtocol(scheme) ||
-       base::LowerCaseEqualsASCII(scheme, content::kViewSourceScheme) ||
-       base::LowerCaseEqualsASCII(scheme, url::kJavaScriptScheme) ||
-       base::LowerCaseEqualsASCII(scheme, url::kDataScheme))) {
+       base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) ||
+       base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) ||
+       base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme))) {
     return metrics::OmniboxInputType::URL;
   }
 
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index 653813d..b121c265 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 #include <tuple>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
@@ -379,6 +380,8 @@
 // Test profile is saved if phone number is valid in selected country.
 // The data file contains two profiles with valid phone numbers and two
 // profiles with invalid phone numbers from their respective country.
+// If AutofillRemoveInvalidPhoneNumberOnImport is enabled, profiles with invalid
+// phone numbers are imported, but with the number removed.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfileSavedWithValidCountryPhone) {
   std::vector<FormMap> profiles;
 
@@ -429,20 +432,25 @@
   for (const auto& profile : profiles)
     FillFormAndSubmit("autofill_test_form.html", profile);
 
-  ASSERT_EQ(2u, personal_data_manager()->GetProfiles().size());
-  int us_address_index = personal_data_manager()->GetProfiles()[0]->GetRawInfo(
-                             ADDRESS_HOME_LINE1) == u"123 Cherry Ave"
-                             ? 0
-                             : 1;
+  // The two valid phone numbers are imported in any case.
+  std::vector<std::u16string> expected_phone_numbers{u"408-871-4567",
+                                                     u"+49 40-80-81-79-000"};
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillRemoveInvalidPhoneNumberOnImport)) {
+    // With the feature enabled, all four profiles are imported, but two without
+    // a phone number.
+    expected_phone_numbers.resize(4, u"");
+  }
 
-  EXPECT_EQ(
-      u"408-871-4567",
-      personal_data_manager()->GetProfiles()[us_address_index]->GetRawInfo(
-          PHONE_HOME_WHOLE_NUMBER));
-  ASSERT_EQ(
-      u"+49 40-80-81-79-000",
-      personal_data_manager()->GetProfiles()[1 - us_address_index]->GetRawInfo(
-          PHONE_HOME_WHOLE_NUMBER));
+  std::vector<std::u16string> actual_phone_numbers;
+  for (const AutofillProfile* profile :
+       personal_data_manager()->GetProfiles()) {
+    actual_phone_numbers.push_back(
+        profile->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  }
+
+  EXPECT_THAT(actual_phone_numbers,
+              testing::UnorderedElementsAreArray(expected_phone_numbers));
 }
 
 // Prepend country codes when formatting phone numbers, but only if the user
diff --git a/chrome/browser/autofill_assistant/password_change/proto/BUILD.gn b/chrome/browser/autofill_assistant/password_change/proto/BUILD.gn
new file mode 100644
index 0000000..b5e8895
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2022 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("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  proto_in_dir = "//"
+  sources = [ "extensions.proto" ]
+  link_deps = [ "//components/autofill_assistant/browser/public:proto" ]
+}
diff --git a/chrome/browser/autofill_assistant/password_change/proto/extensions.proto b/chrome/browser/autofill_assistant/password_change/proto/extensions.proto
new file mode 100644
index 0000000..d8f9e6bc
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/proto/extensions.proto
@@ -0,0 +1,67 @@
+// Copyright 2022 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "org.chromium.chrome.browser.autofill_assistant.password_change.proto";
+option java_multiple_files = true;
+
+package autofill_assistant.password_change;
+
+import "components/autofill_assistant/browser/public/external_action.proto";
+
+enum TopIcon {
+  TOP_ICON_UNSPECIFIED = 0;
+}
+
+enum ProgressStep {
+  PROGRESS_STEP_UNSPECIFIED = 0;
+
+  PROGRESS_STEP_START = 1;
+  PROGRESS_STEP_CHANGE_PASSWORD = 3;
+  PROGRESS_STEP_SAVE_PASSWORD = 4;
+  PROGRESS_STEP_END = 5;
+}
+
+message BasePrompt {
+  message Choice {
+    // The text shown on the chip/button.
+    optional string text = 1;
+
+    // Tag that identifies a choice.
+    optional string tag = 2;
+  }
+  // List of available choices in a prompt
+  repeated Choice choices = 1;
+}
+
+// Updates the side panel rendered in desktop during APC runs.
+message UpdateDesktopSidePanelSpecification {
+  // Icon rendered on top of the side panel.
+  optional TopIcon top_icon = 1;
+
+  // The title message shown to the user.
+  optional string title = 2;
+
+  // The description message shown to the user.
+  optional string description = 3;
+
+  // The current password change flow step.
+  optional ProgressStep progress_step = 4;
+
+  message Prompt {
+    oneof type {
+      // TODO(crbug.com/1328093): Add remaining prompt fieds .
+      BasePrompt prompt = 1;
+    }
+  }
+
+  // Optional prompt to ask for user input.
+  optional Prompt prompt = 5;
+}
+
+extend external.ActionInfo {
+  optional UpdateDesktopSidePanelSpecification update_side_panel = 447949102;
+}
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 690f7fa..bfd47736 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -583,124 +583,6 @@
   ]
 
   sources = [
-    "../ash/assistant/assistant_util.cc",
-    "../ash/assistant/assistant_util.h",
-    "../ash/attestation/attestation_ca_client.cc",
-    "../ash/attestation/attestation_ca_client.h",
-    "../ash/attestation/attestation_policy_observer.cc",
-    "../ash/attestation/attestation_policy_observer.h",
-    "../ash/attestation/certificate_util.cc",
-    "../ash/attestation/certificate_util.h",
-    "../ash/attestation/enrollment_certificate_uploader.h",
-    "../ash/attestation/enrollment_certificate_uploader_impl.cc",
-    "../ash/attestation/enrollment_certificate_uploader_impl.h",
-    "../ash/attestation/enrollment_id_upload_manager.cc",
-    "../ash/attestation/enrollment_id_upload_manager.h",
-    "../ash/attestation/machine_certificate_uploader.h",
-    "../ash/attestation/machine_certificate_uploader_impl.cc",
-    "../ash/attestation/machine_certificate_uploader_impl.h",
-    "../ash/attestation/platform_verification_flow.cc",
-    "../ash/attestation/platform_verification_flow.h",
-    "../ash/attestation/soft_bind_attestation_flow.cc",
-    "../ash/attestation/soft_bind_attestation_flow.h",
-    "../ash/attestation/tpm_challenge_key.cc",
-    "../ash/attestation/tpm_challenge_key.h",
-    "../ash/attestation/tpm_challenge_key_result.cc",
-    "../ash/attestation/tpm_challenge_key_result.h",
-    "../ash/attestation/tpm_challenge_key_subtle.cc",
-    "../ash/attestation/tpm_challenge_key_subtle.h",
-    "../ash/attestation/tpm_challenge_key_with_timeout.cc",
-    "../ash/attestation/tpm_challenge_key_with_timeout.h",
-    "../ash/audio/audio_survey_handler.cc",
-    "../ash/audio/audio_survey_handler.h",
-    "../ash/authpolicy/authpolicy_credentials_manager.cc",
-    "../ash/authpolicy/authpolicy_credentials_manager.h",
-    "../ash/authpolicy/authpolicy_helper.cc",
-    "../ash/authpolicy/authpolicy_helper.h",
-    "../ash/authpolicy/data_pipe_utils.cc",
-    "../ash/authpolicy/data_pipe_utils.h",
-    "../ash/authpolicy/kerberos_files_handler.cc",
-    "../ash/authpolicy/kerberos_files_handler.h",
-    "../ash/base/file_flusher.cc",
-    "../ash/base/file_flusher.h",
-    "../ash/base/locale_util.cc",
-    "../ash/base/locale_util.h",
-    "../ash/bluetooth/debug_logs_manager.cc",
-    "../ash/bluetooth/debug_logs_manager.h",
-    "../ash/bluetooth/debug_logs_manager_factory.cc",
-    "../ash/bluetooth/debug_logs_manager_factory.h",
-    "../ash/boot_times_recorder.cc",
-    "../ash/boot_times_recorder.h",
-    "../ash/borealis/borealis_app_launcher.cc",
-    "../ash/borealis/borealis_app_launcher.h",
-    "../ash/borealis/borealis_app_launcher_impl.cc",
-    "../ash/borealis/borealis_app_launcher_impl.h",
-    "../ash/borealis/borealis_app_uninstaller.cc",
-    "../ash/borealis/borealis_app_uninstaller.h",
-    "../ash/borealis/borealis_capabilities.cc",
-    "../ash/borealis/borealis_capabilities.h",
-    "../ash/borealis/borealis_context.cc",
-    "../ash/borealis/borealis_context.h",
-    "../ash/borealis/borealis_context_manager.h",
-    "../ash/borealis/borealis_context_manager_impl.cc",
-    "../ash/borealis/borealis_context_manager_impl.h",
-    "../ash/borealis/borealis_credits.cc",
-    "../ash/borealis/borealis_credits.h",
-    "../ash/borealis/borealis_disk_manager.h",
-    "../ash/borealis/borealis_disk_manager_dispatcher.cc",
-    "../ash/borealis/borealis_disk_manager_dispatcher.h",
-    "../ash/borealis/borealis_disk_manager_impl.cc",
-    "../ash/borealis/borealis_disk_manager_impl.h",
-    "../ash/borealis/borealis_engagement_metrics.cc",
-    "../ash/borealis/borealis_engagement_metrics.h",
-    "../ash/borealis/borealis_features.cc",
-    "../ash/borealis/borealis_features.h",
-    "../ash/borealis/borealis_features_util.cc",
-    "../ash/borealis/borealis_features_util.h",
-    "../ash/borealis/borealis_game_mode_controller.cc",
-    "../ash/borealis/borealis_game_mode_controller.h",
-    "../ash/borealis/borealis_installer.cc",
-    "../ash/borealis/borealis_installer.h",
-    "../ash/borealis/borealis_installer_impl.cc",
-    "../ash/borealis/borealis_installer_impl.h",
-    "../ash/borealis/borealis_launch_options.cc",
-    "../ash/borealis/borealis_launch_options.h",
-    "../ash/borealis/borealis_launch_watcher.cc",
-    "../ash/borealis/borealis_launch_watcher.h",
-    "../ash/borealis/borealis_metrics.cc",
-    "../ash/borealis/borealis_metrics.h",
-    "../ash/borealis/borealis_power_controller.cc",
-    "../ash/borealis/borealis_power_controller.h",
-    "../ash/borealis/borealis_prefs.cc",
-    "../ash/borealis/borealis_prefs.h",
-    "../ash/borealis/borealis_service.cc",
-    "../ash/borealis/borealis_service.h",
-    "../ash/borealis/borealis_service_factory.cc",
-    "../ash/borealis/borealis_service_factory.h",
-    "../ash/borealis/borealis_service_impl.cc",
-    "../ash/borealis/borealis_service_impl.h",
-    "../ash/borealis/borealis_shutdown_monitor.cc",
-    "../ash/borealis/borealis_shutdown_monitor.h",
-    "../ash/borealis/borealis_switches.cc",
-    "../ash/borealis/borealis_switches.h",
-    "../ash/borealis/borealis_task.cc",
-    "../ash/borealis/borealis_task.h",
-    "../ash/borealis/borealis_util.cc",
-    "../ash/borealis/borealis_util.h",
-    "../ash/borealis/borealis_window_manager.cc",
-    "../ash/borealis/borealis_window_manager.h",
-    "../ash/borealis/infra/described.h",
-    "../ash/borealis/infra/expected.h",
-    "../ash/borealis/infra/state_manager.h",
-    "../ash/borealis/infra/transition.h",
-    "../ash/browser_accelerator_configuration.cc",
-    "../ash/browser_accelerator_configuration.h",
-    "../ash/browser_context_keyed_service_factories.cc",
-    "../ash/browser_context_keyed_service_factories.h",
-    "../ash/bruschetta/bruschetta_service.cc",
-    "../ash/bruschetta/bruschetta_service.h",
-    "../ash/bruschetta/bruschetta_service_factory.cc",
-    "../ash/bruschetta/bruschetta_service_factory.h",
     "../ash/camera_detector.cc",
     "../ash/camera_detector.h",
     "../ash/camera_mic/vm_camera_mic_manager.cc",
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index d5af0aa3..316a9766 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -649,7 +649,13 @@
       << message_;
 }
 
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, AddRemoveEventListeners) {
+// TODO(crbug.com/1325383): test is flaky on Chromium OS MSAN builder.
+#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
+#define MAYBE_AddRemoveEventListeners DISABLED_AddRemoveEventListeners
+#else
+#define MAYBE_AddRemoveEventListeners AddRemoveEventListeners
+#endif
+IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_AddRemoveEventListeners) {
   StartEmbeddedTestServer();
   ASSERT_TRUE(RunExtensionTest("automation/tests/desktop",
                                {.page_url = "add_remove_event_listeners.html"}))
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ce71c93..2f7a5f3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4955,6 +4955,14 @@
     "expiry_milestone": 104
   },
   {
+    "name": "privacy-guide-android",
+    "owners": [
+      "andzaytsev",
+      "msramek",
+      "chrome-friendly-settings@google.com"],
+    "expiry_milestone": 114
+  },
+  {
     "name": "privacy-sandbox-ads-apis",
     "owners": [
       "johnidel",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8efc383c3..9d33b1c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2167,6 +2167,11 @@
     "Enables UI updates for Privacy Guide. This requires #privacy-guide to "
     "also be enabled";
 
+const char kPrivacyGuideAndroidName[] = "Privacy Guide on Android";
+const char kPrivacyGuideAndroidDescription[] =
+    "Shows a new subpage in Settings that helps the user to review various "
+    "privacy settings.";
+
 const char kPrivacySandboxAdsAPIsOverrideName[] = "Privacy Sandbox Ads APIs";
 const char kPrivacySandboxAdsAPIsOverrideDescription[] =
     "Enables Privacy Sandbox APIs: Attribution Reporting, Fledge, Topics, "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 9fedd71..f762bb1f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1212,6 +1212,9 @@
 extern const char kPrivacyGuide2Name[];
 extern const char kPrivacyGuide2Description[];
 
+extern const char kPrivacyGuideAndroidName[];
+extern const char kPrivacyGuideAndroidDescription[];
+
 extern const char kPrivacySandboxAdsAPIsOverrideName[];
 extern const char kPrivacySandboxAdsAPIsOverrideDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 5280289..38e2d56 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -118,7 +118,7 @@
     &features::kElasticOverscroll,
     &features::kElidePrioritizationOfPreNativeBootstrapTasks,
     &features::kGiveJavaUiThreadDefaultTaskTraitsUserBlockingPriority,
-    &features::kPrivacyGuide,
+    &features::kPrivacyGuideAndroid,
     &features::kPushMessagingDisallowSenderIDs,
     &features::kPwaUpdateDialogForIcon,
     &features::kPwaUpdateDialogForName,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index ab455bf..a6181887 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -454,7 +454,7 @@
     public static final String PREFETCH_NOTIFICATION_SCHEDULING_INTEGRATION =
             "PrefetchNotificationSchedulingIntegration";
     public static final String PRERENDER2 = "Prerender2";
-    public static final String PRIVACY_REVIEW = "PrivacyGuide";
+    public static final String PRIVACY_REVIEW = "PrivacyGuideAndroid";
     public static final String PRIVACY_SANDBOX_SETTINGS_3 = "PrivacySandboxSettings3";
     public static final String PROBABILISTIC_CRYPTID_RENDERER = "ProbabilisticCryptidRenderer";
     public static final String PUSH_MESSAGING_DISALLOW_SENDER_IDS =
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 2860da9..8b38bae 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -219,6 +219,8 @@
 #if BUILDFLAG(IS_MAC)
     {"iosurface", "IOSurface", MetricSize::kLarge, kSize,
      EmitTo::kSizeInUmaOnly, nullptr},
+    {"iosurface", "IOSurface.DirtyMemory", MetricSize::kLarge,
+     "resident_swapped", EmitTo::kSizeInUmaOnly, nullptr},
 #endif
     {"java_heap", "JavaHeap", MetricSize::kLarge, kEffectiveSize,
      EmitTo::kSizeInUkmAndUma, &Memory_Experimental::SetJavaHeap},
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index 6808e47..26aa12c 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -35,6 +35,7 @@
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
 #include "components/sync/model/proxy_model_type_controller_delegate.h"
+#include "google_apis/gaia/google_service_auth_error.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace password_manager {
@@ -177,6 +178,23 @@
   return SuccessStatus::kError;
 }
 
+void RecordApiErrorInCombinationWithSyncStatus(
+    int error_code,
+    GoogleServiceAuthError sync_error) {
+  std::string histogram_suffix;
+  if (sync_error.IsPersistentError()) {
+    histogram_suffix = "PersistentAuthError";
+  } else if (sync_error.IsTransientError()) {
+    histogram_suffix = "TransientAuthError";
+  } else {
+    histogram_suffix = "NoAuthError";
+  }
+  base::UmaHistogramSparse(
+      "PasswordManager.PasswordStoreAndroidBackend.APIError." +
+          histogram_suffix,
+      error_code);
+}
+
 }  // namespace
 
 class PasswordStoreAndroidBackend::ClearAllLocalPasswordsMetricRecorder {
@@ -539,6 +557,7 @@
 
 void PasswordStoreAndroidBackend::OnSyncServiceInitialized(
     syncer::SyncService* sync_service) {
+  sync_service_ = sync_service;
   sync_service->AddObserver(sync_controller_delegate_.get());
 }
 
@@ -579,7 +598,13 @@
   absl::optional<JobReturnHandler> reply = GetAndEraseJob(job_id);
   if (!reply.has_value())
     return;  // Task cleaned up after returning from background.
-  // TODO(crbug.com/1324588): DCHECK_EQ(api_error_code, 10) to catch dev errors.
+  if (error.api_error_code.has_value() && sync_service_) {
+    // TODO(crbug.com/1324588): DCHECK_EQ(api_error_code, 10) to catch dev
+    // errors.
+    DCHECK_EQ(AndroidBackendErrorType::kExternalError, error.type);
+    RecordApiErrorInCombinationWithSyncStatus(error.api_error_code.value(),
+                                              sync_service_->GetAuthError());
+  }
   reply->RecordMetrics(std::move(error));
   if (reply->Holds<LoginsOrErrorReply>()) {
     main_task_runner_->PostTask(
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.h b/chrome/browser/password_manager/android/password_store_android_backend.h
index c37c2b2..b23a03e 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.h
+++ b/chrome/browser/password_manager/android/password_store_android_backend.h
@@ -227,6 +227,8 @@
   // This object is the proxy to the JNI bridge that performs the API requests.
   std::unique_ptr<PasswordStoreAndroidBackendBridge> bridge_;
 
+  raw_ptr<syncer::SyncService> sync_service_ = nullptr;
+
   // Delegate to obtain sync status, and syncing account.
   std::unique_ptr<SyncDelegate> sync_delegate_;
 
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
index 18a9f09..71bf62a5 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
@@ -574,6 +574,98 @@
   histogram_tester.ExpectBucketCount(kAPIErrorMetric, 11004, 1);
 }
 
+TEST_F(PasswordStoreAndroidBackendTest,
+       OnExternalErrorInCombinationWithNoSyncError) {
+  backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(),
+                        base::RepeatingClosure(), base::DoNothing());
+
+  syncer::TestSyncService sync_service;
+  backend().OnSyncServiceInitialized(&sync_service);
+
+  ASSERT_FALSE(sync_service.GetAuthError().IsTransientError());
+  ASSERT_FALSE(sync_service.GetAuthError().IsPersistentError());
+
+  const JobId kJobId{1337};
+  base::HistogramTester histogram_tester;
+  base::MockCallback<LoginsOrErrorReply> mock_reply;
+  EXPECT_CALL(*bridge(), GetAllLogins).WillOnce(Return(kJobId));
+  backend().GetAllLoginsAsync(mock_reply.Get());
+  EXPECT_CALL(mock_reply,
+              Run(ExpectError(PasswordStoreBackendError::kUnspecified)));
+  AndroidBackendError error{AndroidBackendErrorType::kExternalError};
+  error.api_error_code = absl::optional<int>(11004);
+  consumer().OnError(kJobId, std::move(error));
+  RunUntilIdle();
+
+  constexpr char kAPIErrorMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.APIError.NoAuthError";
+
+  histogram_tester.ExpectBucketCount(kAPIErrorMetric, 11004, 1);
+}
+
+TEST_F(PasswordStoreAndroidBackendTest,
+       OnExternalErrorInCombinationWithTransientSyncError) {
+  backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(),
+                        base::RepeatingClosure(), base::DoNothing());
+
+  syncer::TestSyncService sync_service;
+  backend().OnSyncServiceInitialized(&sync_service);
+
+  GoogleServiceAuthError transient_error(
+      GoogleServiceAuthError::CONNECTION_FAILED);
+  ASSERT_TRUE(transient_error.IsTransientError());
+  sync_service.SetAuthError(transient_error);
+
+  const JobId kJobId{1337};
+  base::HistogramTester histogram_tester;
+  base::MockCallback<LoginsOrErrorReply> mock_reply;
+  EXPECT_CALL(*bridge(), GetAllLogins).WillOnce(Return(kJobId));
+  backend().GetAllLoginsAsync(mock_reply.Get());
+  EXPECT_CALL(mock_reply,
+              Run(ExpectError(PasswordStoreBackendError::kUnspecified)));
+  AndroidBackendError error{AndroidBackendErrorType::kExternalError};
+  error.api_error_code = absl::optional<int>(11004);
+  consumer().OnError(kJobId, std::move(error));
+  RunUntilIdle();
+
+  constexpr char kAPIErrorMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.APIError.TransientAuthError";
+
+  histogram_tester.ExpectBucketCount(kAPIErrorMetric, 11004, 1);
+}
+
+TEST_F(PasswordStoreAndroidBackendTest,
+       OnExternalErrorInCombinationWithPersistentSyncError) {
+  backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(),
+                        base::RepeatingClosure(), base::DoNothing());
+
+  syncer::TestSyncService sync_service;
+  backend().OnSyncServiceInitialized(&sync_service);
+
+  GoogleServiceAuthError persistent_error(
+      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+  ASSERT_TRUE(persistent_error.IsPersistentError());
+  sync_service.SetAuthError(persistent_error);
+
+  const JobId kJobId{1337};
+  base::HistogramTester histogram_tester;
+  base::MockCallback<LoginsOrErrorReply> mock_reply;
+  EXPECT_CALL(*bridge(), GetAllLogins).WillOnce(Return(kJobId));
+  backend().GetAllLoginsAsync(mock_reply.Get());
+  EXPECT_CALL(mock_reply,
+              Run(ExpectError(PasswordStoreBackendError::kUnspecified)));
+  AndroidBackendError error{AndroidBackendErrorType::kExternalError};
+  error.api_error_code = absl::optional<int>(11004);
+  consumer().OnError(kJobId, std::move(error));
+  RunUntilIdle();
+
+  constexpr char kAPIErrorMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.APIError."
+      "PersistentAuthError";
+
+  histogram_tester.ExpectBucketCount(kAPIErrorMetric, 11004, 1);
+}
+
 TEST_F(PasswordStoreAndroidBackendTest, DisableAutoSignInForOrigins) {
   EnableSyncForTestAccount();
   base::HistogramTester histogram_tester;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index bb563fc..8cdf56f 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -740,6 +740,11 @@
     "media_router.access_code_cast.discovered_networks";
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+// Deprecated on non-ChromeOS on 05/2022.
+extern const char kAccountIdMigrationState[] = "account_id_migration_state";
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -964,6 +969,10 @@
 #if !BUILDFLAG(IS_ANDROID)
   registry->RegisterDictionaryPref(kAccessCodeCastDiscoveredNetworks);
 #endif  // !BUILDFLAG(IS_ANDROID)
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+  registry->RegisterIntegerPref(kAccountIdMigrationState, 0);
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 }  // namespace
@@ -1888,6 +1897,11 @@
   crostini::RemoveTerminalFromRegistry(profile_prefs);
 #endif
 
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+  // Added 05/2022
+  profile_prefs->ClearPref(kAccountIdMigrationState);
+#endif
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 
diff --git a/chrome/browser/resources/side_panel/BUILD.gn b/chrome/browser/resources/side_panel/BUILD.gn
index 661371e..aa93fde7 100644
--- a/chrome/browser/resources/side_panel/BUILD.gn
+++ b/chrome/browser/resources/side_panel/BUILD.gn
@@ -8,6 +8,7 @@
 import("//tools/polymer/html_to_js.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
+import("./side_panel.gni")
 
 preprocess_folder = "preprocessed"
 
@@ -44,15 +45,52 @@
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
 }
 
-preprocess_if_expr("preprocess_web_components") {
+preprocess_if_expr("preprocess_src") {
+  in_folder = "."
+  out_folder = "$target_gen_dir/$preprocess_folder"
+  in_files = non_web_component_files
+}
+
+preprocess_if_expr("preprocess_gen") {
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
-  in_files = [ "app.ts" ]
+  in_files = web_component_files
 }
 
 html_to_js("web_components") {
-  js_files = [ "app.ts" ]
+  js_files = web_component_files
+}
+
+mojo_root_folder =
+    "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/side_panel"
+
+copy("copy_mojo_bookmarks") {
+  deps = [
+    "//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings_webui_js",
+  ]
+  sources = [ "$mojo_root_folder/bookmarks/bookmarks.mojom-webui.js" ]
+  outputs =
+      [ "$target_gen_dir/$preprocess_folder/bookmarks/{{source_file_part}}" ]
+}
+
+copy("copy_mojo_read_anything") {
+  deps = [
+    "//chrome/browser/ui/webui/side_panel/read_anything:mojo_bindings_webui_js",
+  ]
+  sources = [ "$mojo_root_folder/read_anything/read_anything.mojom-webui.js" ]
+  outputs = [
+    "$target_gen_dir/$preprocess_folder/read_anything/{{source_file_part}}",
+  ]
+}
+
+copy("copy_mojo_reading_list") {
+  deps = [
+    "//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings_webui_js",
+  ]
+  sources = [ "$mojo_root_folder/reading_list/reading_list.mojom-webui.js" ]
+  outputs =
+      [ "$target_gen_dir/$preprocess_folder/reading_list/{{source_file_part}}" ]
 }
 
 ts_library("build_ts") {
@@ -60,22 +98,7 @@
   root_dir = "$target_gen_dir/$preprocess_folder"
   out_dir = "$target_gen_dir/tsc"
   composite = true
-  in_files = [
-    "app.ts",
-    "bookmarks/bookmark_folder.ts",
-    "bookmarks/bookmarks_list.ts",
-    "bookmarks/bookmarks_api_proxy.ts",
-    "bookmarks/bookmarks_drag_manager.ts",
-    "bookmarks/bookmarks.mojom-webui.js",
-    "read_anything/app.ts",
-    "read_anything/read_anything_api_proxy.ts",
-    "read_anything/read_anything.mojom-webui.js",
-    "reading_list/app.ts",
-    "reading_list/icons.ts",
-    "reading_list/reading_list_api_proxy.ts",
-    "reading_list/reading_list_item.ts",
-    "reading_list/reading_list.mojom-webui.js",
-  ]
+  in_files = non_web_component_files + web_component_files + mojo_files
   definitions = [
     "//tools/typescript/definitions/bookmark_manager_private.d.ts",
     "//tools/typescript/definitions/bookmarks.d.ts",
@@ -88,15 +111,10 @@
     "//ui/webui/resources/mojo:library",
   ]
   extra_deps = [
-    ":preprocess_web_components",
-    "bookmarks:preprocess",
-    "bookmarks:preprocess_mojo",
-    "bookmarks:preprocess_web_components",
-    "read_anything:preprocess",
-    "read_anything:preprocess_mojo",
-    "read_anything:preprocess_web_components",
-    "reading_list:preprocess",
-    "reading_list:preprocess_mojo",
-    "reading_list:preprocess_web_components",
+    ":copy_mojo_bookmarks",
+    ":copy_mojo_read_anything",
+    ":copy_mojo_reading_list",
+    ":preprocess_gen",
+    ":preprocess_src",
   ]
 }
diff --git a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn b/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
deleted file mode 100644
index 3894b79..0000000
--- a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2021 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
-
-preprocess_folder =
-    "$root_gen_dir/chrome/browser/resources/side_panel/preprocessed/bookmarks"
-
-preprocess_if_expr("preprocess") {
-  in_folder = "./"
-  out_folder = preprocess_folder
-  in_files = [
-    "bookmarks_api_proxy.ts",
-    "bookmarks_drag_manager.ts",
-  ]
-}
-
-preprocess_if_expr("preprocess_mojo") {
-  deps = [
-    "//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings_webui_js",
-  ]
-  in_folder =
-      "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/side_panel/bookmarks"
-  out_folder = preprocess_folder
-  out_manifest = "$target_gen_dir/preprocessed_mojo_manifest.json"
-  in_files = [ "bookmarks.mojom-webui.js" ]
-}
-
-preprocess_if_expr("preprocess_web_components") {
-  deps = [ ":web_components" ]
-  in_folder = target_gen_dir
-  out_folder = preprocess_folder
-  in_files = [
-    "bookmark_folder.ts",
-    "bookmarks_list.ts",
-  ]
-}
-
-html_to_js("web_components") {
-  js_files = [
-    "bookmark_folder.ts",
-    "bookmarks_list.ts",
-  ]
-}
diff --git a/chrome/browser/resources/side_panel/read_anything/BUILD.gn b/chrome/browser/resources/side_panel/read_anything/BUILD.gn
deleted file mode 100644
index 25b1a69..0000000
--- a/chrome/browser/resources/side_panel/read_anything/BUILD.gn
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2021 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
-
-preprocess_folder = "$root_gen_dir/chrome/browser/resources/side_panel/preprocessed/read_anything"
-
-preprocess_if_expr("preprocess") {
-  in_folder = "./"
-  out_folder = preprocess_folder
-  in_files = [ "read_anything_api_proxy.ts" ]
-}
-
-preprocess_if_expr("preprocess_mojo") {
-  deps = [
-    "//chrome/browser/ui/webui/side_panel/read_anything:mojo_bindings_webui_js",
-  ]
-  in_folder = "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/side_panel/read_anything"
-  out_folder = preprocess_folder
-  out_manifest = "$target_gen_dir/preprocessed_mojo_manifest.json"
-  in_files = [ "read_anything.mojom-webui.js" ]
-}
-
-preprocess_if_expr("preprocess_web_components") {
-  deps = [ ":web_components" ]
-  in_folder = target_gen_dir
-  out_folder = preprocess_folder
-  in_files = [ "app.ts" ]
-}
-
-html_to_js("web_components") {
-  js_files = [ "app.ts" ]
-}
diff --git a/chrome/browser/resources/side_panel/reading_list/BUILD.gn b/chrome/browser/resources/side_panel/reading_list/BUILD.gn
deleted file mode 100644
index ac12f0c7..0000000
--- a/chrome/browser/resources/side_panel/reading_list/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2021 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
-
-preprocess_folder = "$root_gen_dir/chrome/browser/resources/side_panel/preprocessed/reading_list"
-
-preprocess_if_expr("preprocess") {
-  in_folder = "./"
-  out_folder = preprocess_folder
-  in_files = [ "reading_list_api_proxy.ts" ]
-}
-
-preprocess_if_expr("preprocess_mojo") {
-  deps = [
-    "//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings_webui_js",
-  ]
-  in_folder = "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/side_panel/reading_list/"
-  out_folder = preprocess_folder
-  out_manifest = "$target_gen_dir/preprocessed_mojo_manifest.json"
-  in_files = [ "reading_list.mojom-webui.js" ]
-}
-
-preprocess_if_expr("preprocess_web_components") {
-  deps = [ ":web_components" ]
-  in_folder = target_gen_dir
-  out_folder = preprocess_folder
-  in_files = [
-    "app.ts",
-    "icons.ts",
-    "reading_list_item.ts",
-  ]
-}
-
-html_to_js("web_components") {
-  js_files = [
-    "app.ts",
-    "icons.ts",
-    "reading_list_item.ts",
-  ]
-}
diff --git a/chrome/browser/resources/side_panel/side_panel.gni b/chrome/browser/resources/side_panel/side_panel.gni
new file mode 100644
index 0000000..c0fa0009
--- /dev/null
+++ b/chrome/browser/resources/side_panel/side_panel.gni
@@ -0,0 +1,27 @@
+# Copyright 2022 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.
+
+non_web_component_files = [
+  "bookmarks/bookmarks_api_proxy.ts",
+  "bookmarks/bookmarks_drag_manager.ts",
+  "read_anything/read_anything_api_proxy.ts",
+  "reading_list/reading_list_api_proxy.ts",
+]
+
+# Files holding a Polymer element definition and have an equivalent .html file.
+web_component_files = [
+  "app.ts",
+  "bookmarks/bookmark_folder.ts",
+  "bookmarks/bookmarks_list.ts",
+  "read_anything/app.ts",
+  "reading_list/app.ts",
+  "reading_list/icons.ts",
+  "reading_list/reading_list_item.ts",
+]
+
+mojo_files = [
+  "bookmarks/bookmarks.mojom-webui.js",
+  "read_anything/read_anything.mojom-webui.js",
+  "reading_list/reading_list.mojom-webui.js",
+]
diff --git a/chrome/browser/resources/signin/BUILD.gn b/chrome/browser/resources/signin/BUILD.gn
index 6b40802..d47754d 100644
--- a/chrome/browser/resources/signin/BUILD.gn
+++ b/chrome/browser/resources/signin/BUILD.gn
@@ -50,12 +50,17 @@
   if (!is_chromeos_ash) {
     input_files += [
       "enterprise_profile_welcome/enterprise_profile_welcome.html",
-      "enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg",
       "profile_customization/profile_customization.html",
       "signin_email_confirmation/signin_email_confirmation.html",
       "signin_error/signin_error.html",
     ]
   }
+  if (is_chromeos_lacros) {
+    input_files += [ "enterprise_profile_welcome/images/lacros_enterprise_profile_welcome_illustration.svg" ]
+  }
+  if (!is_chromeos_ash && !is_chromeos_lacros) {
+    input_files += [ "enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg" ]
+  }
   if (enable_dice_support) {
     input_files += [
       "dice_web_signin_intercept/dice_web_signin_intercept.html",
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html
index abe73b6..2354bf9f 100644
--- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html
+++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html
@@ -29,6 +29,43 @@
     width: 512px;
   }
 
+<if expr="chromeos_lacros">
+  :host {
+    --background-image:
+        url(images/lacros_enterprise_profile_welcome_illustration.svg);
+    --content-container-font-size: 14px;
+    --content-container-line-height: 20px;
+    --content-container-margin-top: 72px;
+    --content-container-width: 382px;
+    --content-container-title-font-size: 24px;
+    --content-container-title-font-weight: 500;
+    --content-container-title-line-height: 32px;
+    --info-box-bottom: 0;
+    --info-box-position: absolute;
+    --info-box-border: none;
+    --info-box-border-radius: 0px;
+    --info-box-font-size: 11px;
+    --info-box-line-height: 16px;
+  }
+</if>
+
+<if expr="not chromeos_lacros">
+  :host {
+    --background-image: url(images/enterprise_profile_welcome_illustration.svg);
+    --content-container-font-size: auto;
+    --content-container-line-height: auto;
+    --content-container-width: auto;
+    --content-container-title-font-size: 1.85em;
+    --content-container-title-font-weight: normal;
+    --content-container-title-line-height: auto;
+    --info-box-position: auto;
+    --info-box-border: 1px solid var(--google-grey-200);
+    --info-box-border-radius: 8px;
+    --info-box-font-size: auto;
+    --info-box-line-height: auto;
+  }
+</if>
+
   .secondary {
     color: var(--cr-secondary-text-color);
   }
@@ -49,7 +86,7 @@
   }
 
   #banner {
-    background-image: url(images/enterprise_profile_welcome_illustration.svg);
+    background-image: var(--background-image);
     background-position: center;
     background-repeat: no-repeat;
     background-size: var(--banner-size);
@@ -102,29 +139,37 @@
   }
 
   #contentContainer {
+    font-size: var(--content-container-font-size);
+    line-height: var(--content-container-line-height);
     margin-bottom: var(--content-container-margin-bottom);
     margin-inline: auto;
     margin-top: var(--content-container-margin-top);
     text-align: center;
+    width: var(--content-container-width);
   }
 
   #contentContainer h2 {
-    font-size: 1.85em;
-    font-weight: normal;
+    font-size: var(--content-container-title-font-size);
+    font-weight: var(--content-container-title-font-weight);
+    line-height: var(--content-container-title-line-height);
     margin-bottom: 8px;
   }
 
   .info-box {
     align-items: center;
-    border: 1px solid var(--google-grey-200);
-    border-radius: 8px;
+    border: var(--info-box-border);
+    border-radius: var(--info-box-border-radius);
+    bottom: var(--info-box-bottom);
     color: var(--google-grey-700);
     display: flex;
     flex-direction: row;
+    font-size: var(--info-box-font-size);
+    line-height: var(--info-box-line-height);
     margin-inline: var(--info-box-margin-inline);
     margin-top: var(--info-box-margin-top);
     padding-block: 12px;
     padding-inline-end: 18px;
+    position: var(--info-box-position);
     width: var(--info-box-width);
   }
 
@@ -175,7 +220,6 @@
     }
 
     .info-box {
-      border-color: var(--google-grey-600);
       color: var(--google-grey-100);
     }
 
@@ -206,6 +250,7 @@
       [[subtitle_]]
     </p>
   </template>
+  <if expr="not chromeos_lacros">
   <template is="dom-if" if="[[enterpriseInfo_]]">
     <div class="info-box">
       <div class="icon-container">
@@ -216,7 +261,20 @@
       </p>
     </div>
   </template>
+  </if>
 </div>
+<if expr="chromeos_lacros">
+<template is="dom-if" if="[[enterpriseInfo_]]">
+  <div class="info-box">
+    <div class="icon-container">
+      <iron-icon icon="cr:domain"></iron-icon>
+    </div>
+    <p id="enterpriseInfo" >
+      [[enterpriseInfo_]]
+    </p>
+  </div>
+</template>
+</if>
 <template is="dom-if" if="[[showLinkDataCheckbox_]]">
   <cr-checkbox id="linkData" checked="{{linkData_}}">
     <div>$i18n{linkDataText}</div>
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts
index b4aaa74..c78f3d47 100644
--- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts
+++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.ts
@@ -153,7 +153,9 @@
   }
 
   private setProfileInfo_(info: EnterpriseProfileInfo) {
+    // <if expr="not chromeos_lacros">
     this.style.setProperty('--header-background-color', info.backgroundColor);
+    // </if>
     this.pictureUrl_ = info.pictureUrl;
     this.showEnterpriseBadge_ = info.showEnterpriseBadge;
     this.title_ = info.title;
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg b/chrome/browser/resources/signin/enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg
index 07b340c..13b82a2 100644
--- a/chrome/browser/resources/signin/enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg
+++ b/chrome/browser/resources/signin/enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg
@@ -1 +1 @@
-<svg width="768" height="204" viewBox="0 0 768 204" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M625.349 182.757h-13.05v-13.268h-12.975v-13.344h-12.975v-13.268h-9.45V68.409h-43.275v65.495h-26.475v-29.45h-43.35v69.56" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="m693.671 162.813-13.65 5.905c-.825.383-1.8 0-2.1-.844l-5.775-13.958c-.375-.843 0-1.84.825-2.147l13.65-5.905c.825-.384 1.8 0 2.1.843l5.775 13.958c.375.844 0 1.841-.825 2.148z" fill="#34A853"/><path d="M576.899 68.41V83.9c1.125.154 2.325.23 3.525.23 14.325 0 25.95-11.887 25.95-26.535s-11.625-26.535-25.95-26.535-25.95 11.887-25.95 26.535c0 3.835.825 7.516 2.25 10.813h20.175z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M580.424 8.437v9.356m-41.625 15.262 7.95 4.678m67.35 39.803 7.95 4.678m-7.95-44.481 7.95-4.678M509.325 76.31V40.646H476.55v49.467h-20.025v-22.24H423.75v69.253" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M549.074 79.913h-6.3v8.13h6.3v-8.13zm14.551 0h-6.3v8.13h6.3v-8.13zm-14.551 18.099h-6.3v8.129h6.3v-8.13zm14.551 0h-6.3v8.129h6.3v-8.13zm-14.551 18.1h-6.3v8.13h6.3v-8.13zm14.551 0h-6.3v8.13h6.3v-8.13zm-14.551 18.099h-6.3v8.129h6.3v-8.129z" fill="#FBBC05"/><path d="M518.849 151.85h-6.3v8.129h6.3v-8.129zm0 18.099h-6.3v8.13h6.3v-8.13z" fill="#4285F4"/><path d="M563.625 134.211h-6.3v8.129h6.3v-8.129z" fill="#FBBC05"/><path d="M486.599 117.723h-6.3v8.129h6.3v-8.129zm14.55 0h-6.3v8.129h6.3v-8.129zm-14.55 18.098h-6.3v8.13h6.3v-8.13zm14.55 0h-6.3v8.13h6.3v-8.13zm-14.55 18.099h-6.3v8.129h6.3v-8.129zm181.726-64.037c4.184 0 7.575-3.468 7.575-7.745 0-4.279-3.391-7.746-7.575-7.746s-7.575 3.468-7.575 7.746c0 4.277 3.391 7.745 7.575 7.745z" fill="#4285F4"/><path d="m150.291 105.311 11.243-55.464-9.838-1.532-9.946 66.459 46.703 7.165 1.297-8.423-39.459-8.205z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m260.867 31.61-2.85 16.75c-.143.962.641 1.684 1.425 1.443l14.324-5.53c.784-.32.998-1.523.357-2.084L262.72 31.05c-.641-.72-1.639-.32-1.853.561z" fill="#4285F4"/><path d="M341.839 139.986c3.571-1.305 5.49-5.447 4.317-9.249-1.226-3.802-5.117-5.845-8.688-4.596l-17.057 6.128c-3.571 1.305-5.489 5.448-4.317 9.25 1.226 3.801 5.117 5.844 8.688 4.596l17.057-6.129z" fill="#FBBC05"/><path d="m182.25 68.018 23.25 4.84-18.524-28.377-4.726 23.537z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M151.5 165.654c2.9 0 5.25-2.404 5.25-5.369 0-2.964-2.35-5.368-5.25-5.368-2.899 0-5.25 2.404-5.25 5.368 0 2.965 2.351 5.369 5.25 5.369z" fill="#FBBC05"/><path d="m252.494 189.251-46.002-16.628a2.614 2.614 0 0 1-1.551-3.337l24.392-70.614c.481-1.367 1.925-2.078 3.263-1.586l46.002 16.628a2.614 2.614 0 0 1 1.551 3.336l-24.392 70.615a2.617 2.617 0 0 1-3.263 1.586z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m258.859 183.891-5.616-2.024m8.024-4.868-5.617-2.023m7.97-4.869-5.616-2.024m8.023-4.923-5.616-2.024m8.023-4.868-5.616-2.024m7.97-4.922-5.617-2.024m8.024-4.869-5.617-2.024m7.971-4.867-5.564-2.078m7.97-4.868-5.616-2.024m8.023-4.867-5.616-2.024" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="m243.239 121.097 14.228.219-6.9-12.69-7.328 12.471z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m250.522 108.597 6.915 12.716 74.194-42.187-6.915-12.716-74.194 42.187zm-63.398-63.921L164.06 39.88l-13.31 65.565 46.182 9.593 8.568-42.24-18.376-28.122z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M156.783 93.162c-.381 4.907 2.608 9.483 7.227 11.082.706.22 1.467-.221 1.576-.937l1.63-8.105c.163-.661-.272-1.378-.978-1.488l-7.988-1.654c-.707-.166-1.413.386-1.467 1.102z" fill="#34A853"/><path d="M178.125 95.098c3.521 0 6.375-2.918 6.375-6.519 0-3.6-2.854-6.518-6.375-6.518s-6.375 2.918-6.375 6.518c0 3.6 2.854 6.52 6.375 6.52z" fill="#FBBC05"/><path d="m177.432 106.546-7.235-1.459c-1.478-.302-2.446-1.761-2.141-3.219.306-1.459 1.784-2.415 3.262-2.113l7.235 1.459c1.478.302 2.446 1.76 2.141 3.219-.255 1.459-1.733 2.415-3.262 2.113z" fill="#4285F4"/></svg>
\ No newline at end of file
+<svg width="768" height="204" viewBox="0 0 768 204" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M625.349 182.757h-13.05v-13.268h-12.975v-13.344h-12.975v-13.268h-9.45V68.409h-43.275v65.495h-26.475v-29.45h-43.35v69.56" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="m693.671 162.813-13.65 5.905c-.825.383-1.8 0-2.1-.844l-5.775-13.958c-.375-.843 0-1.84.825-2.147l13.65-5.905c.825-.384 1.8 0 2.1.843l5.775 13.958c.375.844 0 1.841-.825 2.148z" fill="#34A853"/><path d="M576.899 68.41V83.9c1.125.154 2.325.23 3.525.23 14.325 0 25.95-11.887 25.95-26.535s-11.625-26.535-25.95-26.535-25.95 11.887-25.95 26.535c0 3.835.825 7.516 2.25 10.813h20.175z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M580.424 8.437v9.356m-41.625 15.262 7.95 4.678m67.35 39.803 7.95 4.678m-7.95-44.481 7.95-4.678M509.325 76.31V40.646H476.55v49.467h-20.025v-22.24H423.75v69.253" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M549.074 79.913h-6.3v8.13h6.3v-8.13zm14.551 0h-6.3v8.13h6.3v-8.13zm-14.551 18.099h-6.3v8.129h6.3v-8.13zm14.551 0h-6.3v8.129h6.3v-8.13zm-14.551 18.1h-6.3v8.13h6.3v-8.13zm14.551 0h-6.3v8.13h6.3v-8.13zm-14.551 18.099h-6.3v8.129h6.3v-8.129z" fill="#FBBC05"/><path d="M518.849 151.85h-6.3v8.129h6.3v-8.129zm0 18.099h-6.3v8.13h6.3v-8.13z" fill="#4285F4"/><path d="M563.625 134.211h-6.3v8.129h6.3v-8.129z" fill="#FBBC05"/><path d="M486.599 117.723h-6.3v8.129h6.3v-8.129zm14.55 0h-6.3v8.129h6.3v-8.129zm-14.55 18.098h-6.3v8.13h6.3v-8.13zm14.55 0h-6.3v8.13h6.3v-8.13zm-14.55 18.099h-6.3v8.129h6.3v-8.129zm181.726-64.037c4.184 0 7.575-3.468 7.575-7.745 0-4.279-3.391-7.746-7.575-7.746s-7.575 3.468-7.575 7.746c0 4.277 3.391 7.745 7.575 7.745z" fill="#4285F4"/><path d="m150.291 105.311 11.243-55.464-9.838-1.532-9.946 66.459 46.703 7.165 1.297-8.423-39.459-8.205z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m260.867 31.61-2.85 16.75c-.143.962.641 1.684 1.425 1.443l14.324-5.53c.784-.32.998-1.523.357-2.084L262.72 31.05c-.641-.72-1.639-.32-1.853.561z" fill="#4285F4"/><path d="M341.839 139.986c3.571-1.305 5.49-5.447 4.317-9.249-1.226-3.802-5.117-5.845-8.688-4.596l-17.057 6.128c-3.571 1.305-5.489 5.448-4.317 9.25 1.226 3.801 5.117 5.844 8.688 4.596l17.057-6.129z" fill="#FBBC05"/><path d="m182.25 68.018 23.25 4.84-18.524-28.377-4.726 23.537z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M151.5 165.654c2.9 0 5.25-2.404 5.25-5.369 0-2.964-2.35-5.368-5.25-5.368-2.899 0-5.25 2.404-5.25 5.368 0 2.965 2.351 5.369 5.25 5.369z" fill="#FBBC05"/><path d="m252.494 189.251-46.002-16.628a2.614 2.614 0 0 1-1.551-3.337l24.392-70.614c.481-1.367 1.925-2.078 3.263-1.586l46.002 16.628a2.614 2.614 0 0 1 1.551 3.336l-24.392 70.615a2.617 2.617 0 0 1-3.263 1.586z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m258.859 183.891-5.616-2.024m8.024-4.868-5.617-2.023m7.97-4.869-5.616-2.024m8.023-4.923-5.616-2.024m8.023-4.868-5.616-2.024m7.97-4.922-5.617-2.024m8.024-4.869-5.617-2.024m7.971-4.867-5.564-2.078m7.97-4.868-5.616-2.024m8.023-4.867-5.616-2.024" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="m243.239 121.097 14.228.219-6.9-12.69-7.328 12.471z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="m250.522 108.597 6.915 12.716 74.194-42.187-6.915-12.716-74.194 42.187zm-63.398-63.921L164.06 39.88l-13.31 65.565 46.182 9.593 8.568-42.24-18.376-28.122z" stroke="#4285F4" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M156.783 93.162c-.381 4.907 2.608 9.483 7.227 11.082.706.22 1.467-.221 1.576-.937l1.63-8.105c.163-.661-.272-1.378-.978-1.488l-7.988-1.654c-.707-.166-1.413.386-1.467 1.102z" fill="#34A853"/><path d="M178.125 95.098c3.521 0 6.375-2.918 6.375-6.519 0-3.6-2.854-6.518-6.375-6.518s-6.375 2.918-6.375 6.518c0 3.6 2.854 6.52 6.375 6.52z" fill="#FBBC05"/><path d="m177.432 106.546-7.235-1.459c-1.478-.302-2.446-1.761-2.141-3.219.306-1.459 1.784-2.415 3.262-2.113l7.235 1.459c1.478.302 2.446 1.76 2.141 3.219-.255 1.459-1.733 2.415-3.262 2.113z" fill="#4285F4"/></svg>
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/images/lacros_enterprise_profile_welcome_illustration.svg b/chrome/browser/resources/signin/enterprise_profile_welcome/images/lacros_enterprise_profile_welcome_illustration.svg
new file mode 100644
index 0000000..84e095599
--- /dev/null
+++ b/chrome/browser/resources/signin/enterprise_profile_welcome/images/lacros_enterprise_profile_welcome_illustration.svg
@@ -0,0 +1 @@
+<svg width="768" height="176" viewBox="0 0 768 176" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M331.381 51.256c-3.426.433-6.141 2.286-7.808 4.919-1.149 1.773-2.875 3.04-4.883 3.529l-.946.218c-2.008.49-4.119-.02-5.924-1.086-2.633-1.666-5.91-2.137-9.19-1.073-4.806 1.543-8.012 6.474-7.415 11.497.678 6.59 6.929 10.87 13.205 9.5a10.59 10.59 0 0 0 6.778-4.733c1.118-1.69 2.844-2.956 4.852-3.445l.946-.219c2.008-.489 4.067-.095 5.84 1.055 2.329 1.455 5.258 2.082 8.181 1.459 6.276-1.372 10.116-7.982 7.946-14.175-1.648-5.037-6.558-8.044-11.582-7.446Z" fill="#4384F4"/><path d="M614.55 140.585c6.472 3.003 9.225 10.816 6.222 17.288-3.004 6.472-10.816 9.225-17.288 6.222l-30.907-14.499c-6.472-3.004-9.226-10.816-6.222-17.288 3.003-6.472 10.816-9.226 17.288-6.222l30.907 14.499Z" fill="#56A55C"/><path d="m488.802 85.099 60.196 15.679" stroke="#E8EAED" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="m552.844 59.499-47.338-12.33a2.603 2.603 0 0 0-3.177 1.863l-7.538 29.055a2.61 2.61 0 0 0 1.87 3.178l47.338 12.33a2.602 2.602 0 0 0 3.177-1.864l7.538-29.054a2.61 2.61 0 0 0-1.87-3.178Z" fill="#fff" stroke="#DADCE0" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="m539.735 63.491-7.459-1.943a2.042 2.042 0 0 0-2.492 1.462l-1.933 7.45a2.047 2.047 0 0 0 1.467 2.493l7.458 1.943a2.041 2.041 0 0 0 2.492-1.462l1.933-7.45a2.046 2.046 0 0 0-1.466-2.493Z" fill="#4285F4"/><path d="m616.041 38.663-12.013 39.3a3.026 3.026 0 0 0 2.009 3.774l14.344 4.398a3.019 3.019 0 0 0 3.774-2.002l12.013-39.3a3.026 3.026 0 0 0-2.009-3.774l-14.344-4.398a3.019 3.019 0 0 0-3.774 2.002Z" fill="#fff" stroke="#DADCE0" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="m615.317 55.968-2.25 7.36a2.046 2.046 0 0 0 1.358 2.554l7.369 2.259a2.042 2.042 0 0 0 2.553-1.354l2.25-7.36a2.047 2.047 0 0 0-1.359-2.553l-7.369-2.26a2.04 2.04 0 0 0-2.552 1.354Z" fill="#34A853"/><path d="M619.345 42.08a1.294 1.294 0 1 0 .538-2.534 1.293 1.293 0 0 0-1.537.996c-.149.7.298 1.389.999 1.538Z" fill="#E8EAED"/><path d="M558.535 49.767c6.422-7.733 24.275-19.222 44.312-3.318" stroke="#DADCE0" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4.9 5.6"/><path d="m31.648 100.453 12.4 37.102a4.672 4.672 0 0 0 5.918 2.945l26.127-8.75a4.678 4.678 0 0 0 2.956-5.916l-12.4-37.102a4.672 4.672 0 0 0-5.918-2.945l-26.127 8.75a4.679 4.679 0 0 0-2.956 5.916Z" fill="#fff" stroke="#DADCE0" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="m45.952 105.212 4.75 1.054-5.73-17.145-7.911 2.649 5.73 17.145 3.16-3.703Z" fill="#3982F8" stroke="#3982F8" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="m51.783 114.337 14.072-4.712m-11.97 11.003 14.072-4.712m-11.97 11 14.072-4.712" stroke="#DADCE0" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/><path d="M46.309 117.95a1.714 1.714 0 1 0-1.634-3.011 1.715 1.715 0 0 0-.691 2.324 1.715 1.715 0 0 0 2.325.687Zm2.102 6.289a1.715 1.715 0 0 0 .69-2.324 1.715 1.715 0 0 0-3.015 1.637 1.714 1.714 0 0 0 2.325.687Zm2.103 6.29a1.714 1.714 0 0 0 .69-2.324 1.714 1.714 0 0 0-3.015 1.637 1.714 1.714 0 0 0 2.325.687Z" fill="#3982F8"/><path d="M671.546 114.779a7.242 7.242 0 0 1 9.319-4.251l38.424 14.351a7.244 7.244 0 0 1 4.251 9.32l-.621 1.661a7.243 7.243 0 0 1-9.319 4.251l-38.424-14.351a7.244 7.244 0 0 1-4.251-9.32l.621-1.661Z" fill="#fff" stroke="#DADCE0" stroke-width="1.4"/><circle cx="688.042" cy="121.887" r="2.943" transform="rotate(20.48 688.042 121.887)" fill="#34A853"/><circle cx="678.851" cy="118.454" r="2.943" transform="rotate(20.48 678.851 118.454)" fill="#34A853"/><circle cx="706.423" cy="128.752" r="2.943" transform="rotate(20.48 706.423 128.752)" fill="#34A853"/><circle cx="715.613" cy="132.185" r="2.943" transform="rotate(20.48 715.613 132.185)" fill="#34A853"/><circle cx="697.232" cy="125.32" r="2.943" transform="rotate(20.48 697.232 125.32)" fill="#34A853"/><path fill-rule="evenodd" clip-rule="evenodd" d="M690.604 79.038c3.137.176 5.672 2.443 6.326 5.368l13.994.784-.421 7.481-2.496-.14.071-1.25a1.254 1.254 0 0 0-2.503-.14l-.071 1.25-2.495-.14.21-3.74-6.503-.365a6.88 6.88 0 0 1-13.369-2.633c.213-3.785 3.473-6.687 7.257-6.475Zm2.098 8.753a3.121 3.121 0 0 1-2.659 1.227 3.13 3.13 0 0 1-2.949-3.295 3.13 3.13 0 0 1 3.3-2.944 3.117 3.117 0 0 1 2.429 1.396h-.004l-.001.008a3.103 3.103 0 0 1-.116 3.608Z" fill="#DADCE0"/><path d="m237.748 80.487-6.196 2.99a1.806 1.806 0 0 0-.841 2.41l2.99 6.196a1.805 1.805 0 0 0 2.41.84l6.196-2.989a1.805 1.805 0 0 0 .841-2.41l-2.99-6.196a1.805 1.805 0 0 0-2.41-.841Z" fill="#E989F7"/><path d="m124.612 82.962-.138.08c-4.68 2.74-6.253 8.756-3.512 13.437 2.74 4.68 8.756 6.252 13.436 3.512l.138-.08c4.68-2.741 6.253-8.757 3.512-13.437-2.74-4.68-8.756-6.253-13.436-3.512Z" fill="#5185EC"/><path d="M204.298 126.531c.789 2.001.917 4.196.364 6.273a10.196 10.196 0 0 1-3.445 5.294l-19.229 15.577a10.506 10.506 0 0 1-7.602 2.277 10.435 10.435 0 0 1-7.014-3.672 10.31 10.31 0 0 1-1.675-2.79 10.059 10.059 0 0 1-.358-6.269 10.206 10.206 0 0 1 3.439-5.291l19.258-15.585a10.466 10.466 0 0 1 4.379-2.103c1.609-.35 3.28-.32 4.874.089a10.464 10.464 0 0 1 4.297 2.262 10.22 10.22 0 0 1 2.776 3.938h-.064Z" stroke="#D85140" stroke-width="3" stroke-miterlimit="10"/><path d="m667.687 29.01 13.94 1a.582.582 0 0 1 .526.62.577.577 0 0 1-.096.28l-8 11.21a.573.573 0 0 1-.809.155.564.564 0 0 1-.191-.235l-6-12.21a.574.574 0 0 1 .063-.603.58.58 0 0 1 .567-.217Z" fill="#E989F7"/><path d="m375.987 32.537-3.77-3.77a.743.743 0 0 1-.19-.72l1.38-5.11a.75.75 0 0 1 .53-.53l5.15-1.38a.737.737 0 0 1 .72.19l3.77 3.72a.76.76 0 0 1 .2.73l-1.38 5.15a.75.75 0 0 1-.53.53l-5.15 1.38a.763.763 0 0 1-.73-.19Z" fill="#F2BE42"/><path d="M407.043 43.411c8.808 8.963 33.243 24.205 60.52 13.464" stroke="#D95140" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/><path d="m206.175 43.53-8.299-6.868c-.667-.572-.954-1.431-.858-2.29l1.812-10.588c.191-.858.763-1.621 1.527-1.908l10.111-3.72c.858-.286 1.717-.19 2.385.382l8.299 6.868c.667.572.954 1.43.858 2.29l-1.812 10.587c-.191.859-.763 1.622-1.527 1.908l-10.111 3.72c-.763.287-1.717.096-2.385-.381Z" fill="#F1F3F4"/><path d="M69 34.774a23.85 23.85 0 0 1 7.36-2.39 29.9 29.9 0 0 1 16.71 2.1l.36.14.52.23.35.15.34.16.34.16.35.17.35.17.54.28.37.2.59.31.41.23.43.24.69.39 1 .58 1.65 1 1.22.7.86.49.6.33.57.3.36.19.52.26.5.25.17.08.33.15.33.15.34.15 1 .44c7.23 2.9 16.7 2.3 24.25-1.67" stroke="#56A55C" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h768v176H0z"/></clipPath></defs></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html
index bbd5002a..98d168a1 100644
--- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html
+++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html
@@ -113,6 +113,28 @@
     width: 512px;
   }
 
+<if expr="chromeos_lacros">
+  :host {
+    --content-container-margin-top: 72px;
+    --content-container-title-font-size: 24px;
+    --content-container-title-font-weight: 500;
+    --content-container-title-line-height: 32px;
+    --confirmation-description-font-size: 14px;
+    --confirmation-description-line-height: 20px;
+    --theme-frame-color: transparent;
+  }
+</if>
+
+<if expr="not chromeos_lacros">
+  :host {
+    --content-container-title-font-size: 1.85em;
+    --content-container-title-font-weight: normal;
+    --content-container-title-line-height: auto;
+    --confirmation-description-font-size: var(--text-font-size);
+    --confirmation-description-line-height: auto;
+  }
+</if>
+
   /* Makes the absolutely positioned footer relative to confirmationContainer
      which may be larger than the window. */
   #confirmationContainer {
@@ -193,12 +215,14 @@
   }
 
   #contentContainer h2 {
-    font-size: 1.85em;
-    font-weight: normal;
+    font-size: var(--content-container-title-font-size);
+    font-weight: var(--content-container-title-font-weight);
+    line-height: var(--content-container-title-line-height);
   }
 
   #confirmationDescription {
-    font-size: var(--text-font-size);
+    font-size: var(--confirmation-description-font-size);
+    line-height: var(--confirmation-description-line-height);
     margin-inline: var(--confirmation-description-margin-inline);
     margin-top: 16px;
     max-width: 516px;
@@ -297,7 +321,11 @@
 
 <template is="dom-if" if="[[isNewDesign_]]">
   <div id="confirmationContainer">
-    <div id="headerContainer" style$="--theme-frame-color:[[highlightColor_]]">
+    <div id="headerContainer"
+    <if expr="not chromeos_lacros">
+      style$="--theme-frame-color:[[highlightColor_]]"
+    </if>
+    >
       <div id="syncPromoBanner"></div>
       <div id="avatarContainer">
         <img id="avatar" alt="" src="[[accountImageSrc_]]">
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 89817b4..b94afd9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -2205,11 +2205,6 @@
   EXPECT_EQ(GURL(url::kAboutBlankURL),     // Back to "about:blank"
             web_contents->GetLastCommittedURL());
 
-  histograms.ExpectTotalCount(kDelayedWarningsWithElisionDisabledHistogram, 2);
-  histograms.ExpectBucketCount(kDelayedWarningsWithElisionDisabledHistogram,
-                               DelayedWarningEvent::kPageLoaded, 1);
-  histograms.ExpectBucketCount(kDelayedWarningsWithElisionDisabledHistogram,
-                               DelayedWarningEvent::kWarningShownOnKeypress, 1);
   histograms.ExpectUniqueTimeSample(
       kDelayedWarningsTimeOnPageWithElisionDisabledHistogram,
       base::Seconds(kTimeOnPage), 1);
@@ -2237,11 +2232,6 @@
                 ->GetActiveWebContents()
                 ->GetLastCommittedURL());
 
-  histograms.ExpectTotalCount(kDelayedWarningsWithElisionDisabledHistogram, 2);
-  histograms.ExpectBucketCount(kDelayedWarningsWithElisionDisabledHistogram,
-                               DelayedWarningEvent::kPageLoaded, 1);
-  histograms.ExpectBucketCount(kDelayedWarningsWithElisionDisabledHistogram,
-                               DelayedWarningEvent::kWarningShownOnKeypress, 1);
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageDelayedWarningBrowserTest,
diff --git a/chrome/browser/safe_browsing/user_interaction_observer.cc b/chrome/browser/safe_browsing/user_interaction_observer.cc
index 9859165..93c936a 100644
--- a/chrome/browser/safe_browsing/user_interaction_observer.cc
+++ b/chrome/browser/safe_browsing/user_interaction_observer.cc
@@ -37,8 +37,6 @@
 const char kDelayedWarningsTimeOnPageHistogram[] =
     "SafeBrowsing.DelayedWarnings.TimeOnPage";
 
-const char kDelayedWarningsWithElisionDisabledHistogram[] =
-    "SafeBrowsing.DelayedWarnings.Event_UrlElisionDisabled";
 const char kDelayedWarningsTimeOnPageWithElisionDisabledHistogram[] =
     "SafeBrowsing.DelayedWarnings.TimeOnPage_UrlElisionDisabled";
 
@@ -309,10 +307,7 @@
 void SafeBrowsingUserInteractionObserver::RecordUMA(DelayedWarningEvent event) {
   Profile* profile =
       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-  if (IsUrlElisionDisabled(profile, suspicious_site_reporter_extension_id_)) {
-    base::UmaHistogramEnumeration(kDelayedWarningsWithElisionDisabledHistogram,
-                                  event);
-  } else {
+  if (!IsUrlElisionDisabled(profile, suspicious_site_reporter_extension_id_)) {
     base::UmaHistogramEnumeration(kDelayedWarningsHistogram, event);
   }
 }
diff --git a/chrome/browser/safe_browsing/user_interaction_observer.h b/chrome/browser/safe_browsing/user_interaction_observer.h
index fc2be7f..1f16e79 100644
--- a/chrome/browser/safe_browsing/user_interaction_observer.h
+++ b/chrome/browser/safe_browsing/user_interaction_observer.h
@@ -66,7 +66,6 @@
 extern const char kDelayedWarningsTimeOnPageHistogram[];
 
 // Same as above but only recorded if the user disabled URL elision.
-extern const char kDelayedWarningsWithElisionDisabledHistogram[];
 extern const char kDelayedWarningsTimeOnPageWithElisionDisabledHistogram[];
 
 // Observes user interactions and shows an interstitial if necessary.
diff --git a/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
index 0b85aab..46c9208 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
@@ -8,8 +8,10 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/cpp/login_screen_test_api.h"
+#include "ash/public/cpp/login_types.h"
 #include "ash/public/cpp/system_tray_test_api.h"
 #include "ash/shell.h"
+#include "ash/system/model/enterprise_domain_model.h"
 #include "ash/system/model/system_tray_model.h"
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
@@ -21,11 +23,15 @@
 #include "chrome/browser/ash/login/test/login_manager_mixin.h"
 #include "chrome/browser/ash/login/test/user_policy_mixin.h"
 #include "chrome/browser/ash/login/ui/user_adding_screen.h"
+#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h"
+#include "chrome/browser/ash/policy/core/device_cloud_policy_store_ash.h"
 #include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -34,6 +40,8 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/account_id/account_id.h"
+#include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
+#include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
@@ -81,6 +89,96 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
 }
 
+using ConsumerDeviceTest = MixinBasedInProcessBrowserTest;
+
+// Verify that the management device mode is indeed none of the
+// enterprise licenses.
+IN_PROC_BROWSER_TEST_F(ConsumerDeviceTest, WithNoLicense) {
+  EXPECT_EQ(ash::Shell::Get()
+                ->system_tray_model()
+                ->enterprise_domain()
+                ->management_device_mode(),
+            ash::ManagementDeviceMode::kNone);
+}
+
+namespace {
+
+// This is the constant that exists on the server side. It corresponds to
+// the type of enrollment license.
+constexpr char kKioskSkuName[] = "GOOGLE.CHROME_KIOSK_ANNUAL";
+
+}  // namespace
+
+class EnterpriseManagedTest : public MixinBasedInProcessBrowserTest {
+ public:
+  EnterpriseManagedTest() { device_state_.set_skip_initial_policy_setup(true); }
+  ~EnterpriseManagedTest() override = default;
+  EnterpriseManagedTest(const EnterpriseManagedTest&) = delete;
+  void operator=(const EnterpriseManagedTest&) = delete;
+
+ protected:
+  policy::DevicePolicyCrosTestHelper* policy_helper() {
+    return &policy_helper_;
+  }
+
+ private:
+  ash::DeviceStateMixin device_state_{
+      &mixin_host_,
+      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+  policy::DevicePolicyCrosTestHelper policy_helper_;
+};
+
+// Verify that the management device mode is indeed Kiosk Sku.
+IN_PROC_BROWSER_TEST_F(EnterpriseManagedTest, WithKioskSku) {
+  policy_helper()->device_policy()->policy_data().set_license_sku(
+      kKioskSkuName);
+  policy_helper()->RefreshPolicyAndWaitUntilDeviceCloudPolicyUpdated();
+
+  EXPECT_EQ(ash::Shell::Get()
+                ->system_tray_model()
+                ->enterprise_domain()
+                ->management_device_mode(),
+            ash::ManagementDeviceMode::kKioskSku);
+}
+
+// Verify that the management device mode is indeed education license.
+IN_PROC_BROWSER_TEST_F(EnterpriseManagedTest, WithEducationLicense) {
+  policy_helper()->device_policy()->policy_data().set_market_segment(
+      enterprise_management::PolicyData::ENROLLED_EDUCATION);
+  policy_helper()->RefreshPolicyAndWaitUntilDeviceCloudPolicyUpdated();
+
+  EXPECT_EQ(ash::Shell::Get()
+                ->system_tray_model()
+                ->enterprise_domain()
+                ->management_device_mode(),
+            ash::ManagementDeviceMode::kChromeEducation);
+}
+
+// Verify that the management device mode is indeed enterprise license.
+IN_PROC_BROWSER_TEST_F(EnterpriseManagedTest, WithEnterpriseLicense) {
+  policy_helper()->device_policy()->policy_data().set_market_segment(
+      enterprise_management::PolicyData::ENROLLED_ENTERPRISE);
+  policy_helper()->RefreshPolicyAndWaitUntilDeviceCloudPolicyUpdated();
+
+  EXPECT_EQ(ash::Shell::Get()
+                ->system_tray_model()
+                ->enterprise_domain()
+                ->management_device_mode(),
+            ash::ManagementDeviceMode::kChromeEnterprise);
+}
+
+// Verify that the management device mode is indeed unknown when the market
+// segment of the device policy data does not have value.
+IN_PROC_BROWSER_TEST_F(EnterpriseManagedTest, WithUnknownLicense) {
+  policy_helper()->RefreshPolicyAndWaitUntilDeviceCloudPolicyUpdated();
+
+  EXPECT_EQ(ash::Shell::Get()
+                ->system_tray_model()
+                ->enterprise_domain()
+                ->management_device_mode(),
+            ash::ManagementDeviceMode::kOther);
+}
+
 class SystemTrayClientClockTest : public ash::LoginManagerTest {
  public:
   SystemTrayClientClockTest() : LoginManagerTest() {
diff --git a/chrome/browser/ui/views/autofill_assistant/password_change/assistant_onboarding_view.cc b/chrome/browser/ui/views/autofill_assistant/password_change/assistant_onboarding_view.cc
index 42f6340c..54d0be30 100644
--- a/chrome/browser/ui/views/autofill_assistant/password_change/assistant_onboarding_view.cc
+++ b/chrome/browser/ui/views/autofill_assistant/password_change/assistant_onboarding_view.cc
@@ -10,13 +10,24 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "build/branding_buildflags.h"
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/autofill_assistant/password_change/assistant_onboarding_controller.h"
 #include "chrome/browser/ui/autofill_assistant/password_change/assistant_onboarding_prompt.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
 #include "ui/base/ui_base_types.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/layout_provider.h"
 
+namespace {
+// Ratios of element width and dialog width.
+constexpr double kAssistantLogoScaleFactor = 0.2;
+}  // namespace
+
 // Factory function to create onboarding prompts on desktop platforms.
 base::WeakPtr<AssistantOnboardingPrompt> AssistantOnboardingPrompt::Create(
     base::WeakPtr<AssistantOnboardingController> controller,
@@ -64,6 +75,9 @@
   set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
       views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH));
 
+  set_margins(views::LayoutProvider::Get()->GetDialogInsetsForContentType(
+      views::DialogContentType::kControl, views::DialogContentType::kControl));
+
   SetAcceptCallback(
       base::BindOnce(&AssistantOnboardingController::OnAccept, controller_));
   SetCancelCallback(
@@ -73,7 +87,32 @@
 }
 
 void AssistantOnboardingView::InitDialog() {
-  // TODO(crbug.com/1322387): Populate dialog with views for image, texts, and
+  // The dialog is not expected to be resized, so for our purposes, a
+  // `BoxLayout` is sufficient.
+  auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter);
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
+
+  // TODO(crbug.com/1322387): Set spacing between children.
+
+  const int dialog_width = views::LayoutProvider::Get()->GetDistanceMetric(
+      views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH);
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  const gfx::VectorIcon& assistant_icon = kAssistantIcon;
+#else
+  // Only developer builds will ever use this branch and the color used in
+  // `FromVectorIcon` below.
+  const gfx::VectorIcon& assistant_icon = kProductIcon;
+#endif
+  AddChildView(std::make_unique<views::ImageView>())
+      ->SetImage(
+          gfx::CreateVectorIcon(assistant_icon, gfx::kPlaceholderColor,
+                                kAssistantLogoScaleFactor * dialog_width));
+
+  // TODO(crbug.com/1322387): Populate dialog with views for texts and the
   // learn more link.
 }
 
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
index c591550..a163b8f 100644
--- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
+++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
@@ -9,6 +9,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
@@ -40,13 +41,19 @@
        IDR_SIGNIN_ENTERPRISE_PROFILE_WELCOME_ENTERPRISE_PROFILE_WELCOME_APP_HTML_JS},
       {"enterprise_profile_welcome_browser_proxy.js",
        IDR_SIGNIN_ENTERPRISE_PROFILE_WELCOME_ENTERPRISE_PROFILE_WELCOME_BROWSER_PROXY_JS},
-      {"images/enterprise_profile_welcome_illustration.svg",
-       IDR_SIGNIN_ENTERPRISE_PROFILE_WELCOME_IMAGES_ENTERPRISE_PROFILE_WELCOME_ILLUSTRATION_SVG},
       {"signin_shared.css.js", IDR_SIGNIN_SIGNIN_SHARED_CSS_JS},
       {"signin_vars.css.js", IDR_SIGNIN_SIGNIN_VARS_CSS_JS},
   };
   source->AddResourcePaths(kResources);
-
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  source->AddResourcePath(
+      "images/lacros_enterprise_profile_welcome_illustration.svg",
+      IDR_SIGNIN_ENTERPRISE_PROFILE_WELCOME_IMAGES_LACROS_ENTERPRISE_PROFILE_WELCOME_ILLUSTRATION_SVG);
+#else
+  source->AddResourcePath(
+      "images/enterprise_profile_welcome_illustration.svg",
+      IDR_SIGNIN_ENTERPRISE_PROFILE_WELCOME_IMAGES_ENTERPRISE_PROFILE_WELCOME_ILLUSTRATION_SVG);
+#endif
   source->AddLocalizedString("enterpriseProfileWelcomeTitle",
                              IDS_ENTERPRISE_PROFILE_WELCOME_TITLE);
   source->AddLocalizedString("cancelLabel", IDS_CANCEL);
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
index 73ab348..08907edb 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -116,6 +116,8 @@
     title_id = IDS_SYNC_CONFIRMATION_TITLE_LACROS;
     info_title_id = IDS_SYNC_CONFIRMATION_SYNC_INFO_TITLE_LACROS;
     confirm_label_id = IDS_DONE;
+  } else {
+    title_id = IDS_SYNC_CONFIRMATION_TITLE_LACROS_NON_FORCED;
   }
 #endif
   AddStringResource(source, "syncConfirmationTitle", title_id);
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 6487ec61..2962caa8c 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1653285310-05ab8e44ff839714d80ecd7b81dd58d047710853.profdata
+chrome-linux-main-1653307121-1b20e5048bf06dd9cbd32589552cf939d51efba5.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 674037c..2518c115 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1653285310-33ae798904d1454f1b7f7317369b87c48fe902e3.profdata
+chrome-mac-arm-main-1653307121-d686ce354988d903d80534d2d3da5fbf7eeb6598.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index dd487bc..21bb68c5 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1653285310-8776e0cabafaab2134539e8077bc208d5b83c1de.profdata
+chrome-mac-main-1653307121-95591925579c73173df1deba64a898f7cfd75bfb.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 5874648..9439bd6 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1653296201-d65cbd52699822181f14833c5d6cb9010b3469a2.profdata
+chrome-win32-main-1653317740-c35a2a008433fd401259456273af877ad8a1ddd6.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1a7f4a7d..53e6e8b 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1653296201-52b223a5b458bfbdd58f2891cbdd48ac7b1b0506.profdata
+chrome-win64-main-1653317740-22d1a5031f5abac0f28a6f4677e8f80b3c23de78.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 202a0e5c5..14a132b 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -808,6 +808,9 @@
 const base::Feature kPrivacyGuide2{"PrivacyGuide2",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kPrivacyGuideAndroid{"PrivacyGuideAndroid",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables push subscriptions keeping Chrome running in the
 // background when closed.
 const base::Feature kPushMessagingBackgroundMode{
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 54d3797f..ebfe779 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -568,6 +568,9 @@
 extern const base::Feature kPrivacyGuide2;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPrivacyGuideAndroid;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPushMessagingBackgroundMode;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 4d286af..0d0843e6 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -26,7 +26,6 @@
 
 namespace {
 
-const int kCdpMethodNotFoundCode = -32601;
 const char kInspectorDefaultContextError[] =
     "Cannot find default execution context";
 const char kInspectorContextError[] = "Cannot find context with specified id";
@@ -39,6 +38,9 @@
     "Push Permission without userVisibleOnly:true isn't supported";
 const char kInspectorNoSuchFrameError[] =
     "Frame with the given id was not found.";
+
+static constexpr int kSessionNotFoundInspectorCode = -32001;
+static constexpr int kCdpMethodNotFoundCode = -32601;
 static constexpr int kInvalidParamsInspectorCode = -32602;
 
 class ScopedIncrementer {
@@ -564,8 +566,23 @@
             << " (id=" << response.id << ") " << id_ << " " << result;
   }
 
-  if (iter == response_info_map_.end())
+  if (iter == response_info_map_.end()) {
+    // A CDP session may become detached while a command sent to that session
+    // is still pending. When the browser eventually tries to process this
+    // command, it sends a response with an error and no session ID. Since
+    // there is no session ID, this message will be routed here to the root
+    // DevToolsClientImpl. If we receive such a response, just ignore it
+    // since the session it belongs to is already detached.
+    if (parent_ == nullptr) {
+      if (!response.result) {
+        const Status status = internal::ParseInspectorError(response.error);
+        if (status.code() == StatusCode::kNoSuchFrame) {
+          return Status(kOk);
+        }
+      }
+    }
     return Status(kUnknownError, "unexpected command response");
+  }
 
   scoped_refptr<ResponseInfo> response_info = response_info_map_[response.id];
   response_info_map_.erase(response.id);
@@ -698,6 +715,9 @@
     if (maybe_code.value() == kCdpMethodNotFoundCode) {
       return Status(kUnknownCommand,
                     maybe_message ? *maybe_message : "UnknownCommand");
+    } else if (maybe_code.value() == kSessionNotFoundInspectorCode) {
+      return Status(kNoSuchFrame,
+                    maybe_message ? *maybe_message : "inspector detached");
     }
   }
 
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index 1d90c4d..5814198 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -353,6 +353,30 @@
   return true;
 }
 
+bool ReturnUnexpectedIdThenResponse(
+    bool* first,
+    const std::string& message,
+    int expected_id,
+    std::string* session_id,
+    internal::InspectorMessageType* type,
+    internal::InspectorEvent* event,
+    internal::InspectorCommandResponse* command_response) {
+  session_id->clear();
+  if (*first) {
+    *type = internal::kCommandResponseMessageType;
+    command_response->id = expected_id + 100;
+    command_response->error = "{\"code\":-32001,\"message\":\"ERR\"}";
+  } else {
+    *type = internal::kCommandResponseMessageType;
+    command_response->id = expected_id;
+    base::DictionaryValue params;
+    command_response->result = std::make_unique<base::DictionaryValue>();
+    command_response->result->GetDict().Set("key", 2);
+  }
+  *first = false;
+  return true;
+}
+
 bool ReturnCommandError(const std::string& message,
                         int expected_id,
                         std::string* session_id,
@@ -510,6 +534,18 @@
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
 
+TEST_F(DevToolsClientImplTest, SendCommandUnexpectedId) {
+  SyncWebSocketFactory factory =
+      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
+  bool first = true;
+  DevToolsClientImpl client("id", "", "http://url", factory);
+  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
+  client.SetParserFuncForTesting(
+      base::BindRepeating(&ReturnUnexpectedIdThenResponse, &first));
+  base::DictionaryValue params;
+  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
+}
+
 TEST_F(DevToolsClientImplTest, SendCommandResponseError) {
   SyncWebSocketFactory factory =
       base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
@@ -692,6 +728,13 @@
             status.message());
 }
 
+TEST(ParseInspectorError, SessionNotFoundError) {
+  const std::string error("{\"code\":-32001,\"message\":\"SOME MESSAGE\"}");
+  Status status = internal::ParseInspectorError(error);
+  ASSERT_EQ(kNoSuchFrame, status.code());
+  ASSERT_EQ("no such frame: SOME MESSAGE", status.message());
+}
+
 TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
   MockListener listener;
   SyncWebSocketFactory factory =
diff --git a/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts b/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts
index 97abe80..2f07593 100644
--- a/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts
+++ b/chrome/test/data/webui/signin/enterprise_profile_welcome_test.ts
@@ -49,16 +49,6 @@
     assertEquals(expectedUrl, img.src);
   }
 
-  /**
-   * Checks that the expected header color is displayed.
-   */
-  function checkHeaderColor(expectedColor: string) {
-    assertTrue(isChildVisible(app, '#headerContainer'));
-    const headerElement = app.shadowRoot!.querySelector('#headerContainer')!;
-    assertEquals(
-        expectedColor, getComputedStyle(headerElement).backgroundColor);
-  }
-
   test('proceed', async function() {
     assertTrue(isChildVisible(app, '#proceedButton'));
     app.$.proceedButton.click();
@@ -129,7 +119,6 @@
     checkTextValues('title', 'subtitle', 'enterprise_info', 'proceed_label');
     checkImageUrl(AVATAR_URL_1);
     assertFalse(isChildVisible(app, '.work-badge'));
-    checkHeaderColor('rgb(255, 0, 0)');
 
     // Update the values.
     webUIListenerCallback('on-profile-info-changed', {
@@ -149,6 +138,5 @@
     checkImageUrl(AVATAR_URL_2);
     assertTrue(isChildVisible(app, '.work-badge'));
     assertFalse(isChildVisible(app, '#cancelButton'));
-    checkHeaderColor('rgb(0, 255, 0)');
   });
 });
diff --git a/chrome/test/data/webui/signin/sync_confirmation_test.ts b/chrome/test/data/webui/signin/sync_confirmation_test.ts
index 5eac09a..6929f8b 100644
--- a/chrome/test/data/webui/signin/sync_confirmation_test.ts
+++ b/chrome/test/data/webui/signin/sync_confirmation_test.ts
@@ -15,15 +15,6 @@
 [true, false].forEach(isNewDesignEnabled => {
   const suiteDesignSuffix = isNewDesignEnabled ? 'NewDesign' : 'OldDesign';
 
-  // Sync forced comes with different strings but these come from the UI class
-  // so loadTimeData.overrideValues() does not help here.s
-  const STANDARD_TITLE = 'Turn on sync?';
-  const STANDARD_CONSENT_DESCRIPTION_TEXT = [
-    STANDARD_TITLE,
-    'Sync your bookmarks, passwords, history, and more on all your devices',
-    'Google may use your history to personalize Search and other Google ' +
-        'services',
-  ];
   const STANDARD_CONSENT_CONFIRMATION = 'Yes, I\'m in';
 
   [true, false].forEach(syncForcedEnabled => {
@@ -69,11 +60,6 @@
 
           // Tests that no DCHECKS are thrown during initialization of the UI.
           test('LoadPage', function() {
-            assertEquals(
-                STANDARD_TITLE,
-                app.shadowRoot!.querySelector('#syncConfirmationHeading')!
-                    .textContent!.trim());
-
             const cancelButton =
                 app.shadowRoot!.querySelector(
                     isNewDesignEnabled ? '#notNowButton' : '#cancelButton') as
@@ -140,11 +126,7 @@
         // Confirm button.
         test('recordConsentOnConfirm', async function() {
           app.shadowRoot!.querySelector<HTMLElement>('#confirmButton')!.click();
-          const [description, confirmation] =
-              await browserProxy.whenCalled('confirm');
-          assertEquals(
-              JSON.stringify(STANDARD_CONSENT_DESCRIPTION_TEXT),
-              JSON.stringify(description));
+          const [_, confirmation] = await browserProxy.whenCalled('confirm');
           assertEquals(STANDARD_CONSENT_CONFIRMATION, confirmation);
         });
 
@@ -153,11 +135,8 @@
         test('recordConsentOnSettingsLink', async function() {
           app.shadowRoot!.querySelector<HTMLElement>(
                              '#settingsButton')!.click();
-          const [description, confirmation] =
+          const [_, confirmation] =
               await browserProxy.whenCalled('goToSettings');
-          assertEquals(
-              JSON.stringify(STANDARD_CONSENT_DESCRIPTION_TEXT),
-              JSON.stringify(description));
           // 'Sync settings' is recorded for new design but this is passed from
           // the UI class so overriding loadTimeData does not help here.
           assertEquals('Settings', confirmation);
diff --git a/chromeos/ash/components/dbus/kerberos/fake_kerberos_client.cc b/chromeos/ash/components/dbus/kerberos/fake_kerberos_client.cc
index a819ed6a..fbd080f5 100644
--- a/chromeos/ash/components/dbus/kerberos/fake_kerberos_client.cc
+++ b/chromeos/ash/components/dbus/kerberos/fake_kerberos_client.cc
@@ -24,8 +24,8 @@
 // Fake renewal lifetime for TGTs.
 constexpr base::TimeDelta kTgtRenewal = base::Hours(24);
 
-// Blacklist for fake config validation.
-const char* const kBlacklistedConfigOptions[] = {
+// Blocklist for fake config validation.
+const char* const kBlocklistedConfigOptions[] = {
     "allow_weak_crypto",
     "ap_req_checksum_type",
     "ccache_type",
@@ -48,9 +48,9 @@
 };
 
 // Performs a fake validation of a config line by just checking for some
-// non-whitelisted keywords. Returns true if no blacklisted items are contained.
+// non-allowlisted keywords. Returns true if no blocklisted items are contained.
 bool ValidateConfigLine(const std::string& line) {
-  for (const char* option : kBlacklistedConfigOptions) {
+  for (const char* option : kBlocklistedConfigOptions) {
     if (line.find(option) != std::string::npos)
       return false;
   }
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 5c3065d9..405dd08b 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -223,8 +223,8 @@
   # https://crbug.com/1327171
   "policy.PopupsForURLCheck.default",
 
-  # https://crbug.com/1327345
-  "policy.ChromePolicyPageStatusTimestamps.ash",
+  # https://crbug.com/1327361
+  "policy.FullscreenAllowed",
 ]
 
 # To create filters to be used on specific builders add them like this:
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 23fa660a..cecb9429 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1886,8 +1886,8 @@
   field->form_control_ax_id = element.GetAxId();
   field->form_control_type = element.FormControlTypeForAutofill().Utf8();
   field->autocomplete_attribute = GetAutocompleteAttribute(element);
-  if (base::LowerCaseEqualsASCII(element.GetAttribute(*kRole).Utf16(),
-                                 "presentation")) {
+  if (base::EqualsCaseInsensitiveASCII(element.GetAttribute(*kRole).Utf16(),
+                                       "presentation")) {
     field->role = FormFieldData::RoleAttribute::kPresentation;
   }
 
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 0b51352..b482f8bbc 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -54,106 +54,12 @@
 namespace form_util {
 namespace {
 
-struct AutofillFieldLabelSourceCase {
-  const char* html;
-  const FormFieldData::LabelSource label_source;
-};
-
 struct AutofillFieldUtilCase {
   const char* description;
   const char* html;
   const char16_t* expected_label;
 };
 
-const char kElevenChildren[] =
-    "<div id='target'>"
-    "<div>child0</div>"
-    "<div>child1</div>"
-    "<div>child2</div>"
-    "<div>child3</div>"
-    "<div>child4</div>"
-    "<div>child5</div>"
-    "<div>child6</div>"
-    "<div>child7</div>"
-    "<div>child8</div>"
-    "<div>child9</div>"
-    "<div>child10</div>"
-    "</div>";
-const char16_t kElevenChildrenExpected[] =
-    u"child0child1child2child3child4child5child6child7child8";
-
-const char kElevenChildrenNested[] =
-    "<div id='target'>"
-    "<div>child0"
-    "<div>child1"
-    "<div>child2"
-    "<div>child3"
-    "<div>child4"
-    "<div>child5"
-    "<div>child6"
-    "<div>child7"
-    "<div>child8"
-    "<div>child9"
-    "<div>child10"
-    "</div></div></div></div></div></div></div></div></div></div></div></div>";
-// Take 10 elements -1 for target element, -1 as text is a leaf element.
-const char16_t kElevenChildrenNestedExpected[] =
-    u"child0child1child2child3child4";
-
-const char kSkipElement[] =
-    "<div id='target'>"
-    "<div>child0</div>"
-    "<div class='skip'>child1</div>"
-    "<div>child2</div>"
-    "</div>";
-// TODO(crbug.com/796918): Should be child0child2
-const char16_t kSkipElementExpected[] = u"child0";
-
-const char kDivTableExample1[] =
-    "<div>"
-    "<div>label</div><div><input id='target'/></div>"
-    "</div>";
-const char16_t kDivTableExample1Expected[] = u"label";
-
-const char kDivTableExample2[] =
-    "<div>"
-    "<div>label</div>"
-    "<div>should be skipped<input/></div>"
-    "<div><input id='target'/></div>"
-    "</div>";
-const char16_t kDivTableExample2Expected[] = u"label";
-
-const char kDivTableExample3[] =
-    "<div>"
-    "<div>should be skipped<input/></div>"
-    "<div>label</div>"
-    "<div><input id='target'/></div>"
-    "</div>";
-const char16_t kDivTableExample3Expected[] = u"label";
-
-const char kDivTableExample4[] =
-    "<div>"
-    "<div>should be skipped<input/></div>"
-    "label"
-    "<div><input id='target'/></div>"
-    "</div>";
-// TODO(crbug.com/796918): Should be label
-const char16_t kDivTableExample4Expected[] = u"";
-
-const char kDivTableExample5[] =
-    "<div>"
-    "<div>label<div><input id='target'/></div>behind</div>"
-    "</div>";
-// TODO(crbug.com/796918): Should be label
-const char16_t kDivTableExample5Expected[] = u"labelbehind";
-
-const char kDivTableExample6[] =
-    "<div>"
-    "<div>label<div><div>-<div><input id='target'/></div></div>"
-    "</div>";
-// TODO(crbug.com/796918): Should be "label" or "label-"
-const char16_t kDivTableExample6Expected[] = u"";
-
 void VerifyButtonTitleCache(const WebFormElement& form_target,
                             const ButtonTitleList& expected_button_titles,
                             const ButtonTitlesCache& actual_cache) {
@@ -184,14 +90,43 @@
       {"simple test", "<div id='target'>test</div>", u"test"},
       {"Concatenate test", "<div id='target'><span>one</span>two</div>",
        u"onetwo"},
-      // TODO(crbug.com/796918): should be "onetwo"
+      // Test that "two" is not inferred, because for the purpose of label
+      // extraction, we only care about text before the input element.
       {"Ignore input", "<div id='target'>one<input value='test'/>two</div>",
        u"one"},
       {"Trim", "<div id='target'>   one<span>two  </span></div>", u"onetwo"},
-      {"eleven children", kElevenChildren, kElevenChildrenExpected},
-      // TODO(crbug.com/796918): Depth is only 5 elements
-      {"eleven children nested", kElevenChildrenNested,
-       kElevenChildrenNestedExpected},
+      {"eleven children",
+       "<div id='target'>"
+       "<div>child0</div>"
+       "<div>child1</div>"
+       "<div>child2</div>"
+       "<div>child3</div>"
+       "<div>child4</div>"
+       "<div>child5</div>"
+       "<div>child6</div>"
+       "<div>child7</div>"
+       "<div>child8</div>"
+       "<div>child9</div>"
+       "<div>child10</div>",
+       u"child0child1child2child3child4child5child6child7child8"},
+      // TODO(crbug.com/796918): Depth is only 5 elements instead of 10. This
+      // happens because every div and every text node decrease the depth.
+      {"eleven children nested",
+       "<div id='target'>"
+       "<div>child0"
+       "<div>child1"
+       "<div>child2"
+       "<div>child3"
+       "<div>child4"
+       "<div>child5"
+       "<div>child6"
+       "<div>child7"
+       "<div>child8"
+       "<div>child9"
+       "<div>child10"
+       "</div></div></div></div></div></div></div></div></div></div></div></"
+       "div>",
+       u"child0child1child2child3child4"},
   };
   for (auto test_case : test_cases) {
     SCOPED_TRACE(test_case.description);
@@ -205,7 +140,14 @@
 
 TEST_F(FormAutofillUtilsTest, FindChildTextSkipElementTest) {
   static const AutofillFieldUtilCase test_cases[] = {
-      {"Skip div element", kSkipElement, kSkipElementExpected},
+      // Test that everything after the "skip" div is discarded.
+      {"Skip div element", R"(
+       <div id=target>
+         <div>child0</div>
+         <div class=skip>child1</div>
+         <div>child2</div>
+       </div>)",
+       u"child0"},
   };
   for (auto test_case : test_cases) {
     SCOPED_TRACE(test_case.description);
@@ -227,12 +169,48 @@
 
 TEST_F(FormAutofillUtilsTest, InferLabelForElementTest) {
   static const AutofillFieldUtilCase test_cases[] = {
-      {"DIV table test 1", kDivTableExample1, kDivTableExample1Expected},
-      {"DIV table test 2", kDivTableExample2, kDivTableExample2Expected},
-      {"DIV table test 3", kDivTableExample3, kDivTableExample3Expected},
-      {"DIV table test 4", kDivTableExample4, kDivTableExample4Expected},
-      {"DIV table test 5", kDivTableExample5, kDivTableExample5Expected},
-      {"DIV table test 6", kDivTableExample6, kDivTableExample6Expected},
+      {"DIV table test 1", R"(
+       <div>
+         <div>label</div><div><input id=target></div>
+       </div>)",
+       u"label"},
+      {"DIV table test 2", R"(
+       <div>
+         <div>label</div>
+         <div>should be skipped<input></div>
+         <div><input id=target></div>
+       </div>)",
+       u"label"},
+      {"DIV table test 3", R"(
+       <div>
+         <div>should be skipped<input></div>
+         <div>label</div>
+         <div><input id=target></div>
+       </div>)",
+       u"label"},
+      // TODO(crbug.com/796918): Should be label
+      {"DIV table test 4", R"(
+       <div>
+         <div>should be skipped<input></div>
+         label
+         <div><input id=target></div>
+       </div>)",
+       u""},
+      // TODO(crbug.com/796918): Should be label
+      {"DIV table test 5",
+       "<div>"
+       "<div>label<div><input id='target'/></div>behind</div>"
+       "</div>",
+       u"labelbehind"},
+      {"DIV table test 6", R"(
+       <div>
+         label
+         <div>-</div>
+         <div><input id='target'></div>
+       </div>)",
+       // TODO(crbug.com/796918): Should be "label" or "label-". This happens
+       // because "-" is inferred, but discarded because `!IsLabelValid()`.
+       u""},
   };
   for (auto test_case : test_cases) {
     SCOPED_TRACE(test_case.description);
@@ -251,6 +229,10 @@
 }
 
 TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) {
+  struct AutofillFieldLabelSourceCase {
+    const char* html;
+    const FormFieldData::LabelSource label_source;
+  };
   const char16_t kLabelSourceExpectedLabel[] = u"label";
   static const AutofillFieldLabelSourceCase test_cases[] = {
       {"<div><div>label</div><div><input id='target'/></div></div>",
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index e5239ea..000da32 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -332,6 +332,8 @@
     "suggestions_context.cc",
     "suggestions_context.h",
     "sync_utils.h",
+    "touch_to_fill_delegate.cc",
+    "touch_to_fill_delegate.h",
     "ui/accessory_sheet_data.cc",
     "ui/accessory_sheet_data.h",
     "ui/accessory_sheet_enums.h",
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc
index c76a024b..ef6c588 100644
--- a/components/autofill/core/browser/autofill_data_util.cc
+++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -109,7 +109,7 @@
       base::TrimString(element, u".", base::TRIM_ALL);
 
   for (size_t i = 0; i < set_size; ++i) {
-    if (base::LowerCaseEqualsASCII(trimmed_element, set[i]))
+    if (base::EqualsCaseInsensitiveASCII(trimmed_element, set[i]))
       return true;
   }
 
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 3dd8b4b..066225ea 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -420,6 +420,7 @@
                       enable_download_manager),
       external_delegate_(
           std::make_unique<AutofillExternalDelegate>(this, driver)),
+      touch_to_fill_delegate_(std::make_unique<TouchToFillDelegate>()),
       app_locale_(app_locale),
       personal_data_(client->GetPersonalDataManager()),
       field_filler_(app_locale, client->GetAddressNormalizer()),
@@ -1053,9 +1054,14 @@
         field.form_control_type, weak_ptr_factory_.GetWeakPtr(), context);
     return;
   }
-  // TODO(crbug.com/1247698): Try to show TTF if |touch_to_fill_eligible|.
-  // Send Autofill suggestions (could be an empty list).
+
   single_field_form_fill_router_->CancelPendingQueries(this);
+  if (touch_to_fill_eligible &&
+      touch_to_fill_delegate_->TryToShowTouchToFill(query_id, form, field)) {
+    // Touch To Fill is shown.
+    return;
+  }
+  // Send Autofill suggestions (could be an empty list).
   external_delegate_->OnSuggestionsReturned(query_id, suggestions,
                                             autoselect_first_suggestion,
                                             context.should_display_gpay_logo);
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index bffd1f37..5c84077 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -37,6 +37,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/single_field_form_fill_router.h"
 #include "components/autofill/core/browser/sync_utils.h"
+#include "components/autofill/core/browser/touch_to_fill_delegate.h"
 #include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/common/dense_set.h"
 #include "components/autofill/core/common/form_data.h"
@@ -301,6 +302,11 @@
     external_delegate_ = std::move(external_delegate);
   }
 
+  void SetTouchToFillDelegateForTest(
+      std::unique_ptr<TouchToFillDelegate> touch_to_fill_delegate) {
+    touch_to_fill_delegate_ = std::move(touch_to_fill_delegate);
+  }
+
   // A public wrapper that calls |DeterminePossibleFieldTypesForUpload| for
   // testing purposes only.
   static void DeterminePossibleFieldTypesForUploadForTest(
@@ -627,9 +633,10 @@
   void SetDataList(const std::vector<std::u16string>& values,
                    const std::vector<std::u16string>& labels);
 
-  // Delegate to perform external processing (display, selection) on
+  // Delegates to perform external processing (display, selection) on
   // our behalf.
   std::unique_ptr<AutofillExternalDelegate> external_delegate_;
+  std::unique_ptr<TouchToFillDelegate> touch_to_fill_delegate_;
 
   std::string app_locale_;
 
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index ba343e8..1af3ef0 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -162,6 +162,19 @@
               (override));
 };
 
+class MockTouchToFillDelegate : public TouchToFillDelegate {
+ public:
+  MockTouchToFillDelegate() = default;
+  MockTouchToFillDelegate(const MockTouchToFillDelegate&) = delete;
+  MockTouchToFillDelegate& operator=(const MockTouchToFillDelegate&) = delete;
+  ~MockTouchToFillDelegate() override = default;
+
+  MOCK_METHOD(bool,
+              TryToShowTouchToFill,
+              (int query_id, const FormData& form, const FormFieldData& field),
+              (override));
+};
+
 void ExpectFilledField(const char* expected_label,
                        const char* expected_name,
                        const char* expected_value,
@@ -410,6 +423,11 @@
     browser_autofill_manager_->SetExternalDelegateForTest(
         std::move(external_delegate));
 
+    auto touch_to_fill_delegate = std::make_unique<MockTouchToFillDelegate>();
+    touch_to_fill_delegate_ = touch_to_fill_delegate.get();
+    browser_autofill_manager_->SetTouchToFillDelegateForTest(
+        std::move(touch_to_fill_delegate));
+
     auto test_strike_database = std::make_unique<TestStrikeDatabase>();
     strike_database_ = test_strike_database.get();
     autofill_client_.set_test_strike_database(std::move(test_strike_database));
@@ -489,6 +507,15 @@
     GetAutofillSuggestions(kDefaultPageID, form, field);
   }
 
+  void TryToShowTouchToFill(int query_id,
+                            const FormData& form,
+                            const FormFieldData& field,
+                            TouchToFillEligible touch_to_fill_eligible) {
+    browser_autofill_manager_->OnAskForValuesToFill(
+        query_id, form, field, gfx::RectF(),
+        /*autoselect_first_suggestion=*/false, touch_to_fill_eligible);
+  }
+
   void AutocompleteSuggestionsReturned(
       const std::vector<std::u16string>& results,
       int query_id = kDefaultPageID) {
@@ -728,6 +755,7 @@
   std::unique_ptr<MockAutofillDriver> autofill_driver_;
   std::unique_ptr<TestBrowserAutofillManager> browser_autofill_manager_;
   raw_ptr<TestAutofillExternalDelegate> external_delegate_;
+  raw_ptr<MockTouchToFillDelegate> touch_to_fill_delegate_;
   scoped_refptr<AutofillWebDataService> database_;
   raw_ptr<MockAutofillDownloadManager> download_manager_;
   std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
@@ -9362,6 +9390,35 @@
   EXPECT_EQ(response_data.fields[3].value, u"Test Country");
 }
 
+// Tests that Autofill suggestions are not shown if TTF is eligible and shown.
+TEST_F(BrowserAutofillManagerTest, AutofillSuggestionsOrTouchToFill) {
+  FormData form;
+  CreateTestCreditCardFormData(&form, /*is_https=*/true,
+                               /*use_month_type=*/false);
+  std::vector<FormData> forms(1, form);
+  FormsSeen(forms);
+  const FormFieldData& field = form.fields[1];
+  int query_id = 1;
+
+  // TTF not eligible, Autofill suggestions shown.
+  EXPECT_CALL(*touch_to_fill_delegate_, TryToShowTouchToFill(query_id, _, _))
+      .Times(0);
+  TryToShowTouchToFill(query_id++, form, field, TouchToFillEligible(false));
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+
+  // TTF not shown, Autofill suggestions shown.
+  EXPECT_CALL(*touch_to_fill_delegate_, TryToShowTouchToFill(query_id, _, _))
+      .WillOnce(Return(false));
+  TryToShowTouchToFill(query_id++, form, field, TouchToFillEligible(true));
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+
+  // TTF eligible and shown, Autofill suggestions not shown
+  EXPECT_CALL(*touch_to_fill_delegate_, TryToShowTouchToFill(query_id, _, _))
+      .WillOnce(Return(true));
+  TryToShowTouchToFill(query_id++, form, field, TouchToFillEligible(true));
+  EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+}
+
 // Desktop only tests.
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 class BrowserAutofillManagerTestForVirtualCardOption
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index e00f386..4032144 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -1154,7 +1154,7 @@
       types_seen.insert(server_field_type);
     }
     // If |field| is an HTML5 month input, handle it as a special case.
-    if (base::LowerCaseEqualsASCII(field->form_control_type, "month")) {
+    if (base::EqualsCaseInsensitiveASCII(field->form_control_type, "month")) {
       DCHECK_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, server_field_type);
       candidate_credit_card.SetInfoForMonthInputType(value);
       continue;
diff --git a/components/autofill/core/browser/form_parsing/credit_card_field.cc b/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 51aa1db..806c8b7 100644
--- a/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -514,7 +514,7 @@
                                           LogManager* log_manager,
                                           const LanguageCode& page_language,
                                           PatternSource pattern_source) {
-  if (!expiration_date_ && base::LowerCaseEqualsASCII(
+  if (!expiration_date_ && base::EqualsCaseInsensitiveASCII(
                                scanner->Cursor()->form_control_type, "month")) {
     expiration_date_ = scanner->Cursor();
     expiration_month_ = nullptr;
diff --git a/components/autofill/core/browser/personal_data_manager_cleaner.cc b/components/autofill/core/browser/personal_data_manager_cleaner.cc
index 7ec31ff..ce4317ca 100644
--- a/components/autofill/core/browser/personal_data_manager_cleaner.cc
+++ b/components/autofill/core/browser/personal_data_manager_cleaner.cc
@@ -157,7 +157,8 @@
 
 void PersonalDataManagerCleaner::RemoveInaccessibleProfileValues() {
   if (!base::FeatureList::IsEnabled(
-          features::kAutofillRemoveInaccessibleProfileValues)) {
+          features::kAutofillRemoveInaccessibleProfileValues) ||
+      !features::kAutofillRemoveInaccessibleProfileValuesOnStartup.Get()) {
     return;
   }
 
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index fbdedcc3..b954f63 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -4934,11 +4934,13 @@
 }
 
 // Tests that settings-inaccessible profile values are removed from every stored
-// profile.
-TEST_F(PersonalDataManagerTest, RemoveInaccessibleProfileValues) {
+// profile on startup.
+TEST_F(PersonalDataManagerTest, RemoveInaccessibleProfileValuesOnStartup) {
   base::test::ScopedFeatureList feature;
-  feature.InitAndEnableFeature(
-      features::kAutofillRemoveInaccessibleProfileValues);
+  feature.InitAndEnableFeatureWithParameters(
+      features::kAutofillRemoveInaccessibleProfileValues,
+      {{features::kAutofillRemoveInaccessibleProfileValuesOnStartup.name,
+        "true"}});
 
   // Add a German and a US profile.
   AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
diff --git a/components/autofill/core/browser/touch_to_fill_delegate.cc b/components/autofill/core/browser/touch_to_fill_delegate.cc
new file mode 100644
index 0000000..55af4f1d
--- /dev/null
+++ b/components/autofill/core/browser/touch_to_fill_delegate.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/touch_to_fill_delegate.h"
+
+namespace autofill {
+
+TouchToFillDelegate::TouchToFillDelegate() = default;
+TouchToFillDelegate::~TouchToFillDelegate() = default;
+
+bool TouchToFillDelegate::TryToShowTouchToFill(int query_id,
+                                               const FormData& form,
+                                               const FormFieldData& field) {
+  // TODO(crbug.com/1247698): Add eligibility checks and trigger TTF.
+  return false;
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/touch_to_fill_delegate.h b/components/autofill/core/browser/touch_to_fill_delegate.h
new file mode 100644
index 0000000..2bea4e8
--- /dev/null
+++ b/components/autofill/core/browser/touch_to_fill_delegate.h
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_H_
+
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+
+namespace autofill {
+
+// Delegate for in-browser Touch To Fill (TTF) surface display and selection.
+// TODO(crbug.com/1324900): Consider using more descriptive name.
+class TouchToFillDelegate {
+ public:
+  TouchToFillDelegate();
+  TouchToFillDelegate(const TouchToFillDelegate&) = delete;
+  TouchToFillDelegate& operator=(const TouchToFillDelegate&) = delete;
+  virtual ~TouchToFillDelegate();
+
+  // Checks whether TTF is eligible for the given web form data. On success
+  // triggers the corresponding surface and returns |true|.
+  virtual bool TryToShowTouchToFill(int query_id,
+                                    const FormData& form,
+                                    const FormFieldData& field);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_H_
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index f990782..61739ba 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -425,12 +425,19 @@
     "AutofillRationalizeStreetAddressAndAddressLine",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Clear fields which are not visible in the settings for a profile's country,
-// both during profile import and on startup.
+// Prevents Autofill from importing setting-inaccessible field types on profile
+// import.
 // TODO(crbug.com/1299435): Cleanup when launched.
 const base::Feature kAutofillRemoveInaccessibleProfileValues{
     "AutofillRemoveInaccessibleProfileValues",
     base::FEATURE_DISABLED_BY_DEFAULT};
+// If enabled, setting-inaccessible field types are additionally removed from
+// existing profiles on startup. These can exit in profile imported prior to
+// AutofillRemoveInaccessibleProfileValues.
+const base::FeatureParam<bool>
+    kAutofillRemoveInaccessibleProfileValuesOnStartup{
+        &kAutofillRemoveInaccessibleProfileValues,
+        "remove_inaccessible_fields_on_startup", false};
 
 // If enabled, invalid phone numbers are removed on profile import, rather than
 // invalidating the entire profile.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index a3a5baa..e479d9a 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -160,6 +160,9 @@
 COMPONENT_EXPORT(AUTOFILL)
 extern const base::Feature kAutofillRemoveInaccessibleProfileValues;
 COMPONENT_EXPORT(AUTOFILL)
+extern const base::FeatureParam<bool>
+    kAutofillRemoveInaccessibleProfileValuesOnStartup;
+COMPONENT_EXPORT(AUTOFILL)
 extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache;
 COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillSaveAndFillVPA;
 COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index b4fb2eb3..1b3bd92 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "9.20",
-  "log_list_timestamp": "2022-05-22T12:56:19Z",
+  "version": "9.21",
+  "log_list_timestamp": "2022-05-23T12:55:37Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/cronet/PRESUBMIT.py b/components/cronet/PRESUBMIT.py
index 06b53f9..ac3c411b 100644
--- a/components/cronet/PRESUBMIT.py
+++ b/components/cronet/PRESUBMIT.py
@@ -82,6 +82,7 @@
       '.',
       [ r'^tools_unittest\.py$'],
       run_on_python3=USE_PYTHON3,
+      run_on_python2=False,
       skip_shebang_check = True)
 
 
diff --git a/components/exo/extended_drag_source.cc b/components/exo/extended_drag_source.cc
index c0d9ce4..93e80a9 100644
--- a/components/exo/extended_drag_source.cc
+++ b/components/exo/extended_drag_source.cc
@@ -20,6 +20,7 @@
 #include "components/exo/wm_helper.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -219,7 +220,7 @@
   MaybeLockCursor();
 
   if (dragged_window_holder_ && dragged_window_holder_->toplevel_window())
-    StartDrag(dragged_window_holder_->toplevel_window(), start_location);
+    StartDrag(dragged_window_holder_->toplevel_window());
 }
 
 DragOperation ExtendedDragSource::OnToplevelWindowDragDropped() {
@@ -239,7 +240,9 @@
 
 void ExtendedDragSource::OnToplevelWindowDragEvent(ui::LocatedEvent* event) {
   DCHECK(event);
+  aura::Window* target = static_cast<aura::Window*>(event->target());
   pointer_location_ = event->root_location_f();
+  wm::ConvertPointToScreen(target->GetRootWindow(), &pointer_location_);
 
   if (!dragged_window_holder_)
     return;
@@ -278,13 +281,12 @@
   }
 }
 
-void ExtendedDragSource::StartDrag(aura::Window* toplevel,
-                                   const gfx::PointF& pointer_location) {
+void ExtendedDragSource::StartDrag(aura::Window* toplevel) {
   // Ensure |toplevel| window does skip events while it's being dragged.
   event_blocker_ =
       std::make_unique<aura::ScopedWindowEventTargetingBlocker>(toplevel);
 
-  DVLOG(1) << "Starting drag. pointer_loc=" << pointer_location.ToString();
+  DVLOG(1) << "Starting drag. pointer_loc=" << pointer_location_.ToString();
   auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler();
   auto move_source = drag_event_source_ == ui::mojom::DragEventSource::kTouch
                          ? ::wm::WINDOW_MOVE_SOURCE_TOUCH
@@ -305,8 +307,12 @@
 
   // TODO(crbug.com/1167581): Experiment setting |update_gesture_target| back
   // to true when capture is removed from drag and drop.
+
+  gfx::PointF pointer_location_in_parent(pointer_location_);
+  wm::ConvertPointFromScreen(toplevel->parent(), &pointer_location_in_parent);
+
   toplevel_handler->AttemptToStartDrag(
-      toplevel, pointer_location, HTCAPTION, move_source,
+      toplevel, pointer_location_in_parent, HTCAPTION, move_source,
       std::move(end_closure),
       /*update_gesture_target=*/false,
       /*grab_capture =*/
@@ -324,7 +330,6 @@
 
   aura::Window* toplevel = dragged_window_holder_->toplevel_window();
   DCHECK(toplevel);
-
   DCHECK(drag_source_window_);
   toplevel->SetProperty(ash::kIsDraggingTabsKey, true);
   if (drag_source_window_ != toplevel) {
@@ -349,11 +354,14 @@
   // The |toplevel| window for the dragged surface has just been created and
   // it's about to be mapped. Calculate and set its position based on
   // |drag_offset_| and |pointer_location_| before starting the actual drag.
-  auto screen_location = CalculateOrigin(toplevel);
+  auto screen_location =
+      gfx::ToFlooredPoint(pointer_location_ - dragged_window_holder_->offset());
 
   auto toplevel_bounds =
       gfx::Rect({screen_location, toplevel->bounds().size()});
-  toplevel->SetBounds(toplevel_bounds);
+  auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
+      drag_source_window_);
+  toplevel->SetBoundsInScreen(toplevel_bounds, display);
 
   if (WMHelper::GetInstance()->InTabletMode()) {
     // The bounds that is stored in ash::kRestoreBoundsOverrideKey will be used
@@ -366,16 +374,7 @@
   DVLOG(1) << "Dragged window mapped. toplevel=" << toplevel
            << " origin=" << screen_location.ToString();
 
-  gfx::PointF pointer_location(screen_location +
-                               dragged_window_holder_->offset());
-  StartDrag(toplevel, pointer_location);
-}
-
-gfx::Point ExtendedDragSource::CalculateOrigin(aura::Window* target) const {
-  DCHECK(dragged_window_holder_);
-  gfx::Point screen_location = gfx::ToRoundedPoint(pointer_location_);
-  wm::ConvertPointToScreen(target->GetRootWindow(), &screen_location);
-  return screen_location - dragged_window_holder_->offset();
+  StartDrag(toplevel);
 }
 
 void ExtendedDragSource::Cleanup() {
diff --git a/components/exo/extended_drag_source.h b/components/exo/extended_drag_source.h
index e3a1900..f1fa7c1a 100644
--- a/components/exo/extended_drag_source.h
+++ b/components/exo/extended_drag_source.h
@@ -92,11 +92,9 @@
 
   void MaybeLockCursor();
   void UnlockCursor();
-  void StartDrag(aura::Window* toplevel,
-                 const gfx::PointF& pointer_location_in_screen);
+  void StartDrag(aura::Window* toplevel);
   void OnDraggedWindowVisibilityChanging(bool visible);
   void OnDraggedWindowVisibilityChanged(bool visible);
-  gfx::Point CalculateOrigin(aura::Window* target) const;
   void Cleanup();
 
   static ExtendedDragSource* instance_;
@@ -107,6 +105,7 @@
   // tied to the zcr_extended_drag_source_v1 object it's attached to.
   Delegate* const delegate_;
 
+  // The pointer location in screen coordinates.
   gfx::PointF pointer_location_;
   ui::mojom::DragEventSource drag_event_source_;
   bool cursor_locked_ = false;
diff --git a/components/exo/extended_drag_source_unittest.cc b/components/exo/extended_drag_source_unittest.cc
index c0f2c11..2c41254 100644
--- a/components/exo/extended_drag_source_unittest.cc
+++ b/components/exo/extended_drag_source_unittest.cc
@@ -14,6 +14,7 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/wm/toplevel_window_event_handler.h"
+#include "ash/wm/window_state.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/gmock_callback_support.h"
@@ -596,9 +597,9 @@
   auto operation = DragDropOperation::Create(
       &data_exchange_delegate, data_source.get(), shell_surface->root_surface(),
       nullptr, location, ui::mojom::DragEventSource::kMouse);
-
   auto* drag_drop_controller = static_cast<ash::DragDropController*>(
       aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()));
+
   EXPECT_FALSE(shell_surface->IsDragged());
   base::RunLoop loop;
   drag_drop_controller->SetLoopClosureForTesting(
@@ -615,4 +616,68 @@
   EXPECT_FALSE(shell_surface->IsDragged());
 }
 
+TEST_F(ExtendedDragSourceTest, DragToAnotherDisplay) {
+  UpdateDisplay("800x600,800x600");
+
+  // Create and map a toplevel shell surface.
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({32, 32}).BuildShellSurface();
+  auto* surface = shell_surface->root_surface();
+
+  shell_surface->GetWidget()->SetBounds({810, 10, 32, 32});
+
+  auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
+      shell_surface->GetWidget()->GetNativeWindow());
+  EXPECT_EQ(gfx::Rect(800, 0, 800, 600), display.bounds());
+
+  gfx::Rect expected_bounds =
+      shell_surface->GetWidget()->GetWindowBoundsInScreen();
+
+  constexpr int kDragOffset = 10;
+  extended_drag_source_->Drag(surface, gfx::Vector2d(kDragOffset, 0));
+
+  // Start the DND + extended-drag session.
+  // Creates a mouse-pressed event before starting the drag session.
+  ui::test::EventGenerator* generator = GetEventGenerator();
+  generator->MoveMouseTo({810 + kDragOffset, 10});
+  generator->PressLeftButton();
+
+  // Start a DragDropOperation.
+  drag_drop_controller_->set_should_block_during_drag_drop(true);
+  seat_->StartDrag(data_source_.get(), surface, /*icon=*/nullptr,
+                   ui::mojom::DragEventSource::kMouse);
+  // Just move to the middle to avoid snapping.
+  int x_movement = 500;
+  expected_bounds.set_x(310);
+
+  constexpr int kXDragDelta = 20;
+  auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler();
+
+  base::RunLoop loop;
+  drag_drop_controller_->SetLoopClosureForTesting(
+      base::BindLambdaForTesting([&]() {
+        if (x_movement == 500) {
+          auto* window_state = ash::WindowState::Get(
+              shell_surface->GetWidget()->GetNativeWindow());
+          EXPECT_EQ(gfx::PointF(20, 10),
+                    window_state->drag_details()->initial_location_in_parent);
+        }
+        if (x_movement > 0) {
+          x_movement -= kXDragDelta;
+          generator->MoveMouseBy(-kXDragDelta, 0);
+          EXPECT_TRUE(toplevel_handler->is_drag_in_progress());
+        } else {
+          generator->ReleaseLeftButton();
+        }
+      }),
+      loop.QuitClosure());
+  loop.Run();
+  EXPECT_FALSE(toplevel_handler->is_drag_in_progress());
+  EXPECT_EQ(expected_bounds,
+            shell_surface->GetWidget()->GetWindowBoundsInScreen());
+  display = display::Screen::GetScreen()->GetDisplayNearestWindow(
+      shell_surface->GetWidget()->GetNativeWindow());
+  EXPECT_EQ(gfx::Rect(0, 0, 800, 600), display.bounds());
+}
+
 }  // namespace exo
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 1163ba9..e0bcb66 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -486,8 +486,6 @@
   if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
     return;
 
-  seat_->SetLastPointerLocation(event->root_location_f());
-
   Surface* target = GetEffectiveTargetForEvent(event);
   gfx::PointF location_in_target = event->location_f();
   if (target) {
diff --git a/components/exo/seat.cc b/components/exo/seat.cc
index 08354790..156952b 100644
--- a/components/exo/seat.cc
+++ b/components/exo/seat.cc
@@ -31,6 +31,7 @@
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint_serializer.h"
+#include "ui/display/screen.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -130,13 +131,11 @@
                      Surface* icon,
                      ui::mojom::DragEventSource event_source) {
   // DragDropOperation manages its own lifetime.
+  auto cursor_location =
+      gfx::PointF(display::Screen::GetScreen()->GetCursorScreenPoint());
   drag_drop_operation_ =
       DragDropOperation::Create(data_exchange_delegate_.get(), source, origin,
-                                icon, last_pointer_location_, event_source);
-}
-
-void Seat::SetLastPointerLocation(const gfx::PointF& last_pointer_location) {
-  last_pointer_location_ = last_pointer_location;
+                                icon, cursor_location, event_source);
 }
 
 void Seat::AbortPendingDragOperation() {
diff --git a/components/exo/seat.h b/components/exo/seat.h
index 619eda3..82129c4 100644
--- a/components/exo/seat.h
+++ b/components/exo/seat.h
@@ -118,10 +118,6 @@
                  Surface* icon,
                  ui::mojom::DragEventSource event_source);
 
-  // Sets the last location in screen coordinates, irrespective of mouse or
-  // touch.
-  void SetLastPointerLocation(const gfx::PointF& last_pointer_location);
-
   // Abort any drag operations that haven't been started yet.
   void AbortPendingDragOperation();
 
@@ -237,8 +233,6 @@
   // True while Seat is updating clipboard data to selection source.
   bool changing_clipboard_data_to_selection_source_;
 
-  gfx::PointF last_pointer_location_;
-
   bool was_shutdown_ = false;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/components/exo/touch.cc b/components/exo/touch.cc
index 6ad1588..2991da66 100644
--- a/components/exo/touch.cc
+++ b/components/exo/touch.cc
@@ -65,8 +65,6 @@
   if (seat_->was_shutdown())
     return;
 
-  seat_->SetLastPointerLocation(event->root_location_f());
-
   bool send_details = false;
 
   const int touch_pointer_id = event->pointer_details().id;
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index b582df1..a2ffc32 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -723,10 +723,10 @@
     if (!is_keyword_generated && request.consider_for_ntp_most_visited) {
       UpdateSegments(request.url, from_visit_id, last_visit_id, t,
                      request.time);
-
-      // Update the referrer's duration.
-      UpdateVisitDuration(from_visit_id, request.time);
     }
+
+    // Update the referrer's duration.
+    UpdateVisitDuration(from_visit_id, request.time);
   } else {
     // Redirect case. Add the redirect chain.
 
@@ -850,7 +850,7 @@
                          last_visit_id, t, request.time);
         }
 
-        // Update the visit_details for this visit.
+        // Update the referrer's duration.
         UpdateVisitDuration(from_visit_id, request.time);
       }
 
@@ -872,6 +872,10 @@
   // views can keep in sync.
 
   // Add the last visit to the tracker so we can get outgoing transitions.
+  // Keyword-generated visits are artificially generated. They duplicate the
+  // real navigation, and are added to ensure autocompletion in the omnibox
+  // works. As they are artificial they shouldn't be tracked for referral
+  // chains.
   // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
   // navigation anyway, so last_visit_id is always zero for them.  But adding
   // them here confuses main frame history, so we skip them for now.
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index b677f255..028b80d 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -2863,6 +2863,51 @@
   ASSERT_TRUE(backend_->RemoveVisits(visits1));
 }
 
+TEST_F(HistoryBackendTest, UpdateVisitDurationForReferrer) {
+  const ContextID context_id = reinterpret_cast<ContextID>(0x1);
+  base::Time start_ts = base::Time::Now() - base::Days(1);
+  base::Time end_ts = start_ts + base::Seconds(2);
+
+  // Add two visits, the first referring to the second. Adding the second visit
+  // should populate the visit_duration for the first one.
+
+  GURL referrer_url("https://referrer.url");
+  GURL second_url("https://other.url");
+
+  HistoryAddPageArgs referrer_args(referrer_url, start_ts, context_id,
+                                   /*nav_entry_id=*/0, GURL(), RedirectList(),
+                                   ui::PAGE_TRANSITION_TYPED, false,
+                                   SOURCE_BROWSED,
+                                   /*did_replace_entry=*/false,
+                                   /*consider_for_ntp_most_visited=*/false,
+                                   /*floc_allowed=*/false);
+  backend_->AddPage(referrer_args);
+
+  // So far, the visit duration should be empty.
+  URLRow row;
+  URLID referrer_url_id = backend_->db()->GetRowForURL(referrer_url, &row);
+  VisitVector visits;
+  ASSERT_TRUE(backend_->db()->GetVisitsForURL(referrer_url_id, &visits));
+  ASSERT_EQ(1U, visits.size());
+  ASSERT_EQ(0, visits[0].visit_duration.ToInternalValue());
+
+  HistoryAddPageArgs second_args(second_url, end_ts, context_id,
+                                 /*nav_entry_id=*/0, referrer_url,
+                                 RedirectList(), ui::PAGE_TRANSITION_TYPED,
+                                 false, SOURCE_BROWSED,
+                                 /*did_replace_entry=*/false,
+                                 /*consider_for_ntp_most_visited=*/false,
+                                 /*floc_allowed=*/false);
+  backend_->AddPage(second_args);
+
+  // Adding the second visit should have populated the visit duration for the
+  // first one.
+  ASSERT_TRUE(backend_->db()->GetVisitsForURL(referrer_url_id, &visits));
+  base::TimeDelta expected_duration = end_ts - start_ts;
+  EXPECT_EQ(expected_duration.ToInternalValue(),
+            visits[0].visit_duration.ToInternalValue());
+}
+
 // Test for migration of adding visit_duration column.
 TEST_F(HistoryBackendTest, MigrationVisitDuration) {
   ASSERT_TRUE(backend_.get());
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 40a675e..214632f 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -954,13 +954,19 @@
         const TemplateURL* template_url =
             i->GetTemplateURL(template_url_service_, false);
         if (template_url) {
-          // For extension keywords, just make the description the extension
-          // name -- don't assume that the normal search keyword description is
-          // applicable.
-          i->description = template_url->AdjustedShortNameForLocaleDirection();
-          if (template_url->type() != TemplateURL::OMNIBOX_API_EXTENSION) {
-            i->description = l10n_util::GetStringFUTF16(
-                IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, i->description);
+          if (OmniboxFieldTrial::IsSiteSearchStarterPackEnabled() &&
+              template_url->starter_pack_id() > 0) {
+            i->description = base::UTF8ToUTF16(template_url->url());
+          } else {
+            // For extension keywords, just make the description the extension
+            // name -- don't assume that the normal search keyword description
+            // is applicable.
+            i->description =
+                template_url->AdjustedShortNameForLocaleDirection();
+            if (template_url->type() != TemplateURL::OMNIBOX_API_EXTENSION) {
+              i->description = l10n_util::GetStringFUTF16(
+                  IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, i->description);
+            }
           }
           i->description_class.push_back(
               ACMatchClassification(0, ACMatchClassification::DIM));
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index a6f9e1c..076dea7 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -281,7 +281,8 @@
   void UpdateHeaderInfoFromZeroSuggestProvider(AutocompleteResult* result);
 
   // For each group of contiguous matches from the same TemplateURL, show the
-  // provider name as a description on the first match in the group.
+  // provider name as a description on the first match in the group. Starter
+  // Pack matches show their URLs as descriptions instead of the provider name.
   void UpdateKeywordDescriptions(AutocompleteResult* result);
 
   // For each AutocompleteMatch in |result|, updates the assisted query stats
diff --git a/components/omnibox/browser/builtin_provider.cc b/components/omnibox/browser/builtin_provider.cc
index fbb905a9..9ffe1d29 100644
--- a/components/omnibox/browser/builtin_provider.cc
+++ b/components/omnibox/browser/builtin_provider.cc
@@ -27,6 +27,7 @@
 #include "url/url_constants.h"
 
 const int BuiltinProvider::kRelevance = 860;
+const int BuiltinProvider::kStarterPackRelevance = 1200;
 
 BuiltinProvider::BuiltinProvider(AutocompleteProviderClient* client)
     : AutocompleteProvider(AutocompleteProvider::TYPE_BUILTIN),
@@ -44,117 +45,129 @@
   }
 
   const std::u16string text = input.text();
-  if (OmniboxFieldTrial::IsSiteSearchStarterPackEnabled()) {
-    // When the user's input begins with '@', we want to prioritize providing
-    // suggestions for all active starter pack search engines.
-    bool starts_with_starter_pack_symbol =
-        base::StartsWith(text, u"@", base::CompareCase::INSENSITIVE_ASCII);
+  DoStarterPackAutocompletion(text);
 
-    if (starts_with_starter_pack_symbol) {
-      TemplateURLService::TURLsAndMeaningfulLengths matches;
-      template_url_service_->AddMatchingKeywords(text, false, &matches);
-      for (auto match : matches) {
-        if (match.first->starter_pack_id() > 0 &&
-            match.first->is_active() == TemplateURLData::ActiveStatus::kTrue) {
-          AddStarterPackMatch(*match.first);
-        }
+  if (input.type() != metrics::OmniboxInputType::QUERY) {
+    DoBuiltinAutocompletion(text);
+  }
+
+  UpdateRelevanceScores(input);
+}
+
+BuiltinProvider::~BuiltinProvider() = default;
+
+void BuiltinProvider::DoStarterPackAutocompletion(const std::u16string& text) {
+  if (!OmniboxFieldTrial::IsSiteSearchStarterPackEnabled()) {
+    return;
+  }
+
+  // When the user's input begins with '@', we want to prioritize providing
+  // suggestions for all active starter pack search engines.
+  bool starts_with_starter_pack_symbol =
+      base::StartsWith(text, u"@", base::CompareCase::INSENSITIVE_ASCII);
+
+  if (starts_with_starter_pack_symbol) {
+    TemplateURLService::TURLsAndMeaningfulLengths matches;
+    template_url_service_->AddMatchingKeywords(text, false, &matches);
+    for (auto match : matches) {
+      if (match.first->starter_pack_id() > 0 &&
+          match.first->is_active() == TemplateURLData::ActiveStatus::kTrue) {
+        AddStarterPackMatch(*match.first);
       }
     }
+  }
+}
+
+void BuiltinProvider::DoBuiltinAutocompletion(const std::u16string& text) {
+  const size_t kAboutSchemeLength = strlen(url::kAboutScheme);
+  const std::u16string kAbout =
+      base::StrCat({url::kAboutScheme16, url::kStandardSchemeSeparator16});
+  const std::u16string embedderAbout = base::StrCat(
+      {base::UTF8ToUTF16(client_->GetEmbedderRepresentationOfAboutScheme()),
+       url::kStandardSchemeSeparator16});
+
+  const int kUrl = ACMatchClassification::URL;
+  const int kMatch = kUrl | ACMatchClassification::MATCH;
+
+  bool starting_about = base::StartsWith(embedderAbout, text,
+                                         base::CompareCase::INSENSITIVE_ASCII);
+  if (starting_about ||
+      base::StartsWith(kAbout, text, base::CompareCase::INSENSITIVE_ASCII)) {
+    // Highlight the input portion matching |embedderAbout|; or if the user
+    // has input "about:" (with optional slashes), highlight the whole
+    // |embedderAbout|.
+    TermMatches style_matches;
+    if (starting_about)
+      style_matches.emplace_back(0, 0, text.length());
+    else if (text.length() > kAboutSchemeLength)
+      style_matches.emplace_back(0, 0, embedderAbout.length());
+    ACMatchClassifications styles =
+        ClassifyTermMatches(style_matches, std::string::npos, kMatch, kUrl);
+    // Include some common builtin URLs as the user types the scheme.
+    for (std::u16string url : client_->GetBuiltinsToProvideAsUserTypes())
+      AddBuiltinMatch(url, std::u16string(), styles);
+
   } else {
-    if (input.type() == metrics::OmniboxInputType::QUERY)
-      return;
+    // Match input about: or |embedderAbout| URL input against builtin URLs.
+    GURL url = url_formatter::FixupURL(base::UTF16ToUTF8(text), std::string());
+    const bool text_ends_with_slash =
+        base::EndsWith(text, u"/", base::CompareCase::SENSITIVE);
+    // BuiltinProvider doesn't know how to suggest valid ?query or #fragment
+    // extensions to builtin URLs.
+    if (url.SchemeIs(client_->GetEmbedderRepresentationOfAboutScheme()) &&
+        url.has_host() && !url.has_query() && !url.has_ref()) {
+      // Suggest about:blank for substrings, taking URL fixup into account.
+      // Chrome does not support trailing slashes or paths for about:blank.
+      const std::u16string blank_host = u"blank";
+      const std::u16string host = base::UTF8ToUTF16(url.host());
+      if (base::StartsWith(text, url::kAboutScheme16,
+                           base::CompareCase::INSENSITIVE_ASCII) &&
+          base::StartsWith(blank_host, host,
+                           base::CompareCase::INSENSITIVE_ASCII) &&
+          (url.path().length() <= 1) && !text_ends_with_slash) {
+        std::u16string match(url::kAboutBlankURL16);
+        const size_t corrected_length = kAboutSchemeLength + 1 + host.length();
+        TermMatches style_matches = {{0, 0, corrected_length}};
+        ACMatchClassifications styles =
+            ClassifyTermMatches(style_matches, match.length(), kMatch, kUrl);
+        AddBuiltinMatch(match, match.substr(corrected_length), styles);
+      }
 
-    const size_t kAboutSchemeLength = strlen(url::kAboutScheme);
-    const std::u16string kAbout =
-        base::StrCat({url::kAboutScheme16, url::kStandardSchemeSeparator16});
-    const std::u16string embedderAbout = base::StrCat(
-        {base::UTF8ToUTF16(client_->GetEmbedderRepresentationOfAboutScheme()),
-         url::kStandardSchemeSeparator16});
-
-    const int kUrl = ACMatchClassification::URL;
-    const int kMatch = kUrl | ACMatchClassification::MATCH;
-
-    bool starting_about = base::StartsWith(
-        embedderAbout, text, base::CompareCase::INSENSITIVE_ASCII);
-    if (starting_about ||
-        base::StartsWith(kAbout, text, base::CompareCase::INSENSITIVE_ASCII)) {
-      // Highlight the input portion matching |embedderAbout|; or if the user
-      // has input "about:" (with optional slashes), highlight the whole
-      // |embedderAbout|.
-      TermMatches style_matches;
-      if (starting_about)
-        style_matches.emplace_back(0, 0, text.length());
-      else if (text.length() > kAboutSchemeLength)
-        style_matches.emplace_back(0, 0, embedderAbout.length());
-      ACMatchClassifications styles =
-          ClassifyTermMatches(style_matches, std::string::npos, kMatch, kUrl);
-      // Include some common builtin URLs as the user types the scheme.
-      for (std::u16string url : client_->GetBuiltinsToProvideAsUserTypes())
-        AddMatch(url, std::u16string(), styles);
-
-    } else {
-      // Match input about: or |embedderAbout| URL input against builtin URLs.
-      GURL url =
-          url_formatter::FixupURL(base::UTF16ToUTF8(text), std::string());
-      const bool text_ends_with_slash =
-          base::EndsWith(text, u"/", base::CompareCase::SENSITIVE);
-      // BuiltinProvider doesn't know how to suggest valid ?query or #fragment
-      // extensions to builtin URLs.
-      if (url.SchemeIs(client_->GetEmbedderRepresentationOfAboutScheme()) &&
-          url.has_host() && !url.has_query() && !url.has_ref()) {
-        // Suggest about:blank for substrings, taking URL fixup into account.
-        // Chrome does not support trailing slashes or paths for about:blank.
-        const std::u16string blank_host = u"blank";
-        const std::u16string host = base::UTF8ToUTF16(url.host());
-        if (base::StartsWith(text, url::kAboutScheme16,
-                             base::CompareCase::INSENSITIVE_ASCII) &&
-            base::StartsWith(blank_host, host,
-                             base::CompareCase::INSENSITIVE_ASCII) &&
-            (url.path().length() <= 1) && !text_ends_with_slash) {
-          std::u16string match(url::kAboutBlankURL16);
-          const size_t corrected_length =
-              kAboutSchemeLength + 1 + host.length();
-          TermMatches style_matches = {{0, 0, corrected_length}};
-          ACMatchClassifications styles =
-              ClassifyTermMatches(style_matches, match.length(), kMatch, kUrl);
-          AddMatch(match, match.substr(corrected_length), styles);
-        }
-
-        // Include the path for sub-pages (e.g. "chrome://settings/browser").
-        std::u16string host_and_path =
-            base::UTF8ToUTF16(url.host() + url.path());
-        base::TrimString(host_and_path, u"/", &host_and_path);
-        size_t match_length = embedderAbout.length() + host_and_path.length();
-        for (Builtins::const_iterator i(builtins_.begin());
-             (i != builtins_.end()) &&
-             (matches_.size() < provider_max_matches_);
-             ++i) {
-          if (base::StartsWith(*i, host_and_path,
-                               base::CompareCase::INSENSITIVE_ASCII)) {
-            std::u16string match_string = embedderAbout + *i;
-            TermMatches style_matches = {{0, 0, match_length}};
-            ACMatchClassifications styles = ClassifyTermMatches(
-                style_matches, match_string.length(), kMatch, kUrl);
-            // FixupURL() may have dropped a trailing slash on the user's input.
-            // Ensure that in that case, we don't inline autocomplete unless the
-            // autocompletion restores the slash.  This prevents us from e.g.
-            // trying to add a 'y' to an input like "chrome://histor/".
-            std::u16string inline_autocompletion(
-                match_string.substr(match_length));
-            if (text_ends_with_slash &&
-                !base::StartsWith(match_string.substr(match_length), u"/",
-                                  base::CompareCase::INSENSITIVE_ASCII))
-              inline_autocompletion = std::u16string();
-            AddMatch(match_string, inline_autocompletion, styles);
-          }
+      // Include the path for sub-pages (e.g. "chrome://settings/browser").
+      std::u16string host_and_path = base::UTF8ToUTF16(url.host() + url.path());
+      base::TrimString(host_and_path, u"/", &host_and_path);
+      size_t match_length = embedderAbout.length() + host_and_path.length();
+      for (Builtins::const_iterator i(builtins_.begin());
+           (i != builtins_.end()) && (matches_.size() < provider_max_matches_);
+           ++i) {
+        if (base::StartsWith(*i, host_and_path,
+                             base::CompareCase::INSENSITIVE_ASCII)) {
+          std::u16string match_string = embedderAbout + *i;
+          TermMatches style_matches = {{0, 0, match_length}};
+          ACMatchClassifications styles = ClassifyTermMatches(
+              style_matches, match_string.length(), kMatch, kUrl);
+          // FixupURL() may have dropped a trailing slash on the user's input.
+          // Ensure that in that case, we don't inline autocomplete unless the
+          // autocompletion restores the slash.  This prevents us from e.g.
+          // trying to add a 'y' to an input like "chrome://histor/".
+          std::u16string inline_autocompletion(
+              match_string.substr(match_length));
+          if (text_ends_with_slash &&
+              !base::StartsWith(match_string.substr(match_length), u"/",
+                                base::CompareCase::INSENSITIVE_ASCII))
+            inline_autocompletion = std::u16string();
+          AddBuiltinMatch(match_string, inline_autocompletion, styles);
         }
       }
     }
   }
+}
 
+void BuiltinProvider::UpdateRelevanceScores(const AutocompleteInput& input) {
   // Provide a relevance score for each match.
-  for (size_t i = 0; i < matches_.size(); ++i)
-    matches_[i].relevance = kRelevance + matches_.size() - (i + 1);
+  for (size_t i = 0; i < matches_.size(); ++i) {
+    matches_[i].relevance += matches_.size() - (i + 1);
+  }
 
   // If allowing completions is okay and there's a match that's considered
   // appropriate to be the default match, mark it as such and give it a high
@@ -174,11 +187,9 @@
   }
 }
 
-BuiltinProvider::~BuiltinProvider() {}
-
-void BuiltinProvider::AddMatch(const std::u16string& match_string,
-                               const std::u16string& inline_completion,
-                               const ACMatchClassifications& styles) {
+void BuiltinProvider::AddBuiltinMatch(const std::u16string& match_string,
+                                      const std::u16string& inline_completion,
+                                      const ACMatchClassifications& styles) {
   AutocompleteMatch match(this, kRelevance, false,
                           AutocompleteMatchType::NAVSUGGEST);
   match.fill_into_edit = match_string;
@@ -190,14 +201,13 @@
 }
 
 void BuiltinProvider::AddStarterPackMatch(const TemplateURL& template_url) {
-  AutocompleteMatch match(this, kRelevance, false,
+  AutocompleteMatch match(this, kStarterPackRelevance, false,
                           AutocompleteMatchType::SEARCH_OTHER_ENGINE);
 
   match.fill_into_edit = template_url.keyword();
-  match.additional_text = base::UTF8ToUTF16(template_url.url());
   match.destination_url = GURL(template_url.url());
   match.contents = template_url.short_name();
-  match.contents_class.emplace_back(0, ACMatchClassification::MATCH);
+  match.contents_class.emplace_back(0, ACMatchClassification::NONE);
   match.transition = ui::PAGE_TRANSITION_GENERATED;
   match.keyword = template_url.keyword();
   match.from_keyword = true;
diff --git a/components/omnibox/browser/builtin_provider.h b/components/omnibox/browser/builtin_provider.h
index 9a9ecb559..ae4540b8 100644
--- a/components/omnibox/browser/builtin_provider.h
+++ b/components/omnibox/browser/builtin_provider.h
@@ -32,13 +32,28 @@
   typedef std::vector<std::u16string> Builtins;
 
   static const int kRelevance;
+  static const int kStarterPackRelevance;
 
-  void AddMatch(const std::u16string& match_string,
-                const std::u16string& inline_completion,
-                const ACMatchClassifications& styles);
+  // Populates `matches_` with matching starter pack keywords such as @history,
+  // and @bookmarks
+  void DoStarterPackAutocompletion(const std::u16string& text);
 
-  // Constructs an AutocompleteMatch for starter pack (@bookmarks, @history,
-  // etc.) suggestions and adds it to `matches_`.
+  // Populates `matches_` with matching built-in URLs such as about:settings and
+  // chrome://version.
+  void DoBuiltinAutocompletion(const std::u16string& text);
+
+  // De-deupes the relevance scores, determines if a match can be default, and
+  // if a match can be default, updates its relevance score accordingly.
+  void UpdateRelevanceScores(const AutocompleteInput& input);
+
+  // Constructs an AutocompleteMatch for built-in URLs such as
+  // chrome://settings, etc. and adds it to `matches_`.
+  void AddBuiltinMatch(const std::u16string& match_string,
+                       const std::u16string& inline_completion,
+                       const ACMatchClassifications& styles);
+
+  // Constructs an AutocompleteMatch for starter pack suggestions such as
+  // @bookmarks, @history, etc. and adds it to `matches_`.
   void AddStarterPackMatch(const TemplateURL& template_url);
 
   // Returns true if |matches_| contains a match that should be allowed to be
diff --git a/components/safe_browsing/content/browser/triggers/trigger_throttler.cc b/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
index b203cee2..8f3553e 100644
--- a/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
+++ b/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
@@ -18,7 +18,6 @@
 const size_t kAdSamplerTriggerDefaultQuota = 10;
 const size_t kSuspiciousSiteTriggerDefaultQuota = 5;
 const char kSuspiciousSiteTriggerQuotaParam[] = "suspicious_site_trigger_quota";
-const char kTriggerTypeAndQuotaParam[] = "trigger_type_and_quota_csv";
 
 namespace {
 const size_t kUnlimitedTriggerQuota = std::numeric_limits<size_t>::max();
@@ -49,44 +48,6 @@
     trigger_type_and_quota_list->push_back(
         std::make_pair(TriggerType::SUSPICIOUS_SITE, suspicious_site_quota));
   }
-
-  // If the feature is disabled we just use the default list. Otherwise the list
-  // from the Finch param will be the one used.
-  if (!base::FeatureList::IsEnabled(kTriggerThrottlerDailyQuotaFeature)) {
-    return;
-  }
-
-  const std::string& trigger_and_quota_csv_param =
-      base::GetFieldTrialParamValueByFeature(kTriggerThrottlerDailyQuotaFeature,
-                                             kTriggerTypeAndQuotaParam);
-  if (trigger_and_quota_csv_param.empty()) {
-    return;
-  }
-
-  std::vector<std::string> split =
-      base::SplitString(trigger_and_quota_csv_param, ",", base::TRIM_WHITESPACE,
-                        base::SPLIT_WANT_NONEMPTY);
-  // If we don't have the right number of pairs in the csv then don't bother
-  // parsing further.
-  if (split.size() % 2 != 0) {
-    return;
-  }
-  for (size_t i = 0; i < split.size(); i += 2) {
-    // Make sure both the trigger type and quota are integers. Skip them if not.
-    int trigger_type_int = -1;
-    int quota_int = -1;
-    if (!base::StringToInt(split[i], &trigger_type_int) ||
-        !base::StringToInt(split[i + 1], &quota_int)) {
-      continue;
-    }
-    trigger_type_and_quota_list->push_back(
-        std::make_pair(static_cast<TriggerType>(trigger_type_int), quota_int));
-  }
-
-  std::sort(trigger_type_and_quota_list->begin(),
-            trigger_type_and_quota_list->end(),
-            [](const TriggerTypeAndQuotaItem& a,
-               const TriggerTypeAndQuotaItem& b) { return a.first < b.first; });
 }
 
 // Looks in |trigger_quota_list| for |trigger_type|. If found, sets |out_quota|
@@ -241,7 +202,7 @@
 
 size_t TriggerThrottler::GetDailyQuotaForTrigger(
     const TriggerType trigger_type) const {
-  size_t quota_from_finch = 0;
+  size_t quota = 0;
   switch (trigger_type) {
     case TriggerType::SECURITY_INTERSTITIAL:
     case TriggerType::GAIA_PASSWORD_REUSE:
@@ -253,18 +214,18 @@
       return 0;
 
     case TriggerType::AD_SAMPLE:
-      // Ad Samples have a non-zero default quota, but it can be overwritten
-      // through Finch.
+      // Check for non-default quota (needed for unit tests).
       if (TryFindQuotaForTrigger(trigger_type, trigger_type_and_quota_list_,
-                                 &quota_from_finch)) {
-        return quota_from_finch;
+                                 &quota)) {
+        return quota;
       }
       return kAdSamplerTriggerDefaultQuota;
+
     case TriggerType::SUSPICIOUS_SITE:
       // Suspicious Sites are disabled unless they are configured through Finch.
       if (TryFindQuotaForTrigger(trigger_type, trigger_type_and_quota_list_,
-                                 &quota_from_finch)) {
-        return quota_from_finch;
+                                 &quota)) {
+        return quota;
       }
       break;
   }
diff --git a/components/safe_browsing/content/browser/triggers/trigger_throttler.h b/components/safe_browsing/content/browser/triggers/trigger_throttler.h
index 33fa604..8ee231b 100644
--- a/components/safe_browsing/content/browser/triggers/trigger_throttler.h
+++ b/components/safe_browsing/content/browser/triggers/trigger_throttler.h
@@ -27,14 +27,6 @@
 // trigger.
 extern const char kSuspiciousSiteTriggerQuotaParam[];
 
-// Param name of the finch param containing the comma-separated list of trigger
-// types and daily quotas.
-// TODO(crbug.com/744869): This param should be deprecated after ad sampler
-// launch in favour of having a unique quota feature and param per trigger.
-// Having a single shared feature makes it impossible to run multiple trigger
-// trials simultaneously.
-extern const char kTriggerTypeAndQuotaParam[];
-
 enum class TriggerType {
   SECURITY_INTERSTITIAL = 1,
   AD_SAMPLE = 2,
diff --git a/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc b/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
index b760b99..56c5700 100644
--- a/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
+++ b/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
@@ -229,11 +229,6 @@
                                     const base::Feature** out_feature,
                                     std::string* out_param) {
     switch (trigger_type) {
-      case TriggerType::AD_SAMPLE:
-        *out_feature = &safe_browsing::kTriggerThrottlerDailyQuotaFeature;
-        *out_param = safe_browsing::kTriggerTypeAndQuotaParam;
-        break;
-
       case TriggerType::SUSPICIOUS_SITE:
         *out_feature = &safe_browsing::kSuspiciousSiteTriggerQuotaFeature;
         *out_param = safe_browsing::kSuspiciousSiteTriggerQuotaParam;
@@ -254,42 +249,12 @@
   }
 };
 
-TEST_F(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  SetupQuotaParams(TriggerType::AD_SAMPLE, "Group_ConfigureQuotaViaFinch", 3,
-                   &scoped_feature_list);
-  // Make sure that setting the quota param via Finch params works as expected.
-
-  // The throttler has been configured (above) to allow ad samples to fire three
-  // times per day.
-  TriggerThrottler throttler(nullptr);
-
-  // First three triggers should work
-  EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
-  throttler.TriggerFired(TriggerType::AD_SAMPLE);
-  EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
-  throttler.TriggerFired(TriggerType::AD_SAMPLE);
-  EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
-  throttler.TriggerFired(TriggerType::AD_SAMPLE);
-
-  // Fourth attempt will fail since we're out of quota.
-  EXPECT_FALSE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
-}
-
 TEST_F(TriggerThrottlerTestFinch, AdSamplerDefaultQuota) {
-  // Make sure that the ad sampler gets its own default quota when no finch
-  // config exists, but the quota can be overwritten through Finch.
+  // Make sure that the ad sampler gets its own default quota.
   TriggerThrottler throttler_default(nullptr);
   EXPECT_EQ(kAdSamplerTriggerDefaultQuota,
             GetDailyQuotaForTrigger(throttler_default, TriggerType::AD_SAMPLE));
   EXPECT_TRUE(throttler_default.TriggerCanFire(TriggerType::AD_SAMPLE));
-
-  base::test::ScopedFeatureList scoped_feature_list;
-  SetupQuotaParams(TriggerType::AD_SAMPLE, "Group_AdSamplerDefaultQuota", 4,
-                   &scoped_feature_list);
-  TriggerThrottler throttler_finch(nullptr);
-  EXPECT_EQ(4u,
-            GetDailyQuotaForTrigger(throttler_finch, TriggerType::AD_SAMPLE));
 }
 
 TEST_F(TriggerThrottlerTestFinch, SuspiciousSiteTriggerDefaultQuota) {
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index 26ef957..92d7959 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -132,10 +132,6 @@
 const base::Feature kThreatDomDetailsTagAndAttributeFeature{
     "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kTriggerThrottlerDailyQuotaFeature{
-    "SafeBrowsingTriggerThrottlerDailyQuota",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kUseNewDownloadWarnings{"UseNewDownloadWarnings",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -174,7 +170,6 @@
     {&kSendSampledPingsForProtegoAllowlistDomains, true},
     {&kSuspiciousSiteTriggerQuotaFeature, true},
     {&kThreatDomDetailsTagAndAttributeFeature, false},
-    {&kTriggerThrottlerDailyQuotaFeature, false},
 };
 
 // Adds the name and the enabled/disabled status of a given feature.
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h
index 50cf455..a394be6 100644
--- a/components/safe_browsing/core/common/features.h
+++ b/components/safe_browsing/core/common/features.h
@@ -134,16 +134,6 @@
 // be lower case.
 extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
 
-// Controls the daily quota for data collection triggers. It's a single param
-// containing a comma-separated list of pairs. The format of the param is
-// "T1,Q1,T2,Q2,...Tn,Qn", where Tx is a TriggerType and Qx is how many reports
-// that trigger is allowed to send per day.
-// TODO(crbug.com/744869): This param should be deprecated after ad sampler
-// launch in favour of having a unique quota feature and param per trigger.
-// Having a single shared feature makes it impossible to run multiple trigger
-// trials simultaneously.
-extern const base::Feature kTriggerThrottlerDailyQuotaFeature;
-
 // Controls whether Chrome uses new download warning UX.
 extern const base::Feature kUseNewDownloadWarnings;
 
diff --git a/components/search_engines/template_url_parser.cc b/components/search_engines/template_url_parser.cc
index 8d38add1..4ac09746 100644
--- a/components/search_engines/template_url_parser.cc
+++ b/components/search_engines/template_url_parser.cc
@@ -232,7 +232,7 @@
         data_decoder::GetXmlElementAttribute(*url_value, kURLTemplateAttribute);
     std::string type =
         data_decoder::GetXmlElementAttribute(*url_value, kURLTypeAttribute);
-    bool is_post = base::LowerCaseEqualsASCII(
+    bool is_post = base::EqualsCaseInsensitiveASCII(
         data_decoder::GetXmlElementAttribute(*url_value, kParamMethodAttribute),
         "post");
     bool is_html_url = (type == kHTMLType);
diff --git a/components/signin/internal/identity_manager/account_tracker_service.cc b/components/signin/internal/identity_manager/account_tracker_service.cc
index 49a1dba..01b00a21 100644
--- a/components/signin/internal/identity_manager/account_tracker_service.cc
+++ b/components/signin/internal/identity_manager/account_tracker_service.cc
@@ -26,6 +26,7 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -179,8 +180,10 @@
 // static
 void AccountTrackerService::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterListPref(prefs::kAccountInfo);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   registry->RegisterIntegerPref(prefs::kAccountIdMigrationState,
                                 AccountTrackerService::MIGRATION_NOT_STARTED);
+#endif
 }
 
 void AccountTrackerService::Initialize(PrefService* pref_service,
@@ -250,7 +253,11 @@
 }
 
 void AccountTrackerService::SetMigrationDone() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   SetMigrationState(MIGRATION_DONE);
+#else
+  NOTREACHED() << "Migration cannot be in progress on this platform";
+#endif
 }
 
 void AccountTrackerService::NotifyAccountUpdated(
@@ -393,6 +400,7 @@
   Initialize(prefs, base::FilePath());
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AccountTrackerService::MigrateToGaiaId() {
   DCHECK_EQ(GetMigrationState(), MIGRATION_IN_PROGRESS);
 
@@ -437,6 +445,7 @@
     accounts_.erase(account_id);
   }
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 bool AccountTrackerService::AreAllAccountsMigrated() const {
   for (const auto& pair : accounts_) {
@@ -447,6 +456,7 @@
   return true;
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 AccountTrackerService::AccountIdMigrationState
 AccountTrackerService::ComputeNewMigrationState() const {
   if (accounts_.empty()) {
@@ -456,14 +466,12 @@
     return MIGRATION_DONE;
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Migration on ChromeOS is not started by default due to the following risks:
   // * a lot more data than on desktop is keyed by the account id
   // * bugs in the migration flow can lead to user not being able to sign in
   //   to their device which makes the device unusable.
   if (!base::FeatureList::IsEnabled(switches::kAccountIdMigration))
     return MIGRATION_NOT_STARTED;
-#endif
 
   bool migration_required = false;
   for (const auto& pair : accounts_) {
@@ -483,12 +491,18 @@
   DCHECK(state != MIGRATION_DONE || AreAllAccountsMigrated());
   pref_service_->SetInteger(prefs::kAccountIdMigrationState, state);
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // static
 AccountTrackerService::AccountIdMigrationState
 AccountTrackerService::GetMigrationState(const PrefService* pref_service) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return static_cast<AccountTrackerService::AccountIdMigrationState>(
       pref_service->GetInteger(prefs::kAccountIdMigrationState));
+#else
+  // Migration is now done on all other platforms
+  return AccountIdMigrationState::MIGRATION_DONE;
+#endif
 }
 
 base::FilePath AccountTrackerService::GetImagePathFor(
@@ -675,6 +689,7 @@
     RemoveAccountImageFromDisk(account_id);
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (GetMigrationState() != MIGRATION_DONE) {
     const AccountIdMigrationState new_state = ComputeNewMigrationState();
     SetMigrationState(new_state);
@@ -683,8 +698,11 @@
       MigrateToGaiaId();
     }
   }
-
   DCHECK(GetMigrationState() != MIGRATION_DONE || AreAllAccountsMigrated());
+#else
+  DCHECK(AreAllAccountsMigrated());
+#endif
+
   UMA_HISTOGRAM_ENUMERATION("Signin.AccountTracker.GaiaIdMigrationState",
                             GetMigrationState(), NUM_MIGRATION_STATES);
 
diff --git a/components/signin/internal/identity_manager/account_tracker_service.h b/components/signin/internal/identity_manager/account_tracker_service.h
index bf4650ca..0063ce8 100644
--- a/components/signin/internal/identity_manager/account_tracker_service.h
+++ b/components/signin/internal/identity_manager/account_tracker_service.h
@@ -208,14 +208,17 @@
                              bool success);
   void RemoveAccountImageFromDisk(const CoreAccountId& account_id);
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Migrate accounts to be keyed by gaia id instead of normalized email.
   // Requires that the migration state is set to MIGRATION_IN_PROGRESS.
   void MigrateToGaiaId();
+#endif
 
   // Returns whether the accounts are all keyed by gaia id. This should
   // be the case when the migration state is set to MIGRATION_DONE.
   bool AreAllAccountsMigrated() const;
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Computes the new migration state. The state is saved to preference
   // before performing the migration in order to support resuming the
   // migration if necessary during the next load.
@@ -223,6 +226,7 @@
 
   // Updates the migration state in the preferences.
   void SetMigrationState(AccountIdMigrationState state);
+#endif
 
   // Returns the saved migration state in the preferences.
   static AccountIdMigrationState GetMigrationState(
diff --git a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
index d7058bc..eaa1e2b9 100644
--- a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
+++ b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
@@ -374,8 +374,10 @@
     DCHECK(!account_tracker_);
     DCHECK(!account_fetcher_);
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     pref_service_.SetInteger(prefs::kAccountIdMigrationState,
                              AccountTrackerService::MIGRATION_NOT_STARTED);
+#endif
 
     account_tracker_ = std::make_unique<AccountTrackerService>();
     account_fetcher_ = std::make_unique<AccountFetcherService>();
@@ -1202,6 +1204,7 @@
   EXPECT_FALSE(account_fetcher()->AreAllAccountCapabilitiesFetched());
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(AccountTrackerServiceTest, LegacyDottedAccountIds) {
   // Force legacy of non-normalized email as account_id.
   base::AutoReset<bool> force_account_id_to_email_for_legacy_test(
@@ -1238,10 +1241,8 @@
 }
 
 TEST_F(AccountTrackerServiceTest, MigrateAccountIdToGaiaId) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(switches::kAccountIdMigration);
-#endif
 
   const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
   const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
@@ -1287,10 +1288,8 @@
 }
 
 TEST_F(AccountTrackerServiceTest, CanNotMigrateAccountIdToGaiaId) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(switches::kAccountIdMigration);
-#endif
 
   const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
   const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
@@ -1335,10 +1334,8 @@
 }
 
 TEST_F(AccountTrackerServiceTest, GaiaIdMigrationCrashInTheMiddle) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(switches::kAccountIdMigration);
-#endif
 
   const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
   const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
@@ -1410,6 +1407,7 @@
   accounts = account_tracker()->GetAccounts();
   EXPECT_EQ(2u, accounts.size());
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(AccountTrackerServiceTest, ChildAccountBasic) {
   SimulateTokenAvailable(kAccountKeyChild);
@@ -1676,7 +1674,6 @@
 
   SimulateTokenRevoked(kAccountKeyAdvancedProtection);
 }
-
 #endif
 
 TEST_F(AccountTrackerServiceTest, CountOfLoadedAccounts_NoAccount) {
@@ -1689,6 +1686,40 @@
 }
 
 TEST_F(AccountTrackerServiceTest, CountOfLoadedAccounts_TwoAccounts) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  prefs()->SetInteger(prefs::kAccountIdMigrationState,
+                      AccountTrackerService::MIGRATION_DONE);
+#endif
+
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
+  const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
+
+  ListPrefUpdate update(prefs(), prefs::kAccountInfo);
+
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetStringKey("account_id", gaia_alpha);
+  dict.SetStringKey("email", email_alpha);
+  dict.SetStringKey("gaia", gaia_alpha);
+  update->Append(std::move(dict));
+
+  dict = base::Value(base::Value::Type::DICTIONARY);
+  dict.SetStringKey("account_id", gaia_beta);
+  dict.SetStringKey("email", email_beta);
+  dict.SetStringKey("gaia", gaia_beta);
+  update->Append(std::move(dict));
+
+  base::HistogramTester tester;
+  ResetAccountTracker();
+
+  EXPECT_THAT(
+      tester.GetAllSamples("Signin.AccountTracker.CountOfLoadedAccounts"),
+      testing::ElementsAre(base::Bucket(2, 1)));
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(AccountTrackerServiceTest, Migrate_CountOfLoadedAccounts_TwoAccounts) {
   const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
   const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
   const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
@@ -1716,7 +1747,8 @@
       testing::ElementsAre(base::Bucket(2, 1)));
 }
 
-TEST_F(AccountTrackerServiceTest, CountOfLoadedAccounts_TwoAccountsOneInvalid) {
+TEST_F(AccountTrackerServiceTest,
+       Migrate_CountOfLoadedAccounts_TwoAccountsOneInvalid) {
   const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
   const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
   const std::string email_foobar = AccountKeyToEmail(kAccountKeyFooDotBar);
@@ -1745,6 +1777,7 @@
       tester.GetAllSamples("Signin.AccountTracker.CountOfLoadedAccounts"),
       testing::ElementsAre(base::Bucket(1, 1)));
 }
+#endif
 
 TEST_F(AccountTrackerServiceTest, CapabilityPrefNameMigration) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 8d4ae409..edf02a38 100644
--- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -1035,6 +1035,7 @@
   EXPECT_EQ(1, access_token_failure_count_);
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, CanonicalizeAccountId) {
   pref_service_.SetInteger(prefs::kAccountIdMigrationState,
                            AccountTrackerService::MIGRATION_NOT_STARTED);
@@ -1225,6 +1226,7 @@
     EXPECT_EQ(2u, accounts.size());
   }
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
        LoadPrimaryAccountOnlyWhenAccountConsistencyDisabled) {
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index 428394b..c65305fa 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -385,26 +385,4 @@
       }
     }
   }
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-  // On non-ChromeOS platforms, account ID migration started in 2015. Data is
-  // most probably corrupted for profiles that were not migrated. Clear all
-  // accounts to fix this state.
-
-  // TODO(crbug.com/1224899): This code should be removed once migration
-  // finishes.
-  if (account_tracker_service_->GetMigrationState() ==
-      AccountTrackerService::MIGRATION_NOT_STARTED) {
-    // Clear the primary account if any.
-    ClearPrimaryAccount(signin_metrics::ACCOUNT_ID_MIGRATION,
-                        signin_metrics::SignoutDelete::kIgnoreMetric);
-    // Clean all remaining account information from the account tracker.
-    for (const auto& account : account_tracker_service_->GetAccounts())
-      account_tracker_service_->RemoveAccount(account.account_id);
-    account_tracker_service_->SetMigrationDone();
-    client_->GetPrefs()->CommitPendingWrite();
-  }
-  DCHECK_EQ(AccountTrackerService::MIGRATION_DONE,
-            account_tracker_service_->GetMigrationState());
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 }
diff --git a/components/signin/internal/identity_manager/primary_account_manager_unittest.cc b/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
index fda15ab..6641ccc4 100644
--- a/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
@@ -293,11 +293,10 @@
   EXPECT_EQ(account_id, manager_->GetPrimaryAccountId(ConsentLevel::kSync));
 }
 
-TEST_F(PrimaryAccountManagerTest, GaiaIdMigration) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PrimaryAccountManagerTest, GaiaIdMigration) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(switches::kAccountIdMigration);
-#endif
 
   ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
             account_tracker()->GetMigrationState());
@@ -327,10 +326,8 @@
 }
 
 TEST_F(PrimaryAccountManagerTest, GaiaIdMigrationCrashInTheMiddle) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(switches::kAccountIdMigration);
-#endif
 
   ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
             account_tracker()->GetMigrationState());
@@ -361,38 +358,6 @@
   EXPECT_EQ(AccountTrackerService::MIGRATION_DONE,
             account_tracker()->GetMigrationState());
 }
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-// Test that force migrating the account id to Gaia ID is finished.
-TEST_F(PrimaryAccountManagerTest, GaiaIdMigration_ForceAllAccounts) {
-  ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
-            account_tracker()->GetMigrationState());
-  std::string email = "user@gmail.com";
-  std::string gaia_id = "account_gaia_id";
-
-  PrefService* client_prefs = signin_client()->GetPrefs();
-  client_prefs->SetInteger(prefs::kAccountIdMigrationState,
-                           AccountTrackerService::MIGRATION_NOT_STARTED);
-  ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
-  update->ClearList();
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("account_id", email);
-  dict.SetStringKey("email", email);
-  update->Append(std::move(dict));
-
-  account_tracker()->ResetForTesting();
-
-  client_prefs->SetString(prefs::kGoogleServicesAccountId, email);
-
-  CreatePrimaryAccountManager();
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSignin));
-  EXPECT_EQ("", user_prefs_.GetString(prefs::kGoogleServicesAccountId));
-  EXPECT_TRUE(account_tracker()->GetAccounts().empty());
-  EXPECT_EQ(AccountTrackerService::MIGRATION_DONE,
-            account_tracker()->GetMigrationState());
-}
 #endif
 
 TEST_F(PrimaryAccountManagerTest, RestoreFromPrefsConsented) {
diff --git a/components/signin/public/base/signin_pref_names.cc b/components/signin/public/base/signin_pref_names.cc
index a4edd51b..579fd2b 100644
--- a/components/signin/public/base/signin_pref_names.cc
+++ b/components/signin/public/base/signin_pref_names.cc
@@ -13,12 +13,12 @@
 // automatically. Default value is false.
 const char kForceLogoutUnauthenticatedUserEnabled[] =
     "profile.force_logout_unauthenticated_user_enabled";
-#endif
 
 // An integer property indicating the state of account id migration from
 // email to gaia id for the the profile.  See account_tracker_service.h
 // for possible values.
 const char kAccountIdMigrationState[] = "account_id_migration_state";
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Name of the preference property that persists the account information
 // tracked by this signin.
diff --git a/components/signin/public/base/signin_pref_names.h b/components/signin/public/base/signin_pref_names.h
index 7020950..c481c31 100644
--- a/components/signin/public/base/signin_pref_names.h
+++ b/components/signin/public/base/signin_pref_names.h
@@ -5,14 +5,16 @@
 #ifndef COMPONENTS_SIGNIN_PUBLIC_BASE_SIGNIN_PREF_NAMES_H_
 #define COMPONENTS_SIGNIN_PUBLIC_BASE_SIGNIN_PREF_NAMES_H_
 
+#include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 
 namespace prefs {
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kForceLogoutUnauthenticatedUserEnabled[];
-#endif
 extern const char kAccountIdMigrationState[];
+#endif
 extern const char kAccountInfo[];
 extern const char kAutologinEnabled[];
 extern const char kGaiaCookieHash[];
diff --git a/components/sync/invalidations/fcm_handler.cc b/components/sync/invalidations/fcm_handler.cc
index 39f0df9..7ec4d854 100644
--- a/components/sync/invalidations/fcm_handler.cc
+++ b/components/sync/invalidations/fcm_handler.cc
@@ -9,6 +9,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "components/gcm_driver/gcm_driver.h"
@@ -119,6 +120,8 @@
   DCHECK_EQ(app_id, app_id_);
   DCHECK(base::FeatureList::IsEnabled(kUseSyncInvalidations));
 
+  base::UmaHistogramBoolean("Sync.FCMMessageDeliveredToListeners",
+                            !listeners_.empty());
   for (InvalidationsListener& listener : listeners_) {
     listener.OnInvalidationReceived(message.raw_data);
   }
@@ -151,6 +154,8 @@
 void FCMHandler::DidRetrieveToken(const std::string& subscription_token,
                                   instance_id::InstanceID::Result result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::UmaHistogramEnumeration("Sync.FCMInstanceIdTokenRetrievalStatus",
+                                result);
   waiting_for_token_ = false;
 
   if (!IsListening()) {
@@ -159,7 +164,6 @@
     return;
   }
 
-  // TODO(crbug.com/1108783): add a UMA histogram to monitor results.
   // Notify observers only if the token has changed.
   if (result == instance_id::InstanceID::SUCCESS &&
       fcm_registration_token_ != subscription_token) {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 00a4b8e..eb4f27a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1099,6 +1099,8 @@
     "interest_group/debuggable_auction_worklet_tracker.h",
     "interest_group/interest_group_manager_impl.cc",
     "interest_group/interest_group_manager_impl.h",
+    "interest_group/interest_group_permissions_cache.cc",
+    "interest_group/interest_group_permissions_cache.h",
     "interest_group/interest_group_permissions_checker.cc",
     "interest_group/interest_group_permissions_checker.h",
     "interest_group/interest_group_storage.cc",
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index 88a0c4058..6c4fe96 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -205,17 +205,18 @@
     TCHAR filename[MAX_PATH];
     GetModuleFileName(modules[i], filename, std::size(filename));
     std::string module_name(base::FilePath(filename).BaseName().AsUTF8Unsafe());
-    if (base::LowerCaseEqualsASCII(module_name, "fsdomsrv.dll"))
+    if (base::EqualsCaseInsensitiveASCII(module_name, "fsdomsrv.dll"))
       g_jaws = true;
-    if (base::LowerCaseEqualsASCII(module_name, "vbufbackend_gecko_ia2.dll") ||
-        base::LowerCaseEqualsASCII(module_name, "nvdahelperremote.dll"))
+    if (base::EqualsCaseInsensitiveASCII(module_name,
+                                         "vbufbackend_gecko_ia2.dll") ||
+        base::EqualsCaseInsensitiveASCII(module_name, "nvdahelperremote.dll"))
       g_nvda = true;
-    if (base::LowerCaseEqualsASCII(module_name, "stsaw32.dll"))
+    if (base::EqualsCaseInsensitiveASCII(module_name, "stsaw32.dll"))
       satogo = true;
-    if (base::LowerCaseEqualsASCII(module_name, "dolwinhk.dll"))
+    if (base::EqualsCaseInsensitiveASCII(module_name, "dolwinhk.dll"))
       g_supernova = true;
-    if (base::LowerCaseEqualsASCII(module_name, "zslhook.dll") ||
-        base::LowerCaseEqualsASCII(module_name, "zslhook64.dll"))
+    if (base::EqualsCaseInsensitiveASCII(module_name, "zslhook.dll") ||
+        base::EqualsCaseInsensitiveASCII(module_name, "zslhook64.dll"))
       g_zoomtext = true;
   }
 
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 5f920f0..39e3808 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -586,7 +586,7 @@
   if (node.GetHtmlAttribute(attr, &result))
     return result == value;
 
-  if (base::LowerCaseEqualsASCII(attr, "class"))
+  if (base::EqualsCaseInsensitiveASCII(attr, "class"))
     return node.GetStringAttribute(ax::mojom::StringAttribute::kClassName) ==
            value;
 
diff --git a/content/browser/attribution_reporting/attribution_utils.cc b/content/browser/attribution_reporting/attribution_utils.cc
index 6bb5383..13d4180e 100644
--- a/content/browser/attribution_reporting/attribution_utils.cc
+++ b/content/browser/attribution_reporting/attribution_utils.cc
@@ -162,13 +162,11 @@
 bool AttributionFiltersMatch(const AttributionFilterData& source_filter_data,
                              const AttributionFilterData& trigger_filters,
                              const AttributionFilterData& trigger_not_filters) {
-  if (!trigger_filters.filter_values().empty() &&
-      !AttributionFilterDataMatch(source_filter_data, trigger_filters)) {
+  if (!AttributionFilterDataMatch(source_filter_data, trigger_filters)) {
     return false;
   }
 
-  if (!trigger_not_filters.filter_values().empty() &&
-      !AttributionFilterDataMatch(source_filter_data, trigger_not_filters,
+  if (!AttributionFilterDataMatch(source_filter_data, trigger_not_filters,
                                   /*negated=*/true)) {
     return false;
   }
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 1b2f5170..3a619b3 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -495,9 +495,9 @@
   void SetProcessLock(const ProcessLock& lock_to_set,
                       BrowsingInstanceId browsing_instance_id,
                       bool is_process_used) {
-    DCHECK(!lock_to_set.is_invalid());
-    DCHECK(!process_lock_.is_locked_to_site());
-    DCHECK_NE(SiteInstanceImpl::GetDefaultSiteURL(), lock_to_set.lock_url());
+    CHECK(!lock_to_set.is_invalid());
+    CHECK(!process_lock_.is_locked_to_site());
+    CHECK_NE(SiteInstanceImpl::GetDefaultSiteURL(), lock_to_set.lock_url());
 
     if (process_lock_.is_invalid()) {
       DCHECK(browsing_instance_ids_.empty());
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 89bd21e..45f9e79 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -1733,8 +1733,10 @@
 // should allow the final cross-origin join to send out its .well-known request.
 //
 // Then a cross-origin leave request is issued for the group just joined, which
-// should not wait before issuing a .well-known request, since leaves and joins
-// are throttled separately. The .well-known request for that then succeeds.
+// should not wait before sending the request to the browser process, since
+// leaves and joins are throttled separately. The browser process then leaves
+// the group immediately, using the cached result of the previous .well-known
+// fetch.
 //
 // The remaining two .well-known requests for the joins are then completed,
 // which should result in all pending joins completing successfully.
@@ -1759,9 +1761,9 @@
   net::EmbeddedTestServer cross_origin_server(
       net::test_server::EmbeddedTestServer::TYPE_HTTPS);
   cross_origin_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
-  // There should be 4 .well-known requests. The first 3 for cross-origin joins,
-  // the last for a cross-origin leave.
-  for (int i = 0; i < 4; ++i) {
+  // There should be 3 .well-known requests for the cross-origin joins. The
+  // cross-origin leave should use a cached result.
+  for (int i = 0; i < 3; ++i) {
     permissions_responses.emplace_back(
         std::make_unique<net::test_server::ControllableHttpResponse>(
             &cross_origin_server,
@@ -1832,7 +1834,8 @@
   permissions_responses[1]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
-      /*content=*/R"({"joinAdInterestGroup" : true})",
+      /*content=*/
+      R"({"joinAdInterestGroup" : true, "leaveAdInterestGroup" : true})",
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[1]->Done();
@@ -1846,36 +1849,14 @@
       "2.b.test"));
 
   // A new cross-origin leave should bypass the join queue, and start
-  // immediately.
-  //
-  // TODO(mmenke): Once there's an LRU cache, switch this to
-  // JoinInterestGroupAndVerify().
-  ExecuteScriptAsync(shell(),
-                     JsReplace(R"(
-navigator.leaveAdInterestGroup({name: $1, owner: $2})
-    .then(() => {
-      // Append '-' and the first character of the owner's host to the title.
-      document.title += '-' + (new URL($2)).host[0];
-    });)",
-                               base::NumberToString(kMaxActiveCrossSiteJoins),
-                               cross_origin_server.GetOrigin("1.b.test")));
-  // Respond to the leave's .well-known request.
-  TitleWatcher title_watcher2(web_contents(), u"_1-1");
-  permissions_responses[3]->WaitForRequest();
-  EXPECT_TRUE(base::StartsWith(
-      permissions_responses[3]->http_request()->headers.at("Host"),
-      "1.b.test"));
-  permissions_responses[3]->Send(
-      net::HttpStatusCode::HTTP_OK,
-      /*content_type=*/"application/json",
-      /*content=*/R"({"leaveAdInterestGroup" : true})",
-      /*cookies=*/{},
-      /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
-  permissions_responses[3]->Done();
-  EXPECT_EQ(u"_1-1", title_watcher2.WaitAndGetTitle());
+  // immediately, retrieving the previous .well-known response from the cache.
+  EXPECT_EQ(kSuccess,
+            LeaveInterestGroupAndVerify(
+                /*owner=*/cross_origin_server.GetOrigin("1.b.test"),
+                /*name=*/base::NumberToString(kMaxActiveCrossSiteJoins)));
 
   // Complete the "2.b.test" join's .well-known request.
-  TitleWatcher title_watcher3(web_contents(), u"_1-12");
+  TitleWatcher title_watcher2(web_contents(), u"_12");
   permissions_responses[2]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
@@ -1883,12 +1864,12 @@
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[2]->Done();
-  EXPECT_EQ(u"_1-12", title_watcher3.WaitAndGetTitle());
+  EXPECT_EQ(u"_12", title_watcher2.WaitAndGetTitle());
 
   // Complete the "0.b.test" joins' .well-known request.
   std::u16string final_title =
-      u"_1-12" + std::u16string(kMaxActiveCrossSiteJoins - 1, u'0');
-  TitleWatcher title_watcher4(web_contents(), final_title);
+      u"_12" + std::u16string(kMaxActiveCrossSiteJoins - 1, u'0');
+  TitleWatcher title_watcher3(web_contents(), final_title);
   permissions_responses[0]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
@@ -1896,7 +1877,7 @@
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[0]->Done();
-  EXPECT_EQ(final_title, title_watcher4.WaitAndGetTitle());
+  EXPECT_EQ(final_title, title_watcher3.WaitAndGetTitle());
 }
 
 // The inverse of CrossOriginJoinQueue. Unlike most leave tests, leaves interest
@@ -1915,9 +1896,9 @@
   net::EmbeddedTestServer cross_origin_server(
       net::test_server::EmbeddedTestServer::TYPE_HTTPS);
   cross_origin_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
-  // There should be 4 .well-known requests. The first 3 for cross-origin
-  // leaves, the last for a cross-origin join.
-  for (int i = 0; i < 4; ++i) {
+  // There should be 3 .well-known requests for the cross-origin leaves. The
+  // cross-origin join should use a cached result.
+  for (int i = 0; i < 3; ++i) {
     permissions_responses.emplace_back(
         std::make_unique<net::test_server::ControllableHttpResponse>(
             &cross_origin_server,
@@ -1987,7 +1968,8 @@
   permissions_responses[1]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
-      /*content=*/R"({"leaveAdInterestGroup" : true})",
+      /*content=*/
+      R"({"joinAdInterestGroup" : true, "leaveAdInterestGroup" : true})",
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[1]->Done();
@@ -2001,37 +1983,15 @@
       "2.b.test"));
 
   // A new cross-origin join should bypass the leave queue, and start
-  // immediately.
-  //
-  // TODO(mmenke): Once there's an LRU cache, switch this to
-  // LeaveInterestGroupAndVerify().
-  ExecuteScriptAsync(shell(),
-                     JsReplace(R"(
-navigator.joinAdInterestGroup(
-    {name: $1, owner: $2}, /*joinDurationSec=*/ 300)
-    .then(() => {
-      // Append '+' and the first character of the owner's host to the title.
-      document.title += '+' + (new URL($2)).host[0];
-    });)",
-                               base::NumberToString(kMaxActiveCrossSiteLeaves),
-                               cross_origin_server.GetOrigin("1.b.test")));
-  // Respond to the join's .well-known request.
-  TitleWatcher title_watcher2(web_contents(), u"_1+1");
-  permissions_responses[3]->WaitForRequest();
-  EXPECT_TRUE(base::StartsWith(
-      permissions_responses[1]->http_request()->headers.at("Host"),
-      "1.b.test"));
-  permissions_responses[3]->Send(
-      net::HttpStatusCode::HTTP_OK,
-      /*content_type=*/"application/json",
-      /*content=*/R"({"joinAdInterestGroup" : true})",
-      /*cookies=*/{},
-      /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
-  permissions_responses[3]->Done();
-  EXPECT_EQ(u"_1+1", title_watcher2.WaitAndGetTitle());
+  // immediately, retrieving the previous .well-known response from the cache.
+  EXPECT_EQ(kSuccess,
+            JoinInterestGroupAndVerify(
+                /*owner=*/cross_origin_server.GetOrigin("1.b.test"),
+                /*name=*/base::NumberToString(kMaxActiveCrossSiteLeaves),
+                /*priority=*/0.0));
 
   // Complete the "2.b.test" leave's .well-known request.
-  TitleWatcher title_watcher3(web_contents(), u"_1+12");
+  TitleWatcher title_watcher2(web_contents(), u"_12");
   permissions_responses[2]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
@@ -2039,12 +1999,12 @@
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[2]->Done();
-  EXPECT_EQ(u"_1+12", title_watcher3.WaitAndGetTitle());
+  EXPECT_EQ(u"_12", title_watcher2.WaitAndGetTitle());
 
   // Complete the "0.b.test" leaves' .well-known request.
   std::u16string final_title =
-      u"_1+12" + std::u16string(kMaxActiveCrossSiteLeaves - 1, u'0');
-  TitleWatcher title_watcher4(web_contents(), final_title);
+      u"_12" + std::u16string(kMaxActiveCrossSiteLeaves - 1, u'0');
+  TitleWatcher title_watcher3(web_contents(), final_title);
   permissions_responses[0]->Send(
       net::HttpStatusCode::HTTP_OK,
       /*content_type=*/"application/json",
@@ -2052,7 +2012,7 @@
       /*cookies=*/{},
       /*extra_headers=*/{"Access-Control-Allow-Origin: *"});
   permissions_responses[0]->Done();
-  EXPECT_EQ(final_title, title_watcher4.WaitAndGetTitle());
+  EXPECT_EQ(final_title, title_watcher3.WaitAndGetTitle());
 }
 
 // Much like CrossOriginJoinQueue, but navigates the page when the queue is
diff --git a/content/browser/interest_group/interest_group_permissions_cache.cc b/content/browser/interest_group/interest_group_permissions_cache.cc
new file mode 100644
index 0000000..ad0c6f4
--- /dev/null
+++ b/content/browser/interest_group/interest_group_permissions_cache.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
+
+#include <map>
+#include <memory>
+
+#include "base/callback.h"
+#include "base/containers/lru_cache.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "net/base/network_isolation_key.h"
+#include "url/origin.h"
+
+namespace content {
+
+InterestGroupPermissionsCache::InterestGroupPermissionsCache() = default;
+InterestGroupPermissionsCache::~InterestGroupPermissionsCache() = default;
+
+InterestGroupPermissionsCache::Permissions*
+InterestGroupPermissionsCache::GetPermissions(
+    const url::Origin& frame_origin,
+    const url::Origin& interest_group_owner,
+    const net::NetworkIsolationKey& network_isolation_key) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  CacheShard* shard = FindShard(frame_origin, network_isolation_key, now);
+  if (!shard)
+    return nullptr;
+
+  auto cache_entry = shard->cache->Get(interest_group_owner);
+  if (cache_entry == shard->cache->end())
+    return nullptr;
+  if (cache_entry->second.expiry < now) {
+    // Delete the LRU cache entry if it has expired.
+    shard->cache->Erase(cache_entry);
+    return nullptr;
+  }
+  return &cache_entry->second.permissions;
+}
+
+void InterestGroupPermissionsCache::CachePermissions(
+    Permissions permissions,
+    const url::Origin& frame_origin,
+    const url::Origin& interest_group_owner,
+    const net::NetworkIsolationKey& network_isolation_key) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  // Use FindShard() here to remove shard if it has expired. Reusing expired
+  // entries that haven't been cleaned up yet would potentially leak details
+  // about when the cleanup expired task has last run, which can be influenced
+  // by calls made from cross-origin renderers.
+  CacheShard* shard = FindShard(frame_origin, network_isolation_key, now);
+  if (!shard) {
+    shard = &cache_shards_
+                 .emplace(std::make_pair(
+                     CacheShardKey{frame_origin, network_isolation_key},
+                     CacheShard()))
+                 .first->second;
+  }
+  base::TimeTicks expiry = now + kCacheDuration;
+  shard->cache->Put({interest_group_owner, CacheEntry{expiry, permissions}});
+  // Update the shard expiry to match that of the newly added CacheEntry, as
+  // that should be longest lived entry.
+  shard->expiry = expiry;
+
+  MaybeStartDeleteExpiredTimer();
+}
+
+void InterestGroupPermissionsCache::Clear() {
+  cache_shards_.clear();
+}
+
+size_t InterestGroupPermissionsCache::cache_shards_for_testing() const {
+  return cache_shards_.size();
+}
+
+InterestGroupPermissionsCache::CacheShard::CacheShard()
+    : cache(std::make_unique<base::LRUCache<url::Origin, CacheEntry>>(
+          kMaxCacheEntriesPerShard)) {}
+InterestGroupPermissionsCache::CacheShard::CacheShard(CacheShard&&) = default;
+InterestGroupPermissionsCache::CacheShard::~CacheShard() = default;
+
+InterestGroupPermissionsCache::CacheShard*
+InterestGroupPermissionsCache::FindShard(
+    const url::Origin& frame_origin,
+    const net::NetworkIsolationKey& network_isolation_key,
+    base::TimeTicks now) {
+  auto shard =
+      cache_shards_.find(CacheShardKey{frame_origin, network_isolation_key});
+  if (shard == cache_shards_.end())
+    return nullptr;
+  if (shard->second.expiry < now) {
+    cache_shards_.erase(shard);
+    return nullptr;
+  }
+  return &shard->second;
+}
+
+void InterestGroupPermissionsCache::MaybeStartDeleteExpiredTimer() {
+  if (cache_shards_.empty() || delete_expired_timer_.IsRunning())
+    return;
+  delete_expired_timer_.Start(
+      FROM_HERE, kDeleteExpiredTimerDuration,
+      base::BindOnce(&InterestGroupPermissionsCache::DeleteExpired,
+                     base::Unretained(this)));
+}
+
+void InterestGroupPermissionsCache::DeleteExpired() {
+  base::TimeTicks now = base::TimeTicks::Now();
+  for (auto shard = cache_shards_.begin(); shard != cache_shards_.end();) {
+    auto current_shard = shard;
+    shard = ++shard;
+    if (current_shard->second.expiry < now)
+      cache_shards_.erase(current_shard);
+  }
+
+  MaybeStartDeleteExpiredTimer();
+}
+
+}  // namespace content
diff --git a/content/browser/interest_group/interest_group_permissions_cache.h b/content/browser/interest_group/interest_group_permissions_cache.h
new file mode 100644
index 0000000..0fb7e29
--- /dev/null
+++ b/content/browser/interest_group/interest_group_permissions_cache.h
@@ -0,0 +1,163 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_PERMISSIONS_CACHE_H_
+#define CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_PERMISSIONS_CACHE_H_
+
+#include "content/common/content_export.h"
+
+#include <map>
+#include <memory>
+#include <tuple>
+
+#include "base/containers/lru_cache.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "net/base/network_isolation_key.h"
+#include "url/origin.h"
+
+namespace content {
+
+// Cache of per-origin join/leave interest group permissions, partitioned by
+// NetworkIsolationKey and initiating frame origin. To minimize leaks across
+// first party contexts, uses a separate LRU cache "shard" for each {frame
+// origin, NetworkIsolationKey} pair. Each LRU cache has a maximum number of
+// entries, but there's no global limit, to prevent leaks. The short entry
+// lifetime and delay in creating entries, along with the LRU size cap, should
+// keep memory usage low.
+//
+// In addition to the LRU-ness of the cache, individual entries are passively
+// expired (i.e., no longer returned, but not proactively deleted) after
+// `kCacheDuration` has passed since they were added to the cache. Cache shards
+// are garbage collected on a timer, at some point after all their entries have
+// expired. Expired entries and shards are also deleted on access, which isn't
+// strictly necessary.
+//
+// Permissions are typically learned from .well-known fetches, and should be
+// cached by the network process, depending on HTTP response headers, but
+// caching it in the browser process results in much better performance for
+// sites that want to join (or, more likely, leave) large numbers of
+// cross-origin interest groups, due to the limit of outstanding joins/leaves in
+// the renderer process, and overhead on accessing the network stack's HTTP
+// cache.
+class CONTENT_EXPORT InterestGroupPermissionsCache {
+ public:
+  // Cache duration for cache entries. Cache shards expire when all their
+  // individual entries expire, so this is also the expiration duration of
+  // cache shards, relative to last added entry.
+  static constexpr base::TimeDelta kCacheDuration = base::Minutes(1);
+
+  // How often expired cache shards are evicted. Expired but not-yet-evicted
+  // entries are not returned.
+  static constexpr base::TimeDelta kDeleteExpiredTimerDuration =
+      2 * kCacheDuration;
+
+  // The maximum number of cache entries for each cache shard. There is no
+  // global maximum, to prevent that from becoming a sidechannel.
+  static constexpr int kMaxCacheEntriesPerShard = 50;
+
+  // Permissions associated with an interest group origin.
+  struct Permissions {
+    bool can_join = false;
+    bool can_leave = false;
+
+    // Comparison operators are only useful for testing.
+
+    bool operator==(Permissions permissions) const {
+      return can_join == permissions.can_join &&
+             can_leave == permissions.can_leave;
+    }
+
+    bool operator!=(Permissions permissions) const {
+      return !(*this == permissions);
+    }
+  };
+
+  InterestGroupPermissionsCache();
+  InterestGroupPermissionsCache(InterestGroupPermissionsCache&) = delete;
+  ~InterestGroupPermissionsCache();
+
+  InterestGroupPermissionsCache& operator=(
+      const InterestGroupPermissionsCache&) = delete;
+
+  // Retrieves unexpired cached Permissions that `interest_group_owner` has
+  // granted to `frame_origin`, learned in the context of
+  // `network_isolation_key`.
+  Permissions* GetPermissions(
+      const url::Origin& frame_origin,
+      const url::Origin& interest_group_owner,
+      const net::NetworkIsolationKey& network_isolation_key);
+
+  // Adds `permissions` to the cache as the set of permissions
+  // `interest_group_owner` has granted to `frame_origin`, learned in the
+  // context of `network_isolation_key`.
+  void CachePermissions(Permissions permissions,
+                        const url::Origin& frame_origin,
+                        const url::Origin& interest_group_owner,
+                        const net::NetworkIsolationKey& network_isolation_key);
+
+  // Deletes all cache entries.
+  void Clear();
+
+  // Returns the number of non-deleted cache shards, to test cleanup logic. All
+  // values in a cache shard may be expired, since expired cache shards are only
+  // deleted on access and on a timer.
+  size_t cache_shards_for_testing() const;
+
+ private:
+  // An entry in the cache.
+  struct CacheEntry {
+    base::TimeTicks expiry;
+    Permissions permissions;
+  };
+
+  // An independent shard of the cache. Each shard must have no impact on the
+  // others, including when their entries are observably evicted.
+  struct CacheShard {
+    CacheShard();
+    CacheShard(CacheShard&&);
+    ~CacheShard();
+
+    // Last expiration time of any of the shard's CacheEntry.
+    base::TimeTicks expiry;
+
+    // Map of interest group owner origins to CacheEntries. A std::unique_ptr
+    // wrapper is needed to make these movable, so they can be put in a
+    // std::map.
+    std::unique_ptr<base::LRUCache<url::Origin, CacheEntry>> cache;
+  };
+
+  // Key indicating which cache shard to use.
+  struct CacheShardKey {
+    bool operator<(const CacheShardKey& other) const {
+      return std::tie(frame_origin, network_isolation_key) <
+             std::tie(other.frame_origin, other.network_isolation_key);
+    }
+
+    url::Origin frame_origin;
+    net::NetworkIsolationKey network_isolation_key;
+  };
+
+  // Returns the specified cache shard, if it exists and is not expired. Deletes
+  // the cache shard if it exists but is expired.
+  CacheShard* FindShard(const url::Origin& frame_origin,
+                        const net::NetworkIsolationKey& network_isolation_key,
+                        base::TimeTicks now);
+
+  // Starts a timer to invoke DeleteExpired(), if there are any cache shards and
+  // the timer hasn't already been started.
+  void MaybeStartDeleteExpiredTimer();
+
+  // Walks through the cache shards, deleting any that have expired, and
+  // restarts timer if there are any shards left. Expired LRU entries are not
+  // deleted on an individual basis, except when accessed directly.
+  void DeleteExpired();
+
+  base::OneShotTimer delete_expired_timer_;
+  std::map<CacheShardKey, CacheShard> cache_shards_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_PERMISSIONS_CACHE_H_
diff --git a/content/browser/interest_group/interest_group_permissions_cache_unittest.cc b/content/browser/interest_group/interest_group_permissions_cache_unittest.cc
new file mode 100644
index 0000000..508b8adc
--- /dev/null
+++ b/content/browser/interest_group/interest_group_permissions_cache_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
+
+#include <string>
+#include <vector>
+
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
+#include "net/base/network_isolation_key.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+namespace {
+
+// Very short time used by some tests that want to wait until just after a
+// timer triggers.
+constexpr base::TimeDelta kTinyTime = base::Microseconds(1);
+
+using Permissions = InterestGroupPermissionsCache::Permissions;
+
+class InterestGroupPermissionsCacheTest : public testing::Test {
+ protected:
+  // Default values used in most tests.
+  const url::Origin kFrameOrigin =
+      url::Origin::Create(GURL("https://frame.test"));
+  const url::Origin kGroupOrigin =
+      url::Origin::Create(GURL("https://group.test"));
+  const net::NetworkIsolationKey kNetworkIsolationKey =
+      net::NetworkIsolationKey(kFrameOrigin, kFrameOrigin);
+  const Permissions kPermissions =
+      Permissions{/*can_join=*/true, /*can_leave=*/false};
+
+  // Alternative values when two different values are needed for any field.
+  const url::Origin kOtherFrameOrigin =
+      url::Origin::Create(GURL("https://other_frame.test"));
+  const url::Origin kOtherGroupOrigin =
+      url::Origin::Create(GURL("https://other_group.test"));
+  const net::NetworkIsolationKey kOtherNetworkIsolationKey =
+      net::NetworkIsolationKey(kOtherFrameOrigin, kOtherFrameOrigin);
+  const Permissions kOtherPermissions =
+      Permissions{/*can_join=*/false, /*can_leave=*/true};
+
+  base::test::TaskEnvironment task_environment_ = base::test::TaskEnvironment(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+  InterestGroupPermissionsCache interest_group_permissions_cache_;
+};
+
+TEST_F(InterestGroupPermissionsCacheTest, PermissionsEquality) {
+  EXPECT_EQ(kPermissions, kPermissions);
+  EXPECT_EQ(kOtherPermissions, kOtherPermissions);
+
+  EXPECT_NE(kOtherPermissions, kPermissions);
+  EXPECT_NE(kPermissions, kOtherPermissions);
+
+  // Check that two different Permissions objects that have the same values are
+  // considered equal.
+  //
+  // Same as kPermissions.
+  Permissions permissions1{/*can_join=*/true, /*can_leave=*/false};
+  EXPECT_EQ(kPermissions, permissions1);
+  EXPECT_EQ(permissions1, kPermissions);
+
+  // Matches neither `kPermissions` nor `kOtherPermissions`. Used to make sure
+  // both values matter.
+  Permissions permissions2{/*can_join=*/false, /*can_leave=*/false};
+  EXPECT_NE(kPermissions, permissions2);
+  EXPECT_NE(permissions2, kPermissions);
+  EXPECT_NE(kOtherPermissions, permissions2);
+  EXPECT_NE(permissions2, kOtherPermissions);
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, Basic) {
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, Overwrite) {
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, MultipleEntries) {
+  // Permissions that are each assigned to a different pair of origins +
+  // NetworkIsolationKey. This coincidentally covers all distinct permissions
+  // values, but that is not necessary for this test. They all just need to be
+  // distinct.
+  const Permissions kPermissionsValues[4] = {
+      {/*can_join=*/true, /*can_leave=*/true},
+      {/*can_join=*/true, /*can_leave=*/false},
+      {/*can_join=*/false, /*can_leave=*/true},
+      {/*can_join=*/false, /*can_leave=*/false},
+  };
+
+  // Each set of permissions varies in only one value from the first set. Some
+  // of these combinations can't actually occur (in particular, the frame origin
+  // normally corresponds to the NetworkIsolationKey's frame site), but the
+  // cache layer doesn't care.
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissionsValues[0], kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissionsValues[1], kOtherFrameOrigin, kGroupOrigin,
+      kNetworkIsolationKey);
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissionsValues[2], kFrameOrigin, kOtherGroupOrigin,
+      kNetworkIsolationKey);
+  interest_group_permissions_cache_.CachePermissions(kPermissionsValues[3],
+                                                     kFrameOrigin, kGroupOrigin,
+                                                     kOtherNetworkIsolationKey);
+
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissionsValues[0]);
+
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kOtherFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissionsValues[1]);
+
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissionsValues[2]);
+
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kOtherNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissionsValues[3]);
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, Clear) {
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kOtherFrameOrigin, kOtherGroupOrigin,
+      kOtherNetworkIsolationKey);
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kOtherFrameOrigin, kOtherGroupOrigin, kOtherNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+  EXPECT_EQ(2u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  interest_group_permissions_cache_.Clear();
+  EXPECT_EQ(0u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kOtherFrameOrigin, kOtherGroupOrigin, kOtherNetworkIsolationKey));
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, Expiry) {
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kCacheDuration);
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  task_environment_.FastForwardBy(kTinyTime);
+  // Cache shards are only deleted on a timer or on access, neither of which has
+  // happened yet, though the shard should now be expired.
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+  // The expired cache shard should have been deleted on access.
+  EXPECT_EQ(0u, interest_group_permissions_cache_.cache_shards_for_testing());
+}
+
+// Test the case where a CacheEntry expires without the cache shard also
+// expiring.
+TEST_F(InterestGroupPermissionsCacheTest, CacheEntryExpiry) {
+  // Create a cache entry.
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Wait until just before the entry expires.
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kCacheDuration);
+
+  // Add another entry to the same cache shard.
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+
+  // There should still be only one cache shard.
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Check that the original entry is still there.
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Wait for the origin entry to expire.
+  task_environment_.FastForwardBy(kTinyTime);
+
+  // Original entry should have expired.
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+
+  // Other entry should still be present.
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+
+  // There should still be only one cache shard.
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, DeleteExpired) {
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+
+  // Run until just before the delete expired timer runs. Don't call
+  // GetPermissions(), as it would delete the entry. At this point, the entry is
+  // expired, but has not been deleted.
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kDeleteExpiredTimerDuration - kTinyTime);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Run until the delete expired timer runs, which should delete the entry.
+  task_environment_.FastForwardBy(kTinyTime);
+  EXPECT_EQ(0u, interest_group_permissions_cache_.cache_shards_for_testing());
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, DeleteExpiredPreservesUnexpired) {
+  interest_group_permissions_cache_.CachePermissions(
+      kPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Run until just before the delete expired timer runs. Don't call
+  // GetPermissions(), as it would delete the entry. At this point, the entry is
+  // expired, but has not been deleted.
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kDeleteExpiredTimerDuration - kTinyTime);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Add permission for a different group.
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Run until the delete expired timer runs, which should delete nothing.
+  task_environment_.FastForwardBy(kTinyTime);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // The original permissions should have expired.
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+
+  // But the new permissions should still be around.
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+  EXPECT_EQ(1u, interest_group_permissions_cache_.cache_shards_for_testing());
+
+  // Run until the delete expired timer triggers again, which should now delete
+  // the entry.
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kDeleteExpiredTimerDuration);
+  EXPECT_EQ(0u, interest_group_permissions_cache_.cache_shards_for_testing());
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey));
+}
+
+TEST_F(InterestGroupPermissionsCacheTest, LRU) {
+  // Fill LRU cache.
+  std::vector<url::Origin> group_origins;
+  for (int i = 0; i < InterestGroupPermissionsCache::kMaxCacheEntriesPerShard;
+       ++i) {
+    url::Origin group_origin =
+        url::Origin::Create(GURL(base::StringPrintf("https://%i.test", i)));
+    interest_group_permissions_cache_.CachePermissions(
+        kPermissions, kFrameOrigin, group_origin, kNetworkIsolationKey);
+    group_origins.emplace_back(std::move(group_origin));
+  }
+
+  // Check all entries are present, accessing in order to end with the same LRU
+  // order as before.
+  for (int i = 0; i < InterestGroupPermissionsCache::kMaxCacheEntriesPerShard;
+       ++i) {
+    Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+        kFrameOrigin, group_origins[i], kNetworkIsolationKey);
+    ASSERT_TRUE(permissions);
+    EXPECT_EQ(*permissions, kPermissions);
+  }
+
+  // Access first entry.
+  ASSERT_TRUE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, group_origins[0], kNetworkIsolationKey));
+
+  // Overwrite second entry.
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kFrameOrigin, group_origins[1], kNetworkIsolationKey);
+
+  // Add another entry. The third entry is the last-used entry, and should be
+  // evicted.
+  interest_group_permissions_cache_.CachePermissions(
+      kOtherPermissions, kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+
+  // Check third entry was removed.
+  EXPECT_FALSE(interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, group_origins[2], kNetworkIsolationKey));
+
+  // Check other entries are all still present.
+
+  for (int i = 3; i < InterestGroupPermissionsCache::kMaxCacheEntriesPerShard;
+       ++i) {
+    Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+        kFrameOrigin, group_origins[i], kNetworkIsolationKey);
+    ASSERT_TRUE(permissions);
+    EXPECT_EQ(*permissions, kPermissions);
+  }
+
+  Permissions* permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, group_origins[0], kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kPermissions);
+
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, group_origins[1], kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+
+  permissions = interest_group_permissions_cache_.GetPermissions(
+      kFrameOrigin, kGroupOrigin, kNetworkIsolationKey);
+  ASSERT_TRUE(permissions);
+  EXPECT_EQ(*permissions, kOtherPermissions);
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/interest_group/interest_group_permissions_checker.cc b/content/browser/interest_group/interest_group_permissions_checker.cc
index 0c1c4230..be4fe7f 100644
--- a/content/browser/interest_group/interest_group_permissions_checker.cc
+++ b/content/browser/interest_group/interest_group_permissions_checker.cc
@@ -8,6 +8,7 @@
 #include "base/strings/escape.h"
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
 #include "content/public/browser/global_request_id.h"
 #include "net/base/network_isolation_key.h"
 #include "net/http/http_request_headers.h"
@@ -97,6 +98,17 @@
     return;
   }
 
+  Permissions* permissions = cache_.GetPermissions(
+      frame_origin, interest_group_owner, network_isolation_key);
+  if (permissions) {
+    // If the result is cached, there shouldn't be a pending request for it.
+    DCHECK_EQ(0u, active_requests_.count({frame_origin, interest_group_owner,
+                                          network_isolation_key}));
+    std::move(permissions_check_callback)
+        .Run(AllowsOperation(*permissions, operation));
+    return;
+  }
+
   PermissionsKey key{frame_origin, interest_group_owner, network_isolation_key};
   auto active_request = active_requests_.find(key);
   if (active_request == active_requests_.end()) {
@@ -147,6 +159,10 @@
       /*permissions_check_callback=*/std::move(permissions_check_callback)});
 }
 
+void InterestGroupPermissionsChecker::ClearCache() {
+  cache_.Clear();
+}
+
 void InterestGroupPermissionsChecker::OnRequestComplete(
     ActiveRequestMap::iterator active_request,
     std::unique_ptr<std::string> response_body) {
@@ -187,6 +203,12 @@
 void InterestGroupPermissionsChecker::OnActiveRequestComplete(
     ActiveRequestMap::iterator active_request,
     Permissions permissions) {
+  // Add permissions to cache, regardless of where they came from (failed
+  // request, bad response, valid JSON).
+  cache_.CachePermissions(permissions, active_request->first.frame_origin,
+                          active_request->first.interest_group_owner,
+                          active_request->first.network_isolation_key);
+
   auto pending_checks = std::move(active_request->second->pending_checks);
   active_requests_.erase(active_request);
   for (auto& pending_check : pending_checks) {
diff --git a/content/browser/interest_group/interest_group_permissions_checker.h b/content/browser/interest_group/interest_group_permissions_checker.h
index 23181a91..2b23218 100644
--- a/content/browser/interest_group/interest_group_permissions_checker.h
+++ b/content/browser/interest_group/interest_group_permissions_checker.h
@@ -15,6 +15,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
 #include "net/base/network_isolation_key.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -88,12 +89,10 @@
                         network::mojom::URLLoaderFactory& url_loader_factory,
                         PermissionsCheckCallback permissions_check_callback);
 
+  void ClearCache();
+
  private:
-  // Permissions associated with an interest group origin.
-  struct Permissions {
-    bool can_join = false;
-    bool can_leave = false;
-  };
+  using Permissions = InterestGroupPermissionsCache::Permissions;
 
   // Two permissions checks with the same key can use the same .well-known
   // response, though they may have a different associated Operation.
@@ -159,6 +158,7 @@
   static bool AllowsOperation(Permissions permissions, Operation operation);
 
   ActiveRequestMap active_requests_;
+  InterestGroupPermissionsCache cache_;
 
   base::WeakPtrFactory<InterestGroupPermissionsChecker> weak_factory_{this};
 };
diff --git a/content/browser/interest_group/interest_group_permissions_checker_unittest.cc b/content/browser/interest_group/interest_group_permissions_checker_unittest.cc
index 403d070..fd7a4438 100644
--- a/content/browser/interest_group/interest_group_permissions_checker_unittest.cc
+++ b/content/browser/interest_group/interest_group_permissions_checker_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "content/browser/interest_group/interest_group_permissions_cache.h"
 #include "content/services/auction_worklet/worklet_test_util.h"
 #include "net/base/network_isolation_key.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
@@ -22,6 +23,10 @@
 namespace content {
 namespace {
 
+// Very short time used by some tests that want to wait until just after a
+// timer triggers.
+constexpr base::TimeDelta kTinyTime = base::Microseconds(1);
+
 // Response body that allows everything.
 const char kAllowAllResponse[] = R"({
   "joinAdInterestGroup" : true,
@@ -220,6 +225,10 @@
   for (const auto& test_case : kTestCases) {
     SCOPED_TRACE(test_case.response_body);
 
+    // Since all requests use the same arguments, need to clear the cache
+    // between calls.
+    interest_group_permissions_checker_.ClearCache();
+
     BoolCallback bool_callback;
     auction_worklet::AddJsonResponse(&url_loader_factory_, validation_url_,
                                      test_case.response_body);
@@ -298,7 +307,8 @@
   EXPECT_EQ(1u, url_loader_factory_.total_requests());
 }
 
-// Test that permission checks with different frame origins can't be merged.
+// Test that permission checks with different frame origins can't be merged, and
+// are cached separately.
 TEST_P(InterestGroupPermissionsCheckerParamaterizedTest, DifferentFrameOrigin) {
   // The only way two permissions checks from different frame origins can share
   // a NetworkIsolationKey is if they are same-site. So use an origin that's
@@ -330,10 +340,24 @@
 
   // There should have been one network request for each frame owner.
   EXPECT_EQ(2u, url_loader_factory_.total_requests());
+
+  // Repeat checks. Results should be the same, but with no new network
+  // requests.
+  BoolCallback bool_callback3;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kFrameOrigin, kGroupOrigin, kNetworkIsolationKey,
+      url_loader_factory_, bool_callback3.callback());
+  BoolCallback bool_callback4;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kOtherFrameOrigin, kGroupOrigin, kNetworkIsolationKey,
+      url_loader_factory_, bool_callback4.callback());
+  EXPECT_TRUE(bool_callback3.GetResult());
+  EXPECT_FALSE(bool_callback4.GetResult());
+  EXPECT_EQ(2u, url_loader_factory_.total_requests());
 }
 
 // Test that permission checks with different interest group owners can't be
-// merged.
+// merged, and are cached separately.
 TEST_P(InterestGroupPermissionsCheckerParamaterizedTest, DifferentOwner) {
   const url::Origin kOtherGroupOrigin =
       url::Origin::Create(GURL("https://group2.test"));
@@ -359,10 +383,24 @@
 
   // There should have been one network request for each origin.
   EXPECT_EQ(2u, url_loader_factory_.total_requests());
+
+  // Repeat checks. Results should be the same, but with no new network
+  // requests.
+  BoolCallback bool_callback3;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kFrameOrigin, kGroupOrigin, kNetworkIsolationKey,
+      url_loader_factory_, bool_callback3.callback());
+  BoolCallback bool_callback4;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kFrameOrigin, kOtherGroupOrigin, kNetworkIsolationKey,
+      url_loader_factory_, bool_callback4.callback());
+  EXPECT_TRUE(bool_callback3.GetResult());
+  EXPECT_FALSE(bool_callback4.GetResult());
+  EXPECT_EQ(2u, url_loader_factory_.total_requests());
 }
 
 // Test that permission checks with different NetworkIsolationKeys can't be
-// merged.
+// merged, and are cached separately.
 TEST_P(InterestGroupPermissionsCheckerParamaterizedTest,
        DifferentNetworkIsolationKey) {
   const net::NetworkIsolationKey kOtherNetworkIsolationKey(
@@ -376,22 +414,62 @@
       GetOperation(), kFrameOrigin, kGroupOrigin, kOtherNetworkIsolationKey,
       url_loader_factory_, bool_callback2.callback());
 
-  // Both requests are for the same URL, since they have the same frame and
-  // group origins. The reason it's important to separate them is to protect
-  // against identifying a user across NetworkIsolationKeys.
-  auction_worklet::AddJsonResponse(&url_loader_factory_, validation_url_,
-                                   kAllowAllResponse);
+  // There should be two pending network requests.
+  ASSERT_EQ(2u, url_loader_factory_.pending_requests()->size());
+
+  // Make the first response grant permissions and the second refuse
+  // them. Since there's a single URLLoaderFactory pipe, the requests should be
+  // in the order of the CheckPermissions calls above.
+  for (int i = 0; i < 2; ++i) {
+    auto& pending_request = (*url_loader_factory_.pending_requests())[i];
+    EXPECT_EQ(validation_url_, pending_request.request.url);
+
+    auto head = network::mojom::URLResponseHead::New();
+    head->mime_type = "application/json";
+    head->headers =
+        net::HttpResponseHeaders::TryToCreate("HTTP/1.1 200 OK\r\n\r\n");
+    ASSERT_TRUE(head->headers);
+
+    mojo::ScopedDataPipeProducerHandle producer_handle;
+    std::string response_body = i == 0 ? kAllowAllResponse : kAllowNoneResponse;
+    mojo::ScopedDataPipeConsumerHandle body;
+    ASSERT_EQ(mojo::CreateDataPipe(response_body.size(), producer_handle, body),
+              MOJO_RESULT_OK);
+    uint32_t bytes_written = response_body.size();
+    ASSERT_EQ(MOJO_RESULT_OK,
+              producer_handle->WriteData(response_body.data(), &bytes_written,
+                                         MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
+
+    pending_request.client->OnReceiveResponse(std::move(head), std::move(body));
+
+    auto status = network::URLLoaderCompletionStatus();
+    status.decoded_body_length = response_body.size();
+    pending_request.client->OnComplete(status);
+  }
 
   EXPECT_TRUE(bool_callback_.GetResult());
-  EXPECT_TRUE(bool_callback2.GetResult());
+  EXPECT_FALSE(bool_callback2.GetResult());
 
-  // There should have been one network request for each NetworkIsolationKey.
+  // Repeat checks. Results should be the same, but with no new network
+  // requests.
+  BoolCallback bool_callback3;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kFrameOrigin, kGroupOrigin, kNetworkIsolationKey,
+      url_loader_factory_, bool_callback3.callback());
+  BoolCallback bool_callback4;
+  interest_group_permissions_checker_.CheckPermissions(
+      GetOperation(), kFrameOrigin, kGroupOrigin, kOtherNetworkIsolationKey,
+      url_loader_factory_, bool_callback4.callback());
+  EXPECT_TRUE(bool_callback3.GetResult());
+  EXPECT_FALSE(bool_callback4.GetResult());
   EXPECT_EQ(2u, url_loader_factory_.total_requests());
 }
 
-// Test case with two sequential requests, which should result in two network
-// requests.
-TEST_F(InterestGroupPermissionsCheckerTest, SequentialRequests) {
+// Check the case the same parameters are repeatedly fed into
+// CheckPermissions(), both before and after a cache entry expires.
+TEST_P(InterestGroupPermissionsCheckerParamaterizedTest, CacheExpires) {
+  // Set up a response that denies permissions, and send a request. Permissions
+  // should be denied.
   auction_worklet::AddJsonResponse(&url_loader_factory_, validation_url_,
                                    kAllowNoneResponse);
   interest_group_permissions_checker_.CheckPermissions(
@@ -399,17 +477,33 @@
       kGroupOrigin, kNetworkIsolationKey, url_loader_factory_,
       bool_callback_.callback());
   EXPECT_FALSE(bool_callback_.GetResult());
+  EXPECT_EQ(1u, url_loader_factory_.total_requests());
 
+  // Make future responses allow permissions.
   auction_worklet::AddJsonResponse(&url_loader_factory_, validation_url_,
                                    kAllowAllResponse);
+
+  // Wait until just before the cache entry expired. The original cached
+  // response should be returned.
+  task_environment_.FastForwardBy(
+      InterestGroupPermissionsCache::kCacheDuration);
   BoolCallback bool_callback2;
   interest_group_permissions_checker_.CheckPermissions(
       InterestGroupPermissionsChecker::Operation::kJoin, kFrameOrigin,
       kGroupOrigin, kNetworkIsolationKey, url_loader_factory_,
       bool_callback2.callback());
-  EXPECT_TRUE(bool_callback2.GetResult());
+  EXPECT_FALSE(bool_callback2.GetResult());
+  EXPECT_EQ(1u, url_loader_factory_.total_requests());
 
-  // Requests should not have been merged or response cached.
+  // Wait until the cache entry expires and check permissions again. The result
+  // should change, and there should be a new network request.
+  task_environment_.FastForwardBy(kTinyTime);
+  BoolCallback bool_callback3;
+  interest_group_permissions_checker_.CheckPermissions(
+      InterestGroupPermissionsChecker::Operation::kJoin, kFrameOrigin,
+      kGroupOrigin, kNetworkIsolationKey, url_loader_factory_,
+      bool_callback3.callback());
+  EXPECT_TRUE(bool_callback3.GetResult());
   EXPECT_EQ(2u, url_loader_factory_.total_requests());
 }
 
diff --git a/content/browser/process_lock.h b/content/browser/process_lock.h
index 0ed4da0..5032a0c 100644
--- a/content/browser/process_lock.h
+++ b/content/browser/process_lock.h
@@ -118,10 +118,13 @@
   // Returns whether this ProcessLock is specific to PDF contents.
   bool is_pdf() const { return site_info_.has_value() && site_info_->is_pdf(); }
 
+  // Returns whether this ProcessLock can only be used for error pages.
   bool is_error_page() const {
     return site_info_.has_value() && site_info_->is_error_page();
   }
 
+  // Returns whether this ProcessLock is used for a <webview> guest process.
+  // This may be false for other types of GuestView.
   bool is_guest() const {
     return site_info_.has_value() && site_info_->is_guest();
   }
@@ -130,11 +133,12 @@
   // lock is used with.
   StoragePartitionConfig GetStoragePartitionConfig() const;
 
-  // Representing agent cluster's "cross-origin isolated" concept.
+  // Returns the exposed isolation state (e.g., cross-origin-isolated) of all
+  // agent clusters allowed in this ProcessLock. See
   // https://html.spec.whatwg.org/multipage/webappapis.html#dom-crossoriginisolated
-  // This property is renderer process global because we ensure that a
-  // renderer process host only cross-origin isolated agents or only
-  // non-cross-origin isolated agents, not both.
+  // This is tracked on ProcessLock because a RenderProcessHost can host only
+  // cross-origin isolated agents or only non-cross-origin isolated agents, not
+  // both.
   WebExposedIsolationInfo GetWebExposedIsolationInfo() const;
 
   // Returns whether lock_url() is at least at the granularity of a site (i.e.,
@@ -170,8 +174,9 @@
   explicit ProcessLock(const SiteInfo& site_info);
 
   // TODO(creis): Consider tracking multiple compatible SiteInfos in ProcessLock
-  // (e.g., multiple extensions). This can better restrict what the process has
-  // access to in cases that we don't currently use a ProcessLock.
+  // (e.g., multiple sites when Site Isolation is disabled). This can better
+  // restrict what the process has access to in cases that we currently use an
+  // allows-any-site ProcessLock.
   absl::optional<SiteInfo> site_info_;
 };
 
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index c93548b2..5201af4 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -720,25 +720,21 @@
 }
 
 // Start a new nested async event with the given name.
-void EnterChildTraceEvent(const char* name, NavigationRequest* request) {
-  // Tracing no longer outputs the end event name, so we can simply pass an
-  // empty string here.
-  TRACE_EVENT_NESTABLE_ASYNC_END0("navigation", "", request->GetNavigationId());
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("navigation", name,
-                                    request->GetNavigationId());
+void EnterChildTraceEvent(perfetto::StaticString name,
+                          NavigationRequest* request) {
+  TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(request));
+  TRACE_EVENT_BEGIN("navigation", name, perfetto::Track::FromPointer(request));
 }
 
 // Start a new nested async event with the given name and args.
 template <typename ArgType>
-void EnterChildTraceEvent(const char* name,
+void EnterChildTraceEvent(perfetto::StaticString name,
                           NavigationRequest* request,
                           const char* arg_name,
                           ArgType arg_value) {
-  // Tracing no longer outputs the end event name, so we can simply pass an
-  // empty string here.
-  TRACE_EVENT_NESTABLE_ASYNC_END0("navigation", "", request->GetNavigationId());
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
-      "navigation", name, request->GetNavigationId(), arg_name, arg_value);
+  TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(request));
+  TRACE_EVENT_BEGIN("navigation", name, perfetto::Track::FromPointer(request),
+                    arg_name, arg_value);
 }
 
 network::mojom::RequestDestination GetDestinationFromFrameTreeNode(
@@ -1474,10 +1470,11 @@
     base::debug::DumpWithoutCrashing();
   }
 
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("navigation", "NavigationRequest",
-                                    navigation_id_, "navigation_request", this);
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("navigation", "Initializing",
-                                    navigation_id_);
+  TRACE_EVENT_BEGIN("navigation", "NavigationRequest",
+                    perfetto::Track::FromPointer(this),
+                    ChromeTrackEvent::kNavigationWhenCreated, this);
+  TRACE_EVENT_BEGIN("navigation", "Initializing",
+                    perfetto::Track::FromPointer(this));
 
   if (GetInitiatorFrameToken().has_value()) {
     RenderFrameHostImpl* initiator_rfh = RenderFrameHostImpl::FromFrameToken(
@@ -1716,11 +1713,12 @@
   DCHECK(is_safe_to_delete_);
 #endif
 
-  // Close the last child event. Tracing no longer outputs the end event name,
-  // so we can simply pass an empty string here.
-  TRACE_EVENT_NESTABLE_ASYNC_END0("navigation", "", navigation_id_);
-  TRACE_EVENT_NESTABLE_ASYNC_END0("navigation", "NavigationRequest",
-                                  navigation_id_);
+  // Close the events corresponding to the "NavigationRequest" slice (started
+  // from the constructor) and its child slice corresponding to the
+  // NavigationRequest's state.
+  TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
+  TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
+
   if (loading_mem_tracker_)
     loading_mem_tracker_->Cancel();
   ResetExpectedProcess();
@@ -2353,6 +2351,7 @@
 
 void NavigationRequest::ResetForCrossDocumentRestart() {
   DCHECK(IsSameDocument());
+  EnterChildTraceEvent("ResetForCrossDocumentRestart", this);
 
   // TODO(crbug.com/1188513): A same document history navigation was performed
   // but the renderer thinks there's a different document loaded. Where did
@@ -6292,9 +6291,60 @@
   return origin;
 }
 
+namespace {
+
+using NavigationType = blink::mojom::NavigationType;
+using NavigationProto = perfetto::protos::pbzero::NavigationHandle;
+using NavigationTypeProto =
+    perfetto::protos::pbzero::NavigationHandle::NavigationType;
+using FrameTypeProto = perfetto::protos::pbzero::NavigationHandle::FrameType;
+
+NavigationTypeProto NavigationTypeToProto(NavigationType navigation_type) {
+  switch (navigation_type) {
+    case NavigationType::RELOAD:
+      return NavigationProto::RELOAD;
+    case NavigationType::RELOAD_BYPASSING_CACHE:
+      return NavigationProto::RELOAD_BYPASSING_CACHE;
+    case NavigationType::RELOAD_ORIGINAL_REQUEST_URL:
+      return NavigationProto::RELOAD_ORIGINAL_REQUEST_URL;
+    case NavigationType::RESTORE:
+      return NavigationProto::RESTORE;
+    case NavigationType::RESTORE_WITH_POST:
+      return NavigationProto::RESTORE_WITH_POST;
+    case NavigationType::HISTORY_SAME_DOCUMENT:
+      return NavigationProto::HISTORY_SAME_DOCUMENT;
+    case NavigationType::HISTORY_DIFFERENT_DOCUMENT:
+      return NavigationProto::HISTORY_DIFFERENT_DOCUMENT;
+    case NavigationType::SAME_DOCUMENT:
+      return NavigationProto::SAME_DOCUMENT;
+    case NavigationType::DIFFERENT_DOCUMENT:
+      return NavigationProto::DIFFERENT_DOCUMENT;
+  }
+  return NavigationProto::NAVIGATION_TYPE_UNSPECIFIED;
+}
+
+FrameTypeProto FrameTypeToProto(FrameType frame_type) {
+  switch (frame_type) {
+    case FrameType::kSubframe:
+      return NavigationProto::SUBFRAME;
+    case FrameType::kPrimaryMainFrame:
+      return NavigationProto::PRIMARY_MAIN_FRAME;
+    case FrameType::kPrerenderMainFrame:
+      return NavigationProto::PRERENDER_MAIN_FRAME;
+    case FrameType::kFencedFrameRoot:
+      return NavigationProto::FENCED_FRAME_ROOT;
+  }
+  return NavigationProto::FRAME_TYPE_UNSPECIFIED;
+}
+
+}  // namespace
+
 void NavigationRequest::WriteIntoTrace(
     perfetto::TracedProto<TraceProto> ctx) const {
   ctx->set_navigation_id(navigation_id_);
+  ctx->set_navigation_type(
+      NavigationTypeToProto(common_params_->navigation_type));
+  ctx->set_frame_type(FrameTypeToProto(GetNavigatingFrameType()));
   ctx->set_has_committed(HasCommitted());
   ctx->set_is_error_page(IsErrorPage());
   ctx.Set(TraceProto::kFrameTreeNode, frame_tree_node_);
diff --git a/content/browser/renderer_host/origin_agent_cluster_browsertest.cc b/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
index 77969396..1b9bd39 100644
--- a/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
+++ b/content/browser/renderer_host/origin_agent_cluster_browsertest.cc
@@ -41,7 +41,10 @@
 class OriginAgentClusterBrowserTest : public ContentBrowserTest {
  public:
   OriginAgentClusterBrowserTest()
-      : OriginAgentClusterBrowserTest(false, false) {}
+      : OriginAgentClusterBrowserTest(
+            /* origin_cluster_default_enabled */ false,
+            /* origin_cluster_absent_warning */ false,
+            /* secure_context */ true) {}
   ~OriginAgentClusterBrowserTest() override = default;
 
   void SetUp() override {
@@ -55,10 +58,12 @@
   enum OriginAgentClusterState { kUnset, kSetTrue, kSetFalse, kMalformed };
 
   OriginAgentClusterBrowserTest(bool origin_cluster_default_enabled,
-                                bool origin_cluster_absent_warning)
+                                bool origin_cluster_absent_warning,
+                                bool secure_context)
       : server_(net::EmbeddedTestServer::TYPE_HTTPS),
         origin_cluster_default_enabled_(origin_cluster_default_enabled),
-        origin_cluster_absent_warning_(origin_cluster_absent_warning) {
+        origin_cluster_absent_warning_(origin_cluster_absent_warning),
+        secure_context_(secure_context) {
     server_.AddDefaultHandlers(GetTestDataFilePath());
 
     // InitWithFeatures needs to be called in the constructor in multi-threaded
@@ -94,7 +99,9 @@
     mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
   }
 
-  net::EmbeddedTestServer* server() { return &server_; }
+  net::EmbeddedTestServer* server() {
+    return secure_context_ ? &server_ : embedded_test_server();
+  }
 
   RenderProcessHost* NavigateAndGetProcess(const char* domain,
                                            OriginAgentClusterState oac_state) {
@@ -190,6 +197,7 @@
 
   const bool origin_cluster_default_enabled_;
   const bool origin_cluster_absent_warning_;
+  const bool secure_context_;
   base::test::ScopedFeatureList features_;
 };
 
@@ -199,7 +207,10 @@
     : public OriginAgentClusterBrowserTest {
  public:
   OriginAgentClusterEnabledBrowserTest()
-      : OriginAgentClusterBrowserTest(true, false) {}
+      : OriginAgentClusterBrowserTest(
+            /* origin_cluster_default_enabled */ true,
+            /* origin_cluster_absent_warning */ false,
+            /* secure_context */ true) {}
   ~OriginAgentClusterEnabledBrowserTest() override = default;
 };
 
@@ -209,10 +220,26 @@
     : public OriginAgentClusterBrowserTest {
  public:
   OriginAgentClusterWarningBrowserTest()
-      : OriginAgentClusterBrowserTest(false, true) {}
+      : OriginAgentClusterBrowserTest(
+            /* origin_cluster_default_enabled */ false,
+            /* origin_cluster_absent_warning */ true,
+            /* secure_context */ true) {}
   ~OriginAgentClusterWarningBrowserTest() override = default;
 };
 
+// Test fixture wih the default behaviour change enabled, but using an insecure
+// context. (blink::features::kOriginAgentClusterDefaultEnabled + http:)
+class OriginAgentClusterInsecureEnabledBrowserTest
+    : public OriginAgentClusterBrowserTest {
+ public:
+  OriginAgentClusterInsecureEnabledBrowserTest()
+      : OriginAgentClusterBrowserTest(
+            /* origin_cluster_default_enabled */ true,
+            /* origin_cluster_absent_warning */ false,
+            /* secure_context */ false) {}
+  ~OriginAgentClusterInsecureEnabledBrowserTest() override = default;
+};
+
 // DocumentDomain: Can we set document.domain?
 //
 // Tests are for each Origin-Agent-Cluster: header state
@@ -435,4 +462,32 @@
   SetEnterprisePolicy(true);
   EXPECT_FALSE(CanDocumentDomain("a.domain.test", "domain.test", kMalformed));
 }
+
+// Test that the legacy behaviour continues working in insecure contexts.
+//
+// Origin-Agent-Cluster: is supposed to be a "powerful feature", which is
+// restricted to secure contexts. But disabling it is certainly not powerful,
+// and is specifically geared towards legacy applications, which means we
+// should ensure that one can still set document.domain in an insecure context
+// when Origin-Agent-Cluster: ?0 is set.
+
+IN_PROC_BROWSER_TEST_F(OriginAgentClusterInsecureEnabledBrowserTest,
+                       DocumentDomain_Default) {
+  EXPECT_TRUE(CanDocumentDomain("a.domain.test", "domain.test", kUnset));
+}
+
+IN_PROC_BROWSER_TEST_F(OriginAgentClusterInsecureEnabledBrowserTest,
+                       DocumentDomain_Disabled) {
+  EXPECT_TRUE(CanDocumentDomain("a.domain.test", "domain.test", kSetFalse));
+}
+
+IN_PROC_BROWSER_TEST_F(OriginAgentClusterInsecureEnabledBrowserTest,
+                       DocumentDomain_Malformed) {
+  EXPECT_TRUE(CanDocumentDomain("a.domain.test", "domain.test", kMalformed));
+}
+
+// We are (deliberately) not testing the kSetTrue case in this set of tests,
+// since that is bound to a secure context. But the disable cases should
+// continue to remain compatible with legacy behaviour.
+
 }  // namespace content
diff --git a/content/browser/renderer_host/policy_container_host.cc b/content/browser/renderer_host/policy_container_host.cc
index d1c10cd..936a1ba8 100644
--- a/content/browser/renderer_host/policy_container_host.cc
+++ b/content/browser/renderer_host/policy_container_host.cc
@@ -216,6 +216,7 @@
 
   return blink::mojom::PolicyContainer::New(
       blink::mojom::PolicyContainerPolicies::New(
+          policies_.cross_origin_embedder_policy.value,
           policies_.referrer_policy, policies_.ip_address_space,
           mojo::Clone(policies_.content_security_policies)),
       std::move(remote));
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 2e6a145..305e8a3c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1131,6 +1131,7 @@
 
   return std::make_unique<blink::WebPolicyContainer>(
       blink::WebPolicyContainerPolicies{
+          in->policies->cross_origin_embedder_policy,
           in->policies->referrer_policy,
           in->policies->ip_address_space,
           ToWebContentSecurityPolicies(
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c547597..c89f78f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2205,6 +2205,7 @@
     "../browser/interest_group/auction_runner_unittest.cc",
     "../browser/interest_group/auction_url_loader_factory_proxy_unittest.cc",
     "../browser/interest_group/auction_worklet_manager_unittest.cc",
+    "../browser/interest_group/interest_group_permissions_cache_unittest.cc",
     "../browser/interest_group/interest_group_permissions_checker_unittest.cc",
     "../browser/interest_group/interest_group_storage_unittest.cc",
     "../browser/loader/cors_origin_pattern_setter_unittest.cc",
diff --git a/gin/array_buffer.cc b/gin/array_buffer.cc
index 7b5e613..0adc026 100644
--- a/gin/array_buffer.cc
+++ b/gin/array_buffer.cc
@@ -45,7 +45,7 @@
 
 void* ArrayBufferAllocator::AllocateInternal(size_t length,
                                              unsigned int flags) {
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   // The V8 sandbox requires all ArrayBuffer backing stores to be allocated
   // inside the sandbox address space. This isn't guaranteed if allocation
   // override hooks (which are e.g. used by GWP-ASan) are enabled or if a
@@ -58,7 +58,7 @@
 
 void ArrayBufferAllocator::Free(void* data, size_t length) {
   unsigned int flags = 0;
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   // See |AllocateInternal|.
   flags |= partition_alloc::FreeFlags::kNoMemoryToolOverride;
 #endif
@@ -142,7 +142,7 @@
 // ArrayBufferSharedMemoryMapper ---------------------------------------------
 
 namespace {
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
 // When the V8 sandbox is enabled, shared memory backing ArrayBuffers must be
 // mapped into the sandbox address space. This custom SharedMemoryMapper
 // implements this.
@@ -201,10 +201,10 @@
     address_space->FreeSharedPages(address, mapping_size);
   }
 };
-#endif  // V8_SANDBOX
+#endif  // V8_ENABLE_SANDBOX
 
 base::SharedMemoryMapper* CreateSharedMemoryMapperForArrayBuffers() {
-#if V8_SANDBOX
+#if V8_ENABLE_SANDBOX
   static ArrayBufferSharedMemoryMapper instance;
   // Currently, it is still possible for the sandbox to be disabled at runtime
   // (by not initializing it), in which case the default shared memory mapper
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index ec8de59..b908194 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -373,11 +373,11 @@
   // of the virtual memory cage, already use V8's random number generator.
   v8::V8::SetEntropySource(&GenerateEntropy);
 
-#if defined(V8_SANDBOX)
+#if defined(V8_ENABLE_SANDBOX)
   static_assert(ARCH_CPU_64_BITS, "V8 sandbox can only work in 64-bit builds");
   // For now, initializing the sandbox is optional, and we only do it if the
   // correpsonding feature is enabled. In the future, it will be mandatory when
-  // compiling with V8_SANDBOX.
+  // compiling with V8_ENABLE_SANDBOX.
   // However, if V8 uses sandboxed pointers, then the sandbox must be
   // initialized as sandboxed pointers are simply offsets inside the sandbox.
 #if defined(V8_SANDBOXED_POINTERS)
@@ -406,7 +406,7 @@
     // TODO(1218005) remove this once the finch trial has ended.
     base::UmaHistogramSparse("V8.VirtualMemoryCageSizeGB", sizeInGB);
   }
-#endif  // V8_SANDBOX
+#endif  // V8_ENABLE_SANDBOX
 
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
   if (g_mapped_snapshot) {
@@ -420,7 +420,7 @@
 
   v8_is_initialized = true;
 
-#if defined(V8_SANDBOX)
+#if defined(V8_ENABLE_SANDBOX)
   if (v8_sandbox_is_initialized) {
     // These values are persisted to logs. Entries should not be renumbered and
     // numeric values should never be reused. This should match enum
@@ -486,7 +486,7 @@
     // once sandbox initialization is mandatory.
     CHECK_NE(nullptr, GetSharedMemoryMapperForArrayBuffers());
   }
-#endif  // V8_SANDBOX
+#endif  // V8_ENABLE_SANDBOX
 
   // Initialize the partition used by gin::ArrayBufferAllocator instances. This
   // needs to happen now, after the V8 sandbox has been initialized, so that
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index 72ab4f3..f25e087b 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -124,6 +124,16 @@
 
   dump->AddScalar("size", "bytes", virtual_size);
 
+  // Some IOSurfaces have a non-trivial difference between their mapped size
+  // and their "dirty" size, possibly because some of it has been marked
+  // purgeable, and has been purged (rather than swapped out). Report resident
+  // + swapped, as it is the fraction of memory which is: (a) using actual
+  // memory, and (b) counted in private memory footprint.
+  //
+  // Note: not using "dirty_size", as it doesn't contain the swapped out part.
+  dump->AddScalar("resident_swapped", "bytes",
+                  resident_size + swapped_out_size);
+
   return true;
 }
 }  // namespace
diff --git "a/infra/config/generated/builders/ci/Android ASAN \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Android ASAN \050dbg\051/properties.json"
index 8252801..b7e759ef 100644
--- "a/infra/config/generated/builders/ci/Android ASAN \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Android ASAN \050dbg\051/properties.json"
@@ -1,4 +1,50 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Android ASAN (dbg)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-android-archive",
+              "builder_group": "chromium.android",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_android_config": {
+                "config": "clang_builder_mb"
+              },
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "errorprone"
+                ],
+                "build_config": "Debug",
+                "config": "android_clang",
+                "target_bits": 32,
+                "target_platform": "android"
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "android",
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Android ASAN (dbg)",
+          "project": "chromium"
+        }
+      ]
+    }
+  },
   "$build/reclient": {
     "instance": "rbe-chromium-trusted",
     "jobs": 500,
diff --git a/infra/config/generated/builders/ci/Linux CFI/properties.json b/infra/config/generated/builders/ci/Linux CFI/properties.json
index aed0bc6..4f59144 100644
--- a/infra/config/generated/builders/ci/Linux CFI/properties.json
+++ b/infra/config/generated/builders/ci/Linux CFI/properties.json
@@ -1,4 +1,48 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux CFI",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux CFI",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "linux_chromium_cfi_rel_ng",
+          "group": "tryserver.chromium.linux"
+        }
+      ]
+    }
+  },
   "$build/reclient": {
     "instance": "rbe-chromium-trusted",
     "jobs": 500,
diff --git a/infra/config/generated/builders/ci/Linux TSan Builder/properties.json b/infra/config/generated/builders/ci/Linux TSan Builder/properties.json
index aed0bc6..03c3fda4 100644
--- a/infra/config/generated/builders/ci/Linux TSan Builder/properties.json
+++ b/infra/config/generated/builders/ci/Linux TSan Builder/properties.json
@@ -1,4 +1,89 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Builder",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              }
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Tests",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Linux TSan Builder",
+                "project": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Builder",
+          "project": "chromium"
+        }
+      ],
+      "builder_ids_in_scope_for_testing": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Tests",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "linux_chromium_tsan_rel_ng",
+          "group": "tryserver.chromium.linux"
+        }
+      ]
+    }
+  },
   "$build/reclient": {
     "instance": "rbe-chromium-trusted",
     "jobs": 500,
diff --git a/infra/config/generated/builders/ci/Linux TSan Tests/properties.json b/infra/config/generated/builders/ci/Linux TSan Tests/properties.json
index 70ef393..0f977aa 100644
--- a/infra/config/generated/builders/ci/Linux TSan Tests/properties.json
+++ b/infra/config/generated/builders/ci/Linux TSan Tests/properties.json
@@ -1,4 +1,82 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Builder",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              }
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Tests",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Linux TSan Builder",
+                "project": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Tests",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "linux_chromium_tsan_rel_ng",
+          "group": "tryserver.chromium.linux"
+        }
+      ]
+    }
+  },
   "$build/reclient": {
     "instance": "rbe-chromium-trusted",
     "jobs": 80,
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
index 7b6421ea..087c778 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
@@ -67,5 +67,8 @@
     ]
   },
   "builder_group": "chromium.fuchsia.fyi",
-  "recipe": "chromium"
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "fuchsia"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
index 145c3223..c741980 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
@@ -59,5 +59,8 @@
     ]
   },
   "builder_group": "chromium.fuchsia.fyi",
-  "recipe": "chromium"
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "fuchsia"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
index 3d8895c3..db44f64 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
@@ -65,5 +65,8 @@
     ]
   },
   "builder_group": "chromium.fuchsia.fyi",
-  "recipe": "chromium"
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "fuchsia"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux_chromium_cfi_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_cfi_rel_ng/properties.json
index 19e0479..ad5fa36 100644
--- a/infra/config/generated/builders/try/linux_chromium_cfi_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_cfi_rel_ng/properties.json
@@ -1,4 +1,42 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux CFI",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux CFI",
+          "project": "chromium"
+        }
+      ]
+    }
+  },
   "$build/goma": {
     "enable_ats": true,
     "rpc_extra_params": "?prod",
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
index 39082a33..442bfd5 100644
--- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
@@ -1,4 +1,86 @@
 {
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Builder",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              }
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Tests",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Linux TSan Builder",
+                "project": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Builder",
+          "project": "chromium"
+        }
+      ],
+      "builder_ids_in_scope_for_testing": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Tests",
+          "project": "chromium"
+        }
+      ],
+      "rts_config": {
+        "condition": "QUICK_RUN_ONLY"
+      }
+    }
+  },
   "$build/goma": {
     "enable_ats": true,
     "jobs": 150,
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
index ba82e73..8ca01a17 100644
--- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
@@ -3,6 +3,88 @@
     "compilator": "linux_chromium_tsan_rel_ng-compilator",
     "compilator_watcher_git_revision": "7809a690bbd935bcb3b4d922e24cabe168aaabc8"
   },
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Builder",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              }
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux TSan Tests",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-memory-archive",
+              "builder_group": "chromium.memory",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_tsan2",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "enable_reclient"
+                ],
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Linux TSan Builder",
+                "project": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Builder",
+          "project": "chromium"
+        }
+      ],
+      "builder_ids_in_scope_for_testing": [
+        {
+          "bucket": "ci",
+          "builder": "Linux TSan Tests",
+          "project": "chromium"
+        }
+      ],
+      "rts_config": {
+        "condition": "QUICK_RUN_ONLY"
+      }
+    }
+  },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
     "grouping_keys": [
diff --git a/infra/config/generated/builders/try/win10_chromium_x64_rel_ng-compilator/properties.json b/infra/config/generated/builders/try/win10_chromium_x64_rel_ng-compilator/properties.json
index 2f5679a..73a053a 100644
--- a/infra/config/generated/builders/try/win10_chromium_x64_rel_ng-compilator/properties.json
+++ b/infra/config/generated/builders/try/win10_chromium_x64_rel_ng-compilator/properties.json
@@ -159,6 +159,9 @@
     ],
     "use_clang_coverage": true
   },
+  "$build/flakiness": {
+    "check_for_flakiness": true
+  },
   "$build/goma": {
     "enable_ats": false,
     "jobs": 300,
diff --git a/infra/config/generated/builders/try/win10_chromium_x64_rel_ng/properties.json b/infra/config/generated/builders/try/win10_chromium_x64_rel_ng/properties.json
index e7225eb..ababb152 100644
--- a/infra/config/generated/builders/try/win10_chromium_x64_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/win10_chromium_x64_rel_ng/properties.json
@@ -163,6 +163,9 @@
     ],
     "use_clang_coverage": true
   },
+  "$build/flakiness": {
+    "check_for_flakiness": true
+  },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
     "grouping_keys": [
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 9b2f099..d838e6f5 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -28113,7 +28113,10 @@
         '  },'
         '  "builder_group": "chromium.fuchsia.fyi",'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "fuchsia"'
+        '  ]'
         '}'
       execution_timeout_secs: 36000
       build_numbers: YES
@@ -28350,7 +28353,10 @@
         '  },'
         '  "builder_group": "chromium.fuchsia.fyi",'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "fuchsia"'
+        '  ]'
         '}'
       execution_timeout_secs: 36000
       build_numbers: YES
@@ -28429,7 +28435,10 @@
         '  },'
         '  "builder_group": "chromium.fuchsia.fyi",'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "fuchsia"'
+        '  ]'
         '}'
       execution_timeout_secs: 36000
       build_numbers: YES
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 9992211..cf6f60e 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -6726,6 +6726,26 @@
     category: "debug"
     short_name: "x64"
   }
+  builders {
+    name: "buildbucket/luci.chrome.ci/fuchsia-builder-perf-fyi"
+    category: "perf"
+    short_name: "arm64 builder"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.ci/fuchsia-builder-perf-x64"
+    category: "perf"
+    short_name: "x64 builder"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.ci/fuchsia-fyi-arm64-size"
+    category: "release"
+    short_name: "a64-size"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.ci/fuchsia-x64"
+    category: "release"
+    short_name: "chrome-x64"
+  }
   header {
     oncalls {
       name: "Chromium"
diff --git a/infra/config/generated/sheriff-rotations/fuchsia.txt b/infra/config/generated/sheriff-rotations/fuchsia.txt
new file mode 100644
index 0000000..1f7d467
--- /dev/null
+++ b/infra/config/generated/sheriff-rotations/fuchsia.txt
@@ -0,0 +1,3 @@
+ci/fuchsia-fyi-arm64-dbg
+ci/fuchsia-fyi-x64-asan
+ci/fuchsia-fyi-x64-dbg
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index c69961a4..8dd4c1b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -39,6 +39,28 @@
 
 ci.builder(
     name = "Android ASAN (dbg)",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "android",
+                "enable_reclient",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "android_clang",
+            apply_configs = [
+                "errorprone",
+            ],
+            build_config = builder_config.build_config.DEBUG,
+            target_bits = 32,
+            target_platform = builder_config.target_platform.ANDROID,
+        ),
+        android_config = builder_config.android_config(
+            config = "clang_builder_mb",
+        ),
+        build_gs_bucket = "chromium-android-archive",
+    ),
     console_view_entry = consoles.console_view_entry(
         category = "builder|arm",
         short_name = "san",
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
index 64fd8e31..0c9d29b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
@@ -5,7 +5,7 @@
 
 load("//lib/branches.star", "branches")
 load("//lib/builder_config.star", "builder_config")
-load("//lib/builders.star", "goma", "os")
+load("//lib/builders.star", "goma", "os", "sheriff_rotations")
 load("//lib/ci.star", "ci")
 load("//lib/consoles.star", "consoles")
 
@@ -19,12 +19,26 @@
     os = os.LINUX_DEFAULT,
     pool = ci.DEFAULT_POOL,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
+    sheriff_rotations = sheriff_rotations.FUCHSIA,
 )
 
 consoles.console_view(
     name = "chromium.fuchsia.fyi",
 )
 
+# The chromium.fuchsia.fyi console includes some entries for builders from the chrome project
+[branches.console_view_entry(
+    builder = "chrome:ci/{}".format(name),
+    console_view = "chromium.fuchsia.fyi",
+    category = category,
+    short_name = short_name,
+) for name, category, short_name in (
+    ("fuchsia-fyi-arm64-size", "release", "a64-size"),
+    ("fuchsia-builder-perf-fyi", "perf", "arm64 builder"),
+    ("fuchsia-builder-perf-x64", "perf", "x64 builder"),
+    ("fuchsia-x64", "release", "chrome-x64"),
+)]
+
 ci.builder(
     name = "fuchsia-fyi-arm64-dbg",
     console_view_entry = [
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index ca1dbee..b1a8aced 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -129,6 +129,23 @@
 
 linux_memory_builder(
     name = "Linux TSan Builder",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "enable_reclient",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium_tsan2",
+            apply_configs = [
+                "mb",
+            ],
+            build_config = builder_config.build_config.RELEASE,
+            target_bits = 64,
+        ),
+        build_gs_bucket = "chromium-memory-archive",
+    ),
     branch_selector = branches.STANDARD_MILESTONE,
     console_view_entry = consoles.console_view_entry(
         category = "linux|TSan v2",
@@ -139,6 +156,20 @@
 
 linux_memory_builder(
     name = "Linux CFI",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium",
+            apply_configs = [
+                "mb",
+            ],
+            build_config = builder_config.build_config.RELEASE,
+            target_bits = 64,
+        ),
+        build_gs_bucket = "chromium-memory-archive",
+    ),
     console_view_entry = consoles.console_view_entry(
         category = "cfi",
         short_name = "lnx",
@@ -353,6 +384,24 @@
 
 linux_memory_builder(
     name = "Linux TSan Tests",
+    builder_spec = builder_config.builder_spec(
+        execution_mode = builder_config.execution_mode.TEST,
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "enable_reclient",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium_tsan2",
+            apply_configs = [
+                "mb",
+            ],
+            build_config = builder_config.build_config.RELEASE,
+            target_bits = 64,
+        ),
+        build_gs_bucket = "chromium-memory-archive",
+    ),
     branch_selector = branches.STANDARD_MILESTONE,
     console_view_entry = consoles.console_view_entry(
         category = "linux|TSan v2",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index ad0cf12..cafe358 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -370,6 +370,9 @@
 
 try_.builder(
     name = "linux_chromium_cfi_rel_ng",
+    mirrors = [
+        "ci/Linux CFI",
+    ],
     cores = 32,
     # TODO(thakis): Remove once https://crbug.com/927738 is resolved.
     execution_timeout = 7 * time.hour,
@@ -497,6 +500,15 @@
 
 try_.orchestrator_builder(
     name = "linux_chromium_tsan_rel_ng",
+    mirrors = [
+        "ci/Linux TSan Builder",
+        "ci/Linux TSan Tests",
+    ],
+    try_settings = builder_config.try_settings(
+        rts_config = builder_config.rts_config(
+            condition = builder_config.rts_condition.QUICK_RUN_ONLY,
+        ),
+    ),
     compilator = "linux_chromium_tsan_rel_ng-compilator",
     branch_selector = branches.STANDARD_MILESTONE,
     main_list_view = "try",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
index 93f269e..c8b2a29 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
@@ -164,6 +164,7 @@
 
 try_.orchestrator_builder(
     name = "win10_chromium_x64_rel_ng",
+    check_for_flakiness = True,
     compilator = "win10_chromium_x64_rel_ng-compilator",
     branch_selector = branches.DESKTOP_EXTENDED_STABLE_MILESTONE,
     mirrors = [
@@ -188,6 +189,7 @@
 
 try_.compilator_builder(
     name = "win10_chromium_x64_rel_ng-compilator",
+    check_for_flakiness = True,
     branch_selector = branches.DESKTOP_EXTENDED_STABLE_MILESTONE,
     main_list_view = "try",
     # TODO (crbug.com/1245171): Revert when root issue is fixed
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index 8e91047..9c76418 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -73,7 +73,6 @@
     "//ios/chrome/browser/ui/tab_switcher/tab_grid:features",
     "//ios/chrome/browser/ui/toolbar_container:feature_flags",
     "//ios/chrome/browser/ui/util:features",
-    "//ios/chrome/browser/upgrade/utils:features",
     "//ios/chrome/browser/web:feature_flags",
     "//ios/components/security_interstitials/https_only_mode:feature",
     "//ios/public/provider/chrome/browser/app_utils:app_utils_api",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 399e6b80..27fc539 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -84,7 +84,6 @@
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/features.h"
-#import "ios/chrome/browser/upgrade/utils/features.h"
 #include "ios/chrome/browser/web/features.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/components/security_interstitials/https_only_mode/feature.h"
@@ -926,9 +925,6 @@
      flag_descriptions::kSmartSortingNewOverflowMenuName,
      flag_descriptions::kSmartSortingNewOverflowMenuDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kSmartSortingNewOverflowMenu)},
-    {"upgrade-center-refactor", flag_descriptions::kUpgradeCenterRefactorName,
-     flag_descriptions::kUpgradeCenterRefactorDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kUpgradeCenterRefactor)},
     {"autofill-enable-ranking-formula",
      flag_descriptions::kAutofillEnableRankingFormulaName,
      flag_descriptions::kAutofillEnableRankingFormulaDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 87030db..cea05c9 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -634,12 +634,6 @@
     "When enabled, the entry points to history UI from Incognito mode will be "
     "removed.";
 
-const char kUpgradeCenterRefactorName[] =
-    "Enable Upgrade Center refactored code";
-const char kUpgradeCenterRefactorDescription[] =
-    "When enabled, upgrade сenter logic is provided by a Browser Agent "
-    "not BVC.";
-
 const char kUseLensToSearchForImageName[] =
     "Use Google Lens to Search for images";
 const char kUseLensToSearchForImageDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index c512424..c058597 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -571,11 +571,6 @@
 extern const char kUpdateHistoryEntryPointsInIncognitoName[];
 extern const char kUpdateHistoryEntryPointsInIncognitoDescription[];
 
-// Title and description for the flag to enable UpgradeCenter refactored
-// code.
-extern const char kUpgradeCenterRefactorName[];
-extern const char kUpgradeCenterRefactorDescription[];
-
 // Title and description for the flag to enable using Lens to search for an
 // image from the long press context menu.
 extern const char kUseLensToSearchForImageName[];
diff --git a/ios/chrome/browser/main/BUILD.gn b/ios/chrome/browser/main/BUILD.gn
index f2c9b6568..4c7296b 100644
--- a/ios/chrome/browser/main/BUILD.gn
+++ b/ios/chrome/browser/main/BUILD.gn
@@ -63,7 +63,6 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/start_surface",
     "//ios/chrome/browser/upgrade",
-    "//ios/chrome/browser/upgrade/utils:features",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:delegate",
diff --git a/ios/chrome/browser/main/browser_agent_util.mm b/ios/chrome/browser/main/browser_agent_util.mm
index 2b50413..2bf304b 100644
--- a/ios/chrome/browser/main/browser_agent_util.mm
+++ b/ios/chrome/browser/main/browser_agent_util.mm
@@ -4,16 +4,16 @@
 
 #import "ios/chrome/browser/main/browser_agent_util.h"
 
-#include "base/feature_list.h"
-#include "components/breadcrumbs/core/features.h"
+#import "base/feature_list.h"
+#import "components/breadcrumbs/core/features.h"
 #import "ios/chrome/browser/app_launcher/app_launcher_browser_agent.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h"
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h"
 #import "ios/chrome/browser/device_sharing/device_sharing_browser_agent.h"
-#include "ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h"
 #import "ios/chrome/browser/policy/policy_watcher_browser_agent.h"
-#include "ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h"
+#import "ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h"
 #import "ios/chrome/browser/sessions/live_tab_context_browser_agent.h"
 #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
 #import "ios/chrome/browser/sessions/session_service_ios.h"
@@ -22,18 +22,18 @@
 #import "ios/chrome/browser/tabs/synced_window_delegate_browser_agent.h"
 #import "ios/chrome/browser/tabs/tab_parenting_browser_agent.h"
 #import "ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h"
+#import "ios/chrome/browser/upgrade/upgrade_center.h"
 #import "ios/chrome/browser/upgrade/upgrade_center_browser_agent.h"
-#import "ios/chrome/browser/upgrade/utils/features.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h"
 #import "ios/chrome/browser/web/web_navigation_browser_agent.h"
 #import "ios/chrome/browser/web/web_state_delegate_browser_agent.h"
-#include "ios/chrome/browser/web_state_list/session_metrics.h"
+#import "ios/chrome/browser/web_state_list/session_metrics.h"
 #import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h"
 #import "ios/chrome/browser/web_state_list/view_source_browser_agent.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_metrics_browser_agent.h"
 #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h"
-#include "ios/public/provider/chrome/browser/app_utils/app_utils_api.h"
+#import "ios/public/provider/chrome/browser/app_utils/app_utils_api.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -94,9 +94,8 @@
   if (!browser->GetBrowserState()->IsOffTheRecord())
     StartSurfaceRecentTabBrowserAgent::CreateForBrowser(browser);
 
-  if (IsUpgradeCenterRefactorEnabled()) {
-    UpgradeCenterBrowserAgent::CreateForBrowser(browser);
-  }
+  UpgradeCenterBrowserAgent::CreateForBrowser(browser,
+                                              [UpgradeCenter sharedInstance]);
 
   // This needs to be called last in case any downstream browser agents need to
   // access upstream agents created earlier in this function.
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 17ef4a4..27a5219c 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -148,6 +148,10 @@
 
 // Deprecated 05/2022.
 const char kTrialGroupV3PrefName[] = "fre_refactoringV3.trial_group";
+
+// Deprecated 05/2022.
+extern const char kAccountIdMigrationState[] = "account_id_migration_state";
+
 }  // namespace
 
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
@@ -345,6 +349,8 @@
   // already shown.
   registry->RegisterBooleanPref(
       policy::policy_prefs::kUserPolicyNotificationWasShown, false);
+
+  registry->RegisterIntegerPref(kAccountIdMigrationState, 0);
 }
 
 // This method should be periodically pruned of year+ old migrations.
@@ -427,4 +433,7 @@
 
   // Added 4/2022.
   prefs->ClearPref(kOptimizationGuideRemoteFetchingEnabled);
+
+  // Added 05/2022
+  prefs->ClearPref(kAccountIdMigrationState);
 }
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h
index aef8aff..671f77e72 100644
--- a/ios/chrome/browser/signin/authentication_service.h
+++ b/ios/chrome/browser/signin/authentication_service.h
@@ -174,10 +174,6 @@
       ios::ChromeIdentityCapabilityResult result,
       ProceduralBlock completion);
 
-  // Migrates the token service accounts stored in prefs from emails to account
-  // ids.
-  void MigrateAccountsStoredInPrefsIfNeeded();
-
   // Returns the cached MDM infos associated with |identity|. If the cache
   // is stale for |identity|, the entry might be removed.
   NSDictionary* GetCachedMDMInfo(ChromeIdentity* identity) const;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index 50cd1c63..23a3b9f3 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -65,10 +65,6 @@
   kMaxValue = kUserSignedInBeforeAndAfterDeviceRestore,
 };
 
-// A fake account id used in the list of last signed in accounts when migrating
-// an email for which the corresponding account was removed.
-constexpr char kFakeAccountIdForRemovedAccount[] = "0000000000000";
-
 // Returns the account id associated with |identity|.
 CoreAccountId ChromeIdentityToAccountID(
     signin::IdentityManager* identity_manager,
@@ -123,7 +119,8 @@
   signin::Tribool device_restore_session = IsFirstSessionAfterDeviceRestore();
   initialized_ = true;
 
-  MigrateAccountsStoredInPrefsIfNeeded();
+  DCHECK_EQ(identity_manager_->GetAccountIdMigrationState(),
+            signin::IdentityManager::AccountIdMigrationState::MIGRATION_DONE);
 
   identity_manager_observation_.Observe(identity_manager_);
   HandleForgottenIdentity(nil, /*should_prompt=*/true,
@@ -298,37 +295,6 @@
       current_accounts_info);
 }
 
-void AuthenticationService::MigrateAccountsStoredInPrefsIfNeeded() {
-  if (identity_manager_->GetAccountIdMigrationState() ==
-      signin::IdentityManager::AccountIdMigrationState::MIGRATION_NOT_STARTED) {
-    return;
-  }
-  DCHECK_EQ(signin::IdentityManager::AccountIdMigrationState::MIGRATION_DONE,
-            identity_manager_->GetAccountIdMigrationState());
-  if (pref_service_->GetBoolean(prefs::kSigninLastAccountsMigrated)) {
-    // Already migrated.
-    return;
-  }
-
-  std::vector<CoreAccountId> account_ids =
-      user_approved_account_list_manager_.GetApprovedAccountIDList();
-  std::vector<base::Value> accounts_pref_value;
-  for (const auto& account_id : account_ids) {
-    if (identity_manager_->HasAccountWithRefreshToken(account_id)) {
-      accounts_pref_value.emplace_back(account_id.ToString());
-    } else {
-      // The account for |email| was removed since the last application cold
-      // start. Insert |kFakeAccountIdForRemovedAccount| to ensure the user
-      // account list has to be approved by the user and the removal won't be
-      // silently ignored.
-      accounts_pref_value.emplace_back(kFakeAccountIdForRemovedAccount);
-    }
-  }
-  pref_service_->Set(prefs::kSigninLastAccounts,
-                     base::Value(std::move(accounts_pref_value)));
-  pref_service_->SetBoolean(prefs::kSigninLastAccountsMigrated, true);
-}
-
 bool AuthenticationService::HasPrimaryIdentity(
     signin::ConsentLevel consent_level) const {
   return GetPrimaryIdentity(consent_level) != nil;
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index 58bff29..21e8fccd 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -186,7 +186,6 @@
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/browser/ui/webui",
     "//ios/chrome/browser/upgrade",
-    "//ios/chrome/browser/upgrade/utils:features",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/voice:voice",
     "//ios/chrome/browser/web",
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 84190b7..fb05ed5 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -134,7 +134,6 @@
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller_factory.h"
 #include "ios/chrome/browser/upgrade/upgrade_center.h"
-#import "ios/chrome/browser/upgrade/utils/features.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_observer_bridge.h"
@@ -4015,12 +4014,6 @@
   if (webState == self.currentWebState) {
     self.browserContainerViewController.contentView = nil;
   }
-
-  if (!IsUpgradeCenterRefactorEnabled()) {
-    // TODO(crbug.com/1272546): Move UpgradeCenter updates into a browser agent.
-    [[UpgradeCenter sharedInstance]
-        tabWillClose:webState->GetStableIdentifier()];
-  }
 }
 
 // Observer method, WebState replaced in |webStateList|.
@@ -4053,23 +4046,6 @@
     return;
   }
 
-  if (!IsUpgradeCenterRefactorEnabled()) {
-    // When adding new tabs, check what kind of reminder infobar should
-    // be added to the new tab. Try to add only one of them.
-    // This check is done when a new tab is added either through the Tools Menu
-    // "New Tab", through a long press on the Tab Switcher button "New Tab", and
-    // through creating a New Tab from the Tab Switcher. This logic needs to
-    // happen after a new WebState has added and finished initial navigation. If
-    // this happens earlier, the initial navigation may end up clearing the
-    // infobar(s) that are just added.
-    // TODO(crbug.com/1272546): Move UpgradeCenter updates into a browser agent.
-    infobars::InfoBarManager* infoBarManager =
-        InfoBarManagerImpl::FromWebState(webState);
-    NSString* tabID = webState->GetStableIdentifier();
-    [[UpgradeCenter sharedInstance] addInfoBarToManager:infoBarManager
-                                               forTabId:tabID];
-  }
-
   if (!IsDisplaySyncErrorsRefactorEnabled()) {
     if (!ReSignInInfoBarDelegate::Create(self.browserState, webState,
                                          self /* id<SigninPresenter> */)) {
diff --git a/ios/chrome/browser/ui/icons/chrome_symbol.h b/ios/chrome/browser/ui/icons/chrome_symbol.h
index 12c6fdb..93f22efa 100644
--- a/ios/chrome/browser/ui/icons/chrome_symbol.h
+++ b/ios/chrome/browser/ui/icons/chrome_symbol.h
@@ -36,6 +36,7 @@
 extern NSString* const kWarningSymbol;
 extern NSString* const kWarningFillSymbol;
 extern NSString* const kHelpFillSymbol;
+extern NSString* const kCheckMarkCircleSymbol;
 extern NSString* const kCheckMarkCircleFillSymbol;
 extern NSString* const kFailMarkCircleFillSymbol;
 extern NSString* const kTrashSymbol;
diff --git a/ios/chrome/browser/ui/icons/chrome_symbol.mm b/ios/chrome/browser/ui/icons/chrome_symbol.mm
index e0954dc..2ffc9e5 100644
--- a/ios/chrome/browser/ui/icons/chrome_symbol.mm
+++ b/ios/chrome/browser/ui/icons/chrome_symbol.mm
@@ -74,6 +74,7 @@
 NSString* const kWarningSymbol = @"exclamationmark.triangle";
 NSString* const kWarningFillSymbol = @"exclamationmark.triangle.fill";
 NSString* const kHelpFillSymbol = @"questionmark.circle";
+NSString* const kCheckMarkCircleSymbol = @"checkmark.circle";
 NSString* const kCheckMarkCircleFillSymbol = @"checkmark.circle.fill";
 NSString* const kFailMarkCircleFillSymbol = @"exclamationmark.circle.fill";
 NSString* const kTrashSymbol = @"trash";
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index 8b49ab48..6fa7fa6 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -288,7 +288,7 @@
 
 - (UIAction*)actionToSelectTabsWithBlock:(ProceduralBlock)block {
   UIImage* image = UseSymbols()
-                       ? DefaultSymbolWithPointSize(kCheckMarkCircleFillSymbol,
+                       ? DefaultSymbolWithPointSize(kCheckMarkCircleSymbol,
                                                     kSymbolActionPointSize)
                        : [UIImage imageNamed:@"select"];
   UIAction* action = [self
diff --git a/ios/chrome/browser/ui/menu/action_factory_unittest.mm b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
index 387cc37..7b3b5c4 100644
--- a/ios/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -362,8 +362,8 @@
   ActionFactory* factory =
       [[ActionFactory alloc] initWithScenario:kTestMenuScenario];
 
-  UIImage* expectedImage = DefaultSymbolWithPointSize(
-      kCheckMarkCircleFillSymbol, kSymbolActionPointSize);
+  UIImage* expectedImage = DefaultSymbolWithPointSize(kCheckMarkCircleSymbol,
+                                                      kSymbolActionPointSize);
   NSString* expectedTitle =
       l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_SELECTTABS);
 
diff --git a/ios/chrome/browser/upgrade/BUILD.gn b/ios/chrome/browser/upgrade/BUILD.gn
index 698c50c..900ee79a 100644
--- a/ios/chrome/browser/upgrade/BUILD.gn
+++ b/ios/chrome/browser/upgrade/BUILD.gn
@@ -23,7 +23,6 @@
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/util",
-    "//ios/chrome/browser/upgrade/utils:features",
     "//ios/chrome/browser/web_state_list",
     "//ios/web/common",
     "//net",
@@ -49,10 +48,19 @@
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
-  sources = [ "upgrade_center_unittest.mm" ]
+  sources = [
+    "upgrade_center_browser_agent_unittest.mm",
+    "upgrade_center_unittest.mm",
+  ]
   deps = [
     ":upgrade",
     "//base",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/main:test_support",
+    "//ios/chrome/browser/upgrade/test",
+    "//ios/chrome/browser/web_state_list:web_state_list",
+    "//ios/web/public/test:test",
+    "//ios/web/public/test/fakes:fakes",
     "//testing/gtest",
   ]
 }
diff --git a/ios/chrome/browser/upgrade/test/BUILD.gn b/ios/chrome/browser/upgrade/test/BUILD.gn
new file mode 100644
index 0000000..445b0ffe
--- /dev/null
+++ b/ios/chrome/browser/upgrade/test/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2022 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.
+
+source_set("test") {
+  testonly = true
+  sources = [
+    "fake_upgrade_center.h",
+    "fake_upgrade_center.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser/upgrade",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/upgrade/test/fake_upgrade_center.h b/ios/chrome/browser/upgrade/test/fake_upgrade_center.h
new file mode 100644
index 0000000..26756a5
--- /dev/null
+++ b/ios/chrome/browser/upgrade/test/fake_upgrade_center.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UPGRADE_TEST_FAKE_UPGRADE_CENTER_H_
+#define IOS_CHROME_BROWSER_UPGRADE_TEST_FAKE_UPGRADE_CENTER_H_
+
+#import "ios/chrome/browser/upgrade/upgrade_center.h"
+
+// A wrappeer to NSObject for InfoBarManager.
+@interface InfoBarManagerHolder : NSObject
+
+@property(nonatomic) infobars::InfoBarManager* infoBarManager;
+
+@end
+
+// Fake version of UpgradeCenter that allows access to consumed values.
+@interface FakeUpgradeCenter : UpgradeCenter
+
+@property(nonatomic, readonly)
+    NSDictionary<NSString*, InfoBarManagerHolder*>* infoBarManagers;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UPGRADE_TEST_FAKE_UPGRADE_CENTER_H_
diff --git a/ios/chrome/browser/upgrade/test/fake_upgrade_center.mm b/ios/chrome/browser/upgrade/test/fake_upgrade_center.mm
new file mode 100644
index 0000000..7d998aa
--- /dev/null
+++ b/ios/chrome/browser/upgrade/test/fake_upgrade_center.mm
@@ -0,0 +1,44 @@
+// Copyright 2022 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 "ios/chrome/browser/upgrade/test/fake_upgrade_center.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation InfoBarManagerHolder
+
+@end
+
+@implementation FakeUpgradeCenter {
+  NSMutableDictionary<NSString*, InfoBarManagerHolder*>* _infoBarManagers;
+}
+
+- (instancetype)init {
+  self = [super init];
+  if (self) {
+    _infoBarManagers = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+
+- (NSDictionary<NSString*, InfoBarManagerHolder*>*)infoBarManagers {
+  return [_infoBarManagers copy];
+}
+
+- (void)addInfoBarToManager:(infobars::InfoBarManager*)infoBarManager
+                   forTabId:(NSString*)tabID {
+  InfoBarManagerHolder* infoBarManagerHolder =
+      [[InfoBarManagerHolder alloc] init];
+  infoBarManagerHolder.infoBarManager = infoBarManager;
+
+  [_infoBarManagers setObject:infoBarManagerHolder forKey:tabID];
+}
+
+- (void)tabWillClose:(NSString*)tabID {
+  [_infoBarManagers removeObjectForKey:tabID];
+}
+
+@end
diff --git a/ios/chrome/browser/upgrade/upgrade_center_browser_agent.h b/ios/chrome/browser/upgrade/upgrade_center_browser_agent.h
index 59c26a3..3cbafdd7 100644
--- a/ios/chrome/browser/upgrade/upgrade_center_browser_agent.h
+++ b/ios/chrome/browser/upgrade/upgrade_center_browser_agent.h
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 
 class Browser;
+@class UpgradeCenter;
 
 // Browser agent that handles informing the update center of new tabs.
 class UpgradeCenterBrowserAgent
@@ -17,6 +18,9 @@
       public WebStateListObserver,
       public BrowserUserData<UpgradeCenterBrowserAgent> {
  public:
+  // Creates an UpgradeCenterBrowserAgent scoped to |browser|.
+  static void CreateForBrowser(Browser* browser, UpgradeCenter* upgradeCenter);
+
   UpgradeCenterBrowserAgent(const UpgradeCenterBrowserAgent&) = delete;
   UpgradeCenterBrowserAgent& operator=(const UpgradeCenterBrowserAgent&) =
       delete;
@@ -24,10 +28,11 @@
   ~UpgradeCenterBrowserAgent() override;
 
  private:
-  explicit UpgradeCenterBrowserAgent(Browser* browser);
   friend class BrowserUserData<UpgradeCenterBrowserAgent>;
   BROWSER_USER_DATA_KEY_DECL();
 
+  UpgradeCenterBrowserAgent(Browser* browser, UpgradeCenter* upgradeCenter);
+
   // BrowserObserver methods
   void BrowserDestroyed(Browser* browser) override;
 
@@ -41,7 +46,7 @@
                             web::WebState* web_state,
                             int index) override;
 
-  Browser* browser_ = nullptr;
+  __strong UpgradeCenter* upgrade_center_ = nullptr;
 };
 
 #endif  // IOS_CHROME_BROWSER_UPGRADE_UPGRADE_CENTER_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/upgrade/upgrade_center_browser_agent.mm b/ios/chrome/browser/upgrade/upgrade_center_browser_agent.mm
index 5bbd80a..e92612e8 100644
--- a/ios/chrome/browser/upgrade/upgrade_center_browser_agent.mm
+++ b/ios/chrome/browser/upgrade/upgrade_center_browser_agent.mm
@@ -15,8 +15,24 @@
 
 BROWSER_USER_DATA_KEY_IMPL(UpgradeCenterBrowserAgent)
 
-UpgradeCenterBrowserAgent::UpgradeCenterBrowserAgent(Browser* browser) {
+// static
+void UpgradeCenterBrowserAgent::CreateForBrowser(
+    Browser* browser,
+    UpgradeCenter* upgrade_center) {
   DCHECK(browser);
+  if (!FromBrowser(browser)) {
+    browser->SetUserData(UserDataKey(),
+                         base::WrapUnique(new UpgradeCenterBrowserAgent(
+                             browser, upgrade_center)));
+  }
+}
+
+UpgradeCenterBrowserAgent::UpgradeCenterBrowserAgent(
+    Browser* browser,
+    UpgradeCenter* upgrade_center)
+    : upgrade_center_(upgrade_center) {
+  DCHECK(browser);
+  DCHECK(upgrade_center);
   browser->AddObserver(this);
   browser->GetWebStateList()->AddObserver(this);
 }
@@ -47,10 +63,7 @@
       InfoBarManagerImpl::FromWebState(web_state);
   NSString* tabID = web_state->GetStableIdentifier();
 
-  // TODO(crbug.com/1324514): Replace [UpgradeCenter sharedInstance] with a
-  // dependency
-  [[UpgradeCenter sharedInstance] addInfoBarToManager:infoBarManager
-                                             forTabId:tabID];
+  [upgrade_center_ addInfoBarToManager:infoBarManager forTabId:tabID];
 }
 
 void UpgradeCenterBrowserAgent::WillDetachWebStateAt(
@@ -59,8 +72,5 @@
     int index) {
   DCHECK(web_state);
 
-  // TODO(crbug.com/1324514): Replace [UpgradeCenter sharedInstance] with a
-  // dependency
-  [[UpgradeCenter sharedInstance]
-      tabWillClose:web_state->GetStableIdentifier()];
+  [upgrade_center_ tabWillClose:web_state->GetStableIdentifier()];
 }
diff --git a/ios/chrome/browser/upgrade/upgrade_center_browser_agent_unittest.mm b/ios/chrome/browser/upgrade/upgrade_center_browser_agent_unittest.mm
new file mode 100644
index 0000000..5b81c6a
--- /dev/null
+++ b/ios/chrome/browser/upgrade/upgrade_center_browser_agent_unittest.mm
@@ -0,0 +1,75 @@
+// Copyright 2022 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 "ios/chrome/browser/upgrade/upgrade_center_browser_agent.h"
+
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/main/test_browser.h"
+#import "ios/chrome/browser/upgrade/test/fake_upgrade_center.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
+#import "ios/web/public/test/web_task_environment.h"
+#import "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+class UpgradeCenterBrowserAgentTest : public PlatformTest {
+ public:
+  UpgradeCenterBrowserAgentTest() {}
+  ~UpgradeCenterBrowserAgentTest() override {}
+
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+    browser_ = std::make_unique<TestBrowser>(browser_state_.get());
+
+    fake_upgrade_center_ = [[FakeUpgradeCenter alloc] init];
+    UpgradeCenterBrowserAgent::CreateForBrowser(browser_.get(),
+                                                fake_upgrade_center_);
+  }
+
+  web::WebTaskEnvironment task_environment_;
+  std::unique_ptr<TestChromeBrowserState> browser_state_;
+  std::unique_ptr<TestBrowser> browser_;
+  FakeUpgradeCenter* fake_upgrade_center_;
+};
+
+TEST_F(UpgradeCenterBrowserAgentTest, AddsInfoBarManagerOnWebStateInsert) {
+  auto fake_web_state =
+      std::make_unique<web::FakeWebState>(@"my-stable-identifier");
+
+  browser_->GetWebStateList()->InsertWebState(
+      WebStateList::kInvalidIndex, std::move(fake_web_state),
+      WebStateList::INSERT_NO_FLAGS, WebStateOpener());
+
+  ASSERT_NE(nullptr,
+            fake_upgrade_center_.infoBarManagers[@"my-stable-identifier"]);
+  ASSERT_EQ(fake_upgrade_center_.infoBarManagers.count, 1U);
+}
+
+TEST_F(UpgradeCenterBrowserAgentTest, RemovesInfoBarManagerOnWebStateDetach) {
+  auto fake_web_state =
+      std::make_unique<web::FakeWebState>(@"my-other-stable-identifier");
+
+  browser_->GetWebStateList()->InsertWebState(
+      WebStateList::kInvalidIndex, std::move(fake_web_state),
+      WebStateList::INSERT_NO_FLAGS, WebStateOpener());
+
+  ASSERT_NE(
+      nullptr,
+      fake_upgrade_center_.infoBarManagers[@"my-other-stable-identifier"]);
+  ASSERT_EQ(fake_upgrade_center_.infoBarManagers.count, 1U);
+
+  browser_->GetWebStateList()->DetachWebStateAt(0);
+
+  ASSERT_EQ(
+      nullptr,
+      fake_upgrade_center_.infoBarManagers[@"my-other-stable-identifier"]);
+  ASSERT_EQ(fake_upgrade_center_.infoBarManagers.count, 0U);
+}
diff --git a/ios/chrome/browser/upgrade/utils/BUILD.gn b/ios/chrome/browser/upgrade/utils/BUILD.gn
deleted file mode 100644
index 0350d12..0000000
--- a/ios/chrome/browser/upgrade/utils/BUILD.gn
+++ /dev/null
@@ -1,8 +0,0 @@
-source_set("features") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "features.cc",
-    "features.h",
-  ]
-  public_deps = [ "//base" ]
-}
diff --git a/ios/chrome/browser/upgrade/utils/features.cc b/ios/chrome/browser/upgrade/utils/features.cc
deleted file mode 100644
index 3c53d47..0000000
--- a/ios/chrome/browser/upgrade/utils/features.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/upgrade/utils/features.h"
-
-const base::Feature kUpgradeCenterRefactor{"UpgradeCenterRefactor",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
-
-bool IsUpgradeCenterRefactorEnabled() {
-  return base::FeatureList::IsEnabled(kUpgradeCenterRefactor);
-}
diff --git a/ios/chrome/browser/upgrade/utils/features.h b/ios/chrome/browser/upgrade/utils/features.h
deleted file mode 100644
index 52b81ef..0000000
--- a/ios/chrome/browser/upgrade/utils/features.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UPGRADE_UTILS_FEATURES_H_
-#define IOS_CHROME_BROWSER_UPGRADE_UTILS_FEATURES_H_
-
-#include "base/feature_list.h"
-
-// Feature flag to enable UpgradeCenter refactored code.
-extern const base::Feature kUpgradeCenterRefactor;
-
-// Returns true if UpgradeCenter refactored code is enabled.
-bool IsUpgradeCenterRefactorEnabled();
-
-#endif  // IOS_CHROME_BROWSER_UPGRADE_UTILS_FEATURES_H_
diff --git a/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm b/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
index 5caef4a..6c0e4f40 100644
--- a/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
+++ b/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
@@ -52,6 +52,7 @@
 @property(nonatomic, strong) UIButton* tertiaryActionButton;
 
 @property(nonatomic, strong) UIView* separator;
+@property(nonatomic, assign) CGFloat scrollViewBottomOffsetY;
 
 // Read/Write override.
 @property(nonatomic, assign, readwrite) BOOL didReachBottom;
@@ -126,11 +127,11 @@
   UILayoutGuide* widthLayoutGuide = [[UILayoutGuide alloc] init];
   [self.view addLayoutGuide:widthLayoutGuide];
 
-  NSLayoutYAxisAnchor* specificContentViewBottomAnchor =
-      self.scrollContentView.bottomAnchor;
   if (self.disclaimerView) {
-    specificContentViewBottomAnchor = self.disclaimerView.topAnchor;
     [NSLayoutConstraint activateConstraints:@[
+      [self.disclaimerView.topAnchor
+          constraintEqualToAnchor:self.specificContentView.bottomAnchor
+                         constant:kDefaultMargin],
       [self.disclaimerView.leadingAnchor
           constraintEqualToAnchor:self.scrollContentView.leadingAnchor],
       [self.disclaimerView.trailingAnchor
@@ -138,6 +139,10 @@
       [self.disclaimerView.bottomAnchor
           constraintEqualToAnchor:self.scrollContentView.bottomAnchor],
     ]];
+  } else {
+    [self.scrollContentView.bottomAnchor
+        constraintEqualToAnchor:self.specificContentView.bottomAnchor]
+        .active = YES;
   }
 
   [NSLayoutConstraint activateConstraints:@[
@@ -226,8 +231,6 @@
         constraintEqualToAnchor:self.scrollContentView.leadingAnchor],
     [self.specificContentView.trailingAnchor
         constraintEqualToAnchor:self.scrollContentView.trailingAnchor],
-    [self.specificContentView.bottomAnchor
-        constraintEqualToAnchor:specificContentViewBottomAnchor],
 
     // Action stack view constraints. Constrain the bottom of the action stack
     // view to both the bottom of the screen and the bottom of the safe area, to
@@ -236,9 +239,6 @@
         constraintEqualToAnchor:widthLayoutGuide.leadingAnchor],
     [self.actionStackView.trailingAnchor
         constraintEqualToAnchor:widthLayoutGuide.trailingAnchor],
-    [self.actionStackView.bottomAnchor
-        constraintLessThanOrEqualToAnchor:self.view.bottomAnchor
-                                 constant:-kActionsBottomMargin * 2],
   ]];
 
   self.buttonsVerticalAnchorConstraints = @[
@@ -246,6 +246,9 @@
         constraintEqualToAnchor:self.actionStackView.topAnchor
                        constant:-kDefaultMargin],
     [self.actionStackView.bottomAnchor
+        constraintLessThanOrEqualToAnchor:self.view.bottomAnchor
+                                 constant:-kActionsBottomMargin * 2],
+    [self.actionStackView.bottomAnchor
         constraintLessThanOrEqualToAnchor:self.view.safeAreaLayoutGuide
                                               .bottomAnchor
                                  constant:-kActionsBottomMargin],
@@ -316,16 +319,17 @@
     // fully visible (scrolled), set |didReachBottom| to YES. Otherwise, replace
     // the primary button's label with the read more label to indicate that more
     // scrolling is required.
+    self.scrollViewBottomOffsetY = self.scrollView.contentSize.height -
+                                   self.scrollView.bounds.size.height +
+                                   self.scrollView.contentInset.bottom;
+
     BOOL isScrolledToBottom = [self isScrolledToBottom];
     self.separator.hidden = isScrolledToBottom;
-    if (isScrolledToBottom) {
-      self.didReachBottom = YES;
-    } else if (!self.didReachBottom) {
+    if (self.didReachBottom || isScrolledToBottom) {
+      [self updateActionButtonsAndPushUpScrollView];
+    } else {
       [self setReadMoreText];
     }
-    if (self.didReachBottom) {
-      [self showSecondaryAndTertiaryButtons];
-    }
   });
 }
 
@@ -350,8 +354,8 @@
            (id<UIViewControllerTransitionCoordinator>)coordinator {
   [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
 
-  // Update the primary button once the layout changes take effect to have the
-  // right measurements to evaluate the scroll position.
+  // Update the buttons once the layout changes take effect to have the right
+  // measurements to evaluate the scroll position.
   void (^transition)(id<UIViewControllerTransitionCoordinatorContext>) =
       ^(id<UIViewControllerTransitionCoordinatorContext> context) {
         [self updateViewsOnScrollViewUpdate];
@@ -732,9 +736,8 @@
 }
 
 // If scrolling to the end of the content is mandatory, this method updates the
-// primary button's label based on whether the scroll view is currently scrolled
-// to the end. If the scroll view has scrolled to the end, also sets
-// |didReachBottom|.
+// action buttons based on whether the scroll view is currently scrolled to the
+// end. If the scroll view has scrolled to the end, also sets |didReachBottom|.
 // It also updates the separator visibility based on scroll position.
 - (void)updateViewsOnScrollViewUpdate {
   if (!self.canUpdateViewsOnScroll) {
@@ -742,22 +745,80 @@
   }
 
   BOOL isScrolledToBottom = [self isScrolledToBottom];
-
   self.separator.hidden = isScrolledToBottom;
-
   if (self.scrollToEndMandatory && !self.didReachBottom && isScrolledToBottom) {
-    self.didReachBottom = YES;
-    [self.primaryActionButton setAttributedTitle:nil
-                                        forState:UIControlStateNormal];
-    [self.primaryActionButton setTitle:self.primaryActionString
-                              forState:UIControlStateNormal];
-    // Reset the font to make sure it is properly scaled.
-    [self setPrimaryActionButtonFont:self.primaryActionButton];
-    // Add other buttons with the correct margins.
-    [self showSecondaryAndTertiaryButtons];
+    [self updateActionButtonsAndPushUpScrollView];
   }
 }
 
+// This method should be called right before the view is scrolled to the bottom.
+// It updates the primary button's label and adds secondary and/or tertiary
+// buttons, and as a result, pushing the scroll view up by updating the bottom
+// offset of the scroll view and scroll to the new offset. It also sets
+// |didReachBottom| to YES.
+- (void)updateActionButtonsAndPushUpScrollView {
+  [self.primaryActionButton setAttributedTitle:nil
+                                      forState:UIControlStateNormal];
+  [self.primaryActionButton setTitle:self.primaryActionString
+                            forState:UIControlStateNormal];
+  // Reset the font to make sure it is properly scaled.
+  [self setPrimaryActionButtonFont:self.primaryActionButton];
+
+  CGFloat originalHeightForActionStack =
+      self.primaryActionButton.bounds.size.height;
+  for (NSLayoutConstraint* constraint in self
+           .buttonsVerticalAnchorConstraints) {
+    originalHeightForActionStack += constraint.constant;
+  }
+  CGFloat newEstimatedHeightForActionStack =
+      self.primaryActionButton.bounds.size.height;
+  // Add other buttons with the correct margins.
+  if (self.secondaryActionString) {
+    [self.actionStackView insertArrangedSubview:self.secondaryActionButton
+                                        atIndex:1];
+    newEstimatedHeightForActionStack +=
+        self.secondaryActionButton.intrinsicContentSize.height;
+  }
+  if (self.tertiaryActionString) {
+    [self.actionStackView insertArrangedSubview:self.tertiaryActionButton
+                                        atIndex:0];
+    newEstimatedHeightForActionStack +=
+        self.tertiaryActionButton.intrinsicContentSize.height;
+  }
+  for (NSLayoutConstraint* constraint in self
+           .buttonsVerticalAnchorConstraints) {
+    newEstimatedHeightForActionStack += constraint.constant;
+  }
+  CGFloat estimatedHeightDifference =
+      newEstimatedHeightForActionStack - originalHeightForActionStack;
+  CGPoint updatedBottomOffset =
+      CGPointMake(0, self.scrollViewBottomOffsetY + estimatedHeightDifference);
+
+  if (self.secondaryActionString || self.tertiaryActionString) {
+    // Update constraints.
+    [NSLayoutConstraint
+        deactivateConstraints:self.buttonsVerticalAnchorConstraints];
+    self.buttonsVerticalAnchorConstraints = @[
+      [self.scrollView.bottomAnchor
+          constraintEqualToAnchor:self.actionStackView.topAnchor
+                         constant:self.tertiaryActionString ? 0
+                                                            : -kDefaultMargin],
+      [self.actionStackView.bottomAnchor
+          constraintLessThanOrEqualToAnchor:self.view.bottomAnchor
+                                   constant:-kActionsBottomMargin],
+      [self.actionStackView.bottomAnchor
+          constraintLessThanOrEqualToAnchor:self.view.safeAreaLayoutGuide
+                                                .bottomAnchor],
+    ];
+    [NSLayoutConstraint
+        activateConstraints:self.buttonsVerticalAnchorConstraints];
+  }
+  if (![self isScrolledToBottom]) {
+    [self.scrollView setContentOffset:updatedBottomOffset animated:YES];
+  }
+  self.didReachBottom = YES;
+}
+
 - (void)didTapPrimaryActionButton {
   if (self.scrollToEndMandatory && !self.didReachBottom) {
     // Calculate the offset needed to see the next content while keeping the
@@ -766,16 +827,13 @@
     CGPoint targetOffset = CGPointMake(
         0, currentOffsetY + self.scrollView.bounds.size.height *
                                 (1.0 - kPreviousContentVisibleOnScroll));
-    // Calculate the maximum possible offset. Add one point to work around some
-    // issues when the fonts are increased.
-    CGPoint bottomOffset =
-        CGPointMake(0, self.scrollView.contentSize.height -
-                           self.scrollView.bounds.size.height +
-                           self.scrollView.contentInset.bottom + 1);
-    // Scroll to the smaller of the two offsets.
-    CGPoint newOffset =
-        targetOffset.y < bottomOffset.y ? targetOffset : bottomOffset;
-    [self.scrollView setContentOffset:newOffset animated:YES];
+    // Add one point to maximum possible offset to work around some issues when
+    // the fonts are increased.
+    if (targetOffset.y < self.scrollViewBottomOffsetY + 1) {
+      [self.scrollView setContentOffset:targetOffset animated:YES];
+    } else {
+      [self updateActionButtonsAndPushUpScrollView];
+    }
   } else if ([self.delegate
                  respondsToSelector:@selector(didTapPrimaryActionButton)]) {
     [self.delegate didTapPrimaryActionButton];
@@ -844,49 +902,6 @@
   return attributedText;
 }
 
-// Function to show secondary and tertiary action buttons in the view. Called
-// when |self.scrollToEndMandatory| is false or when the user has scrolled to
-// the end.
-- (void)showSecondaryAndTertiaryButtons {
-  if (self.secondaryActionString) {
-    [self.actionStackView insertArrangedSubview:self.secondaryActionButton
-                                        atIndex:1];
-  }
-  if (self.tertiaryActionString) {
-    [self.actionStackView insertArrangedSubview:self.tertiaryActionButton
-                                        atIndex:0];
-  }
-
-  if (self.secondaryActionString || self.tertiaryActionString) {
-    // Update constraints.
-    [NSLayoutConstraint
-        deactivateConstraints:self.buttonsVerticalAnchorConstraints];
-    self.buttonsVerticalAnchorConstraints = @[
-      [self.scrollView.bottomAnchor
-          constraintEqualToAnchor:self.actionStackView.topAnchor
-                         constant:self.tertiaryActionString ? 0
-                                                            : -kDefaultMargin],
-      [self.actionStackView.bottomAnchor
-          constraintLessThanOrEqualToAnchor:self.view.bottomAnchor
-                                   constant:-kActionsBottomMargin],
-    ];
-    [NSLayoutConstraint
-        activateConstraints:self.buttonsVerticalAnchorConstraints];
-
-    // Handles the edge case that when the new buttons hide the end of the
-    // content, keep scrolling until the end is visible.
-    dispatch_after(
-        dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)),
-        dispatch_get_main_queue(), ^{
-          CGPoint bottomOffset =
-              CGPointMake(0, self.scrollView.contentSize.height -
-                                 self.scrollView.bounds.size.height +
-                                 self.scrollView.contentInset.bottom + 1);
-          [self.scrollView setContentOffset:bottomOffset animated:YES];
-        });
-  }
-}
-
 #pragma mark - UIScrollViewDelegate
 
 - (void)scrollViewDidScroll:(UIScrollView*)scrollView {
diff --git a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
index 639112be4..9f46c4a 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
@@ -76,16 +76,6 @@
       UIViewController* presentingViewController,
       void (^callback)(BOOL success, NSError* error)) = 0;
 
-  // Presents the trusted vault key reauthentication UI for |identity| for the
-  // purpose of opting into trusted vault passphrase. Once the reauth is done
-  // and the UI is dismissed, |callback| is called. |callback| is not called if
-  // the reauthentication is canceled.
-  // TODO(crbug.com/1202088): Make pure.
-  virtual void ReauthenticationForOptIn(
-      ChromeIdentity* chrome_identity,
-      UIViewController* presentingViewController,
-      void (^callback)(BOOL success, NSError* error));
-
   // Cancels the presented trusted vault reauthentication UI, triggered via
   // either Reauthentication() or via
   // FixDegradedRecoverability(). The reauthentication callback
diff --git a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
index e494799..fd1353c 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
@@ -22,11 +22,6 @@
   observer_list_.RemoveObserver(observer);
 }
 
-void ChromeTrustedVaultService::ReauthenticationForOptIn(
-    ChromeIdentity* chrome_identity,
-    UIViewController* presentingViewController,
-    void (^callback)(BOOL success, NSError* error)) {}
-
 void ChromeTrustedVaultService::NotifyKeysChanged() {
   for (Observer& observer : observer_list_) {
     observer.OnTrustedVaultKeysChanged();
diff --git a/media/gpu/test/video_encoder/video_encoder_client.cc b/media/gpu/test/video_encoder/video_encoder_client.cc
index a80a5e4..50d118b 100644
--- a/media/gpu/test/video_encoder/video_encoder_client.cc
+++ b/media/gpu/test/video_encoder/video_encoder_client.cc
@@ -52,7 +52,7 @@
     VideoCodecProfile output_profile,
     const std::vector<VideoEncodeAccelerator::Config::SpatialLayer>&
         spatial_layers,
-    const VideoBitrateAllocation& bitrate,
+    const VideoBitrateAllocation& bitrate_allocation,
     bool reverse)
     : output_profile(output_profile),
       output_resolution(video->Resolution()),
@@ -62,7 +62,7 @@
       num_spatial_layers(
           std::max(spatial_layers.size(), static_cast<size_t>(1u))),
       spatial_layers(spatial_layers),
-      bitrate(bitrate),
+      bitrate_allocation(bitrate_allocation),
       framerate(video->FrameRate()),
       num_frames_to_encode(video->NumFrames()),
       reverse(reverse) {}
@@ -475,7 +475,7 @@
   const VideoEncodeAccelerator::Config config(
       video_->PixelFormat(), encoder_client_config_.output_resolution,
       encoder_client_config_.output_profile,
-      Bitrate::ConstantBitrate(encoder_client_config_.bitrate.GetSumBps()),
+      encoder_client_config_.bitrate_allocation.GetSumBitrate(),
       encoder_client_config_.framerate, absl::nullopt /* gop_length */,
       absl::nullopt /* h264_output_level*/, false /* is_constrained_h264 */,
       encoder_client_config_.input_storage_type,
diff --git a/media/gpu/test/video_encoder/video_encoder_client.h b/media/gpu/test/video_encoder/video_encoder_client.h
index 75251717..1e578001 100644
--- a/media/gpu/test/video_encoder/video_encoder_client.h
+++ b/media/gpu/test/video_encoder/video_encoder_client.h
@@ -57,7 +57,7 @@
   // without waiting for the result of the previous encodes requests.
   size_t max_outstanding_encode_requests = 1;
   // The desired bitrate in bits/second.
-  media::VideoBitrateAllocation bitrate;
+  media::VideoBitrateAllocation bitrate_allocation;
   // The desired framerate in frames/second.
   uint32_t framerate = 30.0;
   // The interval of calling VideoEncodeAccelerator::Encode(). If this is
diff --git a/media/gpu/video_encode_accelerator_tests.cc b/media/gpu/video_encode_accelerator_tests.cc
index 5f0d56b..137d728 100644
--- a/media/gpu/video_encode_accelerator_tests.cc
+++ b/media/gpu/video_encode_accelerator_tests.cc
@@ -507,8 +507,9 @@
   EXPECT_EQ(encoder->GetFlushDoneCount(), 1u);
   EXPECT_EQ(encoder->GetFrameReleasedCount(), config.num_frames_to_encode);
   EXPECT_TRUE(encoder->WaitForBitstreamProcessors());
-  EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate.GetSumBps(),
-              kBitrateTolerance * config.bitrate.GetSumBps());
+  EXPECT_NEAR(encoder->GetStats().Bitrate(),
+              config.bitrate_allocation.GetSumBps(),
+              kBitrateTolerance * config.bitrate_allocation.GetSumBps());
 }
 
 TEST_F(VideoEncoderTest, BitrateCheck_DynamicBitrate) {
@@ -523,7 +524,7 @@
   encoder->SetEventWaitTimeout(kBitrateCheckEventTimeout);
 
   // Encode the video with the first bitrate.
-  const uint32_t first_bitrate = config.bitrate.GetSumBps();
+  const uint32_t first_bitrate = config.bitrate_allocation.GetSumBps();
   encoder->EncodeUntil(VideoEncoder::kFrameReleased,
                        kNumFramesToEncodeForBitrateCheck);
   EXPECT_TRUE(encoder->WaitUntilIdle());
@@ -566,17 +567,19 @@
   encoder->EncodeUntil(VideoEncoder::kFrameReleased,
                        kNumFramesToEncodeForBitrateCheck);
   EXPECT_TRUE(encoder->WaitUntilIdle());
-  EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate.GetSumBps(),
-              kBitrateTolerance * config.bitrate.GetSumBps());
+  EXPECT_NEAR(encoder->GetStats().Bitrate(),
+              config.bitrate_allocation.GetSumBps(),
+              kBitrateTolerance * config.bitrate_allocation.GetSumBps());
 
   // Encode the video with the second framerate.
   const uint32_t second_framerate = first_framerate * 3 / 2;
   encoder->ResetStats();
-  encoder->UpdateBitrate(config.bitrate, second_framerate);
+  encoder->UpdateBitrate(config.bitrate_allocation, second_framerate);
   encoder->Encode();
   EXPECT_TRUE(encoder->WaitForFlushDone());
-  EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate.GetSumBps(),
-              kBitrateTolerance * config.bitrate.GetSumBps());
+  EXPECT_NEAR(encoder->GetStats().Bitrate(),
+              config.bitrate_allocation.GetSumBps(),
+              kBitrateTolerance * config.bitrate_allocation.GetSumBps());
 
   EXPECT_EQ(encoder->GetFlushDoneCount(), 1u);
   EXPECT_EQ(encoder->GetFrameReleasedCount(), config.num_frames_to_encode);
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 6e4b8bc..3011d07 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -343,6 +343,7 @@
 
   sources = [
     "chunked_data_pipe_upload_data_stream_unittest.cc",
+    "cookie_access_delegate_impl_unittest.cc",
     "cookie_manager_unittest.cc",
     "cookie_settings_unittest.cc",
     "cors/cors_url_loader_factory_unittest.cc",
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
index 3958b63..e264b93b 100644
--- a/services/network/cookie_access_delegate_impl.cc
+++ b/services/network/cookie_access_delegate_impl.cc
@@ -85,8 +85,10 @@
     const net::SchemefulSite& site,
     base::OnceCallback<void(FirstPartySetsManager::OwnerResult)> callback)
     const {
-  if (!first_party_sets_manager_)
-    return {absl::nullopt};
+  if (!first_party_sets_manager_) {
+    return absl::make_optional<FirstPartySetsManager::OwnerResult>(
+        absl::nullopt);
+  }
   return first_party_sets_manager_->FindOwner(
       site, first_party_sets_context_config_, std::move(callback));
 }
diff --git a/services/network/cookie_access_delegate_impl_unittest.cc b/services/network/cookie_access_delegate_impl_unittest.cc
new file mode 100644
index 0000000..fe4daca4b
--- /dev/null
+++ b/services/network/cookie_access_delegate_impl_unittest.cc
@@ -0,0 +1,74 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/cookie_access_delegate_impl.h"
+
+#include "base/test/task_environment.h"
+#include "net/base/schemeful_site.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/first_party_set_metadata.h"
+#include "net/cookies/same_party_context.h"
+#include "services/network/first_party_sets/first_party_sets_manager.h"
+#include "services/network/public/mojom/cookie_manager.mojom-shared.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace network {
+namespace {
+
+using testing::_;
+using testing::IsEmpty;
+using testing::Optional;
+
+class CookieAccessDelegateImplTest : public testing::Test {
+ public:
+  CookieAccessDelegateImplTest()
+      : delegate_(mojom::CookieAccessDelegateType::ALWAYS_LEGACY,
+                  /*first_party_sets_manager=*/nullptr,
+                  /*cookie_settings=*/nullptr) {}
+
+ protected:
+  CookieAccessDelegateImpl& delegate() { return delegate_; }
+
+ private:
+  CookieAccessDelegateImpl delegate_;
+};
+
+TEST_F(CookieAccessDelegateImplTest, NullFirstPartySetsManager) {
+  net::SchemefulSite site(GURL("https://site.test"));
+
+  // Since the first_party_sets_manager pointer is nullptr, none of the
+  // callbacks should ever be called, and the return values should all be
+  // non-nullopt.
+
+  // Same as the default ctor, but just to be explicit:
+  net::FirstPartySetMetadata expected_metadata(
+      net::SamePartyContext(), /*frame_owner=*/nullptr,
+      /*top_frame_owner=*/nullptr, net::FirstPartySetsContextType::kUnknown);
+  EXPECT_THAT(delegate().ComputeFirstPartySetMetadataMaybeAsync(
+                  site, &site, {},
+                  base::BindOnce([](net::FirstPartySetMetadata) { FAIL(); })),
+              Optional(std::ref(expected_metadata)));
+
+  EXPECT_THAT(delegate().FindFirstPartySetOwner(
+                  site, base::BindOnce([](FirstPartySetsManager::OwnerResult) {
+                    FAIL();
+                  })),
+              Optional(absl::nullopt));
+
+  EXPECT_THAT(
+      delegate().FindFirstPartySetOwners(
+          {site},
+          base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })),
+      Optional(IsEmpty()));
+
+  EXPECT_THAT(delegate().RetrieveFirstPartySets(base::BindOnce(
+                  [](FirstPartySetsManager::SetsByOwner) { FAIL(); })),
+              Optional(IsEmpty()));
+}
+
+}  // namespace
+}  // namespace network
diff --git a/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc b/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc
index e891ca5..56b0a36 100644
--- a/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc
@@ -42,7 +42,7 @@
   // Intentionally leaked during fuzzing.
   v8::Platform* platform = v8::platform::NewDefaultPlatform().release();
   v8::V8::InitializePlatform(platform);
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   v8::V8::InitializeSandbox();
 #endif
   v8::V8::Initialize();
diff --git a/testing/libfuzzer/fuzzers/v8_fuzzer.cc b/testing/libfuzzer/fuzzers/v8_fuzzer.cc
index a5e725d..21f414c 100644
--- a/testing/libfuzzer/fuzzers/v8_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/v8_fuzzer.cc
@@ -99,7 +99,7 @@
         v8::platform::InProcessStackDumping::kDisabled, nullptr);
 
     v8::V8::InitializePlatform(platform_.get());
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
     v8::V8::InitializeSandbox();
 #endif
     v8::V8::Initialize();
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 81b7058..e31d780 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1231,6 +1231,27 @@
             ]
         }
     ],
+    "AutofillRemoveInvalidPhoneNumberOnImport": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillRemoveInvalidPhoneNumberOnImport"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillRetrieveOverallPredictionsFromCache": [
         {
             "platforms": [
@@ -8835,29 +8856,6 @@
             ]
         }
     ],
-    "WebRtcMetronomeTaskQueue": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ThreadWrapperUsesMetronome",
-                        "WebRtcMetronomeTaskQueue",
-                        "WebRtcTimerUsesMetronome"
-                    ]
-                }
-            ]
-        }
-    ],
     "WebUIBrandingUpdate": [
         {
             "platforms": [
diff --git a/third_party/blink/common/test/run_all_unittests.cc b/third_party/blink/common/test/run_all_unittests.cc
index 9478b681..48fc947 100644
--- a/third_party/blink/common/test/run_all_unittests.cc
+++ b/third_party/blink/common/test/run_all_unittests.cc
@@ -20,7 +20,7 @@
   v8::V8::InitializeExternalStartupData(argv[0]);
   auto platform = v8::platform::NewDefaultPlatform();
   v8::V8::InitializePlatform(platform.get());
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   v8::V8::InitializeSandbox();
 #endif
   v8::V8::Initialize();
diff --git a/third_party/blink/public/mojom/frame/policy_container.mojom b/third_party/blink/public/mojom/frame/policy_container.mojom
index 69a7a379..c0ee6e4 100644
--- a/third_party/blink/public/mojom/frame/policy_container.mojom
+++ b/third_party/blink/public/mojom/frame/policy_container.mojom
@@ -5,12 +5,17 @@
 module blink.mojom;
 
 import "services/network/public/mojom/content_security_policy.mojom";
+import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
 import "services/network/public/mojom/ip_address_space.mojom";
 import "services/network/public/mojom/referrer_policy.mojom";
 
 struct PolicyContainerPolicies {
-  network.mojom.ReferrerPolicy referrer_policy = network.mojom.ReferrerPolicy.kDefault;
-  network.mojom.IPAddressSpace ip_address_space = network.mojom.IPAddressSpace.kUnknown;
+  network.mojom.CrossOriginEmbedderPolicyValue cross_origin_embedder_policy =
+    network.mojom.CrossOriginEmbedderPolicyValue.kNone;
+  network.mojom.ReferrerPolicy referrer_policy =
+    network.mojom.ReferrerPolicy.kDefault;
+  network.mojom.IPAddressSpace ip_address_space =
+    network.mojom.IPAddressSpace.kUnknown;
   array<network.mojom.ContentSecurityPolicy> content_security_policies;
 };
 
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS
index 14617bd..04aa0d8 100644
--- a/third_party/blink/public/platform/DEPS
+++ b/third_party/blink/public/platform/DEPS
@@ -58,6 +58,7 @@
     "+services/network/public/mojom/blocked_by_response_reason.mojom-shared.h",
     "+services/network/public/mojom/content_security_policy.mojom-shared.h",
     "+services/network/public/mojom/cors.mojom-shared.h",
+    "+services/network/public/mojom/cross_origin_embedder_policy.mojom-shared.h",
     "+services/network/public/mojom/data_pipe_getter.mojom-shared.h",
     "+services/network/public/mojom/fetch_api.mojom-forward.h",
     "+services/network/public/mojom/fetch_api.mojom-shared.h",
diff --git a/third_party/blink/public/platform/web_policy_container.h b/third_party/blink/public/platform/web_policy_container.h
index b4eaac0..f4fd33e 100644
--- a/third_party/blink/public/platform/web_policy_container.h
+++ b/third_party/blink/public/platform/web_policy_container.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_POLICY_CONTAINER_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_POLICY_CONTAINER_H_
 
+#include "services/network/public/mojom/cross_origin_embedder_policy.mojom-shared.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
 #include "third_party/blink/public/mojom/frame/policy_container.mojom-shared.h"
@@ -17,6 +18,7 @@
 // TODO(antoniosartori): Remove this when CommitNavigation IPC will be handled
 // directly in blink.
 struct WebPolicyContainerPolicies {
+  network::mojom::CrossOriginEmbedderPolicyValue cross_origin_embedder_policy;
   network::mojom::ReferrerPolicy referrer_policy;
   network::mojom::IPAddressSpace ip_address_space;
   WebVector<WebContentSecurityPolicy> content_security_policies;
diff --git a/third_party/blink/renderer/build/scripts/json5_generator.py b/third_party/blink/renderer/build/scripts/json5_generator.py
index 2977f7b..0a9aa53c 100644
--- a/third_party/blink/renderer/build/scripts/json5_generator.py
+++ b/third_party/blink/renderer/build/scripts/json5_generator.py
@@ -293,7 +293,7 @@
 
         # Only write the file if the contents have changed. This allows ninja to
         # skip rebuilding targets which depend on the output.
-        with open(path, "a+") as output_file:
+        with open(path, "a+", newline='') as output_file:
             output_file.seek(0)
             if output_file.read() != contents:
                 output_file.truncate(0)
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index 2dd233f..9758db522 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -865,6 +865,9 @@
         DCHECK(result.custom_highlight_name);
         style_->SetHasCustomHighlightName(result.custom_highlight_name);
       }
+    } else if (dynamic_pseudo == kPseudoIdFirstLine &&
+               rule_data->GetContainerQuery()) {
+      style_->SetFirstLineDependsOnContainerQueries(true);
     }
   } else {
     matched_rules_.push_back(MatchedRule(rule_data, layer_order, proximity,
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 2e8bfe8..f8bce14 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -2702,8 +2702,22 @@
       break;
   }
 
-  if (query_change != ContainerQueryEvaluator::Change::kNone)
+  if (query_change != ContainerQueryEvaluator::Change::kNone) {
     style.ClearCachedPseudoElementStyles();
+    // When the container query changes, the ::first-line matching the container
+    // itself is not detected as changed. Firstly, because the style for the
+    // container is computed before the layout causing the ::first-line styles
+    // to change. Also, we mark the ComputedStyle with HasPseudoElementStyle()
+    // for kPseudoIdFirstLine, even when the container query for the
+    // ::first-line rules doesn't match, which means a diff for that flag would
+    // not detect a change. Instead, if a container has ::first-line rules which
+    // depends on size container queries, fall back to re-attaching its box tree
+    // when any of the size queries change the evaluation result.
+    if (style.HasPseudoElementStyle(kPseudoIdFirstLine) &&
+        style.FirstLineDependsOnContainerQueries()) {
+      change = change.ForceMarkReattachLayoutTree().ForceReattachLayoutTree();
+    }
+  }
 
   NthIndexCache nth_index_cache(GetDocument());
 
diff --git a/third_party/blink/renderer/core/css/style_recalc_change.cc b/third_party/blink/renderer/core/css/style_recalc_change.cc
index 59c7fdb..55adf0f 100644
--- a/third_party/blink/renderer/core/css/style_recalc_change.cc
+++ b/third_party/blink/renderer/core/css/style_recalc_change.cc
@@ -129,7 +129,14 @@
       result &= ~kRecalcContainer;
   }
 
-  result &= ~(kSuppressRecalc | kMarkReattach);
+  // kSuppressRecalc should only take effect for the query container itself, not
+  // for children. Also make sure the kMarkReattach flag survives one level past
+  // the container for ::first-line re-attachments initiated from
+  // UpdateStyleAndLayoutTreeForContainer().
+  if (result & kSuppressRecalc)
+    result &= ~kSuppressRecalc;
+  else
+    result &= ~kMarkReattach;
 
   return result;
 }
diff --git a/third_party/blink/renderer/core/css/style_recalc_change.h b/third_party/blink/renderer/core/css/style_recalc_change.h
index 7248eb4..9015ed1 100644
--- a/third_party/blink/renderer/core/css/style_recalc_change.h
+++ b/third_party/blink/renderer/core/css/style_recalc_change.h
@@ -102,10 +102,6 @@
   StyleRecalcChange SuppressRecalc() const {
     return {propagate_, static_cast<Flags>(flags_ | kSuppressRecalc)};
   }
-  StyleRecalcChange WithRecalcContainerFlags(StyleRecalcChange& from) const {
-    return {propagate_,
-            static_cast<Flags>(flags_ | (from.flags_ & kRecalcContainerFlags))};
-  }
   StyleRecalcChange Combine(const StyleRecalcChange& other) const {
     return {std::max(propagate_, other.propagate_),
             static_cast<Flags>(flags_ | other.flags_)};
@@ -113,7 +109,8 @@
 
   bool ReattachLayoutTree() const { return flags_ & kReattach; }
   bool MarkReattachLayoutTree() const {
-    return (flags_ & (kMarkReattach | kReattach)) ==
+    // Never mark the query container (kSuppressRecalc) for reattachment.
+    return (flags_ & (kMarkReattach | kReattach | kSuppressRecalc)) ==
            (kMarkReattach | kReattach);
   }
   bool RecalcChildren() const { return propagate_ > kUpdatePseudoElements; }
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index be9e94e..fa3bf343 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3585,6 +3585,8 @@
   DCHECK(InActiveDocument());
   DCHECK(GetDocument().InStyleRecalc());
   DCHECK(!GetDocument().Lifecycle().InDetach());
+  DCHECK(!GetForceReattachLayoutTree() || GetComputedStyle())
+      << "No need to force a layout tree reattach if we had no computed style";
 
   DisplayLockStyleScope display_lock_style_scope(this);
   if (HasCustomStyleCallbacks())
@@ -3596,15 +3598,11 @@
     if (GetStyleChangeType() == kSubtreeStyleChange)
       child_change = child_change.ForceRecalcDescendants();
     ClearNeedsStyleRecalc();
-  } else if (GetForceReattachLayoutTree()) {
-    DCHECK(GetComputedStyle()) << "No need to force a layout tree reattach if "
-                                  "we had no computed style";
+  } else if (GetForceReattachLayoutTree() ||
+             (change.MarkReattachLayoutTree() && GetComputedStyle())) {
     SetNeedsReattachLayoutTree();
     child_change = child_change.ForceReattachLayoutTree();
     ClearNeedsStyleRecalc();
-  } else if (change.MarkReattachLayoutTree() && GetComputedStyle()) {
-    SetNeedsReattachLayoutTree();
-    DCHECK(!NeedsStyleRecalc());
   }
 
   // We're done with self style, notify the display lock.
@@ -3657,8 +3655,9 @@
             // least have a ContainerQueryEvaluator at this point.
             DCHECK(cq_data);
             if (cq_data->SkippedStyleRecalc()) {
-              child_change = cq_data->ClearAndReturnRecalcChangeForChildren()
-                                 .WithRecalcContainerFlags(child_change);
+              child_change =
+                  cq_data->ClearAndReturnRecalcChangeForChildren().Combine(
+                      child_change);
             }
           } else if (SkipStyleRecalcForContainer(*style, child_change)) {
             return;
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 02b5758..4c08ab0a 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -312,6 +312,9 @@
   network::mojom::ReferrerPolicy GetReferrerPolicy() const;
 
   PolicyContainer* GetPolicyContainer() { return policy_container_.get(); }
+  const PolicyContainer* GetPolicyContainer() const {
+    return policy_container_.get();
+  }
   void SetPolicyContainer(std::unique_ptr<PolicyContainer> container);
   std::unique_ptr<PolicyContainer> TakePolicyContainer();
 
diff --git a/third_party/blink/renderer/core/frame/policy_container.cc b/third_party/blink/renderer/core/frame/policy_container.cc
index 648fb5dd..ff95a86 100644
--- a/third_party/blink/renderer/core/frame/policy_container.cc
+++ b/third_party/blink/renderer/core/frame/policy_container.cc
@@ -34,6 +34,7 @@
     return nullptr;
   mojom::blink::PolicyContainerPoliciesPtr policies =
       mojom::blink::PolicyContainerPolicies::New(
+          container->policies.cross_origin_embedder_policy,
           container->policies.referrer_policy,
           container->policies.ip_address_space,
           ConvertToMojoBlink(
diff --git a/third_party/blink/renderer/core/frame/policy_container_test.cc b/third_party/blink/renderer/core/frame/policy_container_test.cc
index b093dbc..d4c9eaf 100644
--- a/third_party/blink/renderer/core/frame/policy_container_test.cc
+++ b/third_party/blink/renderer/core/frame/policy_container_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/frame/policy_container.h"
 
 #include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
+#include "services/network/public/mojom/cross_origin_embedder_policy.mojom-blink-forward.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -14,6 +15,7 @@
 TEST(PolicyContainerTest, MembersAreSetDuringConstruction) {
   MockPolicyContainerHost host;
   auto policies = mojom::blink::PolicyContainerPolicies::New(
+      network::mojom::blink::CrossOriginEmbedderPolicyValue::kNone,
       network::mojom::blink::ReferrerPolicy::kNever,
       network::mojom::blink::IPAddressSpace::kPrivate,
       Vector<network::mojom::blink::ContentSecurityPolicyPtr>());
@@ -29,6 +31,7 @@
 TEST(PolicyContainerTest, UpdateReferrerPolicyIsPropagated) {
   MockPolicyContainerHost host;
   auto policies = mojom::blink::PolicyContainerPolicies::New(
+      network::mojom::blink::CrossOriginEmbedderPolicyValue::kNone,
       network::mojom::blink::ReferrerPolicy::kAlways,
       network::mojom::blink::IPAddressSpace::kPublic,
       Vector<network::mojom::blink::ContentSecurityPolicyPtr>());
diff --git a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
index c278f90..f0fc53c 100644
--- a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
+++ b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/core/frame/dom_timer.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/page_dismissal_scope.h"
+#include "third_party/blink/renderer/core/frame/policy_container.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
@@ -227,6 +228,23 @@
   return execution_context.CrossOriginIsolatedCapability();
 }
 
+// See https://github.com/whatwg/html/issues/7912
+// static
+String WindowOrWorkerGlobalScope::crossOriginEmbedderPolicy(
+    const ExecutionContext& execution_context) {
+  const PolicyContainer* policy_container =
+      execution_context.GetPolicyContainer();
+  CHECK(policy_container);
+  switch (policy_container->GetPolicies().cross_origin_embedder_policy) {
+    case network::mojom::CrossOriginEmbedderPolicyValue::kNone:
+      return "unsafe-none";
+    case network::mojom::CrossOriginEmbedderPolicyValue::kCredentialless:
+      return "credentialless";
+    case network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp:
+      return "require-corp";
+  }
+}
+
 ScriptValue WindowOrWorkerGlobalScope::structuredClone(
     ScriptState* script_state,
     EventTarget& event_target,
diff --git a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
index 5928b15..6bc706a 100644
--- a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
+++ b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
@@ -86,6 +86,7 @@
   static void clearInterval(EventTarget&, int timeout_id);
 
   static bool crossOriginIsolated(const ExecutionContext&);
+  static String crossOriginEmbedderPolicy(const ExecutionContext&);
 
   static ScriptValue structuredClone(ScriptState*,
                                      EventTarget&,
diff --git a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
index b42de3a..58bd4608 100644
--- a/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
+++ b/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
@@ -47,6 +47,8 @@
 
     [RuntimeEnabled=CrossOriginIsolation]
         readonly attribute boolean crossOriginIsolated;
+    [RuntimeEnabled=CoepReflection]
+        readonly attribute DOMString crossOriginEmbedderPolicy;
 
     [RaisesException, CallWith=ScriptState] any structuredClone(any value, optional StructuredSerializeOptions options = {});
 };
diff --git a/third_party/blink/renderer/core/layout/OWNERS b/third_party/blink/renderer/core/layout/OWNERS
index 7836f30..9c23375 100644
--- a/third_party/blink/renderer/core/layout/OWNERS
+++ b/third_party/blink/renderer/core/layout/OWNERS
@@ -1,8 +1,9 @@
-atotic@chromium.org
-cbiesinger@chromium.org
 chrishtr@chromium.org
 fs@opera.com
+ikilpatrick@chromium.org
+kojii@chromium.org
 pdr@chromium.org
+mstensho@chromium.org
 schenney@chromium.org
 tkent@chromium.org
 wangxianzhu@chromium.org
diff --git a/third_party/blink/renderer/core/loader/frame_loader_test.cc b/third_party/blink/renderer/core/loader/frame_loader_test.cc
index b4cb270..256801c3 100644
--- a/third_party/blink/renderer/core/loader/frame_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader_test.cc
@@ -153,15 +153,19 @@
           SharedBuffer::Create(), url);
   MockPolicyContainerHost mock_policy_container_host;
   params->policy_container = std::make_unique<WebPolicyContainer>(
-      WebPolicyContainerPolicies{network::mojom::ReferrerPolicy::kAlways,
-                                 network::mojom::IPAddressSpace::kPublic,
-                                 WebVector<WebContentSecurityPolicy>()},
+      WebPolicyContainerPolicies{
+          network::mojom::CrossOriginEmbedderPolicyValue::kNone,
+          network::mojom::ReferrerPolicy::kAlways,
+          network::mojom::IPAddressSpace::kPublic,
+          WebVector<WebContentSecurityPolicy>(),
+      },
       mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote());
   LocalFrame* local_frame =
       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
   local_frame->Loader().CommitNavigation(std::move(params), nullptr);
 
   EXPECT_EQ(*mojom::blink::PolicyContainerPolicies::New(
+                network::mojom::CrossOriginEmbedderPolicyValue::kNone,
                 network::mojom::ReferrerPolicy::kAlways,
                 network::mojom::IPAddressSpace::kPublic,
                 Vector<network::mojom::blink::ContentSecurityPolicyPtr>()),
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index ddcfdd0..4008776 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -360,15 +360,7 @@
     return Difference::kInherited;
   if (!old_style.IndependentInheritedEqual(new_style) ||
       !inherited_variables_equal) {
-    if (old_style.ChildHasExplicitInheritance()) {
-      // If any of our children have explicit inheritance of an otherwise
-      // non-inherited property, we also have to count that as potentially
-      // inheriting non-independent properties, so we turn off that
-      // optimization here.
-      return Difference::kInherited;
-    } else {
-      return Difference::kIndependentInherited;
-    }
+    return Difference::kIndependentInherited;
   }
   if (non_inherited_equal) {
     DCHECK(old_style == new_style);
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 2a5504a..2e85622 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -1114,6 +1114,15 @@
       default_value: "false",
     },
     {
+      // Set to true if this ComputedStyle is for an element whose ::first-line
+      // style depends on size container queries.
+      name: "FirstLineDependsOnContainerQueries",
+      field_template: "primitive",
+      type_name: "bool",
+      field_group: "*",
+      default_value: "false",
+    },
+    {
       name: "BaseData",
       inherited: false,
       field_template: "external",
diff --git a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
index 6469b5c..7a0339b 100644
--- a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
+++ b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
@@ -161,7 +161,7 @@
     }
   }
 
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   // The V8 sandbox requires all ArrayBuffer backing stores to be allocated
   // inside the sandbox address space. This isn't guaranteed if allocation
   // override hooks (which are e.g. used by GWP-ASan) are enabled or if a
@@ -197,7 +197,7 @@
   InstanceCounters::DecrementCounter(
       InstanceCounters::kArrayBufferContentsCounter);
   unsigned int flags = 0;
-#ifdef V8_SANDBOX
+#ifdef V8_ENABLE_SANDBOX
   // See |AllocateMemoryWithFlags|.
   flags |= partition_alloc::FreeFlags::kNoMemoryToolOverride;
 #endif
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream.cc b/third_party/blink/renderer/modules/mediastream/media_stream.cc
index 2dcc557..2ed33ad5 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream.cc
@@ -39,10 +39,10 @@
 
 namespace blink {
 
-static bool ContainsSource(MediaStreamTrackVector& track_vector,
-                           MediaStreamSource* source) {
+static bool ContainsTrack(MediaStreamTrackVector& track_vector,
+                          MediaStreamTrack* media_stream_track) {
   for (MediaStreamTrack* track : track_vector) {
-    if (source->Id() == track->Component()->Source()->Id())
+    if (media_stream_track->id() == track->id())
       return true;
   }
   return false;
@@ -50,8 +50,7 @@
 
 static void ProcessTrack(MediaStreamTrack* track,
                          MediaStreamTrackVector& track_vector) {
-  MediaStreamSource* source = track->Component()->Source();
-  if (!ContainsSource(track_vector, source))
+  if (!ContainsTrack(track_vector, track))
     track_vector.push_back(track);
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
index 64394d7..67a3fbd 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
@@ -706,14 +706,17 @@
   // properties settings.
   static ProcessingBasedContainer CreateApmProcessedContainer(
       const SourceInfo& source_info,
+      mojom::blink::MediaStreamType stream_type,
       bool is_device_capture,
       const media::AudioParameters& device_parameters,
       bool is_reconfiguration_allowed) {
     int sample_rate_hz = media::kAudioProcessingSampleRateHz;
-    if (!ProcessedLocalAudioSource::OutputAudioAtProcessingSampleRate()) {
+    if (stream_type == mojom::blink::MediaStreamType::DEVICE_AUDIO_CAPTURE &&
+        !ProcessedLocalAudioSource::OutputAudioAtProcessingSampleRate()) {
       // If audio processing runs in the audio service without any mitigations
       // for unnecessary resmapling, ProcessedLocalAudioSource will output audio
       // at the device sample rate.
+      // This is only enabled for mic input sources: https://crbug.com/1328012
       sample_rate_hz = device_parameters.sample_rate();
     }
     return ProcessingBasedContainer(
@@ -1114,6 +1117,7 @@
 class DeviceContainer {
  public:
   DeviceContainer(const AudioDeviceCaptureCapability& capability,
+                  mojom::blink::MediaStreamType stream_type,
                   bool is_device_capture,
                   bool is_reconfiguration_allowed)
       : device_parameters_(capability.Parameters()) {
@@ -1147,7 +1151,7 @@
             is_reconfiguration_allowed));
     processing_based_containers_.push_back(
         ProcessingBasedContainer::CreateApmProcessedContainer(
-            source_info, is_device_capture, device_parameters_,
+            source_info, stream_type, is_device_capture, device_parameters_,
             is_reconfiguration_allowed));
 
     DCHECK_EQ(processing_based_containers_.size(), 3u);
@@ -1383,12 +1387,14 @@
 class CandidatesContainer {
  public:
   CandidatesContainer(const AudioDeviceCaptureCapabilities& capabilities,
+                      mojom::blink::MediaStreamType stream_type,
                       std::string& media_stream_source,
                       std::string& default_device_id,
                       bool is_reconfiguration_allowed)
       : default_device_id_(default_device_id) {
+    const bool is_device_capture = media_stream_source.empty();
     for (const auto& capability : capabilities) {
-      devices_.emplace_back(capability, media_stream_source.empty(),
+      devices_.emplace_back(capability, stream_type, is_device_capture,
                             is_reconfiguration_allowed);
       DCHECK(!devices_.back().IsEmpty());
     }
@@ -1495,6 +1501,7 @@
 AudioCaptureSettings SelectSettingsAudioCapture(
     const AudioDeviceCaptureCapabilities& capabilities,
     const MediaConstraints& constraints,
+    mojom::blink::MediaStreamType stream_type,
     bool should_disable_hardware_noise_suppression,
     bool is_reconfiguration_allowed) {
   if (capabilities.IsEmpty())
@@ -1506,7 +1513,7 @@
   if (is_device_capture)
     default_device_id = capabilities.begin()->DeviceID().Utf8();
 
-  CandidatesContainer candidates(capabilities, media_stream_source,
+  CandidatesContainer candidates(capabilities, stream_type, media_stream_source,
                                  default_device_id, is_reconfiguration_allowed);
   DCHECK(!candidates.IsEmpty());
 
@@ -1580,6 +1587,7 @@
         media::AudioParameters::NOISE_SUPPRESSION);
 
   return SelectSettingsAudioCapture(capabilities, constraints,
+                                    source->device().type,
                                     should_disable_hardware_noise_suppression);
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.h b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.h
index 5cdb259..87210ddb 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_AUDIO_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_AUDIO_H_
 
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -149,6 +150,7 @@
 MODULES_EXPORT blink::AudioCaptureSettings SelectSettingsAudioCapture(
     const AudioDeviceCaptureCapabilities& capabilities,
     const MediaConstraints& constraints,
+    mojom::blink::MediaStreamType stream_type,
     bool should_disable_hardware_noise_suppression,
     bool is_reconfiguration_allowed = false);
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
index 52606f9..ad70402 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
@@ -21,6 +21,7 @@
 #include "media/webrtc/constants.h"
 #include "media/webrtc/webrtc_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_string.h"
@@ -181,10 +182,12 @@
           absl::nullopt) {
     MediaConstraints constraints = constraint_factory_.CreateMediaConstraints();
     if (capabilities) {
-      return SelectSettingsAudioCapture(*capabilities, constraints, false,
+      return SelectSettingsAudioCapture(*capabilities, constraints,
+                                        GetMediaStreamType(), false,
                                         is_reconfigurable);
     } else {
-      return SelectSettingsAudioCapture(capabilities_, constraints, false,
+      return SelectSettingsAudioCapture(capabilities_, constraints,
+                                        GetMediaStreamType(), false,
                                         is_reconfigurable);
     }
   }
@@ -558,33 +561,86 @@
   std::string GetMediaStreamSource() override { return GetParam(); }
 };
 
-enum class ApmLocation {
-  kProcessedLocalAudioSource,
-  kAudioService,
-  kAudioServiceAvoidResampling
+enum class ChromeWideAecExperiment {
+  kDisabled,
+  kEnabledWithoutResamplingMitigation,
+  kEnabledWithResamplingMitigation
 };
 
 class MediaStreamConstraintsRemoteAPMTest
     : public MediaStreamConstraintsUtilAudioTestBase,
-      public testing::WithParamInterface<ApmLocation> {
+      public testing::WithParamInterface<
+          std::tuple<std::string, ChromeWideAecExperiment>> {
  protected:
-  ApmLocation GetApmLocation() { return GetParam(); }
+  std::string GetMediaStreamSource() override {
+    return std::get<0>(GetParam());
+  }
+
+  ChromeWideAecExperiment GetChromeWideAecExperiment() {
+    return std::get<1>(GetParam());
+  }
+
+  testing::Message GetMessageForScopedTrace() {
+    std::string experiment_string;
+    switch (GetChromeWideAecExperiment()) {
+      case ChromeWideAecExperiment::kDisabled:
+        experiment_string = "disabled";
+        break;
+      case ChromeWideAecExperiment::kEnabledWithoutResamplingMitigation:
+        experiment_string = "\"enabled without resampling mitigation\"";
+        break;
+      case ChromeWideAecExperiment::kEnabledWithResamplingMitigation:
+        experiment_string = "\"enabled with resampling mitigation\"";
+        break;
+    }
+    return testing::Message()
+           << "GetMediaStreamSource()=" << GetMediaStreamSource()
+           << ", GetChromeWideAecExperiment()=" << experiment_string;
+  }
+
+  // Indicates where and how audio processing is applied.
+  enum class ApmLocation {
+    kProcessedLocalAudioSource,
+    kAudioService,
+    kAudioServiceAvoidResampling
+  };
+
+  ApmLocation GetApmLocation() {
+    if (GetMediaStreamType() !=
+        mojom::blink::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
+      // Non-mic input sources cannot run APM in the audio service:
+      // https://crbug.com/1328012
+      return ApmLocation::kProcessedLocalAudioSource;
+    }
+
+    switch (GetChromeWideAecExperiment()) {
+      case ChromeWideAecExperiment::kDisabled:
+        return ApmLocation::kProcessedLocalAudioSource;
+      case ChromeWideAecExperiment::kEnabledWithoutResamplingMitigation:
+        return ApmLocation::kAudioService;
+      case ChromeWideAecExperiment::kEnabledWithResamplingMitigation:
+        return ApmLocation::kAudioServiceAvoidResampling;
+    }
+    NOTREACHED();
+  }
 
  private:
   void SetUp() override {
+    MediaStreamConstraintsUtilAudioTestBase::SetUp();
+
 #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION)
-    switch (GetApmLocation()) {
-      case ApmLocation::kProcessedLocalAudioSource:
+    switch (GetChromeWideAecExperiment()) {
+      case ChromeWideAecExperiment::kDisabled:
         scoped_feature_list_.InitAndDisableFeature(
             media::kChromeWideEchoCancellation);
         break;
-      case ApmLocation::kAudioService:
+      case ChromeWideAecExperiment::kEnabledWithoutResamplingMitigation:
         scoped_feature_list_.InitAndEnableFeatureWithParameters(
             media::kChromeWideEchoCancellation,
             {{ "minimize_resampling",
                "false" }});
         break;
-      case ApmLocation::kAudioServiceAvoidResampling:
+      case ChromeWideAecExperiment::kEnabledWithResamplingMitigation:
         scoped_feature_list_.InitAndEnableFeatureWithParameters(
             media::kChromeWideEchoCancellation,
             {{ "minimize_resampling",
@@ -595,15 +651,13 @@
 
     // Setup the capabilities.
     ResetFactory();
-    if (IsDeviceCapture()) {
-      capabilities_.emplace_back(
-          "default_device", "fake_group1",
-          media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                                 media::CHANNEL_LAYOUT_STEREO,
-                                 media::AudioParameters::kAudioCDSampleRate,
-                                 1000));
-      default_device_ = &capabilities_[0];
-    }
+    capabilities_.emplace_back(
+        "default_device", "fake_group1",
+        media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                               media::CHANNEL_LAYOUT_STEREO,
+                               media::AudioParameters::kAudioCDSampleRate,
+                               1000));
+    default_device_ = &capabilities_[0];
   }
 
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -1732,7 +1786,8 @@
 
   AudioDeviceCaptureCapabilities capabilities;
   auto result = SelectSettingsAudioCapture(
-      capabilities, constraint_factory_.CreateMediaConstraints(), false);
+      capabilities, constraint_factory_.CreateMediaConstraints(),
+      GetMediaStreamType(), false);
   EXPECT_FALSE(result.HasValue());
   EXPECT_TRUE(std::string(result.failed_constraint_name()).empty());
 }
@@ -1745,7 +1800,8 @@
   AudioDeviceCaptureCapabilities capabilities;
   constraint_factory_.basic().sample_size.SetExact(16);
   auto result = SelectSettingsAudioCapture(
-      capabilities, constraint_factory_.CreateMediaConstraints(), false);
+      capabilities, constraint_factory_.CreateMediaConstraints(),
+      GetMediaStreamType(), false);
   EXPECT_FALSE(result.HasValue());
   EXPECT_TRUE(std::string(result.failed_constraint_name()).empty());
 }
@@ -1992,6 +2048,7 @@
 
     auto result = SelectSettingsAudioCapture(
         capabilities, constraint_factory_.CreateMediaConstraints(),
+        GetMediaStreamType(),
         false /* should_disable_hardware_noise_suppression */);
     EXPECT_TRUE(result.HasValue());
     EXPECT_EQ(result.device_id(), kUnusedDeviceID.Utf8());
@@ -2004,6 +2061,7 @@
     constraint_factory_.basic().echo_cancellation.SetExact(true);
     auto result = SelectSettingsAudioCapture(
         capabilities, constraint_factory_.CreateMediaConstraints(),
+        GetMediaStreamType(),
         false /* should_disable_hardware_noise_suppression */);
     EXPECT_TRUE(result.HasValue());
     EXPECT_EQ(result.device_id(), processed_source->device().id);
@@ -2012,7 +2070,7 @@
   }
 }
 
-TEST_P(MediaStreamConstraintsUtilAudioTest, ExperimetanlEcWithSource) {
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExperimentalEcWithSource) {
   std::unique_ptr<blink::LocalMediaStreamAudioSource> source =
       GetLocalMediaStreamAudioSource(
           false /* enable_system_echo_canceller */,
@@ -2028,8 +2086,7 @@
 }
 
 TEST_P(MediaStreamConstraintsRemoteAPMTest, DeviceSampleRate) {
-  if (!IsDeviceCapture())
-    return;
+  SCOPED_TRACE(GetMessageForScopedTrace());
 
   AudioCaptureSettings result;
   ResetFactory();
@@ -2048,8 +2105,7 @@
 
 TEST_P(MediaStreamConstraintsRemoteAPMTest,
        WebRtcSampleRateButNotDeviceSampleRate) {
-  if (!IsDeviceCapture())
-    return;
+  SCOPED_TRACE(GetMessageForScopedTrace());
 
   AudioCaptureSettings result;
   ResetFactory();
@@ -2125,13 +2181,23 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     MediaStreamConstraintsRemoteAPMTest,
-    testing::Values(ApmLocation::kProcessedLocalAudioSource,
-                    ApmLocation::kAudioService,
-                    ApmLocation::kAudioServiceAvoidResampling));
+    testing::Combine(
+        testing::Values("",
+                        blink::kMediaStreamSourceTab,
+                        blink::kMediaStreamSourceSystem,
+                        blink::kMediaStreamSourceDesktop),
+        testing::Values(
+            ChromeWideAecExperiment::kDisabled,
+            ChromeWideAecExperiment::kEnabledWithoutResamplingMitigation,
+            ChromeWideAecExperiment::kEnabledWithResamplingMitigation)));
 #else
 INSTANTIATE_TEST_SUITE_P(
     All,
     MediaStreamConstraintsRemoteAPMTest,
-    testing::Values(ApmLocation::kProcessedLocalAudioSource));
+    testing::Combine(testing::Values("",
+                                     blink::kMediaStreamSourceTab,
+                                     blink::kMediaStreamSourceSystem,
+                                     blink::kMediaStreamSourceDesktop),
+                     testing::Values(ChromeWideAecExperiment::kDisabled)));
 #endif
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
index 0727757..8fa98a40f 100644
--- a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
@@ -157,6 +157,12 @@
     : blink::MediaStreamAudioSource(std::move(task_runner),
                                     true /* is_local_source */,
                                     disable_local_echo),
+      // Remote APM is only enabled for mic input, other input sources have
+      // conflicting requirements on echo cancellation:
+      // https://crbug.com/1328012
+      use_remote_apm_(media::IsChromeWideEchoCancellationEnabled() &&
+                      device.type ==
+                          mojom::blink::MediaStreamType::DEVICE_AUDIO_CAPTURE),
       consumer_frame_(&frame),
       dependency_factory_(
           PeerConnectionDependencyFactory::From(*frame.DomWindow())),
@@ -167,8 +173,9 @@
   DCHECK(frame.DomWindow());
   SetDevice(device);
   SendLogMessage(
-      base::StringPrintf("ProcessedLocalAudioSource({session_id=%s})",
-                         device.session_id().ToString().c_str()));
+      base::StringPrintf("ProcessedLocalAudioSource({session_id=%s}, {APM:%s})",
+                         device.session_id().ToString().c_str(),
+                         use_remote_apm_ ? "remote" : "local"));
 }
 
 ProcessedLocalAudioSource::~ProcessedLocalAudioSource() {
@@ -367,7 +374,7 @@
 
   media::AudioSourceParameters source_config(device().session_id());
 
-  if (media::IsChromeWideEchoCancellationEnabled()) {
+  if (use_remote_apm_) {
     if (OutputAudioAtProcessingSampleRate()) {
       // Since audio processing will be applied in the audio service, we request
       // audio here in the audio processing output format to avoid forced
diff --git a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h
index ca57464..f3150a0 100644
--- a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h
+++ b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h
@@ -92,7 +92,9 @@
   void SetOutputDeviceForAec(const std::string& output_device_id);
 
   // Returns true if ProcessedLocalAudioSource produces audio at the processing
-  // sample rate, false if it outputs audio at the device sample rate.
+  // sample rate, false if it outputs audio at the device sample rate. This only
+  // applies for stream type DEVICE_AUDIO_CAPTURE, for other stream types the
+  // output is always at the processing sample rate.
   static bool OutputAudioAtProcessingSampleRate();
 
  protected:
@@ -129,6 +131,13 @@
   // make the log unique.
   void SendLogMessageWithSessionId(const std::string& message) const;
 
+  // If true, processing (controlled via |audio_processor_proxy_|) is done in
+  // the audio service (and Chrome-wide echo cancellation is applied if
+  // requested; otherwise, |media_stream_audio_processor_| will be applying
+  // audio processing locally, and if echo cancellation is requested then only
+  // PeerConnection audio from the same context as |this| is cancelled.
+  const bool use_remote_apm_;
+
   // The LocalFrame that will consume the audio data. Used when creating
   // AudioCapturerSources.
   //
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 802d9f09..18659c3 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -709,8 +709,9 @@
                                     current_request_info_->request_id()));
   auto settings = SelectSettingsAudioCapture(
       capabilities, user_media_request->AudioConstraints(),
+      current_request_info_->stream_controls()->audio.stream_type,
       user_media_request->ShouldDisableHardwareNoiseSuppression(),
-      true /* is_reconfiguration_allowed */);
+      /*is_reconfiguration_allowed=*/true);
   if (!settings.HasValue()) {
     String failed_constraint_name = String(settings.failed_constraint_name());
     MediaStreamRequestResult result =
diff --git a/third_party/blink/renderer/platform/peerconnection/metronome_source_test.cc b/third_party/blink/renderer/platform/peerconnection/metronome_source_test.cc
index 7ca16b2..9b7581c 100644
--- a/third_party/blink/renderer/platform/peerconnection/metronome_source_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/metronome_source_test.cc
@@ -11,6 +11,7 @@
 #include "base/notreached.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/thread_pool.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -59,17 +60,28 @@
 
   void PostLastTask() {
     if (last_task_) {
-      runner_->PostTask(FROM_HERE,
-                        base::BindOnce(
-                            [](FakeTaskQueue* thiz,
-                               std::unique_ptr<webrtc::QueuedTask> task) {
-                              if (!task->Run())
-                                task.release();
-                            },
-                            base::Unretained(this), std::move(last_task_)));
+      PostOnRunner(FROM_HERE,
+                   base::BindOnce(
+                       [](FakeTaskQueue* thiz,
+                          std::unique_ptr<webrtc::QueuedTask> task) {
+                         if (!task->Run())
+                           task.release();
+                       },
+                       base::Unretained(this), std::move(last_task_)));
     }
   }
 
+  void PostOnRunner(base::Location from_here, base::OnceClosure cb) {
+    runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](FakeTaskQueue* thiz, base::OnceClosure cb) {
+              webrtc::TaskQueueBase::CurrentTaskQueueSetter setter(thiz);
+              std::move(cb).Run();
+            },
+            base::Unretained(this), std::move(cb)));
+  }
+
  private:
   const bool retain_tasks_;
   scoped_refptr<base::SequencedTaskRunner> runner_;
@@ -330,7 +342,10 @@
   auto metronome_adapter = metronome_source_->CreateWebRtcMetronome();
 
   EXPECT_FALSE(metronome_source_->HasListenersForTesting());
-  metronome_adapter->AddListener(&tick_listener);
+  fake_queue.PostOnRunner(FROM_HERE, base::BindLambdaForTesting([&] {
+                            metronome_adapter->AddListener(&tick_listener);
+                          }));
+  task_environment_.RunUntilIdle();
   EXPECT_TRUE(metronome_source_->HasListenersForTesting());
 
   // Next tick should trigger callback.
@@ -342,7 +357,9 @@
   EXPECT_EQ(11, callback_count);
 
   // Removing should not fire callback.
-  metronome_adapter->RemoveListener(&tick_listener);
+  fake_queue.PostOnRunner(FROM_HERE, base::BindLambdaForTesting([&] {
+                            metronome_adapter->RemoveListener(&tick_listener);
+                          }));
   task_environment_.FastForwardBy(MetronomeSource::Tick());
   EXPECT_EQ(11, callback_count);
 
@@ -361,7 +378,9 @@
       &fake_queue);
   auto metronome_adapter = metronome_source_->CreateWebRtcMetronome();
 
-  metronome_adapter->AddListener(&tick_listener);
+  fake_queue.PostOnRunner(FROM_HERE, base::BindLambdaForTesting([&] {
+                            metronome_adapter->AddListener(&tick_listener);
+                          }));
   task_environment_.FastForwardBy(MetronomeSource::Tick());
   EXPECT_EQ(0, callback_count);
   // Now task should have been posted to fake queue. Running it should increase
@@ -377,7 +396,9 @@
   task_environment_.FastForwardBy(MetronomeSource::Tick());
   EXPECT_EQ(1, callback_count);
 
-  metronome_adapter->RemoveListener(&tick_listener);
+  fake_queue.PostOnRunner(FROM_HERE, base::BindLambdaForTesting([&] {
+                            metronome_adapter->RemoveListener(&tick_listener);
+                          }));
   fake_queue.PostLastTask();
   task_environment_.RunUntilIdle();
   EXPECT_EQ(1, callback_count);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9b48dac..c545259 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -399,6 +399,16 @@
       status: "experimental",
     },
     {
+      name: "CoepReflection",
+      status: "test",
+
+      // If a feature is implied by one supporting an origin trial, it must also
+      // support origin trial.
+      implied_by: ["AnonymousIframe"],
+      origin_trial_allows_third_party: true,
+      origin_trial_feature_name: "CoepReflection",
+    },
+    {
       name: "CompositeBGColorAnimation",
       status: "experimental",
     },
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index b071bb20..3fa35130 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -80,7 +80,7 @@
 crbug.com/678482 http/tests/devtools/debugger/fetch-breakpoints.js [ Slow ]
 crbug.com/1236466 inspector-protocol/runtime/runtime-execution-contexts-events.js [ Slow ]
 crbug.com/1229701 http/tests/inspector-protocol/network/disable-cache-media-resource.js [ Slow ]
-crbug.com/1300409 [ Win ] http/tests/inspector-protocol/network/websocket/offline-no-send.js [ Slow ]
+crbug.com/1300409 http/tests/inspector-protocol/network/websocket/offline-no-send.js [ Slow ]
 crbug.com/1280873 http/tests/inspector-protocol/network/xhr-cors-preflight-redirect-failure.js [ Slow ]
 crbug.com/1280697 http/tests/inspector-protocol/network/block_cross_site_document_load.js [ Slow ]
 crbug.com/1280585 http/tests/inspector-protocol/network/xhr-post-replay-cors.js [ Slow ]
@@ -779,3 +779,4 @@
 crbug.com/1314927 external/wpt/IndexedDB/idbobjectstore_batchGetAll_largeValue.tentative.any.html [ Slow ]
 
 crbug.com/1307791 external/wpt/credential-management/fedcm-logout.sub.https.html [ Slow ]
+crbug.com/1327869 css3/calc/simple-calcs-prefixed.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 6f5210d..0a345d1 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1867,7 +1867,6 @@
 
 # @container
 crbug.com/1294155 external/wpt/css/css-contain/container-queries/canvas-as-container-004.html [ Failure ]
-crbug.com/1273913 external/wpt/css/css-contain/container-queries/pseudo-elements-002.html [ Failure ]
 crbug.com/1307656 external/wpt/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html [ Crash ]
 
 # CSS Scrollbars
@@ -6599,6 +6598,15 @@
 crbug.com/1285275 virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/cache-storage.tentative.https.window.html [ Pass Timeout ]
 crbug.com/1285275 virtual/fenced-frame-shadow-dom/external/wpt/html/anonymous-iframe/cache-storage.tentative.https.window.html [ Pass Timeout ]
 crbug.com/1285275 virtual/partitioned-cookies/external/wpt/html/anonymous-iframe/cache-storage.tentative.https.window.html [ Pass Timeout ]
+# Crash inside NavigationRequest::CoopCoepSanityCheck:
+crbug.com/1314369 external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?7-8 [ Crash Failure ]
+crbug.com/1314369 external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?9-10 [ Crash Failure ]
+crbug.com/1314369 virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?7-8 [ Crash Failure ]
+crbug.com/1314369 virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?9-10 [ Crash Failure ]
+crbug.com/1314369 virtual/fenced-frame-shadow-dom/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?7-8 [ Crash Failure ]
+crbug.com/1314369 virtual/fenced-frame-shadow-dom/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?9-10 [ Crash Failure ]
+crbug.com/1314369 virtual/partitioned-cookies/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?7-8 [ Crash Failure ]
+crbug.com/1314369 virtual/partitioned-cookies/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?9-10 [ Crash Failure ]
 
 # Sheriff 2022-03-10
 crbug.com/1304956 storage/indexeddb/dont-wedge.html [ Failure Pass ]
@@ -6807,6 +6815,9 @@
 # Sheriff 2022-05-11
 crbug.com/1324428 fast/webgl/canvas-toDataURL-crash.html [ Crash Pass ]
 
+# Disabled to allow a DevTools roll
+crbug.com/1325751 http/tests/devtools/extensions/extensions-api.js [ Failure Pass ]
+
 # Throttling a hidden-cross origin frame may stall animations.
 crbug.com/1323246 external/wpt/web-animations/timing-model/timelines/sibling-iframe-timeline.html [ Failure Pass ]
 
@@ -6820,3 +6831,6 @@
 # Sheriff 2022-05-20
 crbug.com/1291841 external/wpt/scroll-to-text-fragment/scroll-to-text-fragment-security.sub.html [ Pass Timeout ]
 crbug.com/1327764 inspector-protocol/overlay/overlay-persistent-overlays.js [ Failure Pass ]
+
+# Disabled to land a change
+crbug.com/1297439 http/tests/devtools/tracing/timeline-js/timeline-stack-trace.js [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
index 696f498..d70fa530 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
 <link rel="help" href="https://www.w3.org/TR/css-cascade-4/#default">
 <meta name="assert" content="Checks that adding 'all: revert' has no effect on elements with no other author rules.">
+<meta name="timeout" content="long">
 
 <style>
 .revert-all {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition-ref.html
deleted file mode 100644
index b7a5824..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <body style="color: black; background-color: white">
-    <div><div>PASS if black on white</div></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition.html
deleted file mode 100644
index f4dec80..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/inherit-background-color-transition.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html id="html" class="reftest-wait">
-  <title>Verifies that 'background-color' from a transition inherits explicitly down if requested</title>
-  <link rel="help" href="https://crbug.com/1325340">
-  <link rel="match" href="inherit-background-color-transition-ref.html">
-  <script src="support/helper.js"></script>
-  <style>
-    body { transition: background-color 1s; color: white; background-color: black; }
-    .light { color: black; background-color: white; }
-  </style>
-</head>
-<body id="body">
-  <div style="background-color: inherit">
-    <div style="background-color: inherit" class="hoverdemo">PASS if black on white</div>
-  </div>
-  <script>
-    body.offsetTop;
-
-    async function run() {
-      let transitionEnd = new Promise((resolve) => {
-        body.addEventListener('transitionend', resolve);
-      });
-
-      // Trigger transition:
-      body.classList.toggle('light');
-
-      const transition = body.getAnimations()[0];
-      await transition.ready;
-      await waitForFrame();
-
-      // Expedite transition, but let it finish naturally.
-      transition.currentTime = transition.effect.getTiming().duration - 1;
-      await transitionEnd;
-
-      await waitForFrame();
-    }
-
-    run().then(() => html.classList.toggle('reftest-wait'));
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.js
new file mode 100644
index 0000000..1a02394
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.js
@@ -0,0 +1,117 @@
+// META: variant=?1-2
+// META: variant=?3-4
+// META: variant=?5-6
+// META: variant=?7-8
+// META: variant=?9-10
+// META: variant=?11-12
+// META: variant=?13-last
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/common/subset-tests.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/html/cross-origin-embedder-policy/credentialless/resources/common.js
+// META: script=./resources/common.js
+// META: script=./resources/embedding-test.js
+
+const {REMOTE_ORIGIN} = get_host_info();
+
+// variant = 1
+subsetTest(embeddingTest,
+  "Parent embeds same-origin anonymous iframe", {
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 2
+subsetTest(embeddingTest,
+  "Parent embeds cross-origin anonymous iframe", {
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 3
+subsetTest(embeddingTest,
+  "COEP:require-corp parent embeds same-origin anonymous iframe", {
+  parent_headers: coep_require_corp,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 4
+subsetTest(embeddingTest,
+  "COEP:require-corp parent embeds cross-origin anonymous iframe", {
+  parent_headers: coep_require_corp,
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 5
+subsetTest(embeddingTest,
+  "COEP:credentialless parent embeds same-origin anonymous iframe", {
+  parent_headers: coep_credentialless,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 6
+subsetTest(embeddingTest,
+  "COEP:credentialless parent embeds cross-origin anonymous iframe", {
+  parent_headers: coep_credentialless,
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 7
+// Regression test for https://crbug.com/1314369
+subsetTest(embeddingTest,
+  "COOP:same-origin + COEP:require-corp embeds same-origin anonymous iframe", {
+  parent_headers: coop_same_origin + coep_require_corp,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 8
+// Regression test for https://crbug.com/1314369
+subsetTest(embeddingTest,
+  "COOP:same-origin + COEP:require-corp embeds cross-origin anonymous iframe", {
+  parent_headers: coop_same_origin + coep_require_corp,
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 9
+// Regression test for https://crbug.com/1314369
+subsetTest(embeddingTest,
+  "COOP:same-origin + COEP:credentialless embeds same-origin anonymous iframe", {
+  parent_headers: coop_same_origin + coep_credentialless,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 10
+// Regression test for https://crbug.com/1314369
+subsetTest(embeddingTest,
+  "COOP:same-origin + COEP:credentialless embeds cross-origin anonymous iframe", {
+  parent_headers: coop_same_origin + coep_credentialless,
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 11
+subsetTest(embeddingTest,
+  "Parents embeds a CSP:frame-ancestore anonymous iframe", {
+  child_headers: "|headers(Content-Security-Policy,frame-ancestors 'none')",
+  expectation: EXPECT_BLOCK,
+});
+
+// variant = 12
+subsetTest(embeddingTest,
+  "Cross-Origin-Isolated parent embeds same-origin COEP anonymous iframe", {
+  parent_headers: coop_same_origin + coep_require_corp,
+  child_headers: coop_same_origin + coep_require_corp,
+  expectation: EXPECT_LOAD,
+});
+
+// variant = 13
+subsetTest(embeddingTest,
+  "Cross-Origin-Isolated parent embeds cross-origin COEP anonymous iframe", {
+  parent_headers: coop_same_origin + coep_require_corp,
+  child_headers: coop_same_origin + coep_require_corp,
+  child_origin: REMOTE_ORIGIN,
+  expectation: EXPECT_LOAD,
+});
diff --git a/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/resources/embedding-test.js b/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/resources/embedding-test.js
new file mode 100644
index 0000000..a21cee52
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/anonymous-iframe/resources/embedding-test.js
@@ -0,0 +1,55 @@
+// One document embeds another in an iframe. Both are loaded from the network.
+// Check whether or not the child can load.
+
+const EXPECT_LOAD = "load";
+const EXPECT_BLOCK = "block";
+
+// Load an anonymous iframe. Control both the parent and the child headers.
+// Check whether it loaded or not.
+const embeddingTest = (description, {
+  parent_headers,
+  child_headers,
+  child_origin,
+  expectation,
+}) => {
+  // Default values:
+  child_origin ||= globalThis.origin;
+  parent_headers ||= "";
+  child_headers||= "";
+
+  const parent_origin = window.origin;
+
+  promise_test_parallel(async test => {
+    const parent_token = token();
+    const parent_url = parent_origin + executor_path + parent_headers +
+      `&uuid=${parent_token}`;
+
+    const child_token = token();
+    const child_url = child_origin + executor_path + child_headers +
+      `&uuid=${child_token}`;
+
+    // Create the parent:
+    window.open(parent_url);
+    add_completion_callback(() => send(parent_token, "close()"));
+
+    // The parent creates its child:
+    await send(parent_token, `
+      const iframe = document.createElement("iframe");
+      iframe.anonymous = true;
+      iframe.src = "${child_url}";
+      document.body.appendChild(iframe);
+    `);
+
+    // Ping the child to know whether it was allowed to load or not:
+    const reply_token = token();
+    await send(child_token, `
+      send("${reply_token}", "load");
+    `);
+
+    // There are no interoperable ways to check an iframe failed to load. So a
+    // timeout is being used. See https://github.com/whatwg/html/issues/125
+    step_timeout(() => send(reply_token, "block"), 4000)
+
+    assert_equals(await receive(reply_token), expectation);
+  }, description);
+};
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js
new file mode 100644
index 0000000..82d42230
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js
@@ -0,0 +1 @@
+test(t => assert_equals(crossOriginEmbedderPolicy, "credentialless"));
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js.headers
new file mode 100644
index 0000000..32523a69
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: credentialless
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js
new file mode 100644
index 0000000..c96b8f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js
@@ -0,0 +1 @@
+test(t => assert_equals(crossOriginEmbedderPolicy, "require-corp"));
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js.headers
new file mode 100644
index 0000000..66044509
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-unsafe-none.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-unsafe-none.tentative.https.any.js
new file mode 100644
index 0000000..4694f91
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reflection-unsafe-none.tentative.https.any.js
@@ -0,0 +1 @@
+test(t => assert_equals(crossOriginEmbedderPolicy, "unsafe-none"));
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/opaque-origin.html b/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/opaque-origin.html
index 7f2f443..c176229 100644
--- a/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/opaque-origin.html
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/opaque-origin.html
@@ -99,7 +99,9 @@
 // For shared workers:
 self.addEventListener("connect", (e) => {
   var port = e.ports[0];
-  handler(msg => port.postMessage(msg));
+  port.onmessage = () => handler(msg => port.postMessage(msg));
+  port.start();
+
 });
 `;
   return "data:,".concat(encodeURIComponent(source));
diff --git a/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js b/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js
index 52c7c34..f237ba5 100644
--- a/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js
+++ b/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js
@@ -100,6 +100,12 @@
     case "isSecureContext":
         expected = "true";
         break;
+
+    // The Cross-Origin-Embedder-Policy default value is 'unsafe-none'.
+    case "crossOriginEmbedderPolicy":
+        expected = "'unsafe-none'";
+        break;
+
     // TODO(dcheng): Figure out why these become undefined...
     case "location.hash":
     case "location.host":
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/websocket/offline-no-send.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/websocket/offline-no-send.js
index 85c89f8..3d1dffa 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/websocket/offline-no-send.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/websocket/offline-no-send.js
@@ -5,13 +5,8 @@
   const {page, session, dp} = await testRunner.startURL(
       '/',
       `Verifies that WebSocket does not send messages when emulating offline network.`);
-  window.onerror = (msg) => testRunner.log('onerror: ' + msg);
-  window.onunhandledrejection = (e) => testRunner.log('onunhandledrejection: ' + e.reason);
-  let errorForLog = new Error();
-  setTimeout(() => testRunner.die('Timeout', errorForLog), 5000);
 
   await dp.Network.enable();
-  errorForLog = new Error();
 
   await session.evaluateAsync(`
         log = '';
@@ -23,22 +18,17 @@
             resolve();
           };
         });`);
-  errorForLog = new Error();
   await dp.Network.emulateNetworkConditions({
     offline: true,
     downloadThroughput: -1,
     uploadThroughput: -1,
     latency: 0,
   });
-  errorForLog = new Error();
   const listener_ws = await new Promise((resolve) => {
     const ws =
         new WebSocket('ws://localhost:8880/network_emulation?role=listener');
     ws.onopen = () => resolve(ws);
-    ws.onerror = () => testRunner.log('onerror: unexpected error in listener_ws');
-    ws.onclose = () => testRunner.log('onclose: unexpected close of listener_ws');
   });
-  errorForLog = new Error();
 
   const messageRecieved = new Promise((resolve) => {
     listener_ws.onmessage = async (msg) => {
@@ -49,12 +39,9 @@
   });
 
   await session.evaluateAsync(`broadcaster_ws.send('Offline');`);
-  errorForLog = new Error();
   listener_ws.send('Control');
   await messageRecieved;
-  errorForLog = new Error();
   testRunner.log(await session.evaluateAsync(`log`));
-  errorForLog = new Error();
 
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.worker-expected.txt
new file mode 100644
index 0000000..cbc0240c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-credentialless.tentative.https.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL reflection-credentialless assert_equals: expected "credentialless" but got "unsafe-none"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.worker-expected.txt
new file mode 100644
index 0000000..0e8a176
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/external/wpt/html/cross-origin-embedder-policy/reflection-require-corp.tentative.https.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL reflection-require-corp assert_equals: expected "require-corp" but got "unsafe-none"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index c8ddd5c..0c595358 100644
--- a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -4,6 +4,7 @@
 
 PASS oldChildWindow.closed is newChildWindow.closed
 PASS oldChildWindow.cookieStore.onchange is newChildWindow.cookieStore.onchange
+PASS oldChildWindow.crossOriginEmbedderPolicy is newChildWindow.crossOriginEmbedderPolicy
 PASS oldChildWindow.crossOriginIsolated is newChildWindow.crossOriginIsolated
 PASS oldChildWindow.defaultStatus is newChildWindow.defaultStatus
 PASS oldChildWindow.defaultstatus is newChildWindow.defaultstatus
diff --git a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 315fe21..b0eeaf2 100644
--- a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -3,6 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 FAIL childWindow.closed should be false. Was true.
+PASS childWindow.crossOriginEmbedderPolicy is 'unsafe-none'
 PASS childWindow.crossOriginIsolated is false
 PASS childWindow.defaultStatus is ''
 PASS childWindow.defaultstatus is ''
diff --git a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index db2d869c..dea95b1 100644
--- a/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -3,6 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 FAIL childWindow.closed should be false. Was true.
+PASS childWindow.crossOriginEmbedderPolicy is 'unsafe-none'
 PASS childWindow.crossOriginIsolated is false
 PASS childWindow.defaultStatus is ''
 PASS childWindow.defaultstatus is ''
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 897cff8..81b9c8d83 100644
--- a/third_party/blink/web_tests/platform/generic/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -2984,6 +2984,7 @@
 interface WorkerGlobalScope : EventTarget
     attribute @@toStringTag
     getter caches
+    getter crossOriginEmbedderPolicy
     getter crossOriginIsolated
     getter crypto
     getter fonts
diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 27a42b7..0403690 100644
--- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -3226,6 +3226,7 @@
 [Worker] interface WorkerGlobalScope : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter caches
+[Worker]     getter crossOriginEmbedderPolicy
 [Worker]     getter crossOriginIsolated
 [Worker]     getter crypto
 [Worker]     getter fonts
diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt
index 7f8b01f..dc80785 100644
--- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt
@@ -11535,6 +11535,7 @@
     getter clientInformation
     getter closed
     getter cookieStore
+    getter crossOriginEmbedderPolicy
     getter crossOriginIsolated
     getter crypto
     getter customElements
diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-shared-worker-expected.txt
index 4f31b0a..18099a4 100644
--- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -2856,6 +2856,7 @@
 [Worker] interface WorkerGlobalScope : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter caches
+[Worker]     getter crossOriginEmbedderPolicy
 [Worker]     getter crossOriginIsolated
 [Worker]     getter crypto
 [Worker]     getter fonts
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 3319ea4..e690538 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 1fa6eb27f6999da18d4fa3584a3cc88949970f56
+Revision: 5f2a706f71de3204c916401f3ea084e47f689057
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/annotation.h b/third_party/crashpad/crashpad/client/annotation.h
index d783aad..036e463 100644
--- a/third_party/crashpad/crashpad/client/annotation.h
+++ b/third_party/crashpad/crashpad/client/annotation.h
@@ -73,7 +73,8 @@
 class Annotation {
  public:
   //! \brief The maximum length of an annotation’s name, in bytes.
-  static constexpr size_t kNameMaxLength = 64;
+  //!    Matches the behavior of Breakpad's SimpleStringDictionary.
+  static constexpr size_t kNameMaxLength = 256;
 
   //! \brief The maximum size of an annotation’s value, in bytes.
   static constexpr size_t kValueMaxSize = 5 * 4096;
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
index 53c2dada..295ec16 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -253,7 +253,12 @@
   ExceptionInformation exception_information_ = {};
   CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr;
   int32_t dump_done_futex_ = kDumpNotDone;
+#if !defined(__cpp_lib_atomic_value_initialization) || \
+    __cpp_lib_atomic_value_initialization < 201911L
   std::atomic_flag disabled_ = ATOMIC_FLAG_INIT;
+#else
+  std::atomic_flag disabled_;
+#endif
 
   static SignalHandler* handler_;
 };
diff --git a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc
index f13b140d..92bb72e 100644
--- a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc
+++ b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc
@@ -62,6 +62,9 @@
 InProcessHandler::InProcessHandler() = default;
 
 InProcessHandler::~InProcessHandler() {
+  if (cached_writer_) {
+    cached_writer_->Close();
+  }
   UpdatePruneAndUploadThreads(false);
 }
 
diff --git a/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler_test.cc
index e61a604..bccc930 100644
--- a/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler_test.cc
+++ b/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler_test.cc
@@ -49,6 +49,7 @@
   }
 
   void TearDown() override {
+    EXPECT_TRUE(writer_->Close());
     writer_.reset();
     EXPECT_FALSE(IsRegularFile(path_));
   }
diff --git a/third_party/crashpad/crashpad/minidump/minidump_annotation_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_annotation_writer.cc
index 54a3ecb..8a62eccb 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_annotation_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_annotation_writer.cc
@@ -147,9 +147,10 @@
     FileWriterInterface* file_writer) {
   DCHECK_EQ(state(), kStateWritable);
 
-  std::vector<WritableIoVec> iov(1 + objects_.size());
-  iov[0].iov_base = minidump_list_.get();
-  iov[0].iov_len = sizeof(*minidump_list_);
+  std::vector<WritableIoVec> iov;
+  iov.reserve(1 + objects_.size());
+  iov.emplace_back(
+      WritableIoVec{minidump_list_.get(), sizeof(*minidump_list_)});
 
   for (const auto& object : objects_) {
     iov.emplace_back(WritableIoVec{object->minidump_annotation(),
diff --git a/third_party/crashpad/crashpad/snapshot/ios/module_snapshot_ios_intermediate_dump.cc b/third_party/crashpad/crashpad/snapshot/ios/module_snapshot_ios_intermediate_dump.cc
index cdef7697..b7541b7 100644
--- a/third_party/crashpad/crashpad/snapshot/ios/module_snapshot_ios_intermediate_dump.cc
+++ b/third_party/crashpad/crashpad/snapshot/ios/module_snapshot_ios_intermediate_dump.cc
@@ -19,6 +19,7 @@
 
 #include "base/files/file_path.h"
 #include "base/mac/mach_logging.h"
+#include "client/annotation.h"
 #include "snapshot/ios/intermediate_dump_reader_util.h"
 #include "util/ios/ios_intermediate_dump_data.h"
 #include "util/ios/ios_intermediate_dump_list.h"
@@ -81,8 +82,11 @@
       std::string name;
       if (!GetDataStringFromMap(
               annotation.get(), Key::kAnnotationName, &name) ||
-          name.empty() || name.length() > 64) {  // Annotation::kNameMaxLength
-        LOG(ERROR) << "Invalid annotation name length.";
+          name.empty() || name.length() > Annotation::kNameMaxLength) {
+        LOG(ERROR) << "Invalid annotation name (" << name
+                   << "), size=" << name.size()
+                   << ", max size=" << Annotation::kNameMaxLength
+                   << ", discarding annotation.";
         continue;
       }
 
@@ -94,8 +98,10 @@
       if (type_dump && value_dump && type_dump->GetValue<uint16_t>(&type)) {
         const std::vector<uint8_t>& bytes = value_dump->bytes();
         uint64_t length = bytes.size();
-        if (!bytes.data() || length > 20480) {  // Annotation::kValueMaxSize
-          LOG(ERROR) << "Invalid annotation value length.";
+        if (!bytes.data() || length > Annotation::kValueMaxSize) {
+          LOG(ERROR) << "Invalid annotation value, size=" << length
+                     << ", max size=" << Annotation::kValueMaxSize
+                     << ", discarding annotation.";
           continue;
         }
         annotation_objects_.push_back(AnnotationSnapshot(name, type, bytes));
diff --git a/third_party/crashpad/crashpad/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/third_party/crashpad/crashpad/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc
index 1a994bd..34c34f8 100644
--- a/third_party/crashpad/crashpad/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc
@@ -51,7 +51,9 @@
 
 class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test {
  protected:
-  // testing::Test:
+  ProcessSnapshotIOSIntermediateDumpTest()
+      : long_annotation_name_(Annotation::kNameMaxLength, 'a'),
+        long_annotation_value_(Annotation::kValueMaxSize, 'b') {}
 
   void SetUp() override {
     path_ = temp_dir_.path().Append("dump_file");
@@ -61,6 +63,7 @@
   }
 
   void TearDown() override {
+    EXPECT_TRUE(writer_->Close());
     writer_.reset();
     EXPECT_FALSE(IsRegularFile(path_));
   }
@@ -158,9 +161,16 @@
     }
   }
 
-  void WriteAnnotations(IOSIntermediateDumpWriter* writer) {
-    constexpr char annotation_name[] = "annotation_name";
-    constexpr char annotation_value[] = "annotation_value";
+  void WriteAnnotations(IOSIntermediateDumpWriter* writer,
+                        bool use_long_annotations) {
+    constexpr char short_annotation_name[] = "annotation_name";
+    constexpr char short_annotation_value[] = "annotation_value";
+    const char* const annotation_name = use_long_annotations
+                                            ? long_annotation_name_.c_str()
+                                            : short_annotation_name;
+    const char* const annotation_value = use_long_annotations
+                                             ? long_annotation_value_.c_str()
+                                             : short_annotation_value;
     {
       IOSIntermediateDumpWriter::ScopedArray annotationObjectArray(
           writer, Key::kAnnotationObjects);
@@ -198,7 +208,9 @@
     }
   }
 
-  void WriteModules(IOSIntermediateDumpWriter* writer, bool has_module_path) {
+  void WriteModules(IOSIntermediateDumpWriter* writer,
+                    bool has_module_path,
+                    bool use_long_annotations) {
     IOSIntermediateDumpWriter::ScopedArray moduleArray(writer, Key::kModules);
     for (uint32_t image_index = 0; image_index < 2; ++image_index) {
       IOSIntermediateDumpWriter::ScopedArrayMap modules(writer);
@@ -239,12 +251,13 @@
       EXPECT_TRUE(writer->AddProperty(Key::kSourceVersion, &source_version));
       EXPECT_TRUE(writer->AddProperty(Key::kUUID, &uuid));
       EXPECT_TRUE(writer->AddProperty(Key::kFileType, &filetype));
-      WriteAnnotations(writer);
+      WriteAnnotations(writer, use_long_annotations);
     }
   }
 
   void ExpectModules(const std::vector<const ModuleSnapshot*>& modules,
-                     bool expect_module_path) {
+                     bool expect_module_path,
+                     bool expect_long_annotations) {
     for (auto module : modules) {
       EXPECT_EQ(module->GetModuleType(),
                 ModuleSnapshot::kModuleTypeSharedLibrary);
@@ -259,22 +272,39 @@
       EXPECT_EQ(uuid.ToString(), "00010203-0405-0607-0809-0a0b0c0d0e0f");
 
       for (auto annotation : module->AnnotationsVector()) {
-        EXPECT_STREQ(annotation.c_str(), "annotation_value");
+        if (expect_long_annotations) {
+          EXPECT_EQ(annotation, long_annotation_value_);
+        } else {
+          EXPECT_STREQ(annotation.c_str(), "annotation_value");
+        }
       }
 
       for (const auto& it : module->AnnotationsSimpleMap()) {
-        EXPECT_STREQ(it.first.c_str(), "annotation_name");
-        EXPECT_STREQ(it.second.c_str(), "annotation_value");
+        if (expect_long_annotations) {
+          EXPECT_EQ(it.first, long_annotation_name_);
+          EXPECT_EQ(it.second, long_annotation_value_);
+        } else {
+          EXPECT_STREQ(it.first.c_str(), "annotation_name");
+          EXPECT_STREQ(it.second.c_str(), "annotation_value");
+        }
       }
 
       for (auto annotation_object : module->AnnotationObjects()) {
-        EXPECT_STREQ(annotation_object.name.c_str(), "annotation_name");
         EXPECT_EQ(annotation_object.type, (short)Annotation::Type::kString);
-        EXPECT_STREQ(std::string(reinterpret_cast<const char*>(
-                                     annotation_object.value.data()),
-                                 annotation_object.value.size())
-                         .c_str(),
-                     "annotation_value");
+        if (expect_long_annotations) {
+          EXPECT_EQ(annotation_object.name, long_annotation_name_);
+          EXPECT_EQ(std::string(reinterpret_cast<const char*>(
+                                    annotation_object.value.data()),
+                                annotation_object.value.size()),
+                    long_annotation_value_);
+        } else {
+          EXPECT_STREQ(annotation_object.name.c_str(), "annotation_name");
+          EXPECT_STREQ(std::string(reinterpret_cast<const char*>(
+                                       annotation_object.value.data()),
+                                   annotation_object.value.size())
+                           .c_str(),
+                       "annotation_value");
+        }
       }
     }
   }
@@ -431,7 +461,8 @@
   }
 
   void ExpectSnapshot(const ProcessSnapshot& snapshot,
-                      bool expect_module_path) {
+                      bool expect_module_path,
+                      bool expect_long_annotations) {
     EXPECT_EQ(snapshot.ProcessID(), 2);
     EXPECT_EQ(snapshot.ParentProcessID(), 1);
 
@@ -454,7 +485,8 @@
 
     ExpectSystem(*snapshot.System());
     ExpectThreads(snapshot.Threads());
-    ExpectModules(snapshot.Modules(), expect_module_path);
+    ExpectModules(
+        snapshot.Modules(), expect_module_path, expect_long_annotations);
     ExpectMachException(*snapshot.Exception());
   }
 
@@ -463,6 +495,8 @@
   ScopedTempDir temp_dir_;
   base::FilePath path_;
   std::map<std::string, std::string> annotations_;
+  const std::string long_annotation_name_;
+  const std::string long_annotation_value_;
 };
 
 TEST_F(ProcessSnapshotIOSIntermediateDumpTest, InitializeNoFile) {
@@ -633,14 +667,38 @@
     WriteSystemInfo(writer());
     WriteProcessInfo(writer());
     WriteThreads(writer());
-    WriteModules(writer(), /*has_module_path=*/false);
+    WriteModules(
+        writer(), /*has_module_path=*/false, /*use_long_annotations=*/false);
     WriteMachException(writer(), true /* short_context=true*/);
   }
   ProcessSnapshotIOSIntermediateDump process_snapshot;
   ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations()));
   EXPECT_FALSE(IsRegularFile(path()));
   EXPECT_TRUE(DumpSnapshot(process_snapshot));
-  ExpectSnapshot(process_snapshot, /*expect_module_path=*/false);
+  ExpectSnapshot(process_snapshot,
+                 /*expect_module_path=*/false,
+                 /*expect_long_annotations=*/false);
+}
+
+TEST_F(ProcessSnapshotIOSIntermediateDumpTest, LongAnnotations) {
+  {
+    IOSIntermediateDumpWriter::ScopedRootMap rootMap(writer());
+    uint8_t version = 1;
+    EXPECT_TRUE(writer()->AddProperty(Key::kVersion, &version));
+    WriteSystemInfo(writer());
+    WriteProcessInfo(writer());
+    WriteThreads(writer());
+    WriteModules(
+        writer(), /*has_module_path=*/false, /*use_long_annotations=*/true);
+    WriteMachException(writer());
+  }
+  ProcessSnapshotIOSIntermediateDump process_snapshot;
+  ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations()));
+  EXPECT_FALSE(IsRegularFile(path()));
+  EXPECT_TRUE(DumpSnapshot(process_snapshot));
+  ExpectSnapshot(process_snapshot,
+                 /*expect_module_path=*/false,
+                 /*expect_long_annotations=*/true);
 }
 
 TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) {
@@ -651,14 +709,17 @@
     WriteSystemInfo(writer());
     WriteProcessInfo(writer());
     WriteThreads(writer());
-    WriteModules(writer(), /*has_module_path=*/true);
+    WriteModules(
+        writer(), /*has_module_path=*/true, /*use_long_annotations=*/false);
     WriteMachException(writer());
   }
   ProcessSnapshotIOSIntermediateDump process_snapshot;
   ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations()));
   EXPECT_FALSE(IsRegularFile(path()));
   EXPECT_TRUE(DumpSnapshot(process_snapshot));
-  ExpectSnapshot(process_snapshot, /*expect_module_path=*/true);
+  ExpectSnapshot(process_snapshot,
+                 /*expect_module_path=*/true,
+                 /*expect_long_annotations=*/false);
 }
 
 TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FuzzTestCases) {
diff --git a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_reader_test.cc b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_reader_test.cc
index a66d6c3d..7dfecdf9 100644
--- a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_reader_test.cc
+++ b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_reader_test.cc
@@ -53,6 +53,7 @@
   }
 
   void TearDown() override {
+    ASSERT_TRUE(writer_->Close());
     fd_.reset();
     writer_.reset();
     EXPECT_FALSE(IsRegularFile(path_));
diff --git a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.cc b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.cc
index cd4d99d..0fd3851 100644
--- a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.cc
+++ b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.cc
@@ -17,6 +17,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <ostream>
+
+#include "base/check.h"
 #include "base/posix/eintr_wrapper.h"
 #include "build/build_config.h"
 #include "util/ios/raw_logging.h"
@@ -50,6 +53,10 @@
   return rv == 0;
 }
 
+IOSIntermediateDumpWriter::~IOSIntermediateDumpWriter() {
+  DCHECK_EQ(fd_, -1) << "Call Close() before this object is destroyed.";
+}
+
 bool IOSIntermediateDumpWriter::Open(const base::FilePath& path) {
   // Set data protection class D (No protection). A file with this type of
   // protection can be read from or written to at any time.
@@ -71,7 +78,12 @@
 }
 
 bool IOSIntermediateDumpWriter::Close() {
-  return RawLoggingCloseFile(fd_);
+  if (fd_ < 0) {
+    return true;
+  }
+  int fd = fd_;
+  fd_ = -1;
+  return RawLoggingCloseFile(fd);
 }
 
 bool IOSIntermediateDumpWriter::ArrayMapStart() {
diff --git a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.h b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.h
index 836fbe7a..d4f7a7b 100644
--- a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.h
+++ b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer.h
@@ -39,12 +39,14 @@
 //! Note: All methods are `RUNS-DURING-CRASH`.
 class IOSIntermediateDumpWriter final {
  public:
-  IOSIntermediateDumpWriter() = default;
+  IOSIntermediateDumpWriter() : fd_(-1) { }
 
   IOSIntermediateDumpWriter(const IOSIntermediateDumpWriter&) = delete;
   IOSIntermediateDumpWriter& operator=(const IOSIntermediateDumpWriter&) =
       delete;
 
+  ~IOSIntermediateDumpWriter();
+
   //! \brief Command instructions for the intermediate dump reader.
   enum class CommandType : uint8_t {
     //! \brief Indicates a new map, followed by associated key.
@@ -73,6 +75,8 @@
   //! \brief Open and lock an intermediate dump file. This is the only method
   //!     in the writer class that is generally run outside of a crash.
   //!
+  //! The client must invoke `Close()` before this object is destroyed.
+  //!
   //! \param[in] path The path to the intermediate dump.
   //!
   //! \return On success, returns `true`, otherwise returns `false`.
diff --git a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer_test.cc b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer_test.cc
index 24f56ef..055ae70 100644
--- a/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer_test.cc
+++ b/third_party/crashpad/crashpad/util/ios/ios_intermediate_dump_writer_test.cc
@@ -41,6 +41,7 @@
   }
 
   void TearDown() override {
+    EXPECT_TRUE(writer_->Close());
     writer_.reset();
     EXPECT_EQ(unlink(path_.value().c_str()), 0) << ErrnoMessage("unlink");
   }
diff --git a/third_party/crashpad/crashpad/util/posix/signals_test.cc b/third_party/crashpad/crashpad/util/posix/signals_test.cc
index 94d8e51..9ccd4c5 100644
--- a/third_party/crashpad/crashpad/util/posix/signals_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/signals_test.cc
@@ -166,7 +166,7 @@
 #if defined(ARCH_CPU_X86_FAMILY)
       [[maybe_unused]] volatile int a = 42;
       volatile int b = 0;
-      a /= b;
+      a = a / b;
 #endif
       break;
     }
diff --git a/third_party/webrtc_overrides/metronome_source.cc b/third_party/webrtc_overrides/metronome_source.cc
index e9163141..c04d2c3a 100644
--- a/third_party/webrtc_overrides/metronome_source.cc
+++ b/third_party/webrtc_overrides/metronome_source.cc
@@ -29,40 +29,33 @@
 
 namespace {
 
-// Wraps a webrtc::Metronome::TickListener to ensure that OnTick is not called
-// after it is removed from the WebRtcMetronomeAdapter, using the Deactive
-// method.
-class WebRtcMetronomeListenerWrapper
-    : public base::RefCountedThreadSafe<WebRtcMetronomeListenerWrapper> {
- public:
-  explicit WebRtcMetronomeListenerWrapper(
-      webrtc::Metronome::TickListener* listener)
-      : listener_(listener) {}
+// Stores a MetronomeSource::ListenerHandle which handles listening to handle
+// ticks, and an atomic flag for cancelling the task attached to the listener.
+// When a TickListener invokes, it will check that the cancel flag was not set.
+// To avoid a race between the cancel flag and `OnTick` being invoked after
+// `RemoveListener`, `RemoveListener` needs to be called from
+// `listener->OnTickTaskQueue()`. This is the case for the only user -
+// webrtc::DecodeSynchronizer.
+//
+// TODO(http://crbug.com/1253787): Clarify threading requirements of
+// webrtc::Metronome, or change interface.
+struct HandleWithCancelation {
+  HandleWithCancelation(
+      scoped_refptr<MetronomeSource::ListenerHandle> handle,
+      rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> task_safety)
+      : handle(std::move(handle)), task_safety(std::move(task_safety)) {}
 
-  void Deactivate() {
-    base::AutoLock auto_lock(lock_);
-    active_ = false;
-  }
-
-  webrtc::Metronome::TickListener* listener() { return listener_; }
-
-  void OnTick() {
-    base::AutoLock auto_lock(lock_);
-    if (!active_)
-      return;
-    listener_->OnTick();
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<WebRtcMetronomeListenerWrapper>;
-  ~WebRtcMetronomeListenerWrapper() = default;
-
-  webrtc::Metronome::TickListener* const listener_;
-
-  base::Lock lock_;
-  bool active_ GUARDED_BY(lock_) = true;
+  scoped_refptr<MetronomeSource::ListenerHandle> handle;
+  rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> task_safety;
 };
 
+void InvokeOnTickOnWebRtcTaskQueue(
+    webrtc::Metronome::TickListener* listener,
+    rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> task_safety) {
+  listener->OnTickTaskQueue()->PostTask(webrtc::ToQueuedTask(
+      std::move(task_safety), [listener] { listener->OnTick(); }));
+}
+
 class WebRtcMetronomeAdapter : public webrtc::Metronome {
  public:
   explicit WebRtcMetronomeAdapter(
@@ -78,19 +71,17 @@
   // only be added to the metronome once.
   void AddListener(TickListener* listener) override {
     DCHECK(listener);
+    auto task_safety = webrtc::PendingTaskSafetyFlag::Create();
+    // `listener` can be unretained since the `handle` will be cancelled when
+    // `listener` is removed.
+    auto handle = metronome_source_->AddListener(
+        nullptr, base::BindRepeating(&InvokeOnTickOnWebRtcTaskQueue,
+                                     base::Unretained(listener), task_safety));
     base::AutoLock auto_lock(lock_);
     auto [it, inserted] = listeners_.emplace(
-        listener,
-        base::MakeRefCounted<WebRtcMetronomeListenerWrapper>(listener));
+        std::piecewise_construct, std::forward_as_tuple(listener),
+        std::forward_as_tuple(std::move(handle), std::move(task_safety)));
     DCHECK(inserted);
-    if (listeners_.size() == 1) {
-      DCHECK(!tick_handle_);
-      tick_handle_ = metronome_source_->AddListener(
-          nullptr,
-          base::BindRepeating(&WebRtcMetronomeAdapter::OnTick,
-                              base::Unretained(this)),
-          base::TimeTicks::Min());
-    }
   }
 
   // Removes the tick listener from the metronome. Once this method has returned
@@ -98,17 +89,22 @@
   // within OnTick.
   void RemoveListener(TickListener* listener) override {
     DCHECK(listener);
-    base::AutoLock auto_lock(lock_);
-    auto it = listeners_.find(listener);
-    if (it == listeners_.end()) {
-      DLOG(WARNING) << __FUNCTION__ << " called with unregistered listener.";
-      return;
+    scoped_refptr<MetronomeSource::ListenerHandle> handle;
+    rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> task_safety;
+
+    {
+      base::AutoLock auto_lock(lock_);
+      auto it = listeners_.find(listener);
+      if (it == listeners_.end()) {
+        DLOG(WARNING) << __FUNCTION__ << " called with unregistered listener.";
+        return;
+      }
+      handle = std::move(it->second.handle);
+      task_safety = std::move(it->second.task_safety);
+      listeners_.erase(listener);
     }
-    it->second->Deactivate();
-    listeners_.erase(it);
-    if (listeners_.size() == 0) {
-      metronome_source_->RemoveListener(std::move(tick_handle_));
-    }
+    task_safety->SetNotAlive();
+    metronome_source_->RemoveListener(std::move(handle));
   }
 
   // Returns the current tick period of the metronome.
@@ -117,19 +113,10 @@
   }
 
  private:
-  void OnTick() {
-    base::AutoLock auto_lock(lock_);
-    for (auto [listener, wrapper] : listeners_) {
-      listener->OnTickTaskQueue()->PostTask(webrtc::ToQueuedTask(
-          [the_wrapper = std::move(wrapper)] { the_wrapper->OnTick(); }));
-    }
-  }
-
   const scoped_refptr<MetronomeSource> metronome_source_;
   base::Lock lock_;
-  base::flat_map<TickListener*, scoped_refptr<WebRtcMetronomeListenerWrapper>>
-      listeners_ GUARDED_BY(lock_);
-  scoped_refptr<MetronomeSource::ListenerHandle> tick_handle_ GUARDED_BY(lock_);
+  base::flat_map<TickListener*, HandleWithCancelation> listeners_
+      GUARDED_BY(lock_);
 };
 
 }  // namespace
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4a4b56a..6690b3e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -56968,6 +56968,7 @@
   <int value="-523030434" label="EnableBackgroundBlur:enabled"/>
   <int value="-522075903"
       label="OmniboxOnFocusSuggestionsContextualWeb:enabled"/>
+  <int value="-521251533" label="PrivacyGuideAndroid:enabled"/>
   <int value="-520221221" label="UserDataSnapshot:enabled"/>
   <int value="-520004021" label="WebXRHitTest:disabled"/>
   <int value="-519960638" label="enable-site-engagement-service"/>
@@ -58750,6 +58751,7 @@
   <int value="682916740" label="PdfUnseasoned:disabled"/>
   <int value="683013217" label="AllowPopupsDuringPageUnload:disabled"/>
   <int value="683433500" label="CommerceMerchantViewer:disabled"/>
+  <int value="683746280" label="PrivacyGuideAndroid:disabled"/>
   <int value="684198422" label="UnifiedPasswordManagerDesktop:enabled"/>
   <int value="684806628" label="TranslateLanguageByULP:disabled"/>
   <int value="685406951" label="UseNotificationCompatBuilder:disabled"/>
@@ -99520,6 +99522,7 @@
   <int value="683177973" label="/cupsPrinters"/>
   <int value="754547746" label="/help/details"/>
   <int value="805959528" label="/security"/>
+  <int value="834907708" label="/privacy/guide"/>
   <int value="838443004" label="/safetyCheck"/>
   <int value="856943564" label="/content/siteDetails"/>
   <int value="868952532" label="/pointer-overlay"/>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index b43993d..cf270c87 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -7802,6 +7802,10 @@
       label="Only counting memory used by Extension value store database."/>
   <suffix name="GpuMemory" label="Only counting memory allocated for the GPU."/>
   <suffix name="IOSurface" label="Memory used for IOSurfaces, on macOS."/>
+  <suffix name="IOSurface.DirtyMemory"
+      label="Memory used for IOSurfaces, on macOS. Only account for dirty
+             (resident and swapped) memory, which is part of private memory
+             footprint."/>
   <suffix name="JavaHeap"
       label="Only counting memory used by Java heap in Android."/>
   <suffix name="Malloc"
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 1a03dde..6069af3 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -2214,6 +2214,23 @@
 </histogram>
 
 <histogram
+    name="PasswordManager.PasswordStoreAndroidBackend.APIError.{SyncErrorStatus}"
+    enum="PasswordStoreAndroidBackendAPIError" expires_after="2022-06-30">
+  <owner>fhorschig@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    The error codes returned by the GMS Core ChromeSync 1P API when
+    {SyncErrorStatus} is returned by SyncService.GetAuthError(). Recorded when
+    the asynchronous job has returned.
+  </summary>
+  <token key="SyncErrorStatus">
+    <variant name="NoAuthError" summary="no error"/>
+    <variant name="PersistentAuthError" summary="a persistent auth error"/>
+    <variant name="TransientAuthError" summary="a transient auth error"/>
+  </token>
+</histogram>
+
+<histogram
     name="PasswordManager.PasswordStoreAndroidBackend.ClearAllLocalPasswords.LoginsToRemove"
     units="count" expires_after="2022-09-11">
   <owner>fhorschig@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 82a7e19..5e3bbca 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -934,17 +934,6 @@
   </summary>
 </histogram>
 
-<histogram name="SafeBrowsing.DelayedWarnings.Event_UrlElisionDisabled"
-    enum="SafeBrowsingDelayedWarningEvent" expires_after="M91">
-  <owner>meacer@chromium.org</owner>
-  <owner>chrome-safebrowsing-alerts@google.com</owner>
-  <summary>
-    Same as SafeBrowsing.DelayedWarnings.Event but only recorded when user has
-    disabled URL elision via &quot;Always Show Full URLs&quot; context menu
-    item, or by installing the Suspicious Site Reporter extension.
-  </summary>
-</histogram>
-
 <histogram name="SafeBrowsing.DelayedWarnings.TimeOnPage" units="ms"
     expires_after="M89">
   <owner>meacer@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index 1188b218..94cfe4f 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -311,7 +311,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.ExtendableMessageEvent.Time" units="ms"
-    expires_after="2022-06-30">
+    expires_after="2022-12-15">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml
index 84196ea..38ac4a5 100644
--- a/tools/metrics/histograms/metadata/settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -192,7 +192,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyGuide.EntryExit"
-    enum="SettingsPrivacyGuideInteractions" expires_after="2022-09-25">
+    enum="SettingsPrivacyGuideInteractions" expires_after="2022-11-13">
   <owner>harrisonsean@chromium.org</owner>
   <owner>rainhard@chromium.org</owner>
   <owner>chrome-friendly-settings@google.com</owner>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyGuide.SettingsStates"
-    enum="SettingsPrivacyGuideSettingsStates" expires_after="M104">
+    enum="SettingsPrivacyGuideSettingsStates" expires_after="2022-11-13">
   <owner>harrisonsean@chromium.org</owner>
   <owner>rainhard@chromium.org</owner>
   <owner>chrome-friendly-settings@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index cf459de..cb8fbb4 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -417,6 +417,29 @@
   </token>
 </histogram>
 
+<histogram name="Sync.FCMInstanceIdTokenRetrievalStatus"
+    enum="InstanceIDResult" expires_after="2022-11-30">
+  <owner>rushans@google.com</owner>
+  <owner>treib@chromium.org</owner>
+  <component>Services&gt;Sync</component>
+  <summary>
+    Records status of each attempt to retrieve the instance id token. Replaces
+    FCMInvalidations.InitialTokenRetrievalStatus for Sync standalone
+    invalidations.
+  </summary>
+</histogram>
+
+<histogram name="Sync.FCMMessageDeliveredToListeners" enum="Boolean"
+    expires_after="2022-11-30">
+  <owner>rushans@google.com</owner>
+  <owner>treib@chromium.org</owner>
+  <component>Services&gt;Sync</component>
+  <summary>
+    Whether an incoming FCM message has been delivered to at least one listener.
+    Recorded on each incoming FCM message for standalone Sync invalidations.
+  </summary>
+</histogram>
+
 <histogram name="Sync.IncomingInvalidationStatus"
     enum="SyncIncomingInvalidationStatus" expires_after="2022-11-13">
   <owner>rushans@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index 4e1d2e26..9507bb5 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -1969,7 +1969,7 @@
 </histogram>
 
 <histogram name="V8.WasmModuleCodeSizeTopTierMiB" units="MB"
-    expires_after="2022-11-06">
+    expires_after="M102">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 7bf9afa..a6a97b4 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -2064,6 +2064,16 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.Screenshare.ZeroHz.TimeUntilFirstFrameMs" units="ms"
+    expires_after="2023-05-22">
+  <owner>handellm@google.com</owner>
+  <owner>ilnik@chromium.org</owner>
+  <summary>
+    The number of milliseconds from the point a zero-Hz frame cadence adapter is
+    created until the first frame arrives from a connected source.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.SentAudioTrackDuration" units="ms"
     expires_after="2022-10-09">
   <owner>perkj@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 8788f68..d524a20 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "dfa666ba78c81ad93ac36b4893c39fde6419e661",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/370def59dcc5b6423f805754160cab7c5b772c2d/trace_processor_shell.exe"
+            "hash": "0748617d91972c5c0e142ba67e82f54165c85b8b",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/785aac6dabe1216142ec32490a9086cd35db3b2d/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "cba2db3019906c1d886a8436d402bd359af1eec7",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/370def59dcc5b6423f805754160cab7c5b772c2d/trace_processor_shell"
+            "hash": "a11dcd1767031dfbe98a487df0baeaa88ab915c9",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/785aac6dabe1216142ec32490a9086cd35db3b2d/trace_processor_shell"
         }
     },
     "power_profile.sql": {