diff --git a/DEPS b/DEPS
index b324f1d..d9a4206fc 100644
--- a/DEPS
+++ b/DEPS
@@ -239,7 +239,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'b4d01cbe41b1b9bfdd6ba8603e457293210cfb32',
+  'skia_revision': '85d6190f60aaafafba4095a1669bdda28a1cf721',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -251,7 +251,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '4625f84e8d56feaf9ba0122f49a04f9cccbad909',
+  'swiftshader_revision': 'ec4bdcf9ac08177801499d5494ca9a3b03be068d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -314,7 +314,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': 'a0f5d966740ebe948b79cdf1ed05a0ddd74f3a2d',
+  'devtools_frontend_revision': '3d57faf4fe5c2c2c3c93ebce4bc3641c84ce0766',
   # 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.
@@ -713,7 +713,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'bx8h2qMq5ktTv_lH-_WkY7nS8q9go7i7r3Ydl7WXf_cC',
+          'version': 'sG1sIFVH9BWih3VgGjNe3D0yeZ7eyHNqB6KetJ-sFK0C',
         },
       ],
       'dep_type': 'cipd',
@@ -724,7 +724,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'uq89uFZNnJdY9GI6wpkwAWVEo5gw7Oj2SAsUhjj7FIsC',
+          'version': 'yBQy7Y23z8xFUV1FlraJfe_kO2R3TBS2C2LINGzmS7MC',
         },
       ],
       'dep_type': 'cipd',
@@ -735,7 +735,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'Wb684G7g-2oIT7edWKg4ZeNMIgrN-SDdi1-OhcMUX6MC',
+          'version': 'Q9tO2G-964TT5U0q_bbveTUhHCjMA-J20RoP5-fRrn4C',
         },
       ],
       'dep_type': 'cipd',
@@ -796,7 +796,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'ZXiG8aqK-I4SG-IHCzog9Uk1AUWULpee7Wo5OGj3sSYC',
+          'version': 'DNc4I2rGk4iZSBl_wBB2ktZtP4RciplkBsSeb0Tex3cC',
       },
     ],
     'condition': 'checkout_android',
@@ -1015,7 +1015,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' + '@' + '193f9dff46e20187c7da0be686468407726da3b0',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b006bf3aaf416eb91340184b20376cad8da8b7a4',
       'condition': 'checkout_chromeos',
   },
 
@@ -1418,7 +1418,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '514135fb1a37ba15cf7daad4918e17cfc1724de4',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '593db496f656e1b936a82ca9e45fb092696091f3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1639,7 +1639,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '4f2c3b6ac243f7e97ae1afb664d2b14b65fcf097',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e33212ade5b86af1dc6f3d66c2e489e28dc662a3',
+    Var('webrtc_git') + '/src.git' + '@' + 'a6b138d6b4ef3a5b2c87f899b67f3b5c8dd3c002',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1697,7 +1697,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@06ee9744c78f2927d013d075ba6740945d02dfcd',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1d313c1e4f3e200e6d4504550ceb65d91ad206b2',
     'condition': 'checkout_src_internal',
   },
 
@@ -1716,7 +1716,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'Lo_CR-eR-KCX5ITWCK7ATbR8GFZhQNhS47vUES5EOzEC',
+        'version': 'GxdQpMONek_GWb4l7bbfYNsURCa_2pQt_VJMIWZ1V4IC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1727,7 +1727,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'qQQSe5fgvGcN6aGrrqZo4XOjWxbQkBzFQ4VRm0zC2nQC',
+        'version': '9ZUrbNE5w6Vm4a1U8bOiQWZsser86JhKm0QxOWDwODEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1738,7 +1738,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'r6-k2vrGWXcquUe49dygRZ0CjXM9BoA5rEmD19zRuHYC',
+        'version': 'pwWl45e8CwnjoRUQRA15C1LdV_vlCgTKrcx6pX5_CY0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index e75963c7..6389196 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -5465,7 +5465,8 @@
 
     errors = []
     pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
-    for f in input_api.AffectedFiles(file_filter=FileFilter):
+    for f in input_api.AffectedFiles(include_deletes=False,
+                                     file_filter=FileFilter):
         if (not pattern.search(input_api.ReadFile(f))):
             errors.append(
                 output_api.PresubmitError(
diff --git a/android_webview/browser/cookie_manager.cc b/android_webview/browser/cookie_manager.cc
index 2444b09..388cf31 100644
--- a/android_webview/browser/cookie_manager.cc
+++ b/android_webview/browser/cookie_manager.cc
@@ -512,12 +512,12 @@
 
   if (GetMojoCookieManager()) {
     GetMojoCookieManager()->GetCookieList(
-        host, options, net::CookiePartitionKeychain::Todo(),
+        host, options, net::CookiePartitionKeyCollection::Todo(),
         base::BindOnce(&CookieManager::GetCookieListCompleted,
                        base::Unretained(this), std::move(complete), result));
   } else {
     GetCookieStore()->GetCookieListWithOptionsAsync(
-        host, options, net::CookiePartitionKeychain::Todo(),
+        host, options, net::CookiePartitionKeyCollection::Todo(),
         base::BindOnce(&CookieManager::GetCookieListCompleted,
                        base::Unretained(this), std::move(complete), result));
   }
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index ae47a185..503e1cf0 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -266,6 +266,7 @@
     "views/app_list_bubble_apps_page_unittest.cc",
     "views/app_list_bubble_view_unittest.cc",
     "views/app_list_folder_view_unittest.cc",
+    "views/app_list_item_view_unittest.cc",
     "views/app_list_main_view_unittest.cc",
     "views/app_list_menu_model_adapter_unittest.cc",
     "views/app_list_view_unittest.cc",
diff --git a/ash/app_list/model/app_list_item.h b/ash/app_list/model/app_list_item.h
index 31f558a..430083b8 100644
--- a/ash/app_list/model/app_list_item.h
+++ b/ash/app_list/model/app_list_item.h
@@ -132,6 +132,7 @@
   friend class AppListBadgeController;
   friend class AppListItemList;
   friend class AppListItemListTest;
+  friend class AppListItemViewProductivityLauncherTest;
   friend class AppListModel;
 
   // These should only be called by AppListModel or in tests so that name
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index b1b2565..c848bae 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -22,6 +22,7 @@
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/style/color_provider.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/check.h"
@@ -87,6 +88,12 @@
 // icon.
 constexpr float kNotificationIndicatorPaddingRatio = 4.0f / 64.0f;
 
+// Size of the "new install" blue dot that appears to the left of the title.
+constexpr int kNewInstallDotSize = 8;
+
+// Distance between the "new install" blue dot and the title.
+constexpr int kNewInstallDotPadding = 4;
+
 // The class clips the provided folder icon image.
 class ClippedFolderIconImageSource : public gfx::CanvasImageSource {
  public:
@@ -119,6 +126,38 @@
   const gfx::ImageSkia image_;
 };
 
+// Draws a dot with no shadow.
+class DotView : public views::View {
+ public:
+  DotView() {
+    // The dot is not clickable.
+    SetCanProcessEventsWithinSubtree(false);
+  }
+  DotView(const DotView&) = delete;
+  DotView& operator=(const DotView&) = delete;
+  ~DotView() override = default;
+
+  // views::View:
+  void OnPaint(gfx::Canvas* canvas) override {
+    DCHECK_EQ(width(), height());
+    const float radius = width() / 2.0f;
+    const float scale = canvas->UndoDeviceScaleFactor();
+    gfx::PointF center = gfx::RectF(GetLocalBounds()).CenterPoint();
+    center.Scale(scale);
+
+    cc::PaintFlags flags;
+    flags.setColor(AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kIconColorProminent));
+    flags.setAntiAlias(true);
+    canvas->DrawCircle(center, scale * radius, flags);
+  }
+
+  void OnThemeChanged() override {
+    views::View::OnThemeChanged();
+    SchedulePaint();
+  }
+};
+
 }  // namespace
 
 // The badge which is activated when the app corresponding with this
@@ -320,6 +359,9 @@
 
   title_ = AddChildView(std::move(title));
 
+  new_install_dot_ = AddChildView(std::make_unique<DotView>());
+  new_install_dot_->SetVisible(item_weak_->is_new_install());
+
   SetIcon(item_weak_->GetIcon(app_list_config_->type()));
   SetItemName(base::UTF8ToUTF16(item->GetDisplayName()),
               base::UTF8ToUTF16(item->name()));
@@ -589,12 +631,7 @@
   if (is_folder_ && display_name.empty()) {
     title_->SetText(folder_name_placeholder);
   } else {
-    std::u16string title_text;
-    // TODO(crbug.com/1272817): Use a view for the dot.
-    if (item() && item()->is_new_install())
-      title_text = u"• ";
-    title_text += display_name;
-    title_->SetText(title_text);
+    title_->SetText(display_name);
   }
 
   tooltip_text_ = display_name == full_name ? std::u16string() : full_name;
@@ -806,8 +843,17 @@
 
   gfx::Rect title_bounds = GetTitleBoundsForTargetViewBounds(
       app_list_config_, rect, title_->GetPreferredSize(), icon_scale_);
+  // Reserve space for the new install dot if it is visible. Otherwise it
+  // extends outside the app grid tile bounds and gets clipped.
+  if (new_install_dot_->GetVisible())
+    title_bounds.Inset(kNewInstallDotSize, 0, 0, 0);
   title_->SetBoundsRect(title_bounds);
 
+  new_install_dot_->SetBounds(
+      title_bounds.x() - kNewInstallDotSize - kNewInstallDotPadding,
+      title_bounds.y() + title_bounds.height() / 2 - kNewInstallDotSize / 2,
+      kNewInstallDotSize, kNewInstallDotSize);
+
   if (notification_indicator_)
     notification_indicator_->SetBoundsRect(icon_bounds);
 }
@@ -962,6 +1008,10 @@
   title_->SetTooltipText(tooltip_text_);
   std::u16string tooltip = title_->GetTooltipText(p);
   title_->SetHandlesTooltips(false);
+  if (item_weak_ && item_weak_->is_new_install()) {
+    // Tooltip becomes two lines: "App Name" + "New install".
+    tooltip = l10n_util::GetStringFUTF16(IDS_APP_LIST_NEW_INSTALL, tooltip);
+  }
   return tooltip;
 }
 
@@ -1166,10 +1216,8 @@
 }
 
 void AppListItemView::ItemIsNewInstallChanged() {
-  // TODO(crbug.com/1272817): Use a view for the dot. For now, just refresh the
-  // label to add or remove the bullet from the name.
-  SetItemName(base::UTF8ToUTF16(item_weak_->GetDisplayName()),
-              base::UTF8ToUTF16(item_weak_->name()));
+  DCHECK(item_weak_);
+  new_install_dot_->SetVisible(item_weak_->is_new_install());
 }
 
 void AppListItemView::ItemBeingDestroyed() {
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h
index 58f4a82..077ea40 100644
--- a/ash/app_list/views/app_list_item_view.h
+++ b/ash/app_list/views/app_list_item_view.h
@@ -231,6 +231,7 @@
   void SetContextMenuShownCallbackForTest(base::RepeatingClosure closure);
 
  private:
+  friend class AppListItemViewProductivityLauncherTest;
   friend class test::AppsGridViewTest;
   friend class test::AppListMainViewTest;
 
@@ -382,6 +383,9 @@
   IconImageView* icon_ = nullptr;  // Strongly typed child view.
   views::Label* title_ = nullptr;  // Strongly typed child view.
 
+  // Draws a dot next to the title for newly installed apps.
+  views::View* new_install_dot_ = nullptr;
+
   // The context menu model adapter used for app item view.
   std::unique_ptr<AppListMenuModelAdapter> item_menu_model_adapter_;
 
diff --git a/ash/app_list/views/app_list_item_view_unittest.cc b/ash/app_list/views/app_list_item_view_unittest.cc
new file mode 100644
index 0000000..5cf2d20
--- /dev/null
+++ b/ash/app_list/views/app_list_item_view_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/app_list/views/app_list_item_view.h"
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/model/app_list_test_model.h"
+#include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/scrollable_apps_grid_view.h"
+#include "ash/constants/ash_features.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "base/test/scoped_feature_list.h"
+
+namespace ash {
+
+class AppListItemViewProductivityLauncherTest : public AshTestBase {
+ public:
+  AppListItemViewProductivityLauncherTest() = default;
+  ~AppListItemViewProductivityLauncherTest() override = default;
+
+  // testing::Test:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    app_list_test_model_ = std::make_unique<test::AppListTestModel>();
+    search_model_ = std::make_unique<SearchModel>();
+    Shell::Get()->app_list_controller()->SetActiveModel(
+        /*profile_id=*/1, app_list_test_model_.get(), search_model_.get());
+  }
+
+  static views::View* GetNewInstallDot(AppListItemView* view) {
+    return view->new_install_dot_;
+  }
+
+  static void SetName(AppListItem* item, const std::string& name) {
+    item->SetName(name);
+  }
+
+  base::test::ScopedFeatureList feature_list_{features::kProductivityLauncher};
+  std::unique_ptr<test::AppListTestModel> app_list_test_model_;
+  std::unique_ptr<SearchModel> search_model_;
+};
+
+TEST_F(AppListItemViewProductivityLauncherTest, NewInstallDot) {
+  auto* item = app_list_test_model_->CreateAndAddItem("id");
+  SetName(item, "Google Buzz");
+  ASSERT_FALSE(item->is_new_install());
+
+  auto* helper = GetAppListTestHelper();
+  helper->ShowAppList();
+
+  // By default, the new install dot is not visible.
+  auto* apps_grid_view = helper->GetScrollableAppsGridView();
+  AppListItemView* item_view = apps_grid_view->GetItemViewAt(0);
+  views::View* new_install_dot = GetNewInstallDot(item_view);
+  EXPECT_FALSE(new_install_dot->GetVisible());
+  EXPECT_EQ(item_view->GetTooltipText({}), u"Google Buzz");
+
+  // When the app is a new install the dot is visible and the tooltip changes.
+  item->SetIsNewInstall(true);
+  EXPECT_TRUE(new_install_dot->GetVisible());
+  EXPECT_EQ(item_view->GetTooltipText({}), u"Google Buzz\nNew install");
+}
+
+}  // namespace ash
diff --git a/ash/app_list/views/continue_task_view.cc b/ash/app_list/views/continue_task_view.cc
index 9e767ec..a42e814 100644
--- a/ash/app_list/views/continue_task_view.cc
+++ b/ash/app_list/views/continue_task_view.cc
@@ -52,10 +52,6 @@
 constexpr int kTaskMaxWidth = 264;
 
 gfx::ImageSkia CreateIconWithCircleBackground(const gfx::ImageSkia& icon) {
-  // The icon with circular background should only be styled when dark light
-  // mode is enabled. Otherwise, use the default chip icon.
-  if (!features::IsDarkLightModeEnabled())
-    return icon;
   return gfx::ImageSkiaOperations::CreateImageWithCircleBackground(
       kCircleRadius,
       ColorProvider::Get()->GetControlsLayerColor(
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 8681e668..21f46b7 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -4402,6 +4402,10 @@
       <message name="IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER" desc="The placeholder text for app list folder name.">
         Unnamed
       </message>
+      <message name="IDS_APP_LIST_NEW_INSTALL" desc="Tooltip text indicating an app is newly installed.">
+        <ph name="APP_NAME">$1<ex>App Name</ex></ph>
+New install
+      </message>
       <message name="IDS_APP_LIST_SEARCH_BOX_AUTOCOMPLETE" desc="The spoken feedback text for when the search box autocompletes a result">
         <ph name="TEXT">$1<ex>typed text + autocomplete</ex></ph>, Autocomplete
       </message>
diff --git a/ash/ash_strings_grd/IDS_APP_LIST_NEW_INSTALL.png.sha1 b/ash/ash_strings_grd/IDS_APP_LIST_NEW_INSTALL.png.sha1
new file mode 100644
index 0000000..4510374
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_APP_LIST_NEW_INSTALL.png.sha1
@@ -0,0 +1 @@
+256f07cfb3542ad38e2b147aa0ec073b55e729ad
\ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 02b4fad..cd4a381 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1006,6 +1006,10 @@
 // Controls whether to enable Projector.
 const base::Feature kProjector{"Projector", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether to enable Projector for managed users.
+const base::Feature kProjectorManagedUser{"ProjectorManagedUser",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to enable Projector in status tray.
 const base::Feature kProjectorFeaturePod{"ProjectorFeaturePod",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
@@ -1757,9 +1761,17 @@
 }
 
 bool IsProjectorEnabled() {
+  return IsProjectorAllUserEnabled() || IsProjectorManagedUserEnabled();
+}
+
+bool IsProjectorAllUserEnabled() {
   return base::FeatureList::IsEnabled(kProjector);
 }
 
+bool IsProjectorManagedUserEnabled() {
+  return base::FeatureList::IsEnabled(kProjectorManagedUser);
+}
+
 bool IsProjectorFeaturePodEnabled() {
   return IsProjectorEnabled() &&
          base::FeatureList::IsEnabled(kProjectorFeaturePod);
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 5bfb725..5912fa5a 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -382,6 +382,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kProductivityLauncherAnimation;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjector;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kProjectorManagedUser;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjectorFeaturePod;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjectorAnnotator;
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -609,6 +611,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProductivityLauncherEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProductivityLauncherAnimationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorAllUserEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorManagedUserEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorFeaturePodEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorAnnotatorEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickDimEnabled();
diff --git a/ash/shelf/scrollable_shelf_view.cc b/ash/shelf/scrollable_shelf_view.cc
index 018b783d..8dd118c 100644
--- a/ash/shelf/scrollable_shelf_view.cc
+++ b/ash/shelf/scrollable_shelf_view.cc
@@ -426,6 +426,15 @@
 
 gfx::Rect ScrollableShelfView::GetTargetScreenBoundsOfItemIcon(
     const ShelfID& id) const {
+  const int item_index_in_model = shelf_view_->model()->ItemIndexByID(id);
+
+  // Return a dummy value if the item specified by `id` does not exist in the
+  // shelf model.
+  // TODO(https://crbug.com/1270498): it is a quick fixing. We should
+  // investigate the root cause.
+  if (item_index_in_model < 0)
+    return gfx::Rect();
+
   // Calculates the available space for child views based on the target bounds.
   // To ease coding, we use the variables before mirroring in computation.
   const gfx::Insets target_edge_padding_RTL_mirrored =
@@ -441,8 +450,8 @@
   const gfx::Insets current_edge_padding_before_RTL_mirror =
       ShouldAdaptToRTL() ? GetMirroredInsets(current_edge_padding_RTL_mirrored)
                          : current_edge_padding_RTL_mirrored;
-  gfx::Rect icon_bounds = shelf_view_->view_model()->ideal_bounds(
-      shelf_view_->model()->ItemIndexByID(id));
+  gfx::Rect icon_bounds =
+      shelf_view_->view_model()->ideal_bounds(item_index_in_model);
   icon_bounds.Offset(target_edge_padding_before_RTL_mirror.left() -
                          current_edge_padding_before_RTL_mirror.left(),
                      0);
diff --git a/ash/shelf/shelf_app_button.cc b/ash/shelf/shelf_app_button.cc
index eb27d2b..17a61db 100644
--- a/ash/shelf/shelf_app_button.cc
+++ b/ash/shelf/shelf_app_button.cc
@@ -851,8 +851,14 @@
 void ShelfAppButton::InkDropRippleAnimationEnded(views::InkDropState state) {
   // Notify the host view of the ink drop to be hidden at the end of ink drop
   // animation.
-  if (state == views::InkDropState::HIDDEN)
+  // TODO(https://crbug.com/1126491): Ideally ink drops should be hidden at the
+  // end. However, it may not be guaranteed in reality. Therefore decrease the
+  // ink drop count when `state` is DEACTIVATED. If this tentative fixing works,
+  // we should fix the code so that an ink drop's final state is HIDDEN.
+  if (state == views::InkDropState::HIDDEN ||
+      state == views::InkDropState::DEACTIVATED) {
     SetInkDropAnimationStarted(/*started=*/false);
+  }
 }
 
 void ShelfAppButton::UpdateState() {
diff --git a/ash/strings/ash_strings_az.xtb b/ash/strings/ash_strings_az.xtb
index a8d68b4..8e99c5a2 100644
--- a/ash/strings/ash_strings_az.xtb
+++ b/ash/strings/ash_strings_az.xtb
@@ -338,6 +338,7 @@
 <translation id="3307642347673023554">Noutbuk rejiminə keçirilib</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> sonradan yenə daxil ola biləcək.</translation>
 <translation id="3321628682574733415">Yanlış valideyn kodu</translation>
+<translation id="3340475855009870209"><ph name="FILENAME" /> endirməsi skanlanır</translation>
 <translation id="3341303451326249809">Skrinşot çəkildi</translation>
 <translation id="334252345105450327">Skrinşot çəkin</translation>
 <translation id="3351879221545518001">Hazırda ekranı paylaşırsınız.</translation>
diff --git a/ash/strings/ash_strings_it.xtb b/ash/strings/ash_strings_it.xtb
index c9c749a..576baa7 100644
--- a/ash/strings/ash_strings_it.xtb
+++ b/ash/strings/ash_strings_it.xtb
@@ -338,6 +338,7 @@
 <translation id="3307642347673023554">Passaggio alla modalità laptop effettuato</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> può ancora accedere in seguito.</translation>
 <translation id="3321628682574733415">Codice genitore errato</translation>
+<translation id="3340475855009870209">Scansione del file <ph name="FILENAME" /> in corso…</translation>
 <translation id="3341303451326249809">Screenshot acquisito</translation>
 <translation id="334252345105450327">Acquisisci uno screenshot</translation>
 <translation id="3351879221545518001">Al momento stai trasmettendo lo schermo.</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index e926684..b5d4e29a 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -338,6 +338,7 @@
 <translation id="3307642347673023554">ノートパソコン モードに切り替えました</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> が後でログインすることは引き続き可能です。</translation>
 <translation id="3321628682574733415">保護者のコードが間違っています</translation>
+<translation id="3340475855009870209">ダウンロードされた <ph name="FILENAME" /> をスキャンしています</translation>
 <translation id="3341303451326249809">スクリーンショットをキャプチャしました</translation>
 <translation id="334252345105450327">スクリーンショットを撮って</translation>
 <translation id="3351879221545518001">現在、画面をキャストしています。</translation>
diff --git a/ash/strings/ash_strings_mk.xtb b/ash/strings/ash_strings_mk.xtb
index d3b5c96..0c7155c 100644
--- a/ash/strings/ash_strings_mk.xtb
+++ b/ash/strings/ash_strings_mk.xtb
@@ -338,6 +338,7 @@
 <translation id="3307642347673023554">Се префрливте во режим на лаптоп</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> сепак ќе може да се најави подоцна.</translation>
 <translation id="3321628682574733415">Неточен код на родител</translation>
+<translation id="3340475855009870209">Се скенира преземање: <ph name="FILENAME" /></translation>
 <translation id="3341303451326249809">Направена е слика од екранот</translation>
 <translation id="334252345105450327">Направи слика од екранот</translation>
 <translation id="3351879221545518001">Во моментов емитувате екран.</translation>
diff --git a/ash/strings/ash_strings_mn.xtb b/ash/strings/ash_strings_mn.xtb
index c3ff555..57b611d 100644
--- a/ash/strings/ash_strings_mn.xtb
+++ b/ash/strings/ash_strings_mn.xtb
@@ -35,6 +35,7 @@
 <translation id="1175572348579024023">Гүйлгэх</translation>
 <translation id="1178581264944972037">Түр зогсоох</translation>
 <translation id="1181037720776840403">Хасах</translation>
+<translation id="118437560755358292">Нэмэлт аюулгүй байдлын үүднээс нууц үг эсвэл ПИН оруулна уу</translation>
 <translation id="118532027333893379">Бүтэн дэлгэцийн зургийг авахын тулд дурын газар товшино уу</translation>
 <translation id="1190609913194133056">Мэдэгдлийн төв</translation>
 <translation id="1190678134285018527">Төхөөрөмж өмнөх хувилбар луу буцах шаардлагатай</translation>
@@ -338,6 +339,7 @@
 <translation id="3307642347673023554">Зөөврийн компьютерын горим руу сэлгэсэн</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> дараа нэвтрэх боломжтой хэвээр байна.</translation>
 <translation id="3321628682574733415">Эцэг эхийн код буруу байна</translation>
+<translation id="3339826665088060472">Дэлгэцийн агшин болон дэлгэцийн бичлэг авах хэрэгсэл болох Дэлгэцийн зураг авах онцлог</translation>
 <translation id="3340475855009870209">Таталтыг скан хийж байна <ph name="FILENAME" /></translation>
 <translation id="3341303451326249809">Дэлгэцийн агшныг авсан</translation>
 <translation id="334252345105450327">Дэлгэцийн агшин авах</translation>
@@ -395,6 +397,7 @@
 <translation id="3606978283550408104">Брайль дэлгэц холбогдсон.</translation>
 <translation id="3615926715408477684">Мобайл датаг идэвхжүүлснээр Bluetooth-г мөн идэвхжүүлнэ</translation>
 <translation id="3616883743181209306">Цэсийг дэлгэцийн баруун дээд булан руу зөөсөн.</translation>
+<translation id="3619536907358025872">Дэлгэцийн зураг авах горимын тохиргоо</translation>
 <translation id="3621202678540785336">Оролт</translation>
 <translation id="3621712662352432595">Аудио тохиргоонууд</translation>
 <translation id="3626281679859535460">Цайралт</translation>
@@ -494,6 +497,7 @@
 <translation id="4269883910223712419">Энэ төхөөрөмжийн админ дараах зүйлсийг хийх боломжтой:</translation>
 <translation id="4274537685965975248">Ctrl + Alt + Доош сумны товчлуурын шууд холбоосыг өөрчилсөн байна. End товчлуурыг ашиглахын тулд <ph name="LAUNCHER_KEY_NAME" /> товчлуур + Баруун сумыг дарна уу.</translation>
 <translation id="4279490309300973883">Толин тусгал үүсгэх</translation>
+<translation id="4283888303416325161">Нэмэлт аюулгүй байдлын үүднээс нууц үг оруулна уу</translation>
 <translation id="4285498937028063278">Сонголтоос гаргах</translation>
 <translation id="429402653707266969">Самбарын байршлыг асаах/унтраах</translation>
 <translation id="4294319844246081198">Өглөөний мэнд <ph name="GIVEN_NAME" />,</translation>
@@ -762,6 +766,7 @@
 <translation id="607652042414456612">Таны компьютер ойролцоо байгаа Bluetooth төхөөрөмж дээр илрэх боломжтой бөгөөд <ph name="ADDRESS" /> хаяг бүхий "<ph name="NAME" />" нэрээр гарч ирэх болно.</translation>
 <translation id="6114505516289286752"><ph name="LANGUAGE" /> дээрх ярианы файлуудыг татсан</translation>
 <translation id="6119360623251949462"><ph name="CHARGING_STATE" />. <ph name="BATTERY_SAVER_STATE" /></translation>
+<translation id="6121838516699723042"><ph name="FILENAME" />-н таталтыг баталгаажуулах</translation>
 <translation id="612734058257491180">Зочны сургалтад Google Туслах боломжгүй байна.</translation>
 <translation id="6134259848159370930">Төхөөрөмж, апп, тохиргоо, вебээс хайна уу.</translation>
 <translation id="6137566720514957455"><ph name="USER_EMAIL_ADDRESS" />-н хасах харилцах цонхыг нээнэ үү</translation>
diff --git a/ash/strings/ash_strings_zh-CN.xtb b/ash/strings/ash_strings_zh-CN.xtb
index 0e8c908c..5087e8f 100644
--- a/ash/strings/ash_strings_zh-CN.xtb
+++ b/ash/strings/ash_strings_zh-CN.xtb
@@ -338,6 +338,7 @@
 <translation id="3307642347673023554">已切换到笔记本电脑模式</translation>
 <translation id="3308453408813785101">日后“<ph name="USER_EMAIL_ADDRESS" />”仍能登录。</translation>
 <translation id="3321628682574733415">家长访问代码不正确</translation>
+<translation id="3340475855009870209">正在扫描下载的文件 <ph name="FILENAME" /></translation>
 <translation id="3341303451326249809">已截取屏幕</translation>
 <translation id="334252345105450327">截屏</translation>
 <translation id="3351879221545518001">您目前正在投射屏幕。</translation>
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_mn.xtb b/ash/webui/camera_app_ui/resources/strings/camera_strings_mn.xtb
index 51098bbc..0f6f220 100644
--- a/ash/webui/camera_app_ui/resources/strings/camera_strings_mn.xtb
+++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_mn.xtb
@@ -22,6 +22,7 @@
 <translation id="1851616744363735765">ТҮР ЗОГСООСОН</translation>
 <translation id="1862930711583847113"><ph name="FILE" />-г экспорт хийх боломжгүй байна</translation>
 <translation id="1899697626337024495">Зургийн нягтрал</translation>
+<translation id="1925845977604399247">Зургийн цомог руу очих</translation>
 <translation id="2022953316617983419">QR код</translation>
 <translation id="2036868001356139588">Цаг хэмжигчийн үргэлжлэх хугацаа</translation>
 <translation id="2050339315714019657">Хөрөг зураг</translation>
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index 3093cc2..df17efd1 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -533,11 +533,13 @@
     PA_DCHECK(!enable_brp);
     PA_DCHECK(!use_dedicated_aligned_partition);
     PA_DCHECK(!current_root->with_thread_cache);
-    auto* root_with_thread_cache =
-        thread_cache_on_non_quarantinable_partition
-            ? internal::NonQuarantinableAllocator::Instance().root()
-            : current_root;
-    root_with_thread_cache->EnableThreadCacheIfSupported();
+    if (thread_cache_on_non_quarantinable_partition) {
+      // The caller is responsible for turning thread cache there. Here, we're
+      // just making sure nobody else turned it on for themselves.
+      // TODO(bartekn): Turn on thread cache in one spot, for consistence.
+    } else {
+      current_root->EnableThreadCacheIfSupported();
+    }
     return;
   }
 
@@ -590,11 +592,10 @@
   // No need for g_original_aligned_root, because in cases where g_aligned_root
   // is replaced, it must've been g_original_root.
 
-  // Enable thread-cache on the non-quarantinable partition, if specified.
   if (thread_cache_on_non_quarantinable_partition) {
-    internal::NonQuarantinableAllocator::Instance()
-        .root()
-        ->EnableThreadCacheIfSupported();
+    // The caller is responsible for turning thread cache there. In this
+    // function, we're just making sure nobody else turned it on for themselves.
+    // TODO(bartekn): Turn on thread cache in one spot, for consistence.
   }
 }
 
@@ -603,6 +604,8 @@
   internal::PCScan::Initialize(config);
 
   internal::PCScan::RegisterScannableRoot(Allocator());
+  if (OriginalAllocator() != nullptr)
+    internal::PCScan::RegisterScannableRoot(OriginalAllocator());
   if (Allocator() != AlignedAllocator())
     internal::PCScan::RegisterScannableRoot(AlignedAllocator());
 
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc
index 3545a1bf..8b98496 100644
--- a/base/allocator/partition_alloc_features.cc
+++ b/base/allocator/partition_alloc_features.cc
@@ -42,6 +42,7 @@
         {BackupRefPtrEnabledProcesses::kBrowserOnly, "browser-only"},
         {BackupRefPtrEnabledProcesses::kBrowserAndRenderer,
          "browser-and-renderer"},
+        {BackupRefPtrEnabledProcesses::kNonRenderer, "non-renderer"},
         {BackupRefPtrEnabledProcesses::kAllProcesses, "all-processes"}};
 
 const base::FeatureParam<BackupRefPtrEnabledProcesses>
diff --git a/base/allocator/partition_alloc_features.h b/base/allocator/partition_alloc_features.h
index 96405ee..7df159ff 100644
--- a/base/allocator/partition_alloc_features.h
+++ b/base/allocator/partition_alloc_features.h
@@ -31,6 +31,8 @@
   kBrowserOnly,
   // BRP enabled only in the browser and renderer processes.
   kBrowserAndRenderer,
+  // BRP enabled in all processes, except renderer.
+  kNonRenderer,
   // BRP enabled in all processes.
   kAllProcesses,
 };
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h
index 927e5c2..2cd2656 100644
--- a/base/allocator/partition_allocator/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -231,6 +231,18 @@
 // PROT_MTE.
 constexpr size_t kMaxMemoryTaggingSize = 1024;
 
+#if HAS_MEMORY_TAGGING
+// Returns whether the tag of a pointer/slot overflowed and slot needs to be
+// moved to quarantine.
+constexpr ALWAYS_INLINE bool HasOverflowTag(uintptr_t ptr) {
+  // The tag with which the slot is put to quarantine.
+  constexpr uintptr_t kOverflowTag = 0x0f00000000000000uLL;
+  static_assert((kOverflowTag & ~kMemTagUnmask) != 0,
+                "Overflow tag must be in tag bits");
+  return (ptr & ~kMemTagUnmask) == kOverflowTag;
+}
+#endif  // HAS_MEMORY_TAGGING
+
 PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
 NumPartitionPagesPerSuperPage() {
   return kSuperPageSize >> PartitionPageShift();
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 3d659f6..794282c4 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -59,6 +59,7 @@
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
 #include "base/compiler_specific.h"
+#include "base/memory/tagging.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
@@ -351,6 +352,8 @@
   uintptr_t inverted_self = 0;
   std::atomic<int> thread_caches_being_constructed_{0};
 
+  bool quarantine_always_for_testing = false;
+
   PartitionRoot() = default;
   explicit PartitionRoot(PartitionOptions opts) { Init(opts); }
   ~PartitionRoot();
@@ -543,6 +546,24 @@
     return quarantine_mode == QuarantineMode::kEnabled;
   }
 
+  ALWAYS_INLINE bool ShouldQuarantine(void* slot_start) const {
+    if (UNLIKELY(quarantine_mode != QuarantineMode::kEnabled))
+      return false;
+#if HAS_MEMORY_TAGGING
+    if (UNLIKELY(quarantine_always_for_testing))
+      return true;
+    // If quarantine is enabled and tag overflows, move slot to quarantine, to
+    // prevent the attacker from exploiting a pointer that has old tag.
+    return HasOverflowTag(reinterpret_cast<uintptr_t>(slot_start));
+#else
+    return true;
+#endif
+  }
+
+  ALWAYS_INLINE void SetQuarantineAlwaysForTesting(bool value) {
+    quarantine_always_for_testing = value;
+  }
+
   ALWAYS_INLINE bool IsScanEnabled() const {
     // Enabled scan implies enabled quarantine.
     PA_DCHECK(scan_mode != ScanMode::kEnabled || IsQuarantineEnabled());
@@ -1066,7 +1087,7 @@
 
   // TODO(bikineev): Change the condition to LIKELY once PCScan is enabled by
   // default.
-  if (UNLIKELY(root->IsQuarantineEnabled())) {
+  if (UNLIKELY(root->ShouldQuarantine(slot_start))) {
     // PCScan safepoint. Call before potentially scheduling scanning task.
     PCScan::JoinScanIfNeeded();
     if (LIKELY(internal::IsManagedByNormalBuckets(
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h
index 8811c0d1..a30e4ea2 100644
--- a/base/allocator/partition_allocator/starscan/pcscan.h
+++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -147,7 +147,7 @@
  private:
   class PCScanThread;
   friend class PCScanTask;
-  friend class PartitionAllocPCScanTest;
+  friend class PartitionAllocPCScanTestBase;
   friend class PCScanInternal;
 
   enum class State : uint8_t {
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.h b/base/allocator/partition_allocator/starscan/pcscan_internal.h
index 118f700..7456fc2 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_internal.h
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.h
@@ -68,8 +68,8 @@
   void SetCurrentPCScanTask(TaskHandle task);
   void ResetCurrentPCScanTask();
 
-  void RegisterScannableRoot(Root* root);
-  void RegisterNonScannableRoot(Root* root);
+  void RegisterScannableRoot(Root*);
+  void RegisterNonScannableRoot(Root*);
 
   RootsMap& scannable_roots() { return scannable_roots_; }
   const RootsMap& scannable_roots() const { return scannable_roots_; }
diff --git a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
index 3fa04a6..ee75dea3 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
@@ -10,7 +10,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_root.h"
 #include "base/allocator/partition_allocator/starscan/stack/stack.h"
+#include "base/cpu.h"
 #include "base/logging.h"
+#include "base/memory/tagging.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -44,9 +46,9 @@
 };
 }  // namespace
 
-class PartitionAllocPCScanTest : public testing::Test {
+class PartitionAllocPCScanTestBase : public testing::Test {
  public:
-  PartitionAllocPCScanTest() {
+  PartitionAllocPCScanTestBase() {
     PartitionAllocGlobalInit([](size_t) { LOG(FATAL) << "Out of memory"; });
     // Previous test runs within the same process decommit GigaCage, therefore
     // we need to make sure that the card table is recommitted for each run.
@@ -64,7 +66,8 @@
 
     PCScan::RegisterScannableRoot(allocator_.root());
   }
-  ~PartitionAllocPCScanTest() override {
+
+  ~PartitionAllocPCScanTestBase() override {
     allocator_.root()->PurgeMemory(PartitionPurgeDecommitEmptySlotSpans |
                                    PartitionPurgeDiscardUnusedSystemPages);
     PartitionAllocGlobalUninitForTesting();
@@ -100,6 +103,18 @@
   PartitionAllocator<ThreadSafe> allocator_;
 };
 
+// The test that expects free() being quarantined only when tag overflow occurs.
+class PartitionAllocPCScanWithMTETest : public PartitionAllocPCScanTestBase {};
+
+// The test that expects every free() being quarantined.
+class PartitionAllocPCScanTest : public PartitionAllocPCScanTestBase {
+ public:
+  PartitionAllocPCScanTest() { root().SetQuarantineAlwaysForTesting(true); }
+  ~PartitionAllocPCScanTest() override {
+    root().SetQuarantineAlwaysForTesting(false);
+  }
+};
+
 namespace {
 
 using SlotSpan = ThreadSafePartitionRoot::SlotSpan;
@@ -472,7 +487,9 @@
   value_root.UncapEmptySlotSpanMemoryForTesting();
 
   PCScan::RegisterScannableRoot(&source_root);
+  source_root.SetQuarantineAlwaysForTesting(true);
   PCScan::RegisterScannableRoot(&value_root);
+  value_root.SetQuarantineAlwaysForTesting(true);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
@@ -505,7 +522,9 @@
   value_root.UncapEmptySlotSpanMemoryForTesting();
 
   PCScan::RegisterScannableRoot(&source_root);
+  source_root.SetQuarantineAlwaysForTesting(true);
   PCScan::RegisterNonScannableRoot(&value_root);
+  value_root.SetQuarantineAlwaysForTesting(true);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
@@ -538,7 +557,9 @@
   value_root.UncapEmptySlotSpanMemoryForTesting();
 
   PCScan::RegisterNonScannableRoot(&source_root);
+  value_root.SetQuarantineAlwaysForTesting(true);
   PCScan::RegisterScannableRoot(&value_root);
+  source_root.SetQuarantineAlwaysForTesting(true);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
@@ -783,6 +804,48 @@
   TestDanglingReference(*this, source, value);
 }
 
+#if HAS_MEMORY_TAGGING
+TEST_F(PartitionAllocPCScanWithMTETest, QuarantineOnlyOnTagOverflow) {
+  using ListType = List<64>;
+
+  if (!CPU::GetInstanceNoAllocation().has_mte())
+    return;
+
+  {
+    auto* obj1 = ListType::Create(root());
+    ListType::Destroy(root(), obj1);
+    auto* obj2 = ListType::Create(root());
+    // The test relies on unrandomized freelist! If the slot was not moved to
+    // quarantine, assert that the obj2 is the same as obj1 and the tags are
+    // different.
+    if (!HasOverflowTag(reinterpret_cast<uintptr_t>(memory::RemaskPtr(obj1)))) {
+      // Assert that the pointer is the same.
+      ASSERT_EQ(memory::UnmaskPtr(obj1), memory::UnmaskPtr(obj2));
+      // Assert that the tag is different.
+      ASSERT_NE(obj1, obj2);
+    }
+  }
+
+  for (size_t i = 0; i < 16; ++i) {
+    auto* obj = ListType::Create(root());
+    ListType::Destroy(root(), obj);
+    // Get the current tag of the slot.
+    obj = memory::RemaskPtr(obj);
+    // Check if the tag overflows. If so, the object must be in quarantine.
+    if (HasOverflowTag(reinterpret_cast<uintptr_t>(obj))) {
+      EXPECT_TRUE(IsInQuarantine(obj));
+      EXPECT_FALSE(IsInFreeList(obj));
+      return;
+    } else {
+      EXPECT_FALSE(IsInQuarantine(obj));
+      EXPECT_TRUE(IsInFreeList(obj));
+    }
+  }
+
+  EXPECT_FALSE(true && "Should never be reached");
+}
+#endif  // HAS_MEMORY_TAGGING
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index 6cc7309..8aac84b 100644
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -35,6 +35,10 @@
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
 
+#if defined(OS_APPLE)
+#include "base/mac/backup_util.h"
+#endif
+
 namespace base {
 
 namespace {
@@ -704,6 +708,15 @@
     return false;
   }
 
+#if defined(OS_APPLE)
+  // This prevents backing up and then later restoring the file created above.
+  // Preventing backup saves space and bandwidth. There is little value in
+  // backing up this file since the metrics stored in this file will likely
+  // have already been uploaded at some point between the time the backup was
+  // created and the time it is restored.
+  base::mac::SetBackupExclusion(file_path);
+#endif
+
   Set(WrapUnique(new GlobalHistogramAllocator(
       std::make_unique<FilePersistentMemoryAllocator>(std::move(mmfile), 0, id,
                                                       name, false))));
@@ -828,6 +841,15 @@
   if (success)
     success = ReplaceFile(temp_spare_path, spare_path, nullptr);
 
+#if defined(OS_APPLE)
+  // Then purpose of the "spare" file created above is to save time during the
+  // next startup, when this file can be used instead of creating a new one.
+  // However, this file is large, so it's not worth the storage and bandwidth
+  // costs to back up and restore it; instead, after restoration, a new file
+  // will be created on the next startup.
+  base::mac::SetBackupExclusion(spare_path);
+#endif
+
   if (!success)
     DeleteFile(temp_spare_path);
 
diff --git a/base/task/post_job.cc b/base/task/post_job.cc
index b5232e9b5..140d27c 100644
--- a/base/task/post_job.cc
+++ b/base/task/post_job.cc
@@ -81,14 +81,24 @@
 }
 
 void JobHandle::UpdatePriority(TaskPriority new_priority) {
+  if (!internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
+          task_source_->delegate())) {
+    return;
+  }
   task_source_->delegate()->UpdateJobPriority(task_source_, new_priority);
 }
 
 void JobHandle::NotifyConcurrencyIncrease() {
+  if (!internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
+          task_source_->delegate())) {
+    return;
+  }
   task_source_->NotifyConcurrencyIncrease();
 }
 
 void JobHandle::Join() {
+  DCHECK(internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
+      task_source_->delegate()));
   DCHECK_GE(internal::GetTaskPriorityForCurrentThread(),
             task_source_->priority_racy())
       << "Join may not be called on Job with higher priority than the current "
@@ -104,6 +114,8 @@
 }
 
 void JobHandle::Cancel() {
+  DCHECK(internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
+      task_source_->delegate()));
   task_source_->Cancel();
   bool must_run = task_source_->WillJoin();
   DCHECK(!must_run);
diff --git a/base/values.cc b/base/values.cc
index bb30898..eae6c1e 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1192,18 +1192,6 @@
   return as_const(*this).Get(path, const_cast<const Value**>(out_value));
 }
 
-bool DictionaryValue::GetBoolean(StringPiece path, bool* bool_value) const {
-  const Value* value;
-  if (!Get(path, &value))
-    return false;
-
-  if (bool_value && value->is_bool()) {
-    *bool_value = value->GetBool();
-    return true;
-  }
-  return value->is_bool();
-}
-
 bool DictionaryValue::GetInteger(StringPiece path, int* out_value) const {
   const Value* value;
   if (!Get(path, &value))
diff --git a/base/values.h b/base/values.h
index 2b6a764..43f45ec 100644
--- a/base/values.h
+++ b/base/values.h
@@ -697,9 +697,6 @@
   // and the return value will be true if the path is valid and the value at
   // the end of the path can be returned in the form specified.
   // `out_value` is optional and will only be set if non-NULL.
-  // DEPRECATED, use `Value::FindBoolKey(key)` or `Value::FindBoolPath(path)`
-  // instead.
-  bool GetBoolean(StringPiece path, bool* out_value) const;
   // DEPRECATED, use `Value::FindIntKey(key)` or `Value::FindIntPath(path)`
   // instead.
   bool GetInteger(StringPiece path, int* out_value) const;
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 41216ce7..f35f012 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -2198,15 +2198,6 @@
   EXPECT_TRUE(main_dict.Get("list", nullptr));
   EXPECT_FALSE(main_dict.Get("DNE", nullptr));
 
-  EXPECT_TRUE(main_dict.GetBoolean("bool", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("int", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("double", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("string", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("binary", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("dict", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("list", nullptr));
-  EXPECT_FALSE(main_dict.GetBoolean("DNE", nullptr));
-
   EXPECT_FALSE(main_dict.GetInteger("bool", nullptr));
   EXPECT_TRUE(main_dict.GetInteger("int", nullptr));
   EXPECT_FALSE(main_dict.GetInteger("double", nullptr));
diff --git a/build/android/gyp/compile_java.py b/build/android/gyp/compile_java.py
index 8a7bc98a..cbce3a44 100755
--- a/build/android/gyp/compile_java.py
+++ b/build/android/gyp/compile_java.py
@@ -338,10 +338,9 @@
                                                       class_names, source):
           if self._ShouldIncludeInJarInfo(fully_qualified_name):
             ret[fully_qualified_name] = java_file
-    self._pool.terminate()
     return ret
 
-  def __del__(self):
+  def Close(self):
     # Work around for Python 2.x bug with multiprocessing and daemon threads:
     # https://bugs.python.org/issue4106
     if self._pool is not None:
@@ -472,6 +471,7 @@
   temp_dir = jar_path + '.staging'
   shutil.rmtree(temp_dir, True)
   os.makedirs(temp_dir)
+  info_file_context = None
   try:
     classes_dir = os.path.join(temp_dir, 'classes')
     service_provider_configuration = os.path.join(
@@ -573,6 +573,8 @@
 
     logging.info('Completed all steps in _RunCompiler')
   finally:
+    if info_file_context:
+      info_file_context.Close()
     shutil.rmtree(temp_dir)
 
 
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py
index b9ab7f0..01b15de 100755
--- a/build/android/incremental_install/installer.py
+++ b/build/android/incremental_install/installer.py
@@ -36,6 +36,7 @@
 
 _R8_PATH = os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'r8', 'lib',
                         'r8.jar')
+_SHARD_PREFIX = 'shard'
 
 
 def _DeviceCachePath(device):
@@ -91,7 +92,11 @@
           os.sep, '.')
       shards[name].append(src_path)
     else:
-      name = 'shard{}.dex.jar'.format(hash(src_path) % NUM_CORE_SHARDS)
+      # TODO(wnwen): hash(string) is not stable across python3 invocations.
+      #     Switch this to a stable hash that consistently shards the same file
+      #     to the same shard across runs.
+      name = '{}{}.dex.jar'.format(_SHARD_PREFIX,
+                                   hash(src_path) % NUM_CORE_SHARDS)
       shards[name].append(src_path)
   logging.info('Sharding %d dex files into %d buckets', len(dex_files),
                len(shards))
@@ -103,7 +108,9 @@
   tasks = []
   for name, src_paths in shards.items():
     dest_path = os.path.join(dex_staging_dir, name)
-    if _IsStale(src_paths, dest_path):
+    # TODO(wnwen): _IsStale() also needs to check if src_paths has changed for
+    #     shards comprised of multiple inputs. https://crbug.com/1269298
+    if name.startswith(_SHARD_PREFIX) or _IsStale(src_paths, dest_path):
       tasks.append(
           functools.partial(dex.MergeDexForIncrementalInstall, _R8_PATH,
                             src_paths, dest_path, min_api))
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 59caa7b4..1e76a54c 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -41,6 +41,11 @@
   #  and with this switch, clang emits it like this:
   #    foo/bar.cc:12:34: error: something went wrong
   use_clang_diagnostics_format = false
+
+  # Indicates whether to use /pdbpagesize:8192 to allow PDBs larger than 4 GiB.
+  # This requires updated debugging and profiling tools which are not widely
+  # distributed yet which is why it is currently opt-in.
+  use_large_pdbs = false
 }
 
 # This is included by reference in the //build/config/compiler config that
@@ -152,6 +157,12 @@
     ldflags += [ "/lldignoreenv" ]
   }
 
+  if (use_large_pdbs) {
+    # This allows PDBs up to 8 GiB in size. This requires lld-link.exe or
+    # link.exe from VS 2022 or later.
+    ldflags += [ "/pdbpagesize:8192" ]
+  }
+
   if (!is_debug && !is_component_build) {
     # Enable standard linker optimizations like GC (/OPT:REF) and ICF in static
     # release builds.
diff --git a/build/fuchsia/target.py b/build/fuchsia/target.py
index ec34164d..7f9594e 100644
--- a/build/fuchsia/target.py
+++ b/build/fuchsia/target.py
@@ -304,6 +304,7 @@
       if ssh_proc.wait() == 0:
         logging.info('Connected!')
         self._started = True
+        self._command_runner = runner
         return True
       time.sleep(_ATTACH_RETRY_INTERVAL)
 
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index a6bdc02..a597753 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -524,8 +524,10 @@
     }
 
     sys_include_flags = "${win_toolchain_data.include_flags_imsvc}"
-    sys_lib_flags =
-        "-libpath:$_clang_lib_dir ${win_toolchain_data.libpath_flags}"
+    if (use_lld) {
+      sys_lib_flags =
+          "-libpath:$_clang_lib_dir ${win_toolchain_data.libpath_flags}"
+    }
 
     toolchain_args = {
       if (defined(invoker.toolchain_args)) {
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index f3f8b593..63fa7a1 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -13,7 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
 #include "build/chromeos_buildflags.h"
-#include "cc/metrics/frame_info.h"
 #include "cc/metrics/frame_sorter.h"
 #include "cc/metrics/total_frame_counter.h"
 #include "cc/metrics/ukm_smoothness_data.h"
@@ -168,7 +167,15 @@
       PopSlidingWindow();
     }
     if (sliding_window_.empty()) {
-      DCHECK_EQ(dropped_frame_count_in_window_, 0u);
+      DCHECK_EQ(
+          dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy],
+          0u);
+      DCHECK_EQ(dropped_frame_count_in_window_
+                    [SmoothnessStrategy::kCompositorFocusedStrategy],
+                0u);
+      DCHECK_EQ(dropped_frame_count_in_window_
+                    [SmoothnessStrategy::kMainFocusedStrategy],
+                0u);
     }
 
     // Report no dropped frames for the sliding windows spanning the rest of the
@@ -177,12 +184,20 @@
       const auto difference = report_until - latest_sliding_window_start_;
       const size_t count =
           std::ceil(difference / latest_sliding_window_interval_);
-      if (count > 0)
-        sliding_window_histogram_.AddPercentDroppedFrame(0., count);
+      if (count > 0) {
+        sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy]
+            .AddPercentDroppedFrame(0., count);
+        sliding_window_histogram_[SmoothnessStrategy::kMainFocusedStrategy]
+            .AddPercentDroppedFrame(0., count);
+        sliding_window_histogram_
+            [SmoothnessStrategy::kCompositorFocusedStrategy]
+                .AddPercentDroppedFrame(0., count);
+      }
     }
   }
 
-  dropped_frame_count_in_window_ = 0;
+  std::fill_n(dropped_frame_count_in_window_,
+              SmoothnessStrategy::kStrategyCount, 0);
   sliding_window_ = {};
   latest_sliding_window_start_ = {};
   latest_sliding_window_interval_ = {};
@@ -268,7 +283,8 @@
   }
 
   uint32_t sliding_window_95pct_percent_dropped =
-      SlidingWindow95PercentilePercentDropped();
+      SlidingWindow95PercentilePercentDropped(
+          SmoothnessStrategy::kDefaultStrategy);
   if (sliding_window_95pct_percent_dropped !=
       last_reported_metrics_.p95_window) {
     UMA_HISTOGRAM_PERCENTAGE(
@@ -294,21 +310,43 @@
         static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
     smoothness_data.worst_smoothness = sliding_window_max_percent_dropped_;
     smoothness_data.percentile_95 = sliding_window_95pct_percent_dropped;
-    smoothness_data.median_smoothness = SlidingWindowMedianPercentDropped();
+    smoothness_data.median_smoothness =
+        SlidingWindowMedianPercentDropped(SmoothnessStrategy::kDefaultStrategy);
 
     uint32_t default_variance =
-        static_cast<uint32_t>(SlidingWindowPercentDroppedVariance());
-    DCHECK_GE(default_variance, 0u);
+        static_cast<uint32_t>(SlidingWindowPercentDroppedVariance(
+            SmoothnessStrategy::kDefaultStrategy));
     DCHECK_LE(default_variance, 5000u);
+    DCHECK_LE(0u, default_variance);
     smoothness_data.variance = default_variance;
 
     std::vector<double> sliding_window_buckets =
-        sliding_window_histogram_.GetPercentDroppedFrameBuckets();
+        sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy]
+            .GetPercentDroppedFrameBuckets();
     DCHECK_EQ(sliding_window_buckets.size(),
               base::size(smoothness_data.buckets));
     std::copy(sliding_window_buckets.begin(), sliding_window_buckets.end(),
               smoothness_data.buckets);
 
+    smoothness_data.main_focused_median = SlidingWindowMedianPercentDropped(
+        SmoothnessStrategy::kMainFocusedStrategy);
+    smoothness_data.main_focused_percentile_95 =
+        SlidingWindow95PercentilePercentDropped(
+            SmoothnessStrategy::kMainFocusedStrategy);
+    smoothness_data.main_focused_variance =
+        static_cast<uint32_t>(SlidingWindowPercentDroppedVariance(
+            SmoothnessStrategy::kMainFocusedStrategy));
+
+    smoothness_data.compositor_focused_median =
+        SlidingWindowMedianPercentDropped(
+            SmoothnessStrategy::kCompositorFocusedStrategy);
+    smoothness_data.compositor_focused_percentile_95 =
+        SlidingWindow95PercentilePercentDropped(
+            SmoothnessStrategy::kCompositorFocusedStrategy);
+    smoothness_data.compositor_focused_variance =
+        static_cast<uint32_t>(SlidingWindowPercentDroppedVariance(
+            SmoothnessStrategy::kCompositorFocusedStrategy));
+
     if (sliding_window_max_percent_dropped_After_1_sec_.has_value())
       smoothness_data.worst_smoothness_after1sec =
           sliding_window_max_percent_dropped_After_1_sec_.value();
@@ -368,11 +406,16 @@
   sliding_window_max_percent_dropped_After_1_sec_.reset();
   sliding_window_max_percent_dropped_After_2_sec_.reset();
   sliding_window_max_percent_dropped_After_5_sec_.reset();
-  dropped_frame_count_in_window_ = 0;
+  std::fill_n(dropped_frame_count_in_window_,
+              SmoothnessStrategy::kStrategyCount, 0);
   fcp_received_ = false;
   sliding_window_ = {};
   latest_sliding_window_start_ = {};
-  sliding_window_histogram_.Clear();
+  sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy].Clear();
+  sliding_window_histogram_[SmoothnessStrategy::kScrollFocusedStrategy].Clear();
+  sliding_window_histogram_[SmoothnessStrategy::kMainFocusedStrategy].Clear();
+  sliding_window_histogram_[SmoothnessStrategy::kCompositorFocusedStrategy]
+      .Clear();
   ring_buffer_.Clear();
   time_max_delta_ = {};
   last_reported_metrics_ = {};
@@ -395,16 +438,17 @@
   if (args.interval >= kSlidingWindowInterval)
     return;
 
-  const bool is_dropped = frame_info.IsDroppedAffectingSmoothness();
-  sliding_window_.push({args, is_dropped});
+  sliding_window_.push({args, frame_info});
+  UpdateDroppedFrameCountInWindow(frame_info, 1);
 
-  if (is_dropped)
-    ++dropped_frame_count_in_window_;
   if (ComputeCurrentWindowSize() < kSlidingWindowInterval)
     return;
 
-  DCHECK_GE(dropped_frame_count_in_window_, 0u);
-  DCHECK_GE(sliding_window_.size(), dropped_frame_count_in_window_);
+  DCHECK_GE(
+      dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy], 0u);
+  DCHECK_GE(
+      sliding_window_.size(),
+      dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy]);
 
   while (ComputeCurrentWindowSize() > kSlidingWindowInterval) {
     PopSlidingWindow();
@@ -414,21 +458,20 @@
 
 void DroppedFrameCounter::PopSlidingWindow() {
   const auto removed_args = sliding_window_.front().first;
-  const auto removed_was_dropped = sliding_window_.front().second;
-  if (removed_was_dropped) {
-    DCHECK_GT(dropped_frame_count_in_window_, 0u);
-    --dropped_frame_count_in_window_;
-  }
+  const auto removed_frame_info = sliding_window_.front().second;
+  UpdateDroppedFrameCountInWindow(removed_frame_info, -1);
   sliding_window_.pop();
   if (sliding_window_.empty())
     return;
 
   // Don't count the newest element if it is outside the current window.
   const auto& newest_args = sliding_window_.back().first;
-  const auto newest_was_dropped = sliding_window_.back().second;
-  auto dropped = dropped_frame_count_in_window_;
+  const auto newest_was_dropped =
+      sliding_window_.back().second.IsDroppedAffectingSmoothness();
+
+  uint32_t invalidated_frames = 0;
   if (ComputeCurrentWindowSize() > kSlidingWindowInterval && newest_was_dropped)
-    --dropped;
+    invalidated_frames++;
 
   // If two consecutive 'completed' frames are far apart from each other (in
   // time), then report the 'dropped frame count' for the sliding window(s) in
@@ -444,10 +487,31 @@
   const size_t count = difference > max_difference
                            ? std::ceil(difference / newest_args.interval)
                            : 1;
+
+  uint32_t dropped =
+      dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] -
+      invalidated_frames;
   double percent_dropped_frame =
       std::min((dropped * 100.0) / total_frames_in_window_, 100.0);
-  sliding_window_histogram_.AddPercentDroppedFrame(percent_dropped_frame,
-                                                   count);
+  sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy]
+      .AddPercentDroppedFrame(percent_dropped_frame, count);
+
+  uint32_t dropped_compositor =
+      dropped_frame_count_in_window_
+          [SmoothnessStrategy::kCompositorFocusedStrategy] -
+      invalidated_frames;
+  double percent_dropped_frame_compositor =
+      std::min((dropped_compositor * 100.0) / total_frames_in_window_, 100.0);
+  sliding_window_histogram_[SmoothnessStrategy::kCompositorFocusedStrategy]
+      .AddPercentDroppedFrame(percent_dropped_frame_compositor, count);
+
+  uint32_t dropped_main =
+      dropped_frame_count_in_window_[SmoothnessStrategy::kMainFocusedStrategy] -
+      invalidated_frames;
+  double percent_dropped_frame_main =
+      std::min((dropped_main * 100.0) / total_frames_in_window_, 100.0);
+  sliding_window_histogram_[SmoothnessStrategy::kMainFocusedStrategy]
+      .AddPercentDroppedFrame(percent_dropped_frame_main, count);
 
   if (percent_dropped_frame > sliding_window_max_percent_dropped_) {
     time_max_delta_ = newest_args.frame_time - time_fcp_received_;
@@ -460,6 +524,35 @@
   UpdateMaxPercentDroppedFrame(percent_dropped_frame);
 }
 
+void DroppedFrameCounter::UpdateDroppedFrameCountInWindow(
+    const FrameInfo& frame_info,
+    int count) {
+  if (frame_info.IsDroppedAffectingSmoothness()) {
+    DCHECK_GE(
+        dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] +
+            count,
+        0u);
+    dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] +=
+        count;
+  }
+  if (frame_info.WasCompositorUpdateDropped()) {
+    DCHECK_GE(dropped_frame_count_in_window_
+                      [SmoothnessStrategy::kCompositorFocusedStrategy] +
+                  count,
+              0u);
+    dropped_frame_count_in_window_
+        [SmoothnessStrategy::kCompositorFocusedStrategy] += count;
+  }
+  if (frame_info.WasMainUpdateDropped()) {
+    DCHECK_GE(dropped_frame_count_in_window_
+                      [SmoothnessStrategy::kMainFocusedStrategy] +
+                  count,
+              0u);
+    dropped_frame_count_in_window_[SmoothnessStrategy::kMainFocusedStrategy] +=
+        count;
+  }
+}
+
 void DroppedFrameCounter::UpdateMaxPercentDroppedFrame(
     double percent_dropped_frame) {
   if (!fcp_received_)
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h
index 0b1e32b..a7a1704 100644
--- a/cc/metrics/dropped_frame_counter.h
+++ b/cc/metrics/dropped_frame_counter.h
@@ -14,12 +14,12 @@
 #include "base/containers/ring_buffer.h"
 #include "base/memory/raw_ptr.h"
 #include "cc/cc_export.h"
+#include "cc/metrics/frame_info.h"
 #include "cc/metrics/frame_sorter.h"
 #include "cc/metrics/ukm_smoothness_data.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace cc {
-struct FrameInfo;
 class TotalFrameCounter;
 
 // This class maintains a counter for produced/dropped frames, and can be used
@@ -32,6 +32,15 @@
     kFrameStateComplete
   };
 
+  enum SmoothnessStrategy {
+    kDefaultStrategy,  // All threads and interactions are considered equal.
+    kScrollFocusedStrategy,  // Scroll interactions has the highest priority.
+    kMainFocusedStrategy,    // Reports dropped frames with main thread updates.
+    kCompositorFocusedStrategy,  // Reports dropped frames with compositor
+    // thread updates.
+    kStrategyCount
+  };
+
   class CC_EXPORT SlidingWindowHistogram {
    public:
     void AddPercentDroppedFrame(double percent_dropped_frame, size_t count = 1);
@@ -119,20 +128,30 @@
     return sliding_window_max_percent_dropped_After_5_sec_;
   }
 
-  uint32_t SlidingWindow95PercentilePercentDropped() const {
-    return sliding_window_histogram_.GetPercentDroppedFramePercentile(0.95);
+  uint32_t SlidingWindow95PercentilePercentDropped(
+      SmoothnessStrategy strategy) const {
+    DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy);
+    return sliding_window_histogram_[strategy].GetPercentDroppedFramePercentile(
+        0.95);
   }
 
-  uint32_t SlidingWindowMedianPercentDropped() const {
-    return sliding_window_histogram_.GetPercentDroppedFramePercentile(0.5);
+  uint32_t SlidingWindowMedianPercentDropped(
+      SmoothnessStrategy strategy) const {
+    DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy);
+    return sliding_window_histogram_[strategy].GetPercentDroppedFramePercentile(
+        0.5);
   }
 
-  double SlidingWindowPercentDroppedVariance() const {
-    return sliding_window_histogram_.GetPercentDroppedFrameVariance();
+  double SlidingWindowPercentDroppedVariance(
+      SmoothnessStrategy strategy) const {
+    DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy);
+    return sliding_window_histogram_[strategy].GetPercentDroppedFrameVariance();
   }
 
-  const SlidingWindowHistogram* GetSlidingWindowHistogram() const {
-    return &sliding_window_histogram_;
+  const SlidingWindowHistogram* GetSlidingWindowHistogram(
+      SmoothnessStrategy strategy) const {
+    DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy);
+    return &sliding_window_histogram_[strategy];
   }
 
  private:
@@ -143,11 +162,16 @@
   void PopSlidingWindow();
   void UpdateMaxPercentDroppedFrame(double percent_dropped_frame);
 
+  // Adds count to dropped_frame_count_in_window_ of each strategy.
+  void UpdateDroppedFrameCountInWindow(const FrameInfo& frame_info, int count);
+
   const base::TimeDelta kSlidingWindowInterval = base::Seconds(1);
-  std::queue<std::pair<const viz::BeginFrameArgs, bool>> sliding_window_;
-  uint32_t dropped_frame_count_in_window_ = 0;
+  std::queue<std::pair<const viz::BeginFrameArgs, FrameInfo>> sliding_window_;
+  uint32_t dropped_frame_count_in_window_[SmoothnessStrategy::kStrategyCount] =
+      {0};
   double total_frames_in_window_ = 60.0;
-  SlidingWindowHistogram sliding_window_histogram_;
+  SlidingWindowHistogram
+      sliding_window_histogram_[SmoothnessStrategy::kStrategyCount];
 
   base::TimeTicks latest_sliding_window_start_;
   base::TimeDelta latest_sliding_window_interval_;
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc
index c0cd00b..5addda9 100644
--- a/cc/metrics/dropped_frame_counter_unittest.cc
+++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -21,6 +21,8 @@
 namespace cc {
 namespace {
 
+using SmoothnessStrategy = DroppedFrameCounter::SmoothnessStrategy;
+
 FrameInfo CreateStubFrameInfo(bool is_dropped) {
   return CreateFakeFrameInfo(is_dropped
                                  ? FrameInfo::FrameFinalState::kDropped
@@ -271,6 +273,8 @@
   }
   ~DroppedFrameCounterTest() override = default;
 
+  SmoothnessStrategy default_strategy = SmoothnessStrategy::kDefaultStrategy;
+
   // For each boolean in frame_states produces a frame
   void SimulateFrameSequence(std::vector<bool> frame_states, int repeat) {
     for (int i = 0; i < repeat; i++) {
@@ -355,16 +359,22 @@
     return percent_dropped.value();
   }
 
-  double PercentDroppedFrame95Percentile() {
-    return dropped_frame_counter_.SlidingWindow95PercentilePercentDropped();
+  double PercentDroppedFrame95Percentile(SmoothnessStrategy strategy) {
+    return dropped_frame_counter_.SlidingWindow95PercentilePercentDropped(
+        strategy);
   }
 
-  double PercentDroppedFrameMedian() {
-    return dropped_frame_counter_.SlidingWindowMedianPercentDropped();
+  double PercentDroppedFrameMedian(SmoothnessStrategy strategy) {
+    return dropped_frame_counter_.SlidingWindowMedianPercentDropped(strategy);
   }
 
-  double PercentDroppedFrameVariance() {
-    return dropped_frame_counter_.SlidingWindowPercentDroppedVariance();
+  double PercentDroppedFrameVariance(SmoothnessStrategy strategy) {
+    return dropped_frame_counter_.SlidingWindowPercentDroppedVariance(strategy);
+  }
+
+  const DroppedFrameCounter::SlidingWindowHistogram*
+  GetSlidingWindowHistogram() {
+    return dropped_frame_counter_.GetSlidingWindowHistogram(default_strategy);
   }
 
   double GetTotalFramesInWindow() { return base::Seconds(1) / interval_; }
@@ -379,8 +389,7 @@
     constexpr double epsilon = 0.001;
     bool buckets_match = true;
     std::vector<double> buckets =
-        dropped_frame_counter_.GetSlidingWindowHistogram()
-            ->GetPercentDroppedFrameBuckets();
+        GetSlidingWindowHistogram()->GetPercentDroppedFrameBuckets();
     if (buckets.size() != expected_buckets.size()) {
       buckets_match = false;
     } else {
@@ -429,10 +438,11 @@
   //    16 * <sequence> + {true, true, true, false
   // Which means a max of 67 dropped frames.
   EXPECT_EQ(std::round(MaxPercentDroppedFrame()), 67);
-  EXPECT_EQ(PercentDroppedFrame95Percentile(), 67);  // all values are in the
+  EXPECT_EQ(PercentDroppedFrame95Percentile(default_strategy),
+            67);  // all values are in the
   // 65th-67th bucket, and as a result 95th percentile is also 67.
-  EXPECT_EQ(PercentDroppedFrameMedian(), 65);
-  EXPECT_LE(PercentDroppedFrameVariance(), 1);
+  EXPECT_EQ(PercentDroppedFrameMedian(default_strategy), 65);
+  EXPECT_LE(PercentDroppedFrameVariance(default_strategy), 1);
 }
 
 TEST_F(DroppedFrameCounterTest, SimplePattern2) {
@@ -441,10 +451,11 @@
 
   double expected_percent_dropped_frame = (12 / GetTotalFramesInWindow()) * 100;
   EXPECT_FLOAT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame);
-  EXPECT_EQ(PercentDroppedFrame95Percentile(), 20);  // all values are in the
+  EXPECT_EQ(PercentDroppedFrame95Percentile(default_strategy),
+            20);  // all values are in the
   // 20th bucket, and as a result 95th percentile is also 20.
-  EXPECT_EQ(PercentDroppedFrameMedian(), 20);
-  EXPECT_LE(PercentDroppedFrameVariance(), 1);
+  EXPECT_EQ(PercentDroppedFrameMedian(default_strategy), 20);
+  EXPECT_LE(PercentDroppedFrameVariance(default_strategy), 1);
 }
 
 TEST_F(DroppedFrameCounterTest, IncompleteWindow) {
@@ -452,9 +463,9 @@
   // should report zero.
   SimulateFrameSequence({false, false, false, false, true}, 1);
   EXPECT_EQ(MaxPercentDroppedFrame(), 0.0);
-  EXPECT_EQ(PercentDroppedFrame95Percentile(), 0);
-  EXPECT_EQ(PercentDroppedFrameMedian(), 0);
-  EXPECT_LE(PercentDroppedFrameVariance(), 1);
+  EXPECT_EQ(PercentDroppedFrame95Percentile(default_strategy), 0);
+  EXPECT_EQ(PercentDroppedFrameMedian(default_strategy), 0);
+  EXPECT_LE(PercentDroppedFrameVariance(default_strategy), 1);
 }
 
 TEST_F(DroppedFrameCounterTest, MaxPercentDroppedChanges) {
@@ -464,10 +475,11 @@
   double expected_percent_dropped_frame1 =
       (12 / GetTotalFramesInWindow()) * 100;
   EXPECT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame1);
-  EXPECT_FLOAT_EQ(PercentDroppedFrame95Percentile(), 20);  // There is only one
+  EXPECT_FLOAT_EQ(PercentDroppedFrame95Percentile(default_strategy),
+                  20);  // There is only one
   // element in the histogram and that is 20.
-  EXPECT_EQ(PercentDroppedFrameMedian(), 20);
-  EXPECT_LE(PercentDroppedFrameVariance(), 1);
+  EXPECT_EQ(PercentDroppedFrameMedian(default_strategy), 20);
+  EXPECT_LE(PercentDroppedFrameVariance(default_strategy), 1);
 
   // 30 new frames are added that have 18 dropped frames.
   // and the 30 frame before that had 6 dropped frames.
@@ -489,7 +501,7 @@
   // 1 value exist when we reach 60 frames and 1 value thereafter for each
   // frame added. So there 61 values in histogram. Last value is 70 (2 sampels)
   // and then 67 with 1 sample, which would be the 95th percentile.
-  EXPECT_EQ(PercentDroppedFrame95Percentile(), 67);
+  EXPECT_EQ(PercentDroppedFrame95Percentile(default_strategy), 67);
 }
 
 TEST_F(DroppedFrameCounterTest, MaxPercentDroppedWithIdleFrames) {
@@ -527,7 +539,8 @@
       "kFps must be a multiple of 5 because this test depends on it.");
   SetInterval(kInterval);
 
-  const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+  const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram(
+      DroppedFrameCounter::SmoothnessStrategy::kDefaultStrategy);
 
   // First 4 seconds with 20% dropped frames.
   SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
@@ -561,7 +574,7 @@
       "kFps must be a multiple of 5 because this test depends on it.");
   SetInterval(kInterval);
 
-  const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+  const auto* histogram = GetSlidingWindowHistogram();
 
   // First 4 seconds with 20% dropped frames.
   SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
@@ -594,7 +607,7 @@
       "kFps must be a multiple of 5 because this test depends on it.");
   SetInterval(kInterval);
 
-  const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+  const auto* histogram = GetSlidingWindowHistogram();
 
   // First 4 seconds with 20% dropped frames.
   SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
@@ -654,8 +667,7 @@
 
   // There should be enough sliding windows reported with 0 dropped frames that
   // the 95th percentile stays at 0.
-  EXPECT_EQ(dropped_frame_counter_.SlidingWindow95PercentilePercentDropped(),
-            0u);
+  EXPECT_EQ(PercentDroppedFrame95Percentile(default_strategy), 0u);
 }
 
 TEST_F(DroppedFrameCounterTest, ResetPendingFramesAccountingForPendingFrames) {
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index d49c2d3..d92fe14 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -60,7 +60,8 @@
     const gfx::Rect& playback_rect,
     const gfx::AxisTransform2d& transform,
     const RasterSource::PlaybackSettings& playback_settings,
-    viz::RasterContextProvider* context_provider) {
+    viz::RasterContextProvider* context_provider,
+    bool is_using_raw_draw) {
   gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
   bool mailbox_needs_clear = false;
   if (mailbox->IsZero()) {
@@ -71,7 +72,7 @@
                      gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
     if (texture_is_overlay_candidate) {
       flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
-    } else if (features::IsUsingRawDraw()) {
+    } else if (is_using_raw_draw) {
       flags |= gpu::SHARED_IMAGE_USAGE_RAW_DRAW;
     }
     *mailbox = sii->CreateSharedImage(
@@ -88,10 +89,15 @@
                                         ? gpu::raster::kMSAA
                                         : gpu::raster::kNoMSAA;
 
-  ri->BeginRasterCHROMIUM(
-      raster_source->background_color(), mailbox_needs_clear,
-      playback_settings.msaa_sample_count, msaa_mode,
-      playback_settings.use_lcd_text, color_space, mailbox->name);
+  // With Raw Draw, the framebuffer will be the rasterization target. It cannot
+  // support LCD text, so disable LCD text for Raw Draw backings.
+  // TODO(penghuang): remove it when GrSlug can be serialized.
+  bool is_raw_draw_backing = is_using_raw_draw && !texture_is_overlay_candidate;
+  bool use_lcd_text = playback_settings.use_lcd_text && !is_raw_draw_backing;
+  ri->BeginRasterCHROMIUM(raster_source->background_color(),
+                          mailbox_needs_clear,
+                          playback_settings.msaa_sample_count, msaa_mode,
+                          use_lcd_text, color_space, mailbox->name);
   gfx::Vector2dF recording_to_raster_scale = transform.scale();
   recording_to_raster_scale.Scale(1 / raster_source->recording_scale_factor());
   gfx::Size content_size = raster_source->GetContentSize(transform.scale());
@@ -310,7 +316,8 @@
       enable_oop_rasterization_(enable_oop_rasterization),
       pending_raster_queries_(pending_raster_queries),
       random_generator_(static_cast<uint32_t>(base::RandUint64())),
-      bernoulli_distribution_(raster_metric_probability) {
+      bernoulli_distribution_(raster_metric_probability),
+      is_using_raw_draw_(features::IsUsingRawDraw()) {
   DCHECK(pending_raster_queries);
   DCHECK(compositor_context_provider);
   DCHECK(worker_context_provider);
@@ -514,11 +521,12 @@
     if (measure_raster_metric)
       timer.emplace();
     if (enable_oop_rasterization_) {
-      RasterizeSourceOOP(
-          raster_source, resource_has_previous_content, mailbox, sync_token,
-          texture_target, texture_is_overlay_candidate, resource_size,
-          resource_format, color_space, raster_full_rect, playback_rect,
-          transform, playback_settings, worker_context_provider_);
+      RasterizeSourceOOP(raster_source, resource_has_previous_content, mailbox,
+                         sync_token, texture_target,
+                         texture_is_overlay_candidate, resource_size,
+                         resource_format, color_space, raster_full_rect,
+                         playback_rect, transform, playback_settings,
+                         worker_context_provider_, is_using_raw_draw_);
     } else {
       RasterizeSource(raster_source, resource_has_previous_content, mailbox,
                       sync_token, texture_target, texture_is_overlay_candidate,
diff --git a/cc/raster/gpu_raster_buffer_provider.h b/cc/raster/gpu_raster_buffer_provider.h
index b6b0cd8..a5e4459 100644
--- a/cc/raster/gpu_raster_buffer_provider.h
+++ b/cc/raster/gpu_raster_buffer_provider.h
@@ -172,6 +172,7 @@
   // Accessed with the worker context lock acquired.
   std::mt19937 random_generator_;
   std::bernoulli_distribution bernoulli_distribution_;
+  const bool is_using_raw_draw_;
 };
 
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index e8432c4..88f2ccaa 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=98
 MINOR=0
-BUILD=4757
+BUILD=4758
 PATCH=0
diff --git a/chrome/android/expectations/lint-baseline.xml b/chrome/android/expectations/lint-baseline.xml
index 25fc730..32a7a2691 100644
--- a/chrome/android/expectations/lint-baseline.xml
+++ b/chrome/android/expectations/lint-baseline.xml
@@ -4754,14 +4754,6 @@
     </issue>
 
     <issue
-        id="NotifyDataSetChanged"
-        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort.">
-        <location
-            file="../../chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java"
-            line="127"/>
-    </issue>
-
-    <issue
         id="UseCompoundDrawables"
         message="This tag and its children can be replaced by one `&lt;TextView/>` and a compound drawable">
         <location
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_id.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_id.xtb
index 6953365..7c5b008 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_id.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_id.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">Berikan masukan</translation>
 <translation id="360207483134687714">Bantu membuat VR di Chrome menjadi lebih baik</translation>
 <translation id="3789841737615482174">Instal</translation>
+<translation id="4088809042407767679">Perbarui Layanan Google VR?</translation>
+<translation id="4648883053543509795">Instal Layanan Google VR?</translation>
 <translation id="473775607612524610">Perbarui</translation>
+<translation id="5010116926836661047">Lihat konten virtual reality</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ja.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ja.xtb
index 1f3132d0..b7236dd 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ja.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ja.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">フィードバックを送信</translation>
 <translation id="360207483134687714">Chrome の VR モードの改善にご協力ください</translation>
 <translation id="3789841737615482174">インストール</translation>
+<translation id="4088809042407767679">Google VR サービスを更新しますか?</translation>
+<translation id="4648883053543509795">Google VR サービスをインストールしますか?</translation>
 <translation id="473775607612524610">更新</translation>
+<translation id="5010116926836661047">バーチャル リアリティ コンテンツを表示します</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ko.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ko.xtb
index 6955e3d..2f5e3cb 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ko.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_ko.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">의견 보내기</translation>
 <translation id="360207483134687714">Chrome의 VR 환경을 개선할 수 있도록 도와주세요.</translation>
 <translation id="3789841737615482174">설치</translation>
+<translation id="4088809042407767679">Google VR 서비스를 업데이트하시겠습니까?</translation>
+<translation id="4648883053543509795">Google VR 서비스를 설치하시겠습니까?</translation>
 <translation id="473775607612524610">업데이트</translation>
+<translation id="5010116926836661047">가상 현실 콘텐츠 보기</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_tr.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_tr.xtb
index 786fe10..c7b0c8c3 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_tr.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_tr.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">Geri bildirim gönder</translation>
 <translation id="360207483134687714">Chrome'da Sanal Gerçeklik deneyimini iyileştirmeye yardımcı olun</translation>
 <translation id="3789841737615482174">Yükle</translation>
+<translation id="4088809042407767679">Google VR Hizmetleri güncellensin mi?</translation>
+<translation id="4648883053543509795">Google VR Hizmetleri yüklensin mi?</translation>
 <translation id="473775607612524610">Güncelle</translation>
+<translation id="5010116926836661047">Sanal gerçeklik içeriğini göster</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-HK.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-HK.xtb
index 914f91e..fa199006 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-HK.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-HK.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">提供意見</translation>
 <translation id="360207483134687714">協助我們改善 Chrome 的 VR 體驗</translation>
 <translation id="3789841737615482174">安裝</translation>
+<translation id="4088809042407767679">要更新 Google VR 服務嗎?</translation>
+<translation id="4648883053543509795">要安裝 Google VR 服務嗎?</translation>
 <translation id="473775607612524610">更新</translation>
+<translation id="5010116926836661047">查看虛擬實境內容</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-TW.xtb b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-TW.xtb
index 9be8d39..0e2043f 100644
--- a/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-TW.xtb
+++ b/chrome/android/features/vr/java/strings/translations/android_chrome_vr_strings_zh-TW.xtb
@@ -4,5 +4,8 @@
 <translation id="1938981467853765413">提供意見</translation>
 <translation id="360207483134687714">協助我們改善 Chrome 的 VR 體驗</translation>
 <translation id="3789841737615482174">安裝</translation>
+<translation id="4088809042407767679">要更新 Google VR 服務嗎?</translation>
+<translation id="4648883053543509795">要安裝 Google VR 服務嗎?</translation>
 <translation id="473775607612524610">更新</translation>
+<translation id="5010116926836661047">查看虛擬實境內容</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 1d056bda..6d7d3a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -196,8 +196,6 @@
 import org.chromium.chrome.browser.ui.system.StatusBarColorController;
 import org.chromium.chrome.browser.vr.ArDelegateProvider;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
-import org.chromium.chrome.browser.webapps.PwaBottomSheetController;
-import org.chromium.chrome.browser.webapps.PwaBottomSheetControllerProvider;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkType;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -223,6 +221,8 @@
 import org.chromium.components.webapk.lib.client.WebApkValidator;
 import org.chromium.components.webapps.AddToHomescreenCoordinator;
 import org.chromium.components.webapps.InstallTrigger;
+import org.chromium.components.webapps.bottomsheet.PwaBottomSheetController;
+import org.chromium.components.webapps.bottomsheet.PwaBottomSheetControllerProvider;
 import org.chromium.components.webxr.ArDelegate;
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.LoadUrlParams;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 3c5717e..9dd2d18 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -104,8 +104,6 @@
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.webapps.AddToHomescreenIPHController;
 import org.chromium.chrome.browser.webapps.AddToHomescreenMostVisitedTileClickObserver;
-import org.chromium.chrome.browser.webapps.PwaBottomSheetController;
-import org.chromium.chrome.browser.webapps.PwaBottomSheetControllerFactory;
 import org.chromium.chrome.features.start_surface.StartSurface;
 import org.chromium.chrome.features.start_surface.StartSurfaceState;
 import org.chromium.chrome.features.start_surface.StartSurfaceUserData;
@@ -116,6 +114,8 @@
 import org.chromium.components.browser_ui.widget.TouchEventObserver;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.components.messages.MessageDispatcherProvider;
+import org.chromium.components.webapps.bottomsheet.PwaBottomSheetController;
+import org.chromium.components.webapps.bottomsheet.PwaBottomSheetControllerFactory;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.DeviceFormFactor;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateCustomView.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateCustomView.java
index 6e619e9..ac2f440 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateCustomView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateCustomView.java
@@ -16,6 +16,8 @@
 
 import androidx.annotation.Nullable;
 
+import org.chromium.chrome.R;
+
 /**
  * The custom view part of the {@link WebApkIconNameUpdateDialog}. Shows the icon changes and
  * changes to name and short_name.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialog.java
index 9ab1dae..4076390 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialog.java
@@ -11,6 +11,7 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
+import org.chromium.chrome.R;
 import org.chromium.ui.LayoutInflaterUtils;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateReportAbuseDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateReportAbuseDialog.java
index 1d329fc..1612653 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateReportAbuseDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateReportAbuseDialog.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.PackageUtils;
+import org.chromium.chrome.R;
 import org.chromium.ui.LayoutInflaterUtils;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java
index ad4a5e86..9a90b98 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java
@@ -9,9 +9,8 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
 
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.LargeTest;
 
 import org.hamcrest.Matchers;
 import org.junit.Before;
@@ -21,17 +20,20 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.chrome.R;
 import org.chromium.chrome.test.pagecontroller.rules.ChromeUiApplicationTestRule;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
-import org.chromium.chrome.test.pagecontroller.utils.NonInstrumentedCrashDetector;
 import org.chromium.chrome.test.pagecontroller.utils.Ui2Locators;
+import org.chromium.chrome.test.pagecontroller.utils.UiAutomatorUtils;
+import org.chromium.chrome.test.pagecontroller.utils.UiLocatorHelper;
 
+import java.util.Arrays;
 import java.util.concurrent.Callable;
 
 /**
  * Smoke Test for Chrome Android.
  */
-@SmallTest
+@LargeTest
 @RunWith(BaseJUnit4ClassRunner.class)
 public class ChromeSmokeTest {
     private static final String DATA_URL = "data:,Hello";
@@ -42,11 +44,10 @@
     private String mPackageName;
 
     private static Runnable toNotSatisfiedRunnable(
-            Callable<Boolean> criteria, Callable<String> failureReasonCallable) {
+            Callable<Boolean> criteria, String failureReason) {
         return () -> {
             try {
                 boolean isSatisfied = criteria.call();
-                String failureReason = failureReasonCallable.call();
                 Criteria.checkThat(failureReason, isSatisfied, Matchers.is(true));
             } catch (RuntimeException e) {
                 throw e;
@@ -56,10 +57,99 @@
         };
     }
 
-    private String computeTimeoutFailureMessage() {
-        return NonInstrumentedCrashDetector.checkDidChromeCrash()
-                ? mPackageName + " should not have crashed. Check logcat."
-                : mPackageName + " should have loaded";
+    private void waitUntilAnyVisible(IUi2Locator... locators) {
+        CriteriaHelper.pollInstrumentationThread(
+                toNotSatisfiedRunnable(
+                        ()
+                                -> {
+                            for (IUi2Locator locator : locators) {
+                                if (UiAutomatorUtils.getInstance().getLocatorHelper().isOnScreen(
+                                            locator)) {
+                                    return true;
+                                }
+                            }
+                            return false;
+                        },
+                        "One of " + Arrays.toString(locators) + " should have been visible."),
+                TIMEOUT_MS, UI_CHECK_INTERVAL);
+    }
+
+    private void navigateThroughFRE() {
+        // Used in ToSAndUMAFirstRunFragment FRE page.
+        IUi2Locator termsAcceptButton = Ui2Locators.withAnyResEntry(R.id.terms_accept);
+
+        // Used in SyncConsentFirstRunFragment FRE page.
+        IUi2Locator noAddAccountButton = Ui2Locators.withAnyResEntry(R.id.negative_button);
+
+        // Used in SigninFirstRunFragment FRE page.
+        IUi2Locator signinSkipButton = Ui2Locators.withAnyResEntry(R.id.signin_fre_dismiss_button);
+        IUi2Locator signinContinueButton =
+                Ui2Locators.withAnyResEntry(R.id.signin_fre_continue_button);
+
+        // Used in DataReductionProxyFirstRunFragment FRE page.
+        IUi2Locator dataSaverPromoNextButton = Ui2Locators.withAnyResEntry(R.id.next_button);
+
+        // Used in DefaultSearchEngineFirstRunFragment FRE page.
+        IUi2Locator defaultSearchEngineNextButton =
+                Ui2Locators.withAnyResEntry(R.id.button_primary);
+
+        // Url bar shown after the FRE is over.
+        IUi2Locator urlBar = Ui2Locators.withAnyResEntry(R.id.url_bar);
+
+        // When Play services is too old, android shows an alert.
+        IUi2Locator updatePlayServicesPanel = Ui2Locators.withResName("android:id/parentPanel");
+        IUi2Locator playServicesUpdateText =
+                Ui2Locators.withTextContaining("update Google Play services");
+
+        UiLocatorHelper uiLocatorHelper = UiAutomatorUtils.getInstance().getLocatorHelper();
+
+        // These locators show up in one FRE page or another
+        IUi2Locator[] frePageDetectors = new IUi2Locator[] {
+                playServicesUpdateText,
+                termsAcceptButton,
+                signinSkipButton,
+                signinContinueButton,
+                noAddAccountButton,
+                dataSaverPromoNextButton,
+                defaultSearchEngineNextButton,
+                urlBar,
+        };
+
+        // Manually go through FRE.
+        while (true) {
+            // Wait for an FRE page to show up.
+            waitUntilAnyVisible(frePageDetectors);
+            // If the update play services alert is visible, dismiss it.
+            if (uiLocatorHelper.isOnScreen(playServicesUpdateText)) {
+                UiAutomatorUtils.getInstance().clickOutsideOf(updatePlayServicesPanel);
+                // Different FRE versions show up randomly and in different order,
+                // figure out which one we are on and proceed.
+            } else if (uiLocatorHelper.isOnScreen(termsAcceptButton)) {
+                // Click on the accept terms in FRE.
+                UiAutomatorUtils.getInstance().click(termsAcceptButton);
+            } else if (uiLocatorHelper.isOnScreen(noAddAccountButton)) {
+                // Do not add an account.
+                UiAutomatorUtils.getInstance().click(noAddAccountButton);
+            } else if (uiLocatorHelper.isOnScreen(signinSkipButton)) {
+                // Do not sign in with an account.
+                UiAutomatorUtils.getInstance().click(signinSkipButton);
+            } else if (uiLocatorHelper.isOnScreen(signinContinueButton)) {
+                // Sometimes there is only the continue button (eg: when signin is
+                // disabled.)
+                UiAutomatorUtils.getInstance().click(signinContinueButton);
+            } else if (uiLocatorHelper.isOnScreen(dataSaverPromoNextButton)) {
+                // Just press next on Data saver promo.
+                UiAutomatorUtils.getInstance().click(dataSaverPromoNextButton);
+            } else if (uiLocatorHelper.isOnScreen(defaultSearchEngineNextButton)) {
+                // Just press next on choosing the default SE.
+                UiAutomatorUtils.getInstance().click(defaultSearchEngineNextButton);
+            } else if (uiLocatorHelper.isOnScreen(urlBar)) {
+                // FRE is over.
+                break;
+            } else {
+                throw new RuntimeException("Unexpected FRE or Start page detected.");
+            }
+        }
     }
 
     @Before
@@ -76,22 +166,16 @@
         intent.setComponent(new ComponentName(mPackageName, ACTIVITY_NAME));
         context.startActivity(intent);
 
-        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
-        // TODO (aluo): Check that the data url is loaded after pagecontroller lands.
+        // Looks for the any view/layout with the chrome package name.
         IUi2Locator locatorChrome = Ui2Locators.withPackageName(mPackageName);
+        // Wait until chrome shows up
+        waitUntilAnyVisible(locatorChrome);
 
-        CriteriaHelper.pollInstrumentationThread(
-                toNotSatisfiedRunnable(
-                        ()
-                                -> {
-                            try {
-                                return locatorChrome.locateOne(device) != null;
-                            } catch (NullPointerException e) {
-                                return false; // Throws an NPE on older Android versions.
-                            }
-                        },
-                        () -> { return computeTimeoutFailureMessage(); }),
-                TIMEOUT_MS, UI_CHECK_INTERVAL);
+        // Go through the FRE until you see ChromeTabbedActivity urlbar.
+        navigateThroughFRE();
+
+        // FRE should be over and we should be shown the url we requested.
+        IUi2Locator dataUrlText = Ui2Locators.withText(DATA_URL);
+        UiAutomatorUtils.getInstance().getLocatorHelper().verifyOnScreen(dataUrlText);
     }
 }
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index c51fd73..52b43d9 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -162,6 +162,7 @@
 <translation id="1152346050262092795">Masukkan sandi lagi untuk memverifikasi akun Anda.</translation>
 <translation id="1153356358378277386">Perangkat dihubungkan</translation>
 <translation id="1153636665119721804">Program Perlindungan Lanjutan Google</translation>
+<translation id="1155545602507378023">Tidak, hanya perangkat ini</translation>
 <translation id="1155816283571436363">Menghubungkan ke ponsel Anda</translation>
 <translation id="1158080958325422608">Jadikan Huruf Besar</translation>
 <translation id="1158238185437008462">Lihat kenangan</translation>
@@ -396,6 +397,7 @@
 <translation id="1410197035576869800">Ikon Aplikasi</translation>
 <translation id="1410616244180625362">Terus izinkan <ph name="HOST" /> mengakses kamera Anda</translation>
 <translation id="1410806973194718079">Tidak dapat memeriksa kebijakan</translation>
+<translation id="1412681350727866021">Ekstensi tambahan</translation>
 <translation id="1414315029670184034">Jangan izinkan situs menggunakan kamera Anda</translation>
 <translation id="1414648216875402825">Anda memperbarui ke versi tidak stabil dari <ph name="PRODUCT_NAME" /> yang berisi fitur yang sedang dalam proses. Akan terjadi mogok dan bug tidak terduga. Lanjutkan dengan hati-hati.</translation>
 <translation id="1415708812149920388">Akses baca papan klip ditolak</translation>
@@ -950,6 +952,7 @@
 <translation id="1937774647013465102">Tidak dapat mengimpor jenis arsitektur container <ph name="ARCHITECTURE_CONTAINER" /> dengan perangkat ini yang menggunakan arsitektur <ph name="ARCHITECTURE_DEVICE" />. Anda dapat mencoba memulihkan container ini ke dalam perangkat berbeda, atau mengakses file di dalam gambar container ini dengan membukanya di aplikasi File.</translation>
 <translation id="1938351510777341717">External Command</translation>
 <translation id="1940546824932169984">Perangkat yang terhubung</translation>
+<translation id="1941410638996203291">Waktu mulai <ph name="TIME" /></translation>
 <translation id="1942128823046546853">Membaca dan mengubah semua data Anda di semua situs</translation>
 <translation id="1942600407708803723">Mati saat cover ditutup</translation>
 <translation id="1944528062465413897">Kode penyambungan Bluetooth:</translation>
@@ -1328,6 +1331,7 @@
 <translation id="2320295602967756579">Aktifkan tema terang</translation>
 <translation id="2322193970951063277">Header dan footer</translation>
 <translation id="2322318151094136999">Tanyakan saat situs ingin mengakses port serial (direkomendasikan)</translation>
+<translation id="2322622365472107569">Waktu berakhir <ph name="TIME" /></translation>
 <translation id="2323018538045954000">Jaringan Wi-Fi tersimpan</translation>
 <translation id="2325444234681128157">Ingat sandi</translation>
 <translation id="2326188115274135041">Konfirmasi PIN untuk mengaktifkan buka kunci otomatis</translation>
@@ -1433,6 +1437,7 @@
 <translation id="2435248616906486374">Jaringan terputus</translation>
 <translation id="2435457462613246316">Tampilkan sandi</translation>
 <translation id="2436186046335138073">Izinkan <ph name="HANDLER_HOSTNAME" /> membuka semua link <ph name="PROTOCOL" />?</translation>
+<translation id="2439626940657133600">Memuat <ph name="WINDOW_TITLE" /></translation>
 <translation id="2440604414813129000">Lihat s&amp;umber</translation>
 <translation id="244231003699905658">Alamat tidak valid. Periksa alamatnya, lalu coba lagi.</translation>
 <translation id="2442916515643169563">Bayangan teks</translation>
@@ -1938,6 +1943,7 @@
 <translation id="2935654492420446828">Tambahkan akun sekolah nanti</translation>
 <translation id="2936851848721175671">Pencadangan &amp; pemulihan</translation>
 <translation id="2938225289965773019">Membuka link <ph name="PROTOCOL" /></translation>
+<translation id="2939908794993783865">Situs tidak aktif tambahan</translation>
 <translation id="2939938020978911855">Tampilkan perangkat Bluetooth yang tersedia</translation>
 <translation id="2941112035454246133">Rendah</translation>
 <translation id="2942279350258725020">Android Message</translation>
@@ -2083,6 +2089,7 @@
 <translation id="3090589793601454425">Jangan pindahkan</translation>
 <translation id="3090819949319990166">Tidak dapat menyalin file crx eksternal ke <ph name="TEMP_CRX_FILE" />.</translation>
 <translation id="3090871774332213558">"<ph name="DEVICE_NAME" />" disandingkan</translation>
+<translation id="3093362725605442088">Membaca nomor seri perangkat dan komponen Chrome OS.</translation>
 <translation id="3093714882666365141">Jangan izinkan situs menginstal pengendali pembayaran</translation>
 <translation id="3094141017404513551">Ini akan memisahkan penjelajahan Anda dari <ph name="EXISTING_USER" /></translation>
 <translation id="3095871294753148861">Bookmark, sandi, dan data penjelajahan lainnya disinkronkan dengan akun utama.</translation>
@@ -2270,6 +2277,7 @@
 <translation id="3308852433423051161">Memuat Asisten Google...</translation>
 <translation id="3309330461362844500">ID Profil Sertifikat</translation>
 <translation id="3311445899360743395">Data yang terkait dengan aplikasi ini dapat dihapus dari perangkat ini.</translation>
+<translation id="3312883087018430408">Untuk menelusuri situs tertentu atau bagian dari Chrome, ketik pintasannya di kolom URL, lalu tekan pintasan keyboard yang diinginkan. Misalnya, untuk hanya menelusuri Bookmark, ketik "@bookmark", lalu tekan Tab atau Spasi.</translation>
 <translation id="3313622045786997898">Nilai Tanda Tangan Sertifikat</translation>
 <translation id="3313950410573257029">Periksa koneksi</translation>
 <translation id="3315158641124845231">Sembunyikan <ph name="PRODUCT_NAME" /></translation>
@@ -2689,6 +2697,7 @@
 <translation id="3747077776423672805">Untuk menghapus aplikasi, buka Setelan &gt; Google Play Store &gt; Kelola preferensi Android &gt; Aplikasi atau Pengelola aplikasi. Kemudian, ketuk aplikasi yang ingin di-uninstal (Anda mungkin perlu menggeser ke kanan atau ke kiri untuk menemukan aplikasi). Setelah itu, ketuk Uninstal atau Nonaktifkan.</translation>
 <translation id="3747220812138541072">Tampilkan saran penulisan yang muncul sebaris saat Anda mengetik</translation>
 <translation id="3748706263662799310">Laporkan bug</translation>
+<translation id="3750562496035670393">Chrome menyimpan sandi Anda ke perangkat ini, tetapi Anda dapat menyimpannya ke Akun Google Anda. Dengan begitu, semua sandi dari Akun Google Anda juga akan tersedia saat Anda login.</translation>
 <translation id="3752253558646317685">Minta anak Anda mengangkat dan menyentuhkan jari secara berulang untuk menyimpan sidik jari</translation>
 <translation id="3752582316358263300">Oke...</translation>
 <translation id="3753033997400164841">Simpan sekali. Gunakan di mana saja</translation>
@@ -3129,6 +3138,7 @@
 <translation id="4194570336751258953">Aktifkan ketuk untuk mengklik</translation>
 <translation id="4195643157523330669">Buka di tab baru</translation>
 <translation id="4195814663415092787">Lanjutkan dari halaman terakhir yang dibuka</translation>
+<translation id="4198268995694216131">Situs tambahan</translation>
 <translation id="4200689466366162458">Kata khusus</translation>
 <translation id="4200983522494130825">&amp;Tab baru</translation>
 <translation id="4201546031411513170">Anda dapat memilih konten apa yang akan disinkronkan di setelan kapan saja.</translation>
@@ -3250,6 +3260,7 @@
 <translation id="4341577178275615435">Untuk mengaktifkan atau menonaktifkan penjelajahan dengan keyboard, gunakan pintasan F7</translation>
 <translation id="4341905082470253054">Memeriksa status TPM ...</translation>
 <translation id="434198521554309404">Cepat. Aman. Mudah.</translation>
+<translation id="4343250402091037179">Untuk menelusuri situs tertentu atau bagian dari Chrome, ketik pintasannya di kolom URL, lalu tekan pintasan keyboard yang diinginkan.</translation>
 <translation id="434404122609091467">Dengan penyedia layanan saat ini</translation>
 <translation id="4345587454538109430">Konfigurasikan...</translation>
 <translation id="4345732373643853732">Nama pengguna tidak dikenali server</translation>
@@ -4002,6 +4013,7 @@
 <translation id="5153234146675181447">Lupakan ponsel</translation>
 <translation id="5154108062446123722">Setelan lanjutan untuk <ph name="PRINTING_DESTINATION" /></translation>
 <translation id="5154702632169343078">Subjek</translation>
+<translation id="5155327081870541046">Di kolom URL, masukkan pintasan untuk situs yang ingin Anda telusuri, seperti "@bookmark". Lalu, tekan pintasan keyboard yang diinginkan, dan masukkan istilah penelusuran Anda.</translation>
 <translation id="5157635116769074044">Sematkan halaman ini ke Layar Awal...</translation>
 <translation id="5159094275429367735">Siapkan Crostini</translation>
 <translation id="5159419673777902220">Orang tuamu telah menonaktifkan izin ekstensi</translation>
@@ -4621,6 +4633,7 @@
 <translation id="5816434091619127343">Perubahan printer yang diminta akan membuat printer tidak dapat digunakan.</translation>
 <translation id="5817069030404929329">Pindahkan sandi dari perangkat ini ke Akun Google Anda?</translation>
 <translation id="5817918615728894473">Sandingkan</translation>
+<translation id="581840385858998009">Sesuaikan wallpaper, avatar, screensaver, dan lainnya</translation>
 <translation id="5821565227679781414">Buat Pintasan</translation>
 <translation id="5822095611691580107">Tingkat daya baterai bud kiri <ph name="BATTERY_PERCENTAGE" />%.</translation>
 <translation id="5825412242012995131">Aktif (Direkomendasikan)</translation>
@@ -4908,6 +4921,7 @@
 <translation id="6116921718742659598">Ubah setelan masukan dan bahasa</translation>
 <translation id="6119927814891883061">Beri nama perangkat untuk <ph name="DEVICE_NAME" /></translation>
 <translation id="6120205520491252677">Pasang pin halaman ini ke layar Awal...</translation>
+<translation id="6121773125605585883">Lihat sandi dengan nama pengguna <ph name="USERNAME" /> untuk <ph name="WEBSITE" /></translation>
 <translation id="6122081475643980456">Koneksi internet Anda sedang dikendalikan</translation>
 <translation id="6122093587541546701">Email (opsional):</translation>
 <translation id="6122095009389448667">Terus blokir situs ini dari melihat papan klip</translation>
@@ -4984,6 +4998,7 @@
 <translation id="6208725777148613371">Gagal menyimpan ke <ph name="WEB_DRIVE" /> - <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">Komponen sedang diupdate</translation>
 <translation id="6209908325007204267">Perangkat Anda mencakup Chrome Enterprise Upgrade, tetapi nama pengguna Anda tidak terkait dengan akun perusahaan. Buat akun perusahaan dengan membuka g.co/ChromeEnterpriseAccount di perangkat kedua.</translation>
+<translation id="6210282067670792090">Di kolom URL, gunakan pintasan keyboard ini dengan pintasan untuk mesin telusur dan penelusuran situs</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{Buka Semua di &amp;Grup Tab Baru}=1{Buka di &amp;Grup Tab Baru}other{Buka Semua ({COUNT}) di &amp;Grup Tab Baru}}</translation>
 <translation id="6212039847102026977">Tampilkan properti jaringan lanjutan</translation>
 <translation id="6212168817037875041">Matikan layar</translation>
@@ -5467,6 +5482,7 @@
 <translation id="6709357832553498500">Sambungkan menggunakan <ph name="EXTENSIONNAME" /></translation>
 <translation id="6710213216561001401">Sebelumnya</translation>
 <translation id="6711146141291425900">Tautkan akun <ph name="WEB_DRIVE" /> untuk Hasil Download</translation>
+<translation id="6712943853047024245">Anda sudah menyimpan sandi dengan nama pengguna ini untuk <ph name="WEBSITE" /></translation>
 <translation id="6713233729292711163">Tambahkan Profil Kerja</translation>
 <translation id="6715803357256707211">Terjadi error saat menginstal aplikasi Linux. Klik notifikasi untuk mengetahui detailnya.</translation>
 <translation id="671619610707606484">Ini akan menghapus <ph name="TOTAL_USAGE" /> data yang disimpan oleh situs</translation>
@@ -6092,6 +6108,7 @@
 <translation id="7385854874724088939">Ada yang salah saat mencetak. Periksa pencetak Anda dan coba kembali.</translation>
 <translation id="7385896526023870365">Ekstensi ini tidak memiliki akses situs tambahan.</translation>
 <translation id="7387273928653486359">Dapat diterima</translation>
+<translation id="7387951778417998929">Untuk menggunakan mesin telusur selain mesin telusur default, ketik pintasannya di kolom URL, lalu tekan pintasan keyboard yang diinginkan. Anda juga dapat mengubah mesin telusur default di sini.</translation>
 <translation id="7388209873137778229">Hanya menampilkan perangkat yang didukung.</translation>
 <translation id="7392118418926456391">Pemindaian virus gagal</translation>
 <translation id="7392915005464253525">Buka kembali jendela yang tertutup</translation>
@@ -6269,6 +6286,7 @@
 <translation id="7559719679815339381">Harap tunggu....aplikasi Kios sedang diperbarui. Jangan lepaskan stik USB.</translation>
 <translation id="7560756177962144929">Sinkronkan <ph name="DEVICE_TYPE" /> Anda</translation>
 <translation id="7561196759112975576">Selalu</translation>
+<translation id="7562099761826673163">Personalisasi perangkat Anda</translation>
 <translation id="756445078718366910">Buka Jendela Browser</translation>
 <translation id="7564847347806291057">Akhiri proses</translation>
 <translation id="756503097602602175">Dari <ph name="LINK_BEGIN" />Setelan<ph name="LINK_END" />, Anda dapat mengelola Akun Google yang digunakan untuk login. Izin yang Anda berikan ke situs dan aplikasi dapat berlaku untuk semua akun. Jika tidak ingin situs atau aplikasi mengakses info akun, Anda dapat login ke <ph name="DEVICE_TYPE" /> sebagai tamu atau menjelajahi web di <ph name="LINK_2_BEGIN" />jendela Samaran<ph name="LINK_2_END" />.</translation>
@@ -6586,6 +6604,7 @@
 <translation id="78526636422538552">Penambahan lebih banyak Akun Google dinonaktifkan</translation>
 <translation id="7853747251428735">Alat Lain&amp;nya</translation>
 <translation id="7855678561139483478">Pindahkan tab ke jendela baru</translation>
+<translation id="7856654138655787862">Menjalankan pengujian diagnostik Chrome OS.</translation>
 <translation id="7857093393627376423">Saran teks</translation>
 <translation id="7857949311770343000">Apakah ini halaman tab baru yang Anda harapkan?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" /> (Windows)</translation>
@@ -7235,6 +7254,7 @@
 <translation id="8551588720239073785">Setelan tanggal dan waktu</translation>
 <translation id="8553342806078037065">Kelola orang lain</translation>
 <translation id="8554899698005018844">Tidak ada bahasa</translation>
+<translation id="855604308879080518">Mengizinkan aplikasi Android mengakses perangkat USB di Chromebook ini. Anda akan dimintai izin setiap kali mencolokkan perangkat USB. Setiap aplikasi Android akan meminta izin tambahan.</translation>
 <translation id="8557022314818157177">Terus sentuh kunci keamanan Anda hingga sidik jari terekam</translation>
 <translation id="8557180006508471423">Aktifkan "Google Chrome" di Layanan Lokasi pada Mac</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{Buka Semua di &amp;Jendela Baru}=1{Buka di &amp;Jendela Baru}other{Buka Semua ({COUNT}) di &amp;Jendela Baru}}</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 24f419a..6979e248 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -160,6 +160,7 @@
 <translation id="1152346050262092795">アカウントを確認するには、パスワードをもう一度入力してください。</translation>
 <translation id="1153356358378277386">ペア設定されたデバイス</translation>
 <translation id="1153636665119721804">Google の高度な保護機能プログラム</translation>
+<translation id="1155545602507378023">いいえ、このデバイスのみ</translation>
 <translation id="1155816283571436363">スマートフォンに接続しています</translation>
 <translation id="1158080958325422608">大文字にする</translation>
 <translation id="1158238185437008462">思い出の写真を表示</translation>
@@ -394,6 +395,7 @@
 <translation id="1410197035576869800">アプリのアイコン</translation>
 <translation id="1410616244180625362"><ph name="HOST" /> によるカメラへのアクセスを引き続き許可する</translation>
 <translation id="1410806973194718079">ポリシーを確認できません</translation>
+<translation id="1412681350727866021">追加の拡張機能</translation>
 <translation id="1414315029670184034">サイトにカメラの使用を許可しない</translation>
 <translation id="1414648216875402825">アップデートしようとしているバージョンの <ph name="PRODUCT_NAME" /> には開発中の機能が含まれており、不安定です。クラッシュや予期しないバグが発生します。続行する場合は十分にご注意ください。</translation>
 <translation id="1415708812149920388">クリップボードの読み取りアクセスが拒否されました</translation>
@@ -937,6 +939,7 @@
 <translation id="1937774647013465102">このデバイス(<ph name="ARCHITECTURE_DEVICE" />)でコンテナのアーキテクチャ タイプ <ph name="ARCHITECTURE_CONTAINER" /> をインポートできません。このコンテナを別のデバイスに復元できるかお試しださい。または、ファイルアプリを開いて、このコンテナ イメージ内のファイルにアクセスすることも可能です。</translation>
 <translation id="1938351510777341717">外部コマンド</translation>
 <translation id="1940546824932169984">接続済みのデバイス</translation>
+<translation id="1941410638996203291">開始時間: <ph name="TIME" /></translation>
 <translation id="1942128823046546853">すべてのウェブサイト上にある自分の全データの読み取りと変更</translation>
 <translation id="1942600407708803723">ディスプレイを閉じたときにシャットダウンする</translation>
 <translation id="1944528062465413897">Bluetooth ペア設定コード:</translation>
@@ -1310,6 +1313,7 @@
 <translation id="2320295602967756579">ライトモードを有効にする</translation>
 <translation id="2322193970951063277">ヘッダーとフッター</translation>
 <translation id="2322318151094136999">サイトからシリアルポートへのアクセス許可を求められたときに確認する(推奨)</translation>
+<translation id="2322622365472107569">終了時間: <ph name="TIME" /></translation>
 <translation id="2323018538045954000">保存済みの Wi-Fi ネットワーク</translation>
 <translation id="2325444234681128157">パスワードを保存する</translation>
 <translation id="2326188115274135041">PIN を入力して自動ロック解除を有効にする</translation>
@@ -1415,6 +1419,7 @@
 <translation id="2435248616906486374">ネットワークが切断されました</translation>
 <translation id="2435457462613246316">パスワードを表示</translation>
 <translation id="2436186046335138073">すべての <ph name="PROTOCOL" /> リンクを <ph name="HANDLER_HOSTNAME" /> で開きますか?</translation>
+<translation id="2439626940657133600"><ph name="WINDOW_TITLE" /> を読み込んでいます</translation>
 <translation id="2440604414813129000">ソースを表示(&amp;O)</translation>
 <translation id="244231003699905658">無効なアドレスです。アドレスを確認してから、もう一度お試しください。</translation>
 <translation id="2442916515643169563">テキストの影</translation>
@@ -1920,6 +1925,7 @@
 <translation id="2935654492420446828">学校用アカウントは後で追加します</translation>
 <translation id="2936851848721175671">バックアップと復元</translation>
 <translation id="2938225289965773019">「<ph name="PROTOCOL" />」リンクを開く</translation>
+<translation id="2939908794993783865">追加の無効なサイト</translation>
 <translation id="2939938020978911855">使用可能な Bluetooth デバイスを表示</translation>
 <translation id="2941112035454246133">低</translation>
 <translation id="2942279350258725020">Android メッセージ</translation>
@@ -2065,6 +2071,7 @@
 <translation id="3090589793601454425">移動しない</translation>
 <translation id="3090819949319990166">外部の crx ファイルは <ph name="TEMP_CRX_FILE" /> にコピーできません。</translation>
 <translation id="3090871774332213558">「<ph name="DEVICE_NAME" />」がペア設定されました</translation>
+<translation id="3093362725605442088">Chrome OS デバイスとコンポーネントのシリアル番号を読み取る。</translation>
 <translation id="3093714882666365141">サイトに支払いハンドラのインストールを許可しない</translation>
 <translation id="3094141017404513551">続行すると、<ph name="EXISTING_USER" /> さんとは別のブラウジング環境が使用されるようになります</translation>
 <translation id="3095871294753148861">ブックマークやパスワードなどの閲覧データはメイン アカウントと同期されます。</translation>
@@ -2252,6 +2259,7 @@
 <translation id="3308852433423051161">Google アシスタントを読み込んでいます...</translation>
 <translation id="3309330461362844500">証明書プロファイル ID</translation>
 <translation id="3311445899360743395">このアプリに関連付けられているデータはこのデバイスから削除されます。</translation>
+<translation id="3312883087018430408">特定のサイトや Chrome のセクションを検索するには、アドレスバーにそれらのショートカットを入力して、設定したキーボード ショートカットを押します。たとえばブックマークのみを検索する場合は、「@bookmarks」と入力して Tab または Space キーを押します。</translation>
 <translation id="3313622045786997898">証明書の署名値</translation>
 <translation id="3313950410573257029">接続を確認</translation>
 <translation id="3315158641124845231"><ph name="PRODUCT_NAME" /> を隠す</translation>
@@ -2671,6 +2679,7 @@
 <translation id="3747077776423672805">アプリを削除するには、まず [設定] &gt; [Google Play ストア] &gt; [Android 設定を管理] &gt; [アプリ] または [アプリケーション管理] に移動して、アンインストールするアプリをタップします(必要であれば左右にスワイプしてアプリを見つけます)。次に、[アンインストール] または [無効にする] をタップします。</translation>
 <translation id="3747220812138541072">入力中に予測候補をインラインで表示します</translation>
 <translation id="3748706263662799310">バグを報告</translation>
+<translation id="3750562496035670393">パスワードが Chrome によってこのデバイスに保存されました。パスワードは、Google アカウントに保存することもできます。この場合、Google アカウントにログインしている間、アカウントに保存されたすべてのパスワードを使用できます。</translation>
 <translation id="3752253558646317685">指紋を保存するには、お子様に指をかざしてもらってください</translation>
 <translation id="3752582316358263300">OK...</translation>
 <translation id="3753033997400164841">一度保存すればどこでも使用可能</translation>
@@ -3108,6 +3117,7 @@
 <translation id="4194570336751258953">タップによるクリックを有効にする</translation>
 <translation id="4195643157523330669">新しいタブで開く</translation>
 <translation id="4195814663415092787">前回開いていたページを開く</translation>
+<translation id="4198268995694216131">追加のサイト</translation>
 <translation id="4200689466366162458">カスタムの単語</translation>
 <translation id="4200983522494130825">新しいタブ(&amp;T)</translation>
 <translation id="4201546031411513170">同期する項目はいつでも [設定] で選択できます。</translation>
@@ -3227,6 +3237,7 @@
 <translation id="4341577178275615435">カーソル ブラウジングをオンまたはオフにするには、F7 ショートカット キーを使用します</translation>
 <translation id="4341905082470253054">TPM のステータスを確認しています...</translation>
 <translation id="434198521554309404">高速。安全。簡単。</translation>
+<translation id="4343250402091037179">特定のサイトや Chrome のセクションを検索するには、アドレスバーにそれらのショートカットを入力して、設定したキーボード ショートカットを押します。</translation>
 <translation id="434404122609091467">現在のサービス プロバイダを使用する</translation>
 <translation id="4345587454538109430">設定...</translation>
 <translation id="4345732373643853732">サーバーに認識されないユーザー名です</translation>
@@ -3976,6 +3987,7 @@
 <translation id="5153234146675181447">スマートフォンを削除</translation>
 <translation id="5154108062446123722"><ph name="PRINTING_DESTINATION" /> の詳細設定</translation>
 <translation id="5154702632169343078">件名</translation>
+<translation id="5155327081870541046">検索するサイトのショートカット(例: 「@bookmarks」)をアドレスバーに入力します。続けて、設定したキーボード ショートカットを押して、検索語句を入力します。</translation>
 <translation id="5157635116769074044">このページを起動画面に固定...</translation>
 <translation id="5159094275429367735">Crostini のセットアップ</translation>
 <translation id="5159419673777902220">保護者が拡張機能の許可設定を無効にしました</translation>
@@ -4590,6 +4602,7 @@
 <translation id="5816434091619127343">リクエストされた変更を行うと、プリンタを使用できなくります。</translation>
 <translation id="5817069030404929329">このデバイスから Google アカウントにパスワードを移動しますか?</translation>
 <translation id="5817918615728894473">ペア設定</translation>
+<translation id="581840385858998009">壁紙、アバター、スクリーンセーバーなどをカスタマイズできます</translation>
 <translation id="5821565227679781414">ショートカットを作成</translation>
 <translation id="5822095611691580107">左イヤフォンのバッテリー残量は <ph name="BATTERY_PERCENTAGE" />% です。</translation>
 <translation id="5825412242012995131">オン(推奨)</translation>
@@ -4874,6 +4887,7 @@
 <translation id="6116921718742659598">言語と入力の設定を変更</translation>
 <translation id="6119927814891883061">デバイス名を <ph name="DEVICE_NAME" /> に指定します</translation>
 <translation id="6120205520491252677">このページを起動画面に固定...</translation>
+<translation id="6121773125605585883"><ph name="WEBSITE" /> のユーザー名 <ph name="USERNAME" /> のパスワードを表示します</translation>
 <translation id="6122081475643980456">インターネット接続が制限されています</translation>
 <translation id="6122093587541546701">メール(省略可):</translation>
 <translation id="6122095009389448667">このサイトによるクリップボードへのアクセスを引き続きブロックする</translation>
@@ -4950,6 +4964,7 @@
 <translation id="6208725777148613371"><ph name="WEB_DRIVE" /> に保存できませんでした - <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">コンポーネントを更新しています</translation>
 <translation id="6209908325007204267">デバイスには Chrome Enterprise Upgrade が含まれていますが、ユーザー名が Enterprise アカウントに関連付けられていません。サブデバイスで g.co/ChromeEnterpriseAccount にアクセスし、Enterprise アカウントを作成してください。</translation>
+<translation id="6210282067670792090">アドレスバーで、このキーボード ショートカットを検索エンジンやサイト内検索のショートカットとともに使用します</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{すべてを新しいタブグループで開く(&amp;N)}=1{新しいタブグループで開く(&amp;N)}other{すべて({COUNT} 個)を新しいタブグループで開く(&amp;N)}}</translation>
 <translation id="6212039847102026977">ネットワークの詳細プロパティを表示</translation>
 <translation id="6212168817037875041">画面をオフにする</translation>
@@ -5432,6 +5447,7 @@
 <translation id="6709357832553498500">「<ph name="EXTENSIONNAME" />」を使用して接続</translation>
 <translation id="6710213216561001401">前へ</translation>
 <translation id="6711146141291425900">ダウンロードするには <ph name="WEB_DRIVE" /> アカウントをリンクしてください</translation>
+<translation id="6712943853047024245">このユーザー名で <ph name="WEBSITE" /> のパスワードはすでに保存されています</translation>
 <translation id="6713233729292711163">仕事用プロファイルを追加</translation>
 <translation id="6715803357256707211">Linux アプリケーションのインストール中にエラーが発生しました。詳細を確認するには通知をクリックしてください。</translation>
 <translation id="671619610707606484">サイトにより保存された <ph name="TOTAL_USAGE" /> のデータが削除されます</translation>
@@ -6056,6 +6072,7 @@
 <translation id="7385854874724088939">印刷中に問題が発生しました。プリンタを確認してからもう一度お試しください。</translation>
 <translation id="7385896526023870365">この拡張機能はサイトへのアクセスが追加されていません。</translation>
 <translation id="7387273928653486359">許容範囲内</translation>
+<translation id="7387951778417998929">既定と異なる検索エンジンを使用するには、アドレスバーに検索エンジンのショートカットを入力して、設定したキーボード ショートカットを押します。ここで既定の検索エンジンを変更することもできます。</translation>
 <translation id="7388209873137778229">サポートされているデバイスのみが表示されます。</translation>
 <translation id="7392118418926456391">ウイルス スキャンに失敗しました</translation>
 <translation id="7392915005464253525">閉じたウィンドウを開く(&amp;E)</translation>
@@ -6233,6 +6250,7 @@
 <translation id="7559719679815339381">しばらくお待ちください....キオスクアプリを更新しています。USB スティックを取り外さないでください。</translation>
 <translation id="7560756177962144929"><ph name="DEVICE_TYPE" /> の同期</translation>
 <translation id="7561196759112975576">常に使用</translation>
+<translation id="7562099761826673163">デバイスをカスタマイズする</translation>
 <translation id="756445078718366910">ブラウザ ウィンドウを開く</translation>
 <translation id="7564847347806291057">プロセスを終了</translation>
 <translation id="756503097602602175">ログインする Google アカウントは、<ph name="LINK_BEGIN" />設定<ph name="LINK_END" />で管理できます。ウェブサイトとアプリに許可した権限はすべてのアカウントに適用されます。サイトやアプリがアカウント情報にアクセスしないようにするには、<ph name="DEVICE_TYPE" /> にゲストとしてログインするか、<ph name="LINK_2_BEGIN" />シークレット ウィンドウ<ph name="LINK_2_END" />でウェブ ブラウジングします。</translation>
@@ -6549,6 +6567,7 @@
 <translation id="78526636422538552">Google アカウントをさらに追加するオプションは無効になっています</translation>
 <translation id="7853747251428735">その他のツール(&amp;L)</translation>
 <translation id="7855678561139483478">タブを新しいウィンドウに移動</translation>
+<translation id="7856654138655787862">Chrome OS 診断テストを実行する。</translation>
 <translation id="7857093393627376423">テキスト候補</translation>
 <translation id="7857949311770343000">この新しいタブ ページでよろしいですか?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" />(Windows)</translation>
@@ -7197,6 +7216,7 @@
 <translation id="8551588720239073785">日時の設定</translation>
 <translation id="8553342806078037065">他のユーザーを管理</translation>
 <translation id="8554899698005018844">言語設定なし</translation>
+<translation id="855604308879080518">この Chromebook で Android アプリから USB デバイスへのアクセスを許可します。USB デバイスを接続するたびに許可するよう要求されます。一部の Android アプリでは、他の権限も許可するよう要求される場合があります。</translation>
 <translation id="8557022314818157177">指紋の登録が完了するまで、セキュリティ キーをタッチし続けてください</translation>
 <translation id="8557180006508471423">Mac の位置情報サービスで「Google Chrome」をオンにしてください</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{すべてを新しいウィンドウで開く(&amp;N)}=1{新しいウィンドウで開く(&amp;N)}other{すべて({COUNT} 個)を新しいウィンドウで開く(&amp;N)}}</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index bebfdf51..548e6cbb 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -162,7 +162,9 @@
 <translation id="1152346050262092795">비밀번호를 다시 입력하여 계정을 인증하세요</translation>
 <translation id="1153356358378277386">페어링된 기기</translation>
 <translation id="1153636665119721804">Google 고급 보호 프로그램</translation>
+<translation id="1155545602507378023">아니요, 이 기기에만 저장</translation>
 <translation id="1155816283571436363">휴대전화에 연결하는 중</translation>
+<translation id="1158080958325422608">Make Uppercase(대문자로 표시)</translation>
 <translation id="1158238185437008462">추억 보기</translation>
 <translation id="1161575384898972166"><ph name="TOKEN_NAME" />에 로그인하여 클라이언트 인증서를 내보내세요.</translation>
 <translation id="116173250649946226">관리자가 기본 테마를 설정했으며, 이는 수정할 수 없습니다.</translation>
@@ -395,6 +397,7 @@
 <translation id="1410197035576869800">앱 아이콘</translation>
 <translation id="1410616244180625362"><ph name="HOST" />에서 카메라에 액세스하도록 계속 허용</translation>
 <translation id="1410806973194718079">정책을 확인할 수 없습니다.</translation>
+<translation id="1412681350727866021">추가 확장 프로그램</translation>
 <translation id="1414315029670184034">사이트에서 카메라를 사용하도록 허용하지 않음</translation>
 <translation id="1414648216875402825">개발 중인 기능을 포함하는 <ph name="PRODUCT_NAME" />의 불안정한 버전으로 업데이트합니다. 기기가 비정상 종료되거나 예기치 않은 버그가 발생할 수 있습니다. 주의해서 진행하시기 바랍니다.</translation>
 <translation id="1415708812149920388">클립 보드 읽기 액세스 거부됨</translation>
@@ -696,6 +699,7 @@
 <translation id="1700079447639026019">쿠키를 사용할 수 없는 사이트</translation>
 <translation id="1703331064825191675">비밀번호 안심 관리</translation>
 <translation id="1703666494654169921">사이트에서 가상 현실 기기 또는 데이터를 사용하도록 허용하지 않음</translation>
+<translation id="1704097193565924901">Capitalize(첫 글자 대문자로 표시)</translation>
 <translation id="1704230497453185209">사이트에서 소리를 재생하도록 허용하지 않음</translation>
 <translation id="1704970325597567340">안전 확인이 <ph name="DATE" />에 실행됨</translation>
 <translation id="1706586824377653884">관리자가 추가함</translation>
@@ -948,6 +952,7 @@
 <translation id="1937774647013465102"><ph name="ARCHITECTURE_DEVICE" /> 기기에서는 <ph name="ARCHITECTURE_CONTAINER" /> 컨테이너 아키텍처 유형을 가져올 수 없습니다. 이 컨테이너를 다른 기기에서 복원할 수 있으며, 컨테이너 이미지를 Files 앱에서 열면 컨테이너 이미지에 포함된 파일에 액세스할 수 있습니다.</translation>
 <translation id="1938351510777341717">외부 명령어</translation>
 <translation id="1940546824932169984">연결된 기기</translation>
+<translation id="1941410638996203291">시작 시간: <ph name="TIME" /></translation>
 <translation id="1942128823046546853">모든 웹사이트의 전체 데이터 읽기 및 변경</translation>
 <translation id="1942600407708803723">커버를 닫으면 종료</translation>
 <translation id="1944528062465413897">블루투스 페어링 코드:</translation>
@@ -1326,6 +1331,7 @@
 <translation id="2320295602967756579">밝은 테마 사용 설정</translation>
 <translation id="2322193970951063277">머리글과 바닥글</translation>
 <translation id="2322318151094136999">사이트가 직렬 포트에 액세스하려고 할 때 확인(권장)</translation>
+<translation id="2322622365472107569">종료 시간: <ph name="TIME" /></translation>
 <translation id="2323018538045954000">저장된 Wi-Fi 네트워크</translation>
 <translation id="2325444234681128157">비밀번호 저장</translation>
 <translation id="2326188115274135041">자동 잠금 해제를 사용 설정하려면 PIN을 확인하세요.</translation>
@@ -1431,6 +1437,7 @@
 <translation id="2435248616906486374">네트워크 연결 끊김</translation>
 <translation id="2435457462613246316">비밀번호 표시</translation>
 <translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" />에서 모든 <ph name="PROTOCOL" /> 링크를 열도록 허용하시겠습니까?</translation>
+<translation id="2439626940657133600"><ph name="WINDOW_TITLE" /> 로드 중</translation>
 <translation id="2440604414813129000">소스 보기(&amp;O)</translation>
 <translation id="244231003699905658">잘못된 주소입니다. 주소를 확인한 다음 다시 시도해 보세요.</translation>
 <translation id="2442916515643169563">텍스트 음영</translation>
@@ -1936,6 +1943,7 @@
 <translation id="2935654492420446828">학교 계정 나중에 추가하기</translation>
 <translation id="2936851848721175671">백업 및 복원</translation>
 <translation id="2938225289965773019"><ph name="PROTOCOL" /> 링크 열기</translation>
+<translation id="2939908794993783865">추가 비활성 사이트</translation>
 <translation id="2939938020978911855">사용 가능한 블루투스 기기 표시</translation>
 <translation id="2941112035454246133">낮음</translation>
 <translation id="2942279350258725020">Android 메시지</translation>
@@ -2081,6 +2089,7 @@
 <translation id="3090589793601454425">이동 안함</translation>
 <translation id="3090819949319990166">외부 crx 파일을 <ph name="TEMP_CRX_FILE" />에 복사할 수 없습니다.</translation>
 <translation id="3090871774332213558">'<ph name="DEVICE_NAME" />' 페어링됨</translation>
+<translation id="3093362725605442088">Chrome OS 기기와 구성요소 일련번호를 읽을 수 있습니다.</translation>
 <translation id="3093714882666365141">사이트에서 결제 핸들러를 설치하도록 허용하지 않음</translation>
 <translation id="3094141017404513551">그러면 <ph name="EXISTING_USER" /> 기록과 내 인터넷 사용 기록이 구분됩니다.</translation>
 <translation id="3095871294753148861">북마크, 비밀번호 등의 브라우저 데이터가 기본 계정과 동기화되어 있습니다.</translation>
@@ -2268,6 +2277,7 @@
 <translation id="3308852433423051161">Google 어시스턴트 로드 중...</translation>
 <translation id="3309330461362844500">인증서 프로필 ID</translation>
 <translation id="3311445899360743395">앱과 관련된 데이터가 기기에서 삭제될 수 있습니다.</translation>
+<translation id="3312883087018430408">특정 사이트 또는 Chrome의 일부를 검색하려면 주소 표시줄에 바로가기를 입력한 다음 원하는 단축키를 누르세요. 예를 들어 북마크만 검색하려면 '@bookmarks'라고 입력한 다음 Tab 또는 스페이스바를 누르세요.</translation>
 <translation id="3313622045786997898">인증서 서명 값</translation>
 <translation id="3313950410573257029">연결 확인</translation>
 <translation id="3315158641124845231"><ph name="PRODUCT_NAME" /> 숨기기</translation>
@@ -2687,6 +2697,7 @@
 <translation id="3747077776423672805">앱을 삭제하려면 설정 &gt; Google Play 스토어 &gt; Android 환경설정 관리 &gt; 앱 또는 애플리케이션 관리자로 이동합니다. 그런 다음 제거하려는 앱을 탭합니다(앱을 찾으려면 오른쪽이나 왼쪽으로 스와이프해야 할 수 있음). 그런 다음 제거 또는 사용 중지를 탭합니다.</translation>
 <translation id="3747220812138541072">입력할 때 추천 단어를 인라인으로 표시합니다.</translation>
 <translation id="3748706263662799310">버그 신고</translation>
+<translation id="3750562496035670393">Chrome에서 비밀번호를 이 기기에 저장했으나, 대신 Google 계정에 저장해도 됩니다. 그렇게 하면 로그인한 상태에서 Google 계정에 저장된 모든 비밀번호를 사용할 수도 있습니다.</translation>
 <translation id="3752253558646317685">지문을 저장하려면 자녀가 손가락을 계속 들고 있게 하세요.</translation>
 <translation id="3752582316358263300">확인...</translation>
 <translation id="3753033997400164841">한 번만 저장하고 어디서나 사용하세요</translation>
@@ -3125,6 +3136,7 @@
 <translation id="4194570336751258953">탭하여 클릭 사용</translation>
 <translation id="4195643157523330669">새 탭에서 열기</translation>
 <translation id="4195814663415092787">중단한 위치에서 계속하기</translation>
+<translation id="4198268995694216131">추가 사이트</translation>
 <translation id="4200689466366162458">맞춤 단어</translation>
 <translation id="4200983522494130825">새 탭(&amp;T)</translation>
 <translation id="4201546031411513170">언제든지 설정에서 동기화할 항목을 선택할 수 있습니다.</translation>
@@ -3246,6 +3258,7 @@
 <translation id="4341577178275615435">캐럿 브라우징을 사용 설정하거나 중지하려면 F7 단축키를 사용합니다.</translation>
 <translation id="4341905082470253054">TPM 상태 확인 중...</translation>
 <translation id="434198521554309404">빠르고 안전하며 편리한 브라우저</translation>
+<translation id="4343250402091037179">특정 사이트 또는 Chrome의 일부를 검색하려면 주소 표시줄에 바로가기를 입력한 다음 원하는 단축키를 누르세요.</translation>
 <translation id="434404122609091467">현재 서비스 제공업체 이용</translation>
 <translation id="4345587454538109430">설정...</translation>
 <translation id="4345732373643853732">서버에 알려지지 않은 사용자 이름</translation>
@@ -3575,6 +3588,7 @@
 <translation id="4681453295291708042">Nearby Share 사용 중지</translation>
 <translation id="4681930562518940301">새 탭에서 원본 이미지 열기</translation>
 <translation id="4682551433947286597">로그인 화면에 배경화면이 표시됩니다.</translation>
+<translation id="4683629100208651599">Make Lowercase(소문자로 표시)</translation>
 <translation id="4683947955326903992"><ph name="PERCENTAGE" />%(기본)</translation>
 <translation id="4684427112815847243">모두 동기화</translation>
 <translation id="4684471265911890182"><ph name="APP_NAME" /> 앱에서 카메라에 액세스하려고 합니다. 액세스를 허용하려면 카메라 개인정보 보호 스위치를 끄세요.</translation>
@@ -3996,6 +4010,7 @@
 <translation id="5153234146675181447">휴대전화 지우기</translation>
 <translation id="5154108062446123722"><ph name="PRINTING_DESTINATION" /> 고급 설정</translation>
 <translation id="5154702632169343078">대상</translation>
+<translation id="5155327081870541046">주소 표시줄에 '@bookmarks'와 같이 검색하려는 사이트의 바로가기를 입력하세요. 그런 다음 원하는 단축키를 누르고 검색어를 입력하세요.</translation>
 <translation id="5157635116769074044">이 페이지를 시작 화면에 고정...</translation>
 <translation id="5159094275429367735">Crostini 설정</translation>
 <translation id="5159419673777902220">부모님이 확장 프로그램 권한을 사용 중지했습니다.</translation>
@@ -4615,6 +4630,7 @@
 <translation id="5816434091619127343">프린터 변경을 요청하면 프린터를 사용할 수 없게 됩니다.</translation>
 <translation id="5817069030404929329">기기의 비밀번호를 Google 계정으로 옮기시겠습니까?</translation>
 <translation id="5817918615728894473">페어링</translation>
+<translation id="581840385858998009">배경화면, 아바타, 화면 보호기 등을 맞춤설정합니다.</translation>
 <translation id="5821565227679781414">바로가기 만들기</translation>
 <translation id="5822095611691580107">왼쪽 이어폰 배터리 잔량 <ph name="BATTERY_PERCENTAGE" />%.</translation>
 <translation id="5825412242012995131">사용(권장)</translation>
@@ -4902,6 +4918,7 @@
 <translation id="6116921718742659598">언어 및 입력 설정 변경</translation>
 <translation id="6119927814891883061">기기 이름을 다음으로 지정: <ph name="DEVICE_NAME" /></translation>
 <translation id="6120205520491252677">이 페이지를 시작 화면에 고정...</translation>
+<translation id="6121773125605585883"><ph name="WEBSITE" />의 사용자 이름 <ph name="USERNAME" /> 및 비밀번호 표시</translation>
 <translation id="6122081475643980456">인터넷 연결이 제어되고 있습니다.</translation>
 <translation id="6122093587541546701">이메일(선택사항):</translation>
 <translation id="6122095009389448667">이 사이트에서 클립보드를 보지 못하게 계속 차단</translation>
@@ -4978,6 +4995,7 @@
 <translation id="6208725777148613371"><ph name="WEB_DRIVE" />에 저장할 수 없음(<ph name="INTERRUPT_REASON" />)</translation>
 <translation id="6209838773933913227">구성요소 업데이트 중</translation>
 <translation id="6209908325007204267">기기에 Chrome Enterprise 업그레이드가 있지만 사용자 이름이 엔터프라이즈 계정에 연결되어 있지 않았습니다. 다른 기기에서 다음 페이지를 방문하여 엔터프라이즈 계정을 만드세요. g.co/ChromeEnterpriseAccount</translation>
+<translation id="6210282067670792090">주소 표시줄에 검색엔진 및 사이트 검색의 바로가기를 입력하고 단축키를 누르세요.</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{새 탭 그룹에서 모두 열기(&amp;N)}=1{새 탭 그룹에서 열기(&amp;N)}other{새 탭 그룹에서 {COUNT}개 모두 열기(&amp;N)}}</translation>
 <translation id="6212039847102026977">고급 네트워크 속성 표시</translation>
 <translation id="6212168817037875041">디스플레이 사용 중지</translation>
@@ -5461,6 +5479,7 @@
 <translation id="6709357832553498500"><ph name="EXTENSIONNAME" />을(를) 사용하여 연결</translation>
 <translation id="6710213216561001401">이전</translation>
 <translation id="6711146141291425900">다운로드용 <ph name="WEB_DRIVE" /> 계정 연결</translation>
+<translation id="6712943853047024245">이미 <ph name="WEBSITE" />의 사용자 이름과 비밀번호를 저장했습니다.</translation>
 <translation id="6713233729292711163">직장 프로필 추가</translation>
 <translation id="6715803357256707211">Linux 애플리케이션을 설치하는 중에 오류가 발생했습니다. 알림을 클릭하면 자세한 정보를 확인할 수 있습니다.</translation>
 <translation id="671619610707606484">사이트에서 저장한 <ph name="TOTAL_USAGE" />의 데이터가 삭제됩니다.</translation>
@@ -5966,6 +5985,7 @@
 <translation id="7257173066616499747">Wi-Fi 네트워크</translation>
 <translation id="725758059478686223">인쇄 서비스</translation>
 <translation id="7257666756905341374">복사하여 붙여넣은 데이터 조회</translation>
+<translation id="7258192266780953209">Transformations(변환)</translation>
 <translation id="7258225044283673131">애플리케이션이 응답하지 않습니다. '강제 종료'를 선택하여 앱을 닫으세요.</translation>
 <translation id="7262004276116528033">이 로그인 서비스는 <ph name="SAML_DOMAIN" />에서 호스팅됩니다.</translation>
 <translation id="7264564921322372728"><ph name="BEGIN_PARAGRAPH1" />다음 문제 해결 단계를 시도해 보세요.
@@ -6085,6 +6105,7 @@
 <translation id="7385854874724088939">인쇄를 시도하는 동안 문제가 발생했습니다. 프린터를 점검한 다음 다시 시도해 보세요.</translation>
 <translation id="7385896526023870365">이 확장 프로그램에는 추가적인 사이트 액세스 권한이 없습니다.</translation>
 <translation id="7387273928653486359">양호함</translation>
+<translation id="7387951778417998929">기본 검색엔진이 아닌 다른 검색엔진을 사용하려면 주소 표시줄에 사용할 검색엔진의 바로가기를 입력한 다음 원하는 단축키를 누르세요. 여기에서 기본 검색엔진을 변경할 수도 있습니다.</translation>
 <translation id="7388209873137778229">지원되는 기기만 표시됩니다.</translation>
 <translation id="7392118418926456391">바이러스 검사 실패</translation>
 <translation id="7392915005464253525">닫은 탭 다시 열기(&amp;E)</translation>
@@ -6262,6 +6283,7 @@
 <translation id="7559719679815339381">잠시 기다려주세요. Kiosk 앱을 업데이트하는 중입니다. USB 메모리를 제거하지 마세요.</translation>
 <translation id="7560756177962144929"><ph name="DEVICE_TYPE" /> 동기화</translation>
 <translation id="7561196759112975576">항상</translation>
+<translation id="7562099761826673163">기기 맞춤설정</translation>
 <translation id="756445078718366910">브라우저 창 열기</translation>
 <translation id="7564847347806291057">프로세스 종료</translation>
 <translation id="756503097602602175">로그인된 Google 계정을 <ph name="LINK_BEGIN" />설정<ph name="LINK_END" />에서 관리할 수 있습니다. 웹사이트와 앱에 부여한 권한이 모든 계정에 적용될 수 있습니다. 사이트나 앱에서 계정 정보에 액세스하기를 원하지 않으면 게스트로 <ph name="DEVICE_TYPE" />에 로그인하거나 <ph name="LINK_2_BEGIN" />시크릿 창<ph name="LINK_2_END" />에서 웹을 탐색하세요.</translation>
@@ -6579,6 +6601,7 @@
 <translation id="78526636422538552">Google 계정 추가가 사용 중지되었습니다.</translation>
 <translation id="7853747251428735">도구 더보기(&amp;L)</translation>
 <translation id="7855678561139483478">탭을 새 창으로 이동</translation>
+<translation id="7856654138655787862">Chrome OS 진단 테스트를 실행합니다.</translation>
 <translation id="7857093393627376423">텍스트 추천</translation>
 <translation id="7857949311770343000">설정한 새 탭 페이지가 맞습니까?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" />(Windows)</translation>
@@ -7228,6 +7251,7 @@
 <translation id="8551588720239073785">날짜 및 시간 설정</translation>
 <translation id="8553342806078037065">다른 사용자 관리</translation>
 <translation id="8554899698005018844">언어가 없음</translation>
+<translation id="855604308879080518">Android 앱이 Chromebook에 연결된 USB 기기에 액세스하도록 허용합니다. USB 기기를 삽입할 때마다 권한 요청이 표시됩니다. 추가 권한은 각 Android 앱에서 개별적으로 요청합니다.</translation>
 <translation id="8557022314818157177">지문이 인식될 때까지 보안 키를 계속 터치하세요.</translation>
 <translation id="8557180006508471423">Mac의 Location Services(위치 서비스)에서 'Chrome'을 사용 설정하세요</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{새 창에서 모두 열기(N)}=1{새 창에서 열기(N)}other{새 창에서 {COUNT}개 모두 열기(N)}}</translation>
diff --git a/chrome/app/resources/generated_resources_mn.xtb b/chrome/app/resources/generated_resources_mn.xtb
index 3de425ee..3c1429f 100644
--- a/chrome/app/resources/generated_resources_mn.xtb
+++ b/chrome/app/resources/generated_resources_mn.xtb
@@ -1694,6 +1694,7 @@
 <translation id="2707024448553392710">Бүрэлдэхүүн хэсэг татаж байна</translation>
 <translation id="270921614578699633">Дунджаас дээш</translation>
 <translation id="2709516037105925701">Автоматаар бөглөх</translation>
+<translation id="2710014902399506864">Шинэ утас нэмэх</translation>
 <translation id="2710101514844343743">Ашиглалт болон оношилгооны өгөгдөл</translation>
 <translation id="271033894570825754">Шинэ</translation>
 <translation id="2712173769900027643">Зөвшөөрөл авах</translation>
@@ -2053,6 +2054,7 @@
 <translation id="3055590424724986000">Таны сонгосон үйлчилгээ үзүүлэгчийн</translation>
 <translation id="3058498974290601450">Та синкийг хүссэн үедээ тохиргоонд асааж болно</translation>
 <translation id="3058517085907878899">Төхөөрөмжид нэр өгөх</translation>
+<translation id="3059195548603439580">Системийн бүрэлдэхүүн хэсгүүдийг хайж байна уу? Зочлох</translation>
 <translation id="3060379269883947824">Ярихаар сонгох сонголтыг идэвхжүүлэх</translation>
 <translation id="3060952009917586498">Төхөөрөмжийн хэлийг өөрчилнө. Одоогийн хэл <ph name="LANGUAGE" /> байна.</translation>
 <translation id="3060987956645097882">Бид таны утастай холболт тогтоож чадсангүй. Таны утас ойрхон, түгжээг нь тайлсан, Bluetooth, Wi-Fi-г нь асаасан эсэхийг шалгана уу.</translation>
@@ -2712,6 +2714,7 @@
 <translation id="3764583730281406327">{NUM_DEVICES,plural, =1{ USB төхөөрөмжөөр харилцах}other{ # USB төхөөрөмжүүдээр харилцах}}</translation>
 <translation id="3764974059056958214">{COUNT,plural, =1{<ph name="ATTACHMENTS" />-г <ph name="DEVICE_NAME" /> руу илгээж байна}other{<ph name="ATTACHMENTS" />-г <ph name="DEVICE_NAME" /> руу илгээж байна}}</translation>
 <translation id="3765246971671567135">Офлайн демо горимын удирдамжийг уншиж чадсангүй.</translation>
+<translation id="3766115177661377251">Шинэ дэлгэц рүү дамжуулах</translation>
 <translation id="3766811143887729231"><ph name="REFRESH_RATE" /> Гц</translation>
 <translation id="377050016711188788">Зайрмаг</translation>
 <translation id="3771290962915251154">Эцэг эхийн хяналт асаалттай байгаа тул энэ тохиргоог идэвхгүй болгосон</translation>
@@ -3501,6 +3504,7 @@
 <translation id="4590324241397107707">Өгөгдлийн сангийн хадгалалт</translation>
 <translation id="4592891116925567110">Мэдрэгч үзгийн зурдаг апп</translation>
 <translation id="4593021220803146968">&amp;<ph name="URL" /> руу очих</translation>
+<translation id="4594577641390224176">Системийн талаарх хуудсыг хайж байна уу? Зочлох</translation>
 <translation id="4595560905247879544">Апп болон өргөтгөлийг (<ph name="CUSTODIAN_NAME" />) менежер өөрчлөх боломжтой.</translation>
 <translation id="4596295440756783523">Танд эдгээр серверийг тодорхойлох файлын сертификат байна</translation>
 <translation id="4598556348158889687">Сангийн менежмент</translation>
@@ -4886,6 +4890,7 @@
 <translation id="6085886413119427067">Веб сайтуудтай аюулгүй холболтоор хэрхэн холбогдохыг шийддэг</translation>
 <translation id="6086004606538989567">Таны баталгаажуулсан бүртгэл энэ төхөөрөмжид хандах зөвшөөрөлгүй байна.</translation>
 <translation id="6086846494333236931">Таны админ суулгасан</translation>
+<translation id="6087746524533454243">Хөтчийн талаарх хуудсыг хайж байна уу? Зочлох</translation>
 <translation id="6087960857463881712">Гайхалтай нүүр</translation>
 <translation id="608912389580139775">Энэ хуудсыг унших жагсаалтдаа нэмэхийн тулд Хавчуурганы дүрс тэмдгийг товшино уу</translation>
 <translation id="6091761513005122595">Хуваалцлыг амжилттай салгасан.</translation>
@@ -4984,6 +4989,7 @@
 <translation id="6198102561359457428">Үйлдлийн системээс гараад, дахин нэвтрэнэ үү...</translation>
 <translation id="6198252989419008588">ПИН кодыг өөрчлөх</translation>
 <translation id="6200047250927636406">Файлыг болих</translation>
+<translation id="6200151268994853226">Өргөтгөлийг удирдах</translation>
 <translation id="6201608810045805374">Энэ бүртгэлийг хасах уу?</translation>
 <translation id="6202304368170870640">Ta төхөөрөмждөө нэвтрэх эсвэл түгжээг нь тайлахын тулд ПИН кодоо ашиглаж болно.</translation>
 <translation id="6206311232642889873">Зургийг хуулах</translation>
@@ -5271,6 +5277,7 @@
 <translation id="6497789971060331894">Хулганыг урвуу гүйлгэх</translation>
 <translation id="6498249116389603658">&amp;Таны бүх хэл</translation>
 <translation id="6499143127267478107">Төлөөллийн скриптээр дамжуулан оролцогчийг тодорхойлон шийдэх ...</translation>
+<translation id="6499764981457476645">Ойролцоо ямар ч төхөөрөмж олдсонгүй</translation>
 <translation id="6501086852992132091"><ph name="APP_ORIGIN" /> энэ файлыг нээхийг хүсэж байна:</translation>
 <translation id="6501957628055559556">Бүх контейнер</translation>
 <translation id="650266656685499220">Цомог үүсгэхийн тулд Google Зураг руу очно уу</translation>
@@ -5736,6 +5743,7 @@
 <translation id="6979440798594660689">Дууг хаах (өгөгдмөл)</translation>
 <translation id="6979737339423435258">Бүх цаг</translation>
 <translation id="6981553172137913845">Нууцлалтайгаар үзэхийн тулд цэсийн цэгэн дүрс тэмдгийг товшиж, Нууцлалтай цонхыг нээнэ үү</translation>
+<translation id="6981761993313539853">Bluetooth төхөөрөмжөө хослуулах горимд болон ойролцоо байгаа эсэхийг шалгаарай. Зөвхөн итгэдэг төхөөрөмжүүдтэйгээ хослуулна уу. <ph name="BEGIN_LINK_LEARN_MORE" />Нэмэлт мэдээлэл авах<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="6981982820502123353">Хандалт</translation>
 <translation id="6983507711977005608">Шуурхай модем болгох сүлжээг салгах</translation>
 <translation id="6983783921975806247">OID-ыг бүртгэсэн</translation>
@@ -6641,6 +6649,7 @@
 <translation id="7898725031477653577">Үргэлж хөрвүүлэх</translation>
 <translation id="7901405293566323524">Утасны Hub</translation>
 <translation id="7901914889562552258">Хуудасны хэмжигдэхүүнийг ашиглан сайжруулсан Chrome</translation>
+<translation id="7903290522161827520">Хөтчийн бүрэлдэхүүн хэсгүүдийг хайж байна уу? Зочлох</translation>
 <translation id="7903345046358933331">Энэ хуудас хариу мэдэгдэхгүй байна. Та энэ хуудсыг хариу мэдэгдтэл хүлээх, эсвэл хаах боломжтой.</translation>
 <translation id="7903742244674067440">Танд эдгээр сертификатын эрхийг тодорхойлох файлын сертификат байна</translation>
 <translation id="7903925330883316394">Хэрэгсэл: <ph name="UTILITY_TYPE" /></translation>
@@ -7013,6 +7022,7 @@
 <translation id="8271268254812352141">Та баруун талыг товших эсвэл текстийг удаан дарах үедээ тодорхойлолт, орчуулга эсвэл нэгж хөрвүүлэлт аваарай. Орчуулгын хэлийг <ph name="LINK_BEGIN" />Вебсайтын хэл<ph name="LINK_END" /> хэсэгт өөрчилнө үү.</translation>
 <translation id="8271379370373330993">Эцэг эхчүүд ээ, дараагийн хэдэн алхмыг та бүхэнд зориулсан. Та бүртгэлийг тохируулж дууссаны дараа <ph name="DEVICE_TYPE" />-г хүүхдэдээ буцааж өгч болно.</translation>
 <translation id="8272443605911821513">"More tools" цэсэн дэх өргөтгөл дээр дарж өргөтгөлүүдээ удирдаарай.</translation>
+<translation id="8272677921396592934">QR кодыг скан хийхийн тулд камерыг ашиглана уу</translation>
 <translation id="8274332263553132018">Файл дамжуулах</translation>
 <translation id="8274921654076766238">Томруулагч нь гарын фокусыг дагадаг</translation>
 <translation id="8274924778568117936">Шинэчилж дуустал <ph name="DEVICE_TYPE" />-г унтрааж эсвэл хааж болохгүй. Суулгаж дууссан үед <ph name="DEVICE_TYPE" />-г дахин эхлүүлнэ.</translation>
@@ -7688,6 +7698,7 @@
 <translation id="9004754973617721124"><ph name="SITE_NAME" />, түүний доорх бүх сайт болон суулгасан аппын сайтын өгөгдөл, зөвшөөрлийг арилгах уу?</translation>
 <translation id="9004952710076978168">Үл мэдэгдэх принтерийн талаарх мэдэгдэл хүлээн авсан.</translation>
 <translation id="9008201768610948239">Алгас</translation>
+<translation id="9008201858626224558"><ph name="SUBPAGE_TITLE" />-н дэлгэрэнгүй мэдээллийн хуудасны буцах товч</translation>
 <translation id="9009369504041480176">Татаж оруулах ( <ph name="PROGRESS_PERCENT" /> %) ...</translation>
 <translation id="9009708085379296446">Та энэ хуудсыг өөрчлөх гэж байсан уу?</translation>
 <translation id="9011163749350026987">Байнга дүрс тэмдэг харуулах</translation>
@@ -7871,6 +7882,7 @@
 <translation id="917510707618656279">Сайт Bluetooth төхөөрөмжүүдэд хандах хүсэлтэй үед асуух</translation>
 <translation id="9176476835295860688">Ашиглалт болон оношилгооны өгөгдлийг илгээнэ үү. Энэ төхөөрөмж одоогоор оношилгоо, төхөөрөмж болон аппын ашиглалтын өгөгдлийг Google-д автоматаар илгээж байна. Энэ нь систем, аппын тогтвортой байдал болон бусад зүйлийг сайжруулахад тусална. Зарим хуримтлуулсан өгөгдөл нь Google аппууд болон Android хөгжүүлэгч зэрэг түншүүдэд мөн адил тусална. Энэ <ph name="BEGIN_LINK1" />тохиргоог<ph name="END_LINK1" /> хэрэглэгчийн зүгээс хэрэгжүүлнэ. Хэрэв таны Веб, Аппын нэмэлт үйл ажиллагааны тохиргоо асаалттай байвал энэ өгөгдлийг таны Google бүртгэлд хадгалж болзошгүй. <ph name="BEGIN_LINK2" />Нэмэлт мэдээлэл авах<ph name="END_LINK2" /></translation>
 <translation id="9176611096776448349"><ph name="WINDOW_TITLE" /> - Bluetooth төхөөрөмжийг холбосон</translation>
+<translation id="9178061802301856367">Нэвтрэх өгөгдлийг устгах</translation>
 <translation id="9179524979050048593">Нэвтрэх дэлгэцийн хэрэглэгчийн нэр</translation>
 <translation id="9180281769944411366">Энэ үйл явцад хэдэн минут шаардлагатай. Linux контейнерыг эхлүүлж байна.</translation>
 <translation id="9180380851667544951">Сайт таны дэлгэцийг хуваалцах боломжтой</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index 4375cbc5..17daeef1 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -162,6 +162,7 @@
 <translation id="1153636665119721804">Program rozšírenej ochrany Google</translation>
 <translation id="1155545602507378023">Nie, iba v tomto zariadení</translation>
 <translation id="1155816283571436363">Pripája sa k vášmu telefónu</translation>
+<translation id="1158080958325422608">Zmeniť na veľké písmená</translation>
 <translation id="1158238185437008462">Zobraziť spomienky</translation>
 <translation id="1161575384898972166">Ak chcete exportovať certifikát klienta, prihláste sa do <ph name="TOKEN_NAME" />.</translation>
 <translation id="116173250649946226">Váš správca nastavil predvolený motív, ktorý sa nedá zmeniť.</translation>
@@ -697,6 +698,7 @@
 <translation id="1700079447639026019">Weby, ktoré nemôžu nikdy používať súbory cookie</translation>
 <translation id="1703331064825191675">Už si nemusíte robiť starosti o heslá</translation>
 <translation id="1703666494654169921">Nepovoliť webom používať zariadenia alebo údaje virtuálnej reality</translation>
+<translation id="1704097193565924901">Veľkosť písmen</translation>
 <translation id="1704230497453185209">Nepovoliť webom prehrávať zvuk</translation>
 <translation id="1704970325597567340">Kontrola bezpečnosti prebehla <ph name="DATE" /></translation>
 <translation id="1706586824377653884">Pridané správcom</translation>
@@ -3575,6 +3577,7 @@
 <translation id="4681453295291708042">Zakázať Zdieľanie nablízku</translation>
 <translation id="4681930562518940301">Otvoriť pôvodný &amp;obrázok na novej karte</translation>
 <translation id="4682551433947286597">Tapety sa zobrazia na prihlasovacej obrazovke.</translation>
+<translation id="4683629100208651599">Zmeniť na malé písmená</translation>
 <translation id="4683947955326903992"><ph name="PERCENTAGE" /> % (predvolené)</translation>
 <translation id="4684427112815847243">Synchronizovať všetko</translation>
 <translation id="4684471265911890182"><ph name="APP_NAME" /> sa snaží získať prístup k fotoaparátu. Ak chcete prístup povoliť, vypnite prepínač ochrany súkromia fotoaparátu.</translation>
@@ -5971,6 +5974,7 @@
 <translation id="7257173066616499747">Siete Wi‑Fi</translation>
 <translation id="725758059478686223">Tlačová služba</translation>
 <translation id="7257666756905341374">Čítať údaje, ktoré kopírujete a prilepujete</translation>
+<translation id="7258192266780953209">Transformácie</translation>
 <translation id="7258225044283673131">Aplikácia nereaguje. Zavrite ju výberom možnosti Vynútiť zavretie.</translation>
 <translation id="7262004276116528033">Túto prihlasovaciu službu hostí doména <ph name="SAML_DOMAIN" /></translation>
 <translation id="7264564921322372728"><ph name="BEGIN_PARAGRAPH1" />Vyskúšajte tieto kroky na riešenie problémov:
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index 2d4073f..4c02371 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -160,6 +160,7 @@
 <translation id="1152346050262092795">Hesabınızı doğrulamak için şifrenizi tekrar girin.</translation>
 <translation id="1153356358378277386">Eşlenen cihazlar</translation>
 <translation id="1153636665119721804">Google Gelişmiş Koruma Programı</translation>
+<translation id="1155545602507378023">Hayır, yalnızca bu cihaz</translation>
 <translation id="1155816283571436363">Telefonunuza bağlanılıyor</translation>
 <translation id="1158080958325422608">Büyük Harf Yap</translation>
 <translation id="1158238185437008462">Anıları gör</translation>
@@ -394,6 +395,7 @@
 <translation id="1410197035576869800">Uygulama Simgesi</translation>
 <translation id="1410616244180625362">Kameranıza <ph name="HOST" /> tarafından erişilmesine izin vermeye devam edin</translation>
 <translation id="1410806973194718079">Politikalar kontrol edilemiyor</translation>
+<translation id="1412681350727866021">Ek uzantılar</translation>
 <translation id="1414315029670184034">Sitelerin kameramı kullanmasına izin verme</translation>
 <translation id="1414648216875402825"><ph name="PRODUCT_NAME" /> ürününün kararsız bir sürümüne güncelleme yapıyorsunuz. Bu sürüm geliştirilmekte olan özellikler içerir. Kilitlenmeler ve beklenmeyen hatalar olacaktır. Lütfen dikkatle ilerleyin.</translation>
 <translation id="1415708812149920388">Pano okuma erişimi reddedildi</translation>
@@ -938,6 +940,7 @@
 <translation id="1937774647013465102">Bu cihaz (<ph name="ARCHITECTURE_DEVICE" />) ile kapsayıcı mimarisinin türü <ph name="ARCHITECTURE_CONTAINER" /> içe aktarılamıyor. Bu kapsayıcıyı farklı bir cihaza geri yüklemeyi deneyebilir veya Files uygulamasını açarak bu kapsayıcı görüntüsündeki dosyalara erişebilirsiniz.</translation>
 <translation id="1938351510777341717">Harici Komut</translation>
 <translation id="1940546824932169984">Bağlı cihazlar</translation>
+<translation id="1941410638996203291">Başlangıç zamanı: <ph name="TIME" /></translation>
 <translation id="1942128823046546853">Web sitelerindeki tüm verilerinizi okuma ve değiştirme</translation>
 <translation id="1942600407708803723">Kapak kapatıldığında gücü kapat</translation>
 <translation id="1944528062465413897">Bluetooth eşleme kodu:</translation>
@@ -1312,6 +1315,7 @@
 <translation id="2320295602967756579">Açık temayı etkinleştir</translation>
 <translation id="2322193970951063277">Üstbilgiler ve altbilgiler</translation>
 <translation id="2322318151094136999">Bir site seri bağlantı noktasına erişmek istediğinde sor (önerilir)</translation>
+<translation id="2322622365472107569">Bitiş zamanı: <ph name="TIME" /></translation>
 <translation id="2323018538045954000">Kaydedilen kablosuz ağlar</translation>
 <translation id="2325444234681128157">Şifreyi hatırla</translation>
 <translation id="2326188115274135041">Otomatik kilit açmayı etkinleştirmek için PIN'i onaylayın</translation>
@@ -1417,6 +1421,7 @@
 <translation id="2435248616906486374">Ağ bağlantısı kesildi</translation>
 <translation id="2435457462613246316">Şifreyi göster</translation>
 <translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> ana makinesinin tüm <ph name="PROTOCOL" /> bağlantılarını açmasına izin verilsin mi?</translation>
+<translation id="2439626940657133600"><ph name="WINDOW_TITLE" /> yükleniyor</translation>
 <translation id="2440604414813129000">Ka&amp;ynağı görüntüle</translation>
 <translation id="244231003699905658">Geçersiz adres. Lütfen adresi kontrol edip tekrar deneyin.</translation>
 <translation id="2442916515643169563">Metin gölgesi</translation>
@@ -1921,6 +1926,7 @@
 <translation id="2935654492420446828">Okul hesabını daha sonra ekleyin</translation>
 <translation id="2936851848721175671">Yedekleme ve geri yükleme</translation>
 <translation id="2938225289965773019"><ph name="PROTOCOL" /> bağlantılarını açma</translation>
+<translation id="2939908794993783865">Etkin olmayan diğer siteler</translation>
 <translation id="2939938020978911855">Kullanılabilir Bluetooth cihazlarını göster</translation>
 <translation id="2941112035454246133">Düşük</translation>
 <translation id="2942279350258725020">Android Mesajlar</translation>
@@ -2066,6 +2072,7 @@
 <translation id="3090589793601454425">Hareket etme</translation>
 <translation id="3090819949319990166">Harici crx dosyası <ph name="TEMP_CRX_FILE" /> hedefine kopyalanamıyor.</translation>
 <translation id="3090871774332213558">"<ph name="DEVICE_NAME" />" eşlendi</translation>
+<translation id="3093362725605442088">Chrome OS cihaz ve bileşen seri numaralarını okuyabilir.</translation>
 <translation id="3093714882666365141">Sitelerin ödeme işleyici yüklemesine izin verme</translation>
 <translation id="3094141017404513551">Bu işlem göz atma etkinliklerinizi <ph name="EXISTING_USER" /> hesabından ayıracak</translation>
 <translation id="3095871294753148861">Yer işaretleri, şifreler ve diğer tarayıcı verileri, birincil hesapla senkronize edilir.</translation>
@@ -2253,6 +2260,7 @@
 <translation id="3308852433423051161">Google Asistan yükleniyor...</translation>
 <translation id="3309330461362844500">Sertifika Profil Kimliği</translation>
 <translation id="3311445899360743395">Bu uygulamayla ilişkili veriler bu cihazdan kaldırılacak.</translation>
+<translation id="3312883087018430408">Belirli bir sitede veya Chrome'un bir bölümünde arama yapmak için ilgili kısayolu adres çubuğuna yazdıktan sonra tercih ettiğiniz klavye kısayoluna basın. Örneğin, yalnızca Google Bookmarks'ta arama yapmak için "@bookmarks" yazıp Sekme veya Boşluk tuşuna basın.</translation>
 <translation id="3313622045786997898">Sertifika İmza Değeri</translation>
 <translation id="3313950410573257029">Bağlantıyı kontrol et</translation>
 <translation id="3315158641124845231"><ph name="PRODUCT_NAME" /> uygulamasını gizle</translation>
@@ -2672,6 +2680,7 @@
 <translation id="3747077776423672805">Uygulamaları kaldırmak için Ayarlar &gt; Google Play Store &gt; Android tercihlerini yönet &gt; Uygulamalar veya Uygulama yöneticisi'ne gidin. Daha sonra, yüklemesini kaldırmak istediğiniz uygulamaya dokunun (uygulamayı bulmak için sağa veya sola doğru hızlıca kaydırmanız gerekebilir). Ardından, Kaldır veya Devre Dışı Bırak'a dokunun.</translation>
 <translation id="3747220812138541072">Yazma esnasında satır içi yazım önerileri gösterilir</translation>
 <translation id="3748706263662799310">Hata bildir</translation>
+<translation id="3750562496035670393">Chrome, şifrenizi bu cihaza kaydetti ancak bunun yerine şifrenizi Google Hesabınıza kaydedebilirsiniz. Bu durumda Google Hesabınızdaki tüm şifreler oturumunuz açıkken de kullanılabilir.</translation>
 <translation id="3752253558646317685">Parmak izini kaydetmek için çocuğunuzun parmağını kaldırıp dokundurmaya devam etmesi gerekir</translation>
 <translation id="3752582316358263300">Tamam...</translation>
 <translation id="3753033997400164841">Bir kere depolayın. Her yerde kullanın</translation>
@@ -3112,6 +3121,7 @@
 <translation id="4194570336751258953">Tıklamak için hafifçe vur'u etkinleştir</translation>
 <translation id="4195643157523330669">Yeni sekmede aç</translation>
 <translation id="4195814663415092787">Kaldığım yerden devam et</translation>
+<translation id="4198268995694216131">Ek siteler</translation>
 <translation id="4200689466366162458">Özel kelimeler</translation>
 <translation id="4200983522494130825">Y&amp;eni sekme</translation>
 <translation id="4201546031411513170">Neyin senkronize edileceğini istediğiniz zaman ayarlardan seçebilirsiniz.</translation>
@@ -3233,6 +3243,7 @@
 <translation id="4341577178275615435">Metin imleciyle göz atmayı açmak veya kapatmak için F7 kısayolunu kullanın</translation>
 <translation id="4341905082470253054">TPM durumu kontrol ediliyor...</translation>
 <translation id="434198521554309404">Hızlı. Güvenli. Zahmetsiz.</translation>
+<translation id="4343250402091037179">Belirli bir sitede veya Chrome'un bir bölümünde arama yapmak için ilgili kısayolu adres çubuğuna yazdıktan sonra tercih ettiğiniz klavye kısayoluna basın.</translation>
 <translation id="434404122609091467">Mevcut servis sağlayıcınızla</translation>
 <translation id="4345587454538109430">Yapılandır...</translation>
 <translation id="4345732373643853732">Sunucu, kullanıcı adını tanımıyor</translation>
@@ -3984,6 +3995,7 @@
 <translation id="5153234146675181447">Telefonu unutma</translation>
 <translation id="5154108062446123722"><ph name="PRINTING_DESTINATION" /> için gelişmiş ayarlar</translation>
 <translation id="5154702632169343078">Konu</translation>
+<translation id="5155327081870541046">Adres çubuğuna arama yapmak istediğiniz sitenin kısayolunu (ör. "@bookmarks") girin. Ardından, tercih ettiğiniz klavye kısayoluna basın ve arama teriminizi girin.</translation>
 <translation id="5157635116769074044">Bu sayfayı Başlangıç ekranına sabitle...</translation>
 <translation id="5159094275429367735">Crostini'yi kur</translation>
 <translation id="5159419673777902220">Ebeveyniniz uzantı izinlerini devre dışı bıraktı</translation>
@@ -4604,6 +4616,7 @@
 <translation id="5816434091619127343">Yazıcıda yapılması istenen değişiklikler yazıcıyı kullanılamaz hale getirecekti.</translation>
 <translation id="5817069030404929329">Şifreler bu cihazdan Google Hesabınıza taşınsın mı?</translation>
 <translation id="5817918615728894473">Eşle</translation>
+<translation id="581840385858998009">Duvar kağıdı, avatar, ekran koruyucu ve daha fazlasını özelleştirin</translation>
 <translation id="5821565227679781414">Kısayol Oluştur</translation>
 <translation id="5822095611691580107">Sol kulaklık pil seviyesi %<ph name="BATTERY_PERCENTAGE" />.</translation>
 <translation id="5825412242012995131">Açık (Önerilen)</translation>
@@ -4891,6 +4904,7 @@
 <translation id="6116921718742659598">Dil ve giriş ayarlarını değiştir</translation>
 <translation id="6119927814891883061">Cihazı <ph name="DEVICE_NAME" /> olarak adlandır</translation>
 <translation id="6120205520491252677">Bu sayfayı Başlangıç ekranına sabitle...</translation>
+<translation id="6121773125605585883"><ph name="WEBSITE" /> adresindeki <ph name="USERNAME" /> kullanıcı adına ait şifreyi göster.</translation>
 <translation id="6122081475643980456">İnternet bağlantınız kontrol ediliyor</translation>
 <translation id="6122093587541546701">E-posta (isteğe bağlı):</translation>
 <translation id="6122095009389448667">Bu sitenin panoyu görmesini engellemeye devam et</translation>
@@ -4967,6 +4981,7 @@
 <translation id="6208725777148613371"><ph name="WEB_DRIVE" /> - <ph name="INTERRUPT_REASON" /> koleksiyonuna kaydedilemedi</translation>
 <translation id="6209838773933913227">Bileşen güncelleme</translation>
 <translation id="6209908325007204267">Cihazınız Chrome Enterprise Yükseltme içeriyor anca kullanıcı adınız kurumsal hesapla ilişkilendirilmemiş. Lütfen ikinci bir cihazda g.co/ChromeEnterpriseAccount adresini ziyaret ederek kurumsal bir hesap oluşturun.</translation>
+<translation id="6210282067670792090">Adres çubuğunda arama motorlarına ve site aramaya yönelik kısayolların olduğu bu klavye kısayolunu kullanın</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{Tümünü &amp;Yeni Sekme Grubunda Aç}=1{&amp;Yeni Sekme Grubunda Aç}other{Tümünü ({COUNT}) &amp;Yeni Sekme Grubunda Aç}}</translation>
 <translation id="6212039847102026977">Gelişmiş ağ özelliklerini göster</translation>
 <translation id="6212168817037875041">Ekranı kapat</translation>
@@ -5450,6 +5465,7 @@
 <translation id="6709357832553498500"><ph name="EXTENSIONNAME" /> uzantısını kullanarak bağlan</translation>
 <translation id="6710213216561001401">Önceki</translation>
 <translation id="6711146141291425900">İndirilenler için <ph name="WEB_DRIVE" /> hesabını bağlayın</translation>
+<translation id="6712943853047024245"><ph name="WEBSITE" /> için bu kullanıcı adıyla zaten bir şifre kaydettiniz</translation>
 <translation id="6713233729292711163">Çalışma Profili ekle</translation>
 <translation id="6715803357256707211">Linux uygulamanızın yüklenmesi sırasında bir hata oluştu. Ayrıntılar için bildirimi tıklayın.</translation>
 <translation id="671619610707606484">Bu işlem, siteler tarafından depolanan <ph name="TOTAL_USAGE" /> veriyi temizleyecek</translation>
@@ -6075,6 +6091,7 @@
 <translation id="7385854874724088939">Yazdırmaya çalışırken bir sorun oluştu. Lütfen yazıcınızı denetleyin ve yeniden deneyin.</translation>
 <translation id="7385896526023870365">Bu uzantının ek site erişimi yok.</translation>
 <translation id="7387273928653486359">Kabul Edilebilir Düzeyde</translation>
+<translation id="7387951778417998929">Varsayılan dışında bir arama motoru kullanmak için kısayolunu adres çubuğuna yazdıktan sonra tercih ettiğiniz klavye kısayoluna basın. Varsayılan arama motorunuzu da buradan değiştirebilirsiniz.</translation>
 <translation id="7388209873137778229">Yalnızca desteklenen cihazlar gösterilir.</translation>
 <translation id="7392118418926456391">Virüs taraması başarısız oldu</translation>
 <translation id="7392915005464253525">Kapatılan p&amp;encereyi yeniden aç</translation>
@@ -6252,6 +6269,7 @@
 <translation id="7559719679815339381">Lütfen bekleyin....Kiosk uygulaması güncelleniyor. USB çubuğunu çıkarmayın.</translation>
 <translation id="7560756177962144929"><ph name="DEVICE_TYPE" /> cihazınızı senkronize edin</translation>
 <translation id="7561196759112975576">Her zaman</translation>
+<translation id="7562099761826673163">Cihazınızı kişiselleştirme</translation>
 <translation id="756445078718366910">Tarayıcı Penceresini Aç</translation>
 <translation id="7564847347806291057">İşlemi bitir</translation>
 <translation id="756503097602602175">Oturum açılmış Google Hesaplarınızı <ph name="LINK_BEGIN" />Ayarlar<ph name="LINK_END" />'dan yönetebilirsiniz. Web sitelerine ve uygulamalara verdiğiniz izinler, tüm hesaplar için geçerli olabilir. Sitelerin veya uygulamaların hesap bilgilerinize erişmesini istemiyorsanız <ph name="DEVICE_TYPE" /> cihazınızda misafir olarak oturum açabilir ya da internette gezinmek için <ph name="LINK_2_BEGIN" />Gizli pencere<ph name="LINK_2_END" /> kullanabilirsiniz.</translation>
@@ -6568,6 +6586,7 @@
 <translation id="78526636422538552">Başka Google Hesaplarının eklenmesi devre dışı bırakıldı</translation>
 <translation id="7853747251428735">&amp;Diğer Araçlar</translation>
 <translation id="7855678561139483478">Sekmeyi yeni pencereye taşı</translation>
+<translation id="7856654138655787862">Chrome OS teşhis testlerini çalıştırır.</translation>
 <translation id="7857093393627376423">Metin önerileri</translation>
 <translation id="7857949311770343000">Bu, beklediğiniz yeni sekme sayfası mı?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" /> (Windows)</translation>
@@ -7216,6 +7235,7 @@
 <translation id="8551588720239073785">Tarih ve zaman ayarları</translation>
 <translation id="8553342806078037065">Diğer kişileri yönet</translation>
 <translation id="8554899698005018844">Dil yok</translation>
+<translation id="855604308879080518">Android uygulamalarının bu Chromebook'taki USB cihazlara erişmesine izin verin. Her USB cihaz taktığınızda izin istenir. Ayrı Android uygulamaları da ek izinler isteyecektir.</translation>
 <translation id="8557022314818157177">Parmak iziniz alınana kadar güvenlik anahtarınıza dokunmaya devam edin</translation>
 <translation id="8557180006508471423">Mac'inizdeki Konum Hizmetlerinde "Google Chrome"u açın</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{Tümünü &amp;Yeni Pencerede Aç}=1{&amp;Yeni Pencerede Aç}other{Tümünü ({COUNT}) &amp;Yeni Pencerede Aç}}</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb
index 73bbcd94..3600f1c 100644
--- a/chrome/app/resources/generated_resources_zh-HK.xtb
+++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -162,6 +162,7 @@
 <translation id="1152346050262092795">請再次輸入密碼以驗證帳戶。</translation>
 <translation id="1153356358378277386">已配對的裝置</translation>
 <translation id="1153636665119721804">Google 進階保護計劃</translation>
+<translation id="1155545602507378023">否,僅限這部裝置</translation>
 <translation id="1155816283571436363">正在連接您的手機</translation>
 <translation id="1158080958325422608">設為大寫</translation>
 <translation id="1158238185437008462">查看回憶</translation>
@@ -396,6 +397,7 @@
 <translation id="1410197035576869800">應用程式圖示</translation>
 <translation id="1410616244180625362">繼續允許 <ph name="HOST" /> 存取您的相機</translation>
 <translation id="1410806973194718079">無法檢查政策</translation>
+<translation id="1412681350727866021">其他擴充功能</translation>
 <translation id="1414315029670184034">不允許網站使用攝錄機</translation>
 <translation id="1414648216875402825">您即將更新為不穩定的 <ph name="PRODUCT_NAME" /> 版本,其中含有仍在開發中的功能。系統可能會發生當機情況和無法預期的錯誤,執行時請特別注意。</translation>
 <translation id="1415708812149920388">已禁止讀取剪貼簿</translation>
@@ -949,6 +951,7 @@
 <translation id="1937774647013465102">此裝置使用 <ph name="ARCHITECTURE_DEVICE" />,因此無法匯入容器架構類型 <ph name="ARCHITECTURE_CONTAINER" />。您可嘗試將此容器還原至其他裝置,或透過 Files 應用程式存取此容器圖片內的檔案。</translation>
 <translation id="1938351510777341717">外置 Command 鍵</translation>
 <translation id="1940546824932169984">已連接的裝置</translation>
+<translation id="1941410638996203291">開始時間 <ph name="TIME" /></translation>
 <translation id="1942128823046546853">讀取及變更您在所有網站上的所有資料</translation>
 <translation id="1942600407708803723">蓋上機蓋時關機</translation>
 <translation id="1944528062465413897">藍牙配對碼:</translation>
@@ -1327,6 +1330,7 @@
 <translation id="2320295602967756579">啟用淺色主題背景</translation>
 <translation id="2322193970951063277">頁首及頁尾</translation>
 <translation id="2322318151094136999">在網站要存取序列連接埠時詢問您 (建議)</translation>
+<translation id="2322622365472107569">結束時間 <ph name="TIME" /></translation>
 <translation id="2323018538045954000">已儲存的 Wi-Fi 網絡</translation>
 <translation id="2325444234681128157">記住密碼</translation>
 <translation id="2326188115274135041">確認 PIN 以開啟自動解鎖</translation>
@@ -1432,6 +1436,7 @@
 <translation id="2435248616906486374">網絡已中斷連線</translation>
 <translation id="2435457462613246316">顯示密碼</translation>
 <translation id="2436186046335138073">要允許 <ph name="HANDLER_HOSTNAME" /> 開啟所有 <ph name="PROTOCOL" /> 連結嗎?</translation>
+<translation id="2439626940657133600">正在載入<ph name="WINDOW_TITLE" /></translation>
 <translation id="2440604414813129000">檢視原始碼(&amp;O)</translation>
 <translation id="244231003699905658">地址無效。請檢查地址,然後再試一次。</translation>
 <translation id="2442916515643169563">文字陰影</translation>
@@ -1937,6 +1942,7 @@
 <translation id="2935654492420446828">稍後新增學校帳戶</translation>
 <translation id="2936851848721175671">備份與還原</translation>
 <translation id="2938225289965773019">開放<ph name="PROTOCOL" />連結</translation>
+<translation id="2939908794993783865">其他無效網站</translation>
 <translation id="2939938020978911855">顯示可用的藍牙裝置</translation>
 <translation id="2941112035454246133">低</translation>
 <translation id="2942279350258725020">Android 訊息</translation>
@@ -2082,6 +2088,7 @@
 <translation id="3090589793601454425">不要移動</translation>
 <translation id="3090819949319990166">無法將外部 crx 檔案複製到 <ph name="TEMP_CRX_FILE" />。</translation>
 <translation id="3090871774332213558">已配對「<ph name="DEVICE_NAME" />」</translation>
+<translation id="3093362725605442088">讀取 Chrome OS 裝置序號和元件序號。</translation>
 <translation id="3093714882666365141">不允許網站安裝付款處理常式</translation>
 <translation id="3094141017404513551">這樣做會將您的瀏覽資料與 <ph name="EXISTING_USER" /> 分隔</translation>
 <translation id="3095871294753148861">書籤、密碼和其他瀏覽器資料已與主要帳戶同步。</translation>
@@ -2269,6 +2276,7 @@
 <translation id="3308852433423051161">正在載入「Google 助理」…</translation>
 <translation id="3309330461362844500">憑證設定檔 ID</translation>
 <translation id="3311445899360743395">系統可能會從裝置中移除與此應用程式相關的資料。</translation>
+<translation id="3312883087018430408">如要搜尋特定網站或 Chrome,請在網址列輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。舉例來說,如果只要搜尋書籤,請輸入「@bookmarks」,然後按下 Tab 鍵或空白鍵。</translation>
 <translation id="3313622045786997898">憑證簽署值</translation>
 <translation id="3313950410573257029">檢查連線狀態</translation>
 <translation id="3315158641124845231">隱藏 <ph name="PRODUCT_NAME" /></translation>
@@ -2688,6 +2696,7 @@
 <translation id="3747077776423672805">如要移除應用程式,請前往「設定」&gt;「Google Play 商店」&gt;「管理 Android 偏好設定」&gt;「應用程式」或「應用程式管理員」,然後輕按您想解除安裝的應用程式 (您可能需要向右或向左滑動,才能找到應用程式),再輕按 [解除安裝] 或 [停用]。</translation>
 <translation id="3747220812138541072">在輸入時顯示內嵌輸入內容建議</translation>
 <translation id="3748706263662799310">回報錯誤</translation>
+<translation id="3750562496035670393">Chrome 已將你的密碼儲存至這個裝置,但你可以改為儲存至 Google 帳戶。如此一來,當你登入帳戶時,也可以使用 Google 帳戶中的密碼。</translation>
 <translation id="3752253558646317685">讓子女重覆按壓手指,以便儲存指紋</translation>
 <translation id="3752582316358263300">確定…</translation>
 <translation id="3753033997400164841">只需儲存一次,即可在所有裝置上使用</translation>
@@ -3128,6 +3137,7 @@
 <translation id="4194570336751258953">啟用輕按點擊功能</translation>
 <translation id="4195643157523330669">在新分頁中開啟</translation>
 <translation id="4195814663415092787">開啟上次瀏覽的內容</translation>
+<translation id="4198268995694216131">其他網站</translation>
 <translation id="4200689466366162458">自訂字詞</translation>
 <translation id="4200983522494130825">新分頁(&amp;T)</translation>
 <translation id="4201546031411513170">您隨時可在設定中選擇要同步的資料。</translation>
@@ -3249,6 +3259,7 @@
 <translation id="4341577178275615435">如要開啟或關閉「鍵盤瀏覽」功能,請使用快速鍵 F7</translation>
 <translation id="4341905082470253054">正在檢查 TPM 狀態…</translation>
 <translation id="434198521554309404">快捷。安全。輕鬆便利。</translation>
+<translation id="4343250402091037179">如要搜尋特定網站或 Chrome,請在網址列輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。</translation>
 <translation id="434404122609091467">使用目前的服務供應商</translation>
 <translation id="4345587454538109430">設定…</translation>
 <translation id="4345732373643853732">伺服器無法辨識使用者名稱</translation>
@@ -4002,6 +4013,7 @@
 <translation id="5153234146675181447">刪除手機</translation>
 <translation id="5154108062446123722">「<ph name="PRINTING_DESTINATION" />」進階設定</translation>
 <translation id="5154702632169343078">主旨</translation>
+<translation id="5155327081870541046">在網址列中針對想搜尋的網站輸入快捷字詞 (例如「@bookmarks」),然後按下你慣用的鍵盤快速鍵並輸入搜尋字詞。</translation>
 <translation id="5157635116769074044">將網頁固定到 [開始] 螢幕…</translation>
 <translation id="5159094275429367735">設定 Crostini</translation>
 <translation id="5159419673777902220">您的家長已停用擴充程式權限</translation>
@@ -4621,6 +4633,7 @@
 <translation id="5816434091619127343">要求的打印機變更會讓此打印機無法使用。</translation>
 <translation id="5817069030404929329">要將密碼從此裝置移至傯的 Google 帳戶嗎?</translation>
 <translation id="5817918615728894473">配對</translation>
+<translation id="581840385858998009">自訂桌布、顯示圖片、螢幕保護程式和更多項目</translation>
 <translation id="5821565227679781414">建立捷徑</translation>
 <translation id="5822095611691580107">左邊耳機嘅電量係 <ph name="BATTERY_PERCENTAGE" />%。</translation>
 <translation id="5825412242012995131">啟用 (建議設定)</translation>
@@ -4908,6 +4921,7 @@
 <translation id="6116921718742659598">變更語言和輸入設定</translation>
 <translation id="6119927814891883061">將裝置個名改做 <ph name="DEVICE_NAME" /></translation>
 <translation id="6120205520491252677">將這個網頁固定到 [開始] 螢幕…</translation>
+<translation id="6121773125605585883">檢視使用者名稱「<ph name="USERNAME" />」在「<ph name="WEBSITE" />」的密碼</translation>
 <translation id="6122081475643980456">您的互聯網連線目前受到控制</translation>
 <translation id="6122093587541546701">電郵 (選擇性):</translation>
 <translation id="6122095009389448667">繼續禁止此網站查看剪貼簿</translation>
@@ -4984,6 +4998,7 @@
 <translation id="6208725777148613371">無法儲存至「<ph name="WEB_DRIVE" />」- <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">正在更新組件</translation>
 <translation id="6209908325007204267">您的裝置包含一項 Chrome Enterprise 升級,但您的使用者名稱尚未連結企業賬戶。請透過另一部裝置前往 g.co/ChromeEnterpriseAccount 建立企業帳戶。</translation>
+<translation id="6210282067670792090">請在網址列中輸入相應的鍵盤快速鍵和快捷字詞,以使用搜尋引擎和網站搜尋</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{在新分頁群組中開啟所有網址(&amp;N)}=1{在新分頁群組中開啟所有網址(&amp;N)}other{在新分頁群組中開啟所有 ({COUNT} 個) 網址(&amp;N)}}</translation>
 <translation id="6212039847102026977">顯示進階網絡屬性</translation>
 <translation id="6212168817037875041">關閉螢幕</translation>
@@ -5467,6 +5482,7 @@
 <translation id="6709357832553498500">使用「<ph name="EXTENSIONNAME" />」連線</translation>
 <translation id="6710213216561001401">上一個</translation>
 <translation id="6711146141291425900">連結「<ph name="WEB_DRIVE" />」帳戶即可重新轉送下載檔案</translation>
+<translation id="6712943853047024245">你已儲存過這個使用者名稱在「<ph name="WEBSITE" />」的密碼</translation>
 <translation id="6713233729292711163">新增工作設定檔</translation>
 <translation id="6715803357256707211">安裝 Linux 應用程式時發生錯誤。按一下通知即可瞭解詳情。</translation>
 <translation id="671619610707606484">此操作會清除網站儲存的資料,共 <ph name="TOTAL_USAGE" /></translation>
@@ -6092,6 +6108,7 @@
 <translation id="7385854874724088939">準備列印時出現錯誤,請檢查您的打印機,然後再試一次。</translation>
 <translation id="7385896526023870365">此擴充程式沒有其他網站存取權。</translation>
 <translation id="7387273928653486359">可以接受</translation>
+<translation id="7387951778417998929">如要使用非系統預設的搜尋引擎,請在網址列中輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。你也可以在這裡變更你的預設搜尋引擎。</translation>
 <translation id="7388209873137778229">只顯示支援的裝置。</translation>
 <translation id="7392118418926456391">病毒掃描失敗</translation>
 <translation id="7392915005464253525">重新開啟已關閉視窗(&amp;E)</translation>
@@ -6269,6 +6286,7 @@
 <translation id="7559719679815339381">請稍候…系統正在更新 Kiosk 應用程式。請勿移除 USB 記憶體。</translation>
 <translation id="7560756177962144929">同步處理 <ph name="DEVICE_TYPE" /></translation>
 <translation id="7561196759112975576">永遠使用</translation>
+<translation id="7562099761826673163">打造個人化的裝置</translation>
 <translation id="756445078718366910">開啟瀏覽器視窗</translation>
 <translation id="7564847347806291057">結束處理程序</translation>
 <translation id="756503097602602175">您可透過<ph name="LINK_BEGIN" />設定<ph name="LINK_END" />管理已登入的 Google 帳戶。您向網站和應用程式授予的權限,可能會套用到所有帳戶。如果您不想網站和應用程式存取您的帳戶資料,請以訪客身分登入您的 <ph name="DEVICE_TYPE" />,或透過<ph name="LINK_2_BEGIN" />無痕式視窗<ph name="LINK_2_END" />瀏覽網頁。</translation>
@@ -6586,6 +6604,7 @@
 <translation id="78526636422538552">新增更多 Google 帳戶功能已停用</translation>
 <translation id="7853747251428735">更多工具(&amp;L)</translation>
 <translation id="7855678561139483478">把分頁移至新視窗</translation>
+<translation id="7856654138655787862">執行 Chrome OS 診斷測試。</translation>
 <translation id="7857093393627376423">文字建議</translation>
 <translation id="7857949311770343000">這是您想要的新分頁嗎?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" /> (Windows)</translation>
@@ -7235,6 +7254,7 @@
 <translation id="8551588720239073785">日期和時間設定</translation>
 <translation id="8553342806078037065">管理其他使用者</translation>
 <translation id="8554899698005018844">未選取語言</translation>
+<translation id="855604308879080518">允許 Android 應用程式在這台 Chromebook 上存取 USB 裝置。每次你插入 USB 裝置時,系統皆會要求權限。個別 Android 應用程式會要求額外權限。</translation>
 <translation id="8557022314818157177">請持續輕觸安全密鑰,直至指紋擷取完成</translation>
 <translation id="8557180006508471423">請在 Mac 上的「定位服務」中開啟「Google Chrome」</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{在新視窗中開啟所有書籤(&amp;N)}=1{在新視窗中開啟書籤(&amp;N)}other{在新視窗中開啟全部 {COUNT} 個書籤(&amp;N)}}</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index e89ad918..b6c61986 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -160,6 +160,7 @@
 <translation id="1152346050262092795">請再次輸入密碼以驗證帳戶。</translation>
 <translation id="1153356358378277386">配對裝置</translation>
 <translation id="1153636665119721804">Google 進階保護計畫</translation>
+<translation id="1155545602507378023">否,僅限這部裝置</translation>
 <translation id="1155816283571436363">正在連線到你的手機</translation>
 <translation id="1158080958325422608">使用大寫字母</translation>
 <translation id="1158238185437008462">查看回憶集錦</translation>
@@ -394,6 +395,7 @@
 <translation id="1410197035576869800">應用程式圖示</translation>
 <translation id="1410616244180625362">繼續允許 <ph name="HOST" /> 存取你的攝影機</translation>
 <translation id="1410806973194718079">無法檢查政策</translation>
+<translation id="1412681350727866021">其他擴充功能</translation>
 <translation id="1414315029670184034">禁止網站使用攝影機</translation>
 <translation id="1414648216875402825">你即將更新為不穩定的 <ph name="PRODUCT_NAME" />版本,其中含有仍在開發中的功能。系統可能會發生當機情況和無法預期的錯誤,執行時請特別注意。</translation>
 <translation id="1415708812149920388">已禁止讀取剪貼簿</translation>
@@ -938,6 +940,7 @@
 <translation id="1937774647013465102">這個裝置使用 <ph name="ARCHITECTURE_DEVICE" />,因此無法匯入容器架構類型 <ph name="ARCHITECTURE_CONTAINER" />。你可以嘗試將這個容器還原至其他裝置,或透過 Files 應用程式開啟這個容器映像檔,以存取其中的檔案。</translation>
 <translation id="1938351510777341717">外部 Command 鍵</translation>
 <translation id="1940546824932169984">已連結的裝置</translation>
+<translation id="1941410638996203291">開始時間 <ph name="TIME" /></translation>
 <translation id="1942128823046546853">讀取及變更你在所有網站上的所有資料</translation>
 <translation id="1942600407708803723">蓋上機蓋時關機</translation>
 <translation id="1944528062465413897">藍牙配對碼:</translation>
@@ -1313,6 +1316,7 @@
 <translation id="2320295602967756579">啟用淺色主題</translation>
 <translation id="2322193970951063277">頁首及頁尾</translation>
 <translation id="2322318151094136999">當網站要存取序列埠時,必須先詢問你 (建議)</translation>
+<translation id="2322622365472107569">結束時間 <ph name="TIME" /></translation>
 <translation id="2323018538045954000">已儲存的 Wi-Fi 網路</translation>
 <translation id="2325444234681128157">記住密碼</translation>
 <translation id="2326188115274135041">確認 PIN 碼以開啟自動解鎖功能</translation>
@@ -1418,6 +1422,7 @@
 <translation id="2435248616906486374">網路已中斷連線</translation>
 <translation id="2435457462613246316">顯示密碼</translation>
 <translation id="2436186046335138073">要允許 <ph name="HANDLER_HOSTNAME" /> 開啟所有<ph name="PROTOCOL" />連結嗎?</translation>
+<translation id="2439626940657133600">正在載入<ph name="WINDOW_TITLE" /></translation>
 <translation id="2440604414813129000">檢視原始碼(&amp;O)</translation>
 <translation id="244231003699905658">位址無效。請檢查位址是否正確,然後再試一次。</translation>
 <translation id="2442916515643169563">文字陰影</translation>
@@ -1923,6 +1928,7 @@
 <translation id="2935654492420446828">稍後再新增學校帳戶</translation>
 <translation id="2936851848721175671">備份與還原</translation>
 <translation id="2938225289965773019">開啟<ph name="PROTOCOL" />連結</translation>
+<translation id="2939908794993783865">其他無效網站</translation>
 <translation id="2939938020978911855">顯示可用的藍牙裝置</translation>
 <translation id="2941112035454246133">低</translation>
 <translation id="2942279350258725020">Android 訊息</translation>
@@ -2068,6 +2074,7 @@
 <translation id="3090589793601454425">不要移動</translation>
 <translation id="3090819949319990166">無法將外部 crx 檔案複製到 <ph name="TEMP_CRX_FILE" />。</translation>
 <translation id="3090871774332213558">「<ph name="DEVICE_NAME" />」已配對</translation>
+<translation id="3093362725605442088">讀取 Chrome OS 裝置序號和元件序號。</translation>
 <translation id="3093714882666365141">禁止網站安裝付款處理常式</translation>
 <translation id="3094141017404513551">這會將你和 <ph name="EXISTING_USER" /> 的瀏覽資料分開保存</translation>
 <translation id="3095871294753148861">書籤、密碼和其他瀏覽器資料已與主要帳戶同步。</translation>
@@ -2255,6 +2262,7 @@
 <translation id="3308852433423051161">正在載入 Google 助理…</translation>
 <translation id="3309330461362844500">憑證設定檔 ID</translation>
 <translation id="3311445899360743395">系統可能會從這部裝置中移除與這個應用程式相關聯的資料。</translation>
+<translation id="3312883087018430408">如要搜尋特定網站或 Chrome,請在網址列輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。舉例來說,如果只要搜尋書籤,請輸入「@bookmarks」,然後按下 Tab 鍵或空白鍵。</translation>
 <translation id="3313622045786997898">憑證簽署值</translation>
 <translation id="3313950410573257029">檢查連線狀態</translation>
 <translation id="3315158641124845231">隱藏 <ph name="PRODUCT_NAME" /></translation>
@@ -2674,6 +2682,7 @@
 <translation id="3747077776423672805">如要移除應用程式,請依序前往 [設定] &gt; [Google Play 商店] &gt; [管理 Android 偏好設定] &gt; [應用程式] 或 [應用程式管理員],然後輕觸你要解除安裝的應用程式 (你可能需要向左或向右滑動才能找出所需應用程式)。接著,輕觸 [解除安裝] 或 [停用]。</translation>
 <translation id="3747220812138541072">在你輸入文字的同時,系統會顯示內嵌的書寫建議</translation>
 <translation id="3748706263662799310">回報錯誤</translation>
+<translation id="3750562496035670393">Chrome 已將你的密碼儲存至這個裝置,但你可以改為儲存至 Google 帳戶。如此一來,當你登入帳戶時,也可以使用 Google 帳戶中的密碼。</translation>
 <translation id="3752253558646317685">讓孩子不斷抬起再放下手指,藉此儲存指紋</translation>
 <translation id="3752582316358263300">確定...</translation>
 <translation id="3753033997400164841">只要儲存一次,即可在所有裝置上使用。</translation>
@@ -3113,6 +3122,7 @@
 <translation id="4194570336751258953">啟用點按功能</translation>
 <translation id="4195643157523330669">在新分頁中開啟</translation>
 <translation id="4195814663415092787">繼續瀏覽上次開啟的網頁</translation>
+<translation id="4198268995694216131">其他網站</translation>
 <translation id="4200689466366162458">自訂字詞</translation>
 <translation id="4200983522494130825">新增分頁(&amp;T)</translation>
 <translation id="4201546031411513170">你隨時可以在設定中選擇要同步處理的資料。</translation>
@@ -3234,6 +3244,7 @@
 <translation id="4341577178275615435">如要開啟或關閉鍵盤瀏覽功能,請使用快速鍵 F7</translation>
 <translation id="4341905082470253054">正在檢查 TPM 狀態...</translation>
 <translation id="434198521554309404">快速、安全又便利。</translation>
+<translation id="4343250402091037179">如要搜尋特定網站或 Chrome,請在網址列輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。</translation>
 <translation id="434404122609091467">使用目前的服務供應商</translation>
 <translation id="4345587454538109430">設定...</translation>
 <translation id="4345732373643853732">伺服器無法辨識使用者名稱</translation>
@@ -3985,6 +3996,7 @@
 <translation id="5153234146675181447">移除手機</translation>
 <translation id="5154108062446123722">「<ph name="PRINTING_DESTINATION" />」進階設定</translation>
 <translation id="5154702632169343078">主旨</translation>
+<translation id="5155327081870541046">在網址列中針對想搜尋的網站輸入快捷字詞 (例如「@bookmarks」),然後按下你慣用的鍵盤快速鍵並輸入搜尋字詞。</translation>
 <translation id="5157635116769074044">將網頁固定到開始畫面...</translation>
 <translation id="5159094275429367735">設定 Crostini</translation>
 <translation id="5159419673777902220">貴家長已停用擴充功能權限</translation>
@@ -4604,6 +4616,7 @@
 <translation id="5816434091619127343">要求的印表機變更會讓這部印表機無法使用。</translation>
 <translation id="5817069030404929329">要將密碼從這部裝置移至你的 Google 帳戶嗎?</translation>
 <translation id="5817918615728894473">配對</translation>
+<translation id="581840385858998009">自訂桌布、顯示圖片、螢幕保護程式和更多項目</translation>
 <translation id="5821565227679781414">建立捷徑</translation>
 <translation id="5822095611691580107">左側無線耳機的電池電量為 <ph name="BATTERY_PERCENTAGE" />%。</translation>
 <translation id="5825412242012995131">啟用 (建議設定)</translation>
@@ -4891,6 +4904,7 @@
 <translation id="6116921718742659598">變更語言和輸入設定</translation>
 <translation id="6119927814891883061">將裝置命名為「<ph name="DEVICE_NAME" />」</translation>
 <translation id="6120205520491252677">將這個網頁固定到開始畫面...</translation>
+<translation id="6121773125605585883">檢視使用者名稱「<ph name="USERNAME" />」在「<ph name="WEBSITE" />」的密碼</translation>
 <translation id="6122081475643980456">你的網際網路連線目前受到控制</translation>
 <translation id="6122093587541546701">電子郵件地址 (選填):</translation>
 <translation id="6122095009389448667">繼續禁止這個網站讀取剪貼簿</translation>
@@ -4967,6 +4981,7 @@
 <translation id="6208725777148613371">無法儲存至「<ph name="WEB_DRIVE" />」- <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">正在更新元件</translation>
 <translation id="6209908325007204267">你的裝置包含 Chrome Enterprise 升級版,但你的使用者名稱未申請企業版帳戶。請透過其他裝置前往 g.co/ChromeEnterpriseAccount 建立企業版帳戶。</translation>
+<translation id="6210282067670792090">請在網址列中輸入相應的鍵盤快速鍵和快捷字詞,以使用搜尋引擎和網站搜尋</translation>
 <translation id="621172521139737651">{COUNT,plural, =0{在新分頁群組中開啟所有網址(&amp;N)}=1{在新分頁群組中開啟網址(&amp;N)}other{在新分頁群組中開啟所有 ({COUNT} 個) 網址(&amp;N)}}</translation>
 <translation id="6212039847102026977">顯示進階網路屬性</translation>
 <translation id="6212168817037875041">關閉螢幕</translation>
@@ -5450,6 +5465,7 @@
 <translation id="6709357832553498500">使用「<ph name="EXTENSIONNAME" />」連線</translation>
 <translation id="6710213216561001401">返回</translation>
 <translation id="6711146141291425900">連結「<ph name="WEB_DRIVE" />」帳戶即可重新轉送下載內容</translation>
+<translation id="6712943853047024245">你已儲存過這個使用者名稱在「<ph name="WEBSITE" />」的密碼</translation>
 <translation id="6713233729292711163">新增工作資料夾</translation>
 <translation id="6715803357256707211">安裝 Linux 應用程式的過程中發生錯誤。如需詳細資料,請按一下通知。</translation>
 <translation id="671619610707606484">這會清除網站儲存的資料,共 <ph name="TOTAL_USAGE" /></translation>
@@ -6075,6 +6091,7 @@
 <translation id="7385854874724088939">準備列印時出現錯誤,請檢查你的印表機,然後再試一次。</translation>
 <translation id="7385896526023870365">這個擴充功能沒有其他網站存取權。</translation>
 <translation id="7387273928653486359">可以接受</translation>
+<translation id="7387951778417998929">如要使用非系統預設的搜尋引擎,請在網址列中輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。你也可以在這裡變更你的預設搜尋引擎。</translation>
 <translation id="7388209873137778229">只顯示支援的裝置。</translation>
 <translation id="7392118418926456391">病毒掃描失敗</translation>
 <translation id="7392915005464253525">重新開啟已關閉視窗(&amp;E)</translation>
@@ -6252,6 +6269,7 @@
 <translation id="7559719679815339381">請稍候.... Kiosk 應用程式正在進行更新,請勿移除 USB 隨身碟。</translation>
 <translation id="7560756177962144929">同步處理 <ph name="DEVICE_TYPE" /></translation>
 <translation id="7561196759112975576">一律使用</translation>
+<translation id="7562099761826673163">打造個人化的裝置</translation>
 <translation id="756445078718366910">開啟瀏覽器視窗</translation>
 <translation id="7564847347806291057">結束處理程序</translation>
 <translation id="756503097602602175">你可以透過<ph name="LINK_BEGIN" />設定<ph name="LINK_END" />管理已登入的 Google 帳戶。你授予網站和應用程式的權限可能適用於所有帳戶。如果不想讓網站和應用程式存取你的帳戶資訊,請以訪客身分登入 <ph name="DEVICE_TYPE" />,或透過<ph name="LINK_2_BEGIN" />無痕式視窗<ph name="LINK_2_END" />瀏覽網頁。</translation>
@@ -6569,6 +6587,7 @@
 <translation id="78526636422538552">新增 Google 帳戶的功能已停用</translation>
 <translation id="7853747251428735">更多工具(&amp;L)</translation>
 <translation id="7855678561139483478">將分頁移到新視窗</translation>
+<translation id="7856654138655787862">執行 Chrome OS 診斷測試。</translation>
 <translation id="7857093393627376423">文字建議</translation>
 <translation id="7857949311770343000">這是你想要的新分頁嗎?</translation>
 <translation id="7858328180167661092"><ph name="APP_NAME" /> (Windows)</translation>
@@ -7218,6 +7237,7 @@
 <translation id="8551588720239073785">日期和時間設定</translation>
 <translation id="8553342806078037065">管理其他使用者</translation>
 <translation id="8554899698005018844">未指定語言</translation>
+<translation id="855604308879080518">允許 Android 應用程式在這台 Chromebook 上存取 USB 裝置。每次你插入 USB 裝置時,系統皆會要求權限。個別 Android 應用程式會要求額外權限。</translation>
 <translation id="8557022314818157177">請持續輕觸安全金鑰,直到指紋擷取完成</translation>
 <translation id="8557180006508471423">請在 Mac 的「定位服務」中開啟「Google Chrome」</translation>
 <translation id="8560327176991673955">{COUNT,plural, =0{在新視窗中開啟所有網址(&amp;N)}=1{在新視窗中開啟(&amp;N)}other{在新視窗中開啟所有 ({COUNT} 個) 網址(&amp;N)}}</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 60c2a4e0..10af269 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3415,8 +3415,6 @@
       "//chrome/browser/ui/webui/feed_internals:mojo_bindings",
       "//chrome/browser/video_tutorials/internal",
       "//chrome/browser/video_tutorials/internal:jni_headers",
-      "//chrome/browser/webapps/android:android",
-      "//chrome/browser/webapps/android:jni_headers",
       "//chrome/common:non_code_constants",
       "//chrome/services/media_gallery_util/public/cpp",
       "//components/assist_ranker/proto",
@@ -3523,14 +3521,7 @@
       "//url:origin_android",
     ]
 
-    allow_circular_includes_from += [
-      # chrome/browser depends on webapps, but that module needs
-      # app_banner_manager_android.h from chrome. However, the .h file will soon
-      # be moved to a component (when WebLayer starts relying on it). Allow the
-      # circular dependency until then.
-      "//chrome/browser/webapps/android:android",
-      "//chrome/browser/share",
-    ]
+    allow_circular_includes_from += [ "//chrome/browser/share" ]
 
     deps -= [ "//components/storage_monitor" ]
 
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 5819ff6..2b94236 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -91,7 +91,7 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jweb_contents,
     jboolean shown) {
-  RuntimeManagerImpl* runtime_manager = RuntimeManagerImpl::GetForWebContents(
+  RuntimeManager* runtime_manager = RuntimeManager::GetForWebContents(
       content::WebContents::FromJavaWebContents(jweb_contents));
   if (runtime_manager)
     runtime_manager->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
@@ -659,7 +659,7 @@
   controller_ = std::make_unique<Controller>(
       GetWebContents(), /* client= */ this,
       base::DefaultTickClock::GetInstance(),
-      RuntimeManagerImpl::GetForWebContents(GetWebContents())->GetWeakPtr(),
+      RuntimeManager::GetForWebContents(GetWebContents())->GetWeakPtr(),
       std::move(service), std::move(tts_controller), ukm::UkmRecorder::Get(),
       AnnotateDomModelServiceFactory::GetInstance()->GetForBrowserContext(
           GetWebContents()->GetBrowserContext()));
diff --git a/chrome/browser/ash/android_sms/android_sms_pairing_state_tracker_impl.cc b/chrome/browser/ash/android_sms/android_sms_pairing_state_tracker_impl.cc
index 1a256561..43049071 100644
--- a/chrome/browser/ash/android_sms/android_sms_pairing_state_tracker_impl.cc
+++ b/chrome/browser/ash/android_sms/android_sms_pairing_state_tracker_impl.cc
@@ -49,7 +49,7 @@
 void AndroidSmsPairingStateTrackerImpl::AttemptFetchMessagesPairingState() {
   GetCookieManager()->GetCookieList(
       GetPairingUrl(), net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain::Todo(),
+      net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(&AndroidSmsPairingStateTrackerImpl::OnCookiesRetrieved,
                      base::Unretained(this)));
 }
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.cc b/chrome/browser/ash/crosapi/browser_data_migrator.cc
index e107f93..cd4b768 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.cc
@@ -243,14 +243,32 @@
   // If `MigrationStep` is not `kCheckStep`, `MaybeRestartToMigrate()` has
   // already moved on to later steps. Namely either in the middle of migration
   // or migration has already run.
-  if (GetMigrationStep(g_browser_process->local_state()) !=
-      MigrationStep::kCheckStep) {
-    // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove
-    // this
-    // log message.
-    LOG(WARNING) << "Migration step is "
-                 << static_cast<int>(
-                        GetMigrationStep(g_browser_process->local_state()));
+  MigrationStep step = GetMigrationStep(g_browser_process->local_state());
+  if (step != MigrationStep::kCheckStep) {
+    switch (step) {
+      case MigrationStep::kRestartCalled:
+        LOG(ERROR) << "RestartToMigrate() was called but Migrate() was not. "
+                      "This indicates that eitehr "
+                      "SessionManagerClient::RequestBrowserDataMigration() "
+                      "failed or ash crashed before reaching Migrate(). Check "
+                      "the previous chrome log and the one before.";
+        break;
+      case MigrationStep::kStarted:
+        LOG(ERROR) << "Migrate() was called but "
+                      "MigrateInternalFinishedUIThread() was not indicating "
+                      "that ash might have crashed during the migration.";
+        break;
+      case MigrationStep::kEnded:
+      default:
+        // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises,
+        // remove
+        // this log message or reduce to VLOG(1).
+        LOG(WARNING)
+            << "Migration has ended and either completed or failed. step = "
+            << static_cast<int>(step);
+        break;
+    }
+
     return;
   }
 
@@ -262,8 +280,7 @@
     return;
   if (force_migration_switch == kBrowserDataMigrationForceMigration) {
     LOG(WARNING) << "`kBrowserDataMigrationForceMigration` switch is present.";
-    MaybeRestartToMigrateCallback(account_id, user_id_hash,
-                                  true /* is_required */);
+    RestartToMigrate(account_id, user_id_hash);
     return;
   }
 
@@ -287,10 +304,13 @@
            "enabled again.";
 
     // If lacros is not enabled other than reaching the maximum retry count of
-    // profile migration, clear the retry count. This will allow users to reset
-    // the retry count by disabling lacros and re-enabling lacros back.
+    // profile migration, clear the retry count and
+    // `kProfileMigrationCompletedForUserPref`. This will allow users to retry
+    // profile migration after disabling and re-enabling lacros.
     ClearMigrationAttemptCountForUser(g_browser_process->local_state(),
                                       user_id_hash);
+    crosapi::browser_util::ClearProfileMigrationCompletedForUser(
+        g_browser_process->local_state(), user_id_hash);
     return;
   }
 
@@ -319,6 +339,9 @@
 
   int attempts = GetMigrationAttemptCountForUser(
       g_browser_process->local_state(), user_id_hash);
+  // TODO(crbug.com/1178702): Once BrowserDataMigrator stabilises, reduce the
+  // log level to VLOG(1).
+  LOG(WARNING) << "Attempt #" << attempts;
   if (attempts >= kMaxMigrationAttemptCount) {
     // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove
     // this log message.
@@ -334,52 +357,24 @@
         << "Restarting to run profile migration since data wipe is required.";
     // If data wipe is required, no need for a further check to determine if
     // lacros data dir exists or not.
-    MaybeRestartToMigrateCallback(account_id, user_id_hash,
-                                  true /* is_required */);
+    RestartToMigrate(account_id, user_id_hash);
     return;
   }
 
-  if (!crosapi::browser_util::IsProfileMigrationCompletedForUser(
+  if (crosapi::browser_util::IsProfileMigrationCompletedForUser(
           g_browser_process->local_state(), user_id_hash)) {
-    // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove
-    // this log message.
-    LOG(WARNING) << "Profile migration has not been completed yet.";
-    MaybeRestartToMigrateCallback(account_id, user_id_hash,
-                                  true /* is_required */);
+    // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises,
+    // remove this log message.
+    LOG(WARNING) << "Profile migration has been completed already.";
     return;
-  } else {
-    // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove
-    // this log message.
-    LOG(WARNING) << "Calling IsMigrationRequiredOnWorker() to determine if "
-                    "migration is required.";
-    // Check if profile migration is required by checking if lacros data
-    // directory exists even if profile migration is marked as completed. This
-    // is needed because until the official release because lacros user data
-    // directory can be wiped by disabling and re-enabling lacros.
-    base::FilePath user_data_dir;
-    if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
-      LOG(ERROR) << "Could not get the original user data dir path.";
-      return;
-    }
-
-    base::ThreadPool::PostTaskAndReplyWithResult(
-        FROM_HERE,
-        {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
-        base::BindOnce(&BrowserDataMigrator::IsMigrationRequiredOnWorker,
-                       user_data_dir, user_id_hash),
-        base::BindOnce(&MaybeRestartToMigrateCallback, account_id,
-                       user_id_hash));
   }
+
+  RestartToMigrate(account_id, user_id_hash);
 }
 
 // static
-void BrowserDataMigrator::MaybeRestartToMigrateCallback(
-    const AccountId& account_id,
-    const std::string& user_id_hash,
-    bool is_required) {
-  if (!is_required)
-    return;
-
+void BrowserDataMigrator::RestartToMigrate(const AccountId& account_id,
+                                           const std::string& user_id_hash) {
   LOG(WARNING) << "Restarting to start profile migration.";
   SetMigrationStep(g_browser_process->local_state(),
                    MigrationStep::kRestartCalled);
@@ -398,23 +393,13 @@
 }
 
 // static
-// Returns true if lacros user data dir doesn't exist.
-bool BrowserDataMigrator::IsMigrationRequiredOnWorker(
-    base::FilePath user_data_dir,
-    const std::string& user_id_hash) {
-  // Use `GetUserProfileDir()` to manually get base name for profile dir so that
-  // this method can be called even before user profile is created.
-  base::FilePath profile_data_dir =
-      user_data_dir.Append(ProfileHelper::GetUserProfileDir(user_id_hash));
-
-  return !base::DirectoryExists(profile_data_dir.Append(kLacrosDir));
-}
-
-// static
 base::OnceClosure BrowserDataMigrator::Migrate(
     const std::string& user_id_hash,
     const ProgressCallback& progress_callback,
     base::OnceClosure completion_callback) {
+  // TODO(crbug.com/1178702): Once BrowserDataMigrator stabilises, reduce the
+  // log level to VLOG(1).
+  LOG(WARNING) << "BrowserDataMigrator::Migrate() is called.";
   DCHECK(GetMigrationStep(g_browser_process->local_state()) ==
          MigrationStep::kRestartCalled);
   SetMigrationStep(g_browser_process->local_state(), MigrationStep::kStarted);
@@ -498,6 +483,7 @@
 
   if (base::DirectoryExists(new_user_dir)) {
     if (!base::DeletePathRecursively(new_user_dir)) {
+      PLOG(ERROR) << "Deleting " << new_user_dir.value() << " failed: ";
       RecordStatus(FinalStatus::kDataWipeFailed);
       return {ResultValue::kFailed, ResultValue::kFailed};
     }
@@ -533,6 +519,7 @@
       base::DeletePathRecursively(tmp_dir);
     }
     if (cancel_flag->IsSet()) {
+      LOG(WARNING) << "Migration was cancelled.";
       RecordStatus(FinalStatus::kCancelled, &target_info);
       return {data_wipe_result, ResultValue::kCancelled};
     }
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.h b/chrome/browser/ash/crosapi/browser_data_migrator.h
index 402742f..7b29b2f9 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.h
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.h
@@ -234,8 +234,6 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorTest,
                            ManipulateMigrationAttemptCount);
-  FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorTest,
-                           IsMigrationRequiredOnWorker);
   FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorTest, GetTargetInfo);
   FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorTest, CopyDirectory);
   FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorTest, SetupTmpDir);
@@ -249,11 +247,6 @@
   // Sets the value of `kMigrationStep` in Local State.
   static void SetMigrationStep(PrefService* local_state, MigrationStep step);
 
-  // The method includes a blocking operation. It checks if lacros user data dir
-  // already exists or not. Check if lacros is enabled or not beforehand.
-  static bool IsMigrationRequiredOnWorker(base::FilePath user_data_dir,
-                                          const std::string& user_id_hash);
-
   // Increments the migration attempt count stored in
   // `kMigrationAttemptCountPref` by 1 for the user identified by
   // `user_id_hash`.
@@ -280,11 +273,10 @@
       std::unique_ptr<MigrationProgressTracker> progress_tracker,
       scoped_refptr<CancelFlag> cancel_flag);
 
-  // This will be posted with `IsMigrationRequiredOnWorker()` as the reply on UI
-  // thread or called directly from `MaybeRestartToMigrate()`.
-  static void MaybeRestartToMigrateCallback(const AccountId& account_id,
-                                            const std::string& user_id_hash,
-                                            bool is_required);
+  // Called from `MaybeRestartToMigrate()` to proceed with restarting to start
+  // the migration.
+  static void RestartToMigrate(const AccountId& account_id,
+                               const std::string& user_id_hash);
 
   // Called on UI thread once migration is finished.
   static void MigrateInternalFinishedUIThread(base::OnceClosure callback,
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
index bb249b2..89c1c076 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
@@ -111,23 +111,6 @@
   TestingPrefServiceSimple pref_service_;
 };
 
-TEST_F(BrowserDataMigratorTest, IsMigrationRequiredOnWorker) {
-  const std::string user_id_hash = "user";
-  const base::FilePath user_data_dir_path = user_data_dir_.GetPath();
-
-  // Lacros UDD does not exist.
-  EXPECT_TRUE(BrowserDataMigrator::IsMigrationRequiredOnWorker(
-      user_data_dir_path, user_id_hash));
-
-  // Create lacros user data dir.
-  ASSERT_TRUE(base::CreateDirectory(
-      user_data_dir_path.Append("user").Append(kLacrosDir)));
-
-  // Lacros UDD exists.
-  EXPECT_FALSE(BrowserDataMigrator::IsMigrationRequiredOnWorker(
-      user_data_dir_path, user_id_hash));
-}
-
 TEST_F(BrowserDataMigratorTest, ManipulateMigrationAttemptCount) {
   const std::string user_id_hash = "user";
 
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
index 79ba149..ac79f7bf 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
@@ -1159,7 +1159,10 @@
   // one where the hash bucket is actually downloaded.
   time_start_bucket_download_ = base::TimeTicks::Now();
 
-  VLOG(1) << "Request bucket #" << remainder;
+  // TODO(crbug.com/1271134): Logging as "WARNING" to make sure it's preserved
+  // in the logs.
+  LOG(WARNING) << "Request bucket #" << remainder;
+
   std::unique_ptr<DMServerJobConfiguration> config = std::make_unique<
       DMServerJobConfiguration>(
       device_management_service_,
@@ -1288,7 +1291,11 @@
                              has_server_state_.value());
     local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_);
     local_state_->CommitPendingWrite();
-    VLOG(1) << "Received has_state=" << has_server_state_.value();
+
+    // TODO(crbug.com/1271134): Logging as "WARNING" to make sure it's preserved
+    // in the logs.
+    LOG(WARNING) << "Received has_state=" << has_server_state_.value();
+
     progress = true;
     // Report timing if hash dance finished successfully and if the caller is
     // still interested in the result.
diff --git a/chrome/browser/ash/web_applications/projector_system_web_app_info.cc b/chrome/browser/ash/web_applications/projector_system_web_app_info.cc
index e677317..b836e056 100644
--- a/chrome/browser/ash/web_applications/projector_system_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/projector_system_web_app_info.cc
@@ -8,6 +8,7 @@
 #include "ash/grit/ash_projector_app_trusted_resources.h"
 #include "ash/webui/projector_app/public/cpp/projector_app_constants.h"
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -49,5 +50,12 @@
 }
 
 bool ProjectorSystemWebAppDelegate::IsAppEnabled() const {
-  return ash::features::IsProjectorEnabled();
+  if (!profile_->GetProfilePolicyConnector()->IsManaged() ||
+      profile_->IsChild()) {
+    return ash::features::IsProjectorAllUserEnabled();
+  }
+
+  // TODO(b/209675088): Check Projector admin policy.
+  return ash::features::IsProjectorEnabled() ||
+         ash::features::IsProjectorManagedUserEnabled();
 }
diff --git a/chrome/browser/banners/android/chrome_app_banner_manager_android.cc b/chrome/browser/banners/android/chrome_app_banner_manager_android.cc
index 737b65f0..44a3c83 100644
--- a/chrome/browser/banners/android/chrome_app_banner_manager_android.cc
+++ b/chrome/browser/banners/android/chrome_app_banner_manager_android.cc
@@ -15,11 +15,11 @@
 #include "chrome/browser/android/webapk/webapk_ukm_recorder.h"
 #include "chrome/browser/banners/android/jni_headers/AppBannerInProductHelpControllerProvider_jni.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
-#include "chrome/browser/webapps/android/pwa_bottom_sheet_controller.h"
 #include "chrome/common/chrome_features.h"
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/feature_engagement/public/tracker.h"
 #include "components/site_engagement/content/site_engagement_service.h"
+#include "components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h"
 #include "components/webapps/browser/banners/app_banner_settings_helper.h"
 #include "components/webapps/browser/installable/installable_data.h"
 #include "content/public/browser/manifest_icon_downloader.h"
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index 707e9d3..7124478 100644
--- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -75,7 +75,6 @@
 import org.chromium.chrome.browser.tab.TabUtils;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuTestSupport;
-import org.chromium.chrome.browser.webapps.PwaInstallBottomSheetView;
 import org.chromium.chrome.browser.webapps.WebappDataStorage;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
@@ -97,6 +96,7 @@
 import org.chromium.components.webapps.AppBannerManager;
 import org.chromium.components.webapps.AppData;
 import org.chromium.components.webapps.AppDetailsDelegate;
+import org.chromium.components.webapps.bottomsheet.PwaInstallBottomSheetView;
 import org.chromium.components.webapps.installable.InstallableAmbientBadgeInfoBar;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 6217cf27..6c691cca 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -278,7 +278,7 @@
     base::RunLoop run_loop;
     cookie_manager_->GetCookieList(
         cookie_url_, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindLambdaForTesting(
             [&](const net::CookieAccessResultList& cookie_list,
                 const net::CookieAccessResultList& excluded_cookies) {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 05f760f6..2d226da 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -4816,6 +4816,7 @@
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system:system",
     "//mojo/public/cpp/test_support:test_utils",
+    "//services/audio/public/cpp:test_support",
     "//services/data_decoder/public/cpp:test_support",
     "//services/device/public/cpp:test_support",
     "//services/service_manager/public/cpp/test:test_support",
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index ab195bb1..4e73163 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -91,7 +91,6 @@
 #include "net/base/mime_util.h"
 #include "net/base/network_change_notifier.h"
 #include "ppapi/buildflags/buildflags.h"
-#include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_ANDROID)
@@ -844,8 +843,7 @@
     return;
   }
 
-  if (!blink::IsSupportedMimeType(download->GetMimeType()) &&
-      !IsOpenInBrowserPreferreredForFile(download->GetTargetFilePath())) {
+  if (!DownloadItemModel(download).ShouldPreferOpeningInBrowser()) {
     RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_PLATFORM);
     OpenDownloadUsingPlatformHandler(download);
     return;
diff --git a/chrome/browser/enterprise/signals/context_info_fetcher.cc b/chrome/browser/enterprise/signals/context_info_fetcher.cc
index 53529b6..1d1c9a7 100644
--- a/chrome/browser/enterprise/signals/context_info_fetcher.cc
+++ b/chrome/browser/enterprise/signals/context_info_fetcher.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/strings/string_split.h"
 #include "base/task/thread_pool.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
@@ -113,6 +114,32 @@
 }
 #endif
 
+#if defined(OS_MAC)
+SettingValue GetMacOSFirewall() {
+  // There is no official Apple documentation on how to obtain the enabled
+  // status of the firewall (System Preferences> Security & Privacy> Firewall).
+  // Reading globalstate from com.apple.alf is the closest way to get such an
+  // API in Chrome without delegating to potentially unstable commands.
+
+  Boolean key_exists_with_valid_format = false;
+  CFIndex globalstate = CFPreferencesGetAppIntegerValue(
+      CFSTR("globalstate"), CFSTR("com.apple.alf"),
+      &key_exists_with_valid_format);
+
+  if (!key_exists_with_valid_format)
+    return SettingValue::UNKNOWN;
+
+  switch (globalstate) {
+    case 0:
+      return SettingValue::DISABLED;
+    case 1:
+      return SettingValue::ENABLED;
+    default:
+      return SettingValue::UNKNOWN;
+  }
+}
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 SettingValue GetChromeosFirewall() {
   // The firewall is always enabled and can only be disabled in dev mode on
@@ -152,6 +179,9 @@
 }
 
 ContextInfo ContextInfoFetcher::FetchAsyncSignals(ContextInfo info) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
+
   // Add other async signals here
   info.system_dns_servers = GetDnsServers();
   info.os_firewall = GetOSFirewall();
@@ -242,6 +272,8 @@
   return GetUfwStatus();
 #elif defined(OS_WIN)
   return GetWinOSFirewall();
+#elif defined(OS_MAC)
+  return GetMacOSFirewall();
 #elif BUILDFLAG(IS_CHROMEOS_ASH)
   return GetChromeosFirewall();
 #else
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.cc b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
index ee30e706..204d24d 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
@@ -152,7 +152,7 @@
     const GURL& url,
     network::mojom::CookieManager::GetCookieListCallback callback) {
   manager->GetCookieList(url, net::CookieOptions::MakeAllInclusive(),
-                         net::CookiePartitionKeychain::Todo(),
+                         net::CookiePartitionKeyCollection::Todo(),
                          std::move(callback));
 }
 
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index ef058fb..1bda972 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -124,6 +124,7 @@
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "ui/base/ui_base_features.h"
 #include "url/origin.h"
@@ -4680,4 +4681,30 @@
                    "preflightResponseStartedSuccessfullyCount"));
 }
 
+class ExtensionWebRequestApiFencedFrameTest
+    : public ExtensionWebRequestApiTest,
+      public testing::WithParamInterface<bool /* shadow_dom_fenced_frame */> {
+ protected:
+  ExtensionWebRequestApiFencedFrameTest() {
+    feature_list_.InitAndEnableFeatureWithParameters(
+        blink::features::kFencedFrames,
+        {{"implementation_type", GetParam() ? "shadow_dom" : "mparch"}});
+  }
+  ~ExtensionWebRequestApiFencedFrameTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiFencedFrameTest, Load) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(
+      RunExtensionTest("webrequest", {.page_url = "test_fenced_frames.html"}))
+      << message_;
+}
+
+INSTANTIATE_TEST_SUITE_P(ExtensionWebRequestApiFencedFrameTest,
+                         ExtensionWebRequestApiFencedFrameTest,
+                         testing::Bool());
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 40660eb..27de263 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -5070,7 +5070,7 @@
 
   cookie_store->GetCookieListWithOptionsAsync(
       ext_url, net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(),
+      net::CookiePartitionKeyCollection(),
       base::BindOnce(&ExtensionCookieCallback::GetAllCookiesCallback,
                      base::Unretained(&callback)));
   task_environment()->RunUntilIdle();
@@ -5137,7 +5137,7 @@
   // Check that the cookie is gone.
   cookie_store->GetCookieListWithOptionsAsync(
       ext_url, net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(),
+      net::CookiePartitionKeyCollection(),
       base::BindOnce(&ExtensionCookieCallback::GetAllCookiesCallback,
                      base::Unretained(&callback)));
   task_environment()->RunUntilIdle();
@@ -5250,7 +5250,7 @@
     std::vector<net::CanonicalCookie> cookies_result;
     cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
     run_loop.Run();
@@ -5320,7 +5320,7 @@
     std::vector<net::CanonicalCookie> cookies_result;
     cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
     run_loop.Run();
@@ -5340,7 +5340,7 @@
     std::vector<net::CanonicalCookie> cookies_result;
     cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
     run_loop.Run();
diff --git a/chrome/browser/hid/chrome_hid_delegate.cc b/chrome/browser/hid/chrome_hid_delegate.cc
index d603177..46e3464 100644
--- a/chrome/browser/hid/chrome_hid_delegate.cc
+++ b/chrome/browser/hid/chrome_hid_delegate.cc
@@ -54,6 +54,10 @@
 
 bool ChromeHidDelegate::CanRequestDevicePermission(
     content::RenderFrameHost* render_frame_host) {
+  // The use below of GetMainFrame is safe as content::HidService instances are
+  // not created for fenced frames.
+  DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
+
   auto* chooser_context = GetChooserContext(render_frame_host);
   const auto& origin =
       render_frame_host->GetMainFrame()->GetLastCommittedOrigin();
@@ -63,6 +67,10 @@
 bool ChromeHidDelegate::HasDevicePermission(
     content::RenderFrameHost* render_frame_host,
     const device::mojom::HidDeviceInfo& device) {
+  // The use below of GetMainFrame is safe as content::HidService instances are
+  // not created for fenced frames.
+  DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
+
   auto* chooser_context = GetChooserContext(render_frame_host);
   const auto& origin =
       render_frame_host->GetMainFrame()->GetLastCommittedOrigin();
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index ad7b81d..a3c03ca 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -618,19 +618,23 @@
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
   );
 
+  // BackupRefPtr_Effective and PCScan_Effective records whether or not
+  // BackupRefPtr and/or PCScan are enabled. The experiments aren't independent,
+  // so having a synthetic Finch will help look only at cases where one isn't
+  // affected by the other.
+
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  // Records whether or not BackupRefPtr and/or PCScan is enabled. The
-  // experiments aren't independent, so having a synthetic Finch will help look
-  // only at cases where one isn't affected by the other.
-  bool brp_enabled =
+  bool brp_finch_enabled = false;
+  ALLOW_UNUSED_LOCAL(brp_finch_enabled);
+  bool brp_truly_enabled = false;
+  ALLOW_UNUSED_LOCAL(brp_truly_enabled);
 #if BUILDFLAG(USE_BACKUP_REF_PTR)
-      base::FeatureList::IsEnabled(
-          base::features::kPartitionAllocBackupRefPtr) &&
-      (base::features::kBackupRefPtrModeParam.Get() ==
-       base::features::BackupRefPtrMode::kEnabled);
-#else
-      false;
-#endif
+  if (base::FeatureList::IsEnabled(base::features::kPartitionAllocBackupRefPtr))
+    brp_finch_enabled = true;
+  if (brp_finch_enabled && base::features::kBackupRefPtrModeParam.Get() ==
+                               base::features::BackupRefPtrMode::kEnabled)
+    brp_truly_enabled = true;
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
   bool pcscan_enabled =
 #if defined(PA_ALLOW_PCSCAN)
       base::FeatureList::IsEnabled(
@@ -638,10 +642,69 @@
 #else
       false;
 #endif
+
+  std::string brp_group_name;
+  if (pcscan_enabled) {
+    // If PCScan is enabled, just ignore the population.
+    brp_group_name = "Ignore";
+  } else if (brp_finch_enabled) {
+    switch (base::features::kBackupRefPtrModeParam.Get()) {
+      case base::features::BackupRefPtrMode::kEnabled:
+#if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
+        brp_group_name = "EnabledPrevSlot";
+#else
+        brp_group_name = "EnabledBeforeAlloc";
+#endif
+        break;
+      case base::features::BackupRefPtrMode::kDisabledButSplitPartitions2Way:
+        brp_group_name = "DisabledBut2WaySplit";
+        break;
+      case base::features::BackupRefPtrMode::kDisabledButSplitPartitions3Way:
+        brp_group_name = "DisabledBut3WaySplit";
+        break;
+    }
+
+    std::string process_selector;
+    switch (base::features::kBackupRefPtrEnabledProcessesParam.Get()) {
+      case base::features::BackupRefPtrEnabledProcesses::kBrowserOnly:
+        process_selector = "BrowserOnly";
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer:
+        process_selector = "BrowserAndRenderer";
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kNonRenderer:
+        process_selector = "NonRenderer";
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kAllProcesses:
+        process_selector = "AllProcesses";
+        break;
+    }
+
+    brp_group_name += ("_" + process_selector);
+  } else {
+    brp_group_name = "Disabled";
+  }
   ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
-      "BackupRefPtrAndPCScan",
-      brp_enabled ? (pcscan_enabled ? "BothEnabled" : "BackupRefPtrEnabledOnly")
-                  : (pcscan_enabled ? "PCScanEnabledOnly" : "BothDisabled"));
+      "BackupRefPtr_Effective", brp_group_name);
+
+  std::string pcscan_group_name;
+#if defined(PA_ALLOW_PCSCAN)
+  if (brp_truly_enabled) {
+    // If BRP is enabled, just ignore the population. Check brp_truly_enabled,
+    // not brp_finch_enabled, because there are certain modes where BRP is
+    // actually disabled.
+    pcscan_group_name = "Ignore";
+  } else {
+    pcscan_group_name = (pcscan_enabled ? "Enabled" : "Disabled");
+  }
+#else
+  // On certain platforms, PCScan is not supported and permanently disabled.
+  // Don't lump it into "Disabled", so that belonging to "Enabled"/"Disabled" is
+  // fully controlled by Finch and thus have identical population sizes.
+  pcscan_group_name = "Unavailable";
+#endif  // defined(PA_ALLOW_PCSCAN)
+  ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial("PCScan_Effective",
+                                                            pcscan_group_name);
 
   // This synthetic Finch setting reflects the new USE_BACKUP_REF_PTR behavior,
   // which simply compiles in the BackupRefPtr support, but keeps it disabled at
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index ab3b7429..d51be2e 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -654,7 +654,7 @@
         ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
     cookie_manager->GetCookieList(
         url, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(
             [](std::string* cookies_out, base::RunLoop* run_loop,
                const net::CookieAccessResultList& cookies,
diff --git a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
index 69a2ad87..4371d31d 100644
--- a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
+++ b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
@@ -25,6 +25,7 @@
 #include "components/optimization_guide/core/optimization_guide_test_util.h"
 #include "components/optimization_guide/core/test_model_info_builder.h"
 #include "components/optimization_guide/machine_learning_tflite_buildflags.h"
+#include "components/optimization_guide/proto/page_entities_metadata.pb.h"
 #include "components/optimization_guide/proto/page_topics_model_metadata.pb.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/render_frame_host.h"
@@ -36,11 +37,18 @@
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 
 namespace optimization_guide {
 
+namespace {
+
+using ::testing::UnorderedElementsAre;
+
+}  // namespace
+
 class FakePageTextService : public mojom::PageTextService {
  public:
   FakePageTextService() = default;
@@ -229,7 +237,6 @@
 #endif
   }
 
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
   absl::optional<history::VisitContentAnnotations> GetContentAnnotationsForURL(
       const GURL& url) {
     history::HistoryService* history_service =
@@ -260,7 +267,6 @@
     run_loop->Run();
     return got_content_annotations;
   }
-#endif  // BUILDFLAG(BUILD_WITH_TFLITE_LIB)
 
   void Annotate(const HistoryVisit& visit, const std::string& text) {
     PageContentAnnotationsService* service =
@@ -377,6 +383,64 @@
   }
 }
 
+class PageContentAnnotationsServiceRemotePageEntitiesBrowserTest
+    : public PageContentAnnotationsServiceBrowserTest {
+ public:
+  PageContentAnnotationsServiceRemotePageEntitiesBrowserTest() {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{features::kOptimizationHints, {}},
+         {features::kPageContentAnnotations,
+          {
+              {"write_to_history_service", "true"},
+              {"fetch_remote_page_entities", "true"},
+          }}},
+        /*disabled_features=*/{});
+    set_load_model_on_startup(false);
+  }
+  ~PageContentAnnotationsServiceRemotePageEntitiesBrowserTest() override =
+      default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    PageContentAnnotationsServiceRemotePageEntitiesBrowserTest,
+    StoresPageEntitiesFromRemoteService) {
+  base::HistogramTester histogram_tester;
+
+  GURL url(embedded_test_server()->GetURL("a.com", "/hello.html"));
+
+  proto::PageEntitiesMetadata page_entities_metadata;
+  proto::Entity* entity = page_entities_metadata.add_entities();
+  entity->set_entity_id("entity1");
+  entity->set_score(50);
+  OptimizationMetadata metadata;
+  metadata.SetAnyMetadataForTesting(page_entities_metadata);
+  OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+      ->AddHintForTesting(url, proto::PAGE_ENTITIES, metadata);
+
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  RetryForHistogramUntilCountReached(
+      &histogram_tester,
+      "OptimizationGuide.PageContentAnnotationsService."
+      "ContentAnnotationsStorageStatus",
+      1);
+
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.PageContentAnnotationsService."
+      "ContentAnnotationsStorageStatus",
+      PageContentAnnotationsStorageStatus::kSuccess, 1);
+
+  absl::optional<history::VisitContentAnnotations> got_content_annotations =
+      GetContentAnnotationsForURL(url);
+  ASSERT_TRUE(got_content_annotations.has_value());
+  EXPECT_THAT(
+      got_content_annotations->model_annotations.entities,
+      UnorderedElementsAre(
+          history::VisitContentModelAnnotations::Category("entity1", 50)));
+}
+
 class PageContentAnnotationsServiceNoHistoryTest
     : public PageContentAnnotationsServiceBrowserTest {
  public:
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
index d5fd751..91fb69d 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
@@ -228,7 +228,7 @@
 
   partition->GetCookieManagerForBrowserProcess()->GetCookieList(
       url, net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain::Todo(),
+      net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(
           &UkmPageLoadMetricsObserver::OnMainFrameRequestHadCookieResult,
           weak_factory_.GetWeakPtr(), base::Time::Now()));
@@ -1162,7 +1162,15 @@
       .SetSmoothnessBad(smoothness_data.buckets[3])
       .SetSmoothnessVeryBad25to50(smoothness_data.buckets[4])
       .SetSmoothnessVeryBad50to75(smoothness_data.buckets[5])
-      .SetSmoothnessVeryBad75to100(smoothness_data.buckets[6]);
+      .SetSmoothnessVeryBad75to100(smoothness_data.buckets[6])
+      .SetMainFocusedMedian(smoothness_data.main_focused_median)
+      .SetMainFocusedPercentile95(smoothness_data.main_focused_percentile_95)
+      .SetMainFocusedVariance(smoothness_data.main_focused_variance)
+      .SetCompositorFocusedMedian(smoothness_data.compositor_focused_median)
+      .SetCompositorFocusedPercentile95(
+          smoothness_data.compositor_focused_percentile_95)
+      .SetCompositorFocusedVariance(
+          smoothness_data.compositor_focused_variance);
   if (smoothness_data.worst_smoothness_after1sec >= 0)
     builder.SetWorstCaseAfter1Sec(smoothness_data.worst_smoothness_after1sec);
   if (smoothness_data.worst_smoothness_after2sec >= 0)
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 50ef2c1..7d9cbf6 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -515,6 +515,12 @@
             content::GetFocusedWebContents(embedder_web_contents));
 }
 
+// TODO(crbug.com/1278357): Flaky on lacros.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#define MAYBE_PdfExtensionLoadedInGuest DISABLED_PdfExtensionLoadedInGuest
+#else
+#define MAYBE_PdfExtensionLoadedInGuest PdfExtensionLoadedInGuest
+#endif
 // This test verifies that when a PDF is loaded, that (i) the embedder
 // WebContents' html consists of a single <embed> tag with appropriate
 // properties, and (ii) that the guest WebContents finishes loading and
@@ -522,7 +528,7 @@
 // TODO(wjmaclean): Are there any attributes we can/should test with respect to
 // the extension's loaded html?
 IN_PROC_BROWSER_TEST_P(PDFExtensionTestWithTestGuestViewManager,
-                       PdfExtensionLoadedInGuest) {
+                       MAYBE_PdfExtensionLoadedInGuest) {
   // Load test HTML, and verify the text area has focus.
   const GURL main_url(embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_url));
@@ -1589,6 +1595,29 @@
 
 namespace {
 
+class ScrollEventWaiter {
+ public:
+  explicit ScrollEventWaiter(content::WebContents* guest_contents)
+      : message_queue_(guest_contents) {
+    content::ExecuteScriptAsync(
+        guest_contents,
+        R"(viewer.shadowRoot.querySelector('#scroller').onscroll = () => {
+          window.domAutomationController.send('dispatchedScrollEvent');
+        })");
+  }
+
+  void Reset() { message_queue_.ClearQueue(); }
+
+  void Wait() {
+    std::string message;
+    ASSERT_TRUE(message_queue_.WaitForMessage(&message));
+    EXPECT_EQ("\"dispatchedScrollEvent\"", message);
+  }
+
+ private:
+  content::DOMMessageQueue message_queue_;
+};
+
 int GetViewportHeight(content::WebContents* guest_contents) {
   int viewport_height = 0;
   EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
@@ -1607,18 +1636,6 @@
   return position_y;
 }
 
-int GetViewportScrollPositionYAfterScrollEvent(
-    content::WebContents* guest_contents) {
-  int position_y = 0;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
-      guest_contents,
-      "viewer.shadowRoot.querySelector('#scroller').onscroll = () => {"
-      "  window.domAutomationController.send(viewer.viewport.position.y);"
-      "};",
-      &position_y));
-  return position_y;
-}
-
 }  // namespace
 
 IN_PROC_BROWSER_TEST_P(PDFExtensionKeyEventTest, ScrollWithSpaceShortcut) {
@@ -1635,19 +1652,22 @@
   EXPECT_EQ(0, GetViewportScrollPositionY(guest_contents));
 
   // Press space key to scroll down.
+  ScrollEventWaiter scroll_waiter(guest_contents);
   content::SimulateKeyPress(guest_contents, ui::DomKey::FromCharacter(' '),
                             ui::DomCode::SPACE, ui::VKEY_SPACE,
                             /*control=*/false, /*shift=*/false, /*alt=*/false,
                             /*command=*/false);
-  EXPECT_EQ(viewport_height,
-            GetViewportScrollPositionYAfterScrollEvent(guest_contents));
+  ASSERT_NO_FATAL_FAILURE(scroll_waiter.Wait());
+  EXPECT_EQ(viewport_height, GetViewportScrollPositionY(guest_contents));
 
   // Press shift + space key to scroll back up to top.
+  scroll_waiter.Reset();
   content::SimulateKeyPress(guest_contents, ui::DomKey::FromCharacter(' '),
                             ui::DomCode::SPACE, ui::VKEY_SPACE,
                             /*control=*/false, /*shift=*/true, /*alt=*/false,
                             /*command=*/false);
-  EXPECT_EQ(0, GetViewportScrollPositionYAfterScrollEvent(guest_contents));
+  ASSERT_NO_FATAL_FAILURE(scroll_waiter.Wait());
+  EXPECT_EQ(0, GetViewportScrollPositionY(guest_contents));
 }
 
 INSTANTIATE_TEST_SUITE_P(All, PDFExtensionKeyEventTest, testing::Values(true));
diff --git a/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
index 62953d9f..f91aa62 100644
--- a/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
@@ -787,7 +787,7 @@
   net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
   base::RunLoop loop;
   storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
-      url, options, net::CookiePartitionKeychain(),
+      url, options, net::CookiePartitionKeyCollection(),
       base::BindOnce(GetCookieCallback, loop.QuitClosure()));
   loop.Run();
 }
@@ -810,7 +810,7 @@
   net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
   base::RunLoop loop;
   storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
-      cross_domain_url, options, net::CookiePartitionKeychain(),
+      cross_domain_url, options, net::CookiePartitionKeyCollection(),
       base::BindOnce(GetCookieCallback, loop.QuitClosure()));
   loop.Run();
 }
diff --git a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_tab_helper.cc b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_tab_helper.cc
index 82bfd37..7d5fd1b 100644
--- a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_tab_helper.cc
+++ b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_tab_helper.cc
@@ -1472,7 +1472,7 @@
   net::CookieOptions options = net::CookieOptions::MakeAllInclusive();
   options.set_return_excluded_cookies();
   default_storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
-      url, options, net::CookiePartitionKeychain::Todo(),
+      url, options, net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(&OnGotCookieList, url, std::move(result_callback)));
 }
 
@@ -1587,7 +1587,7 @@
       ->GetCookieManager()
       ->GetCookieList(
           prefetch_container->GetUrl(), options,
-          net::CookiePartitionKeychain::Todo(),
+          net::CookiePartitionKeyCollection::Todo(),
           base::BindOnce(
               &PrefetchProxyTabHelper::OnGotIsolatedCookiesToCopyAfterSRPClick,
               weak_factory_.GetWeakPtr(), prefetch_container->GetUrl()));
diff --git a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
index 764cb3b0..f484fd3 100644
--- a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
@@ -84,7 +84,7 @@
   net::CookieOptions cookie_options;
   cookie_manager_->GetCookieList(
       GURL("https://" + host + "/"), cookie_options,
-      net::CookiePartitionKeychain(),
+      net::CookiePartitionKeyCollection(),
       base::BindOnce(&RemoveCookieTester::GetCookieListCallback,
                      base::Unretained(this)));
   BlockUntilNotified();
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_id.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_id.xtb
index 65b80a4..eb74f90 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_id.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_id.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">Area praktik: Menu drop-down</translation>
 <translation id="1195238899008218998">Penutup</translation>
 <translation id="1197088940767939838">Oranye</translation>
+<translation id="1198865190323699001">Gestur Sentuh</translation>
 <translation id="1201402288615127009">Berikutnya</translation>
 <translation id="1206619573307042055">marquee</translation>
 <translation id="1207086294218137981">Tidak ada judul level 4 berikutnya</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ja.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ja.xtb
index ae7025c..6779897 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ja.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ja.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">練習エリア: プルダウン リスト</translation>
 <translation id="1195238899008218998">後書き</translation>
 <translation id="1197088940767939838">オレンジ</translation>
+<translation id="1198865190323699001">タップ操作</translation>
 <translation id="1201402288615127009">次へ</translation>
 <translation id="1206619573307042055">マーキー</translation>
 <translation id="1207086294218137981">次のレベル 4 の見出しはありません</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
index 809d0554..609067f 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_ko.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">연습 영역: 드롭다운 목록</translation>
 <translation id="1195238899008218998">후기</translation>
 <translation id="1197088940767939838">오렌지색</translation>
+<translation id="1198865190323699001">터치 동작</translation>
 <translation id="1201402288615127009">다음</translation>
 <translation id="1206619573307042055">marquee</translation>
 <translation id="1207086294218137981">다음 수준 4 제목이 없습니다</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_mn.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_mn.xtb
index a05918a..e232cbf 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_mn.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_mn.xtb
@@ -392,6 +392,7 @@
 <translation id="3497063866483065785">{COUNT,plural, =1{асуултын тэмдэг}other{# асуултын тэмдгүүд}}</translation>
 <translation id="3505359110822747654">ChromeVox цэсийг хаах</translation>
 <translation id="3514822174137761109">{COUNT,plural, =1{^ тэмдэг}other{# ^ тэмдгүүд}}</translation>
+<translation id="3518600448524470129">{COUNT,plural, =1{цагаан тэмдэг}other{# цагаан тэмдэг}}</translation>
 <translation id="352577523970648069">Засах боломжтой текст талбар</translation>
 <translation id="3538907380453898475">dscrplst</translation>
 <translation id="3549141990712742152"><ph name="TEXT" />-г таслах.</translation>
@@ -675,6 +676,7 @@
 <translation id="5597170376237141345">Дараагийн сонгох талбар</translation>
 <translation id="5598905979683743333"><ph name="NAME" />, ганц сонголтот талбарыг сонгоогүй байна</translation>
 <translation id="5601172225407283979">Анхдагч үйлдлийг гүйцэтгэх</translation>
+<translation id="5604302400025591178">{COUNT,plural, =1{дөрвөлжин тэмдэг}other{# дөрвөлжин тэмдэг}}</translation>
 <translation id="5608798115546226984">Autocompletion мөр</translation>
 <translation id="5616029807486814372">Дараагийн хичээл</translation>
 <translation id="561939826962581046">цаг</translation>
@@ -1098,6 +1100,7 @@
 <translation id="8659501358298941449">Эвхмэл жагсаалт</translation>
 <translation id="8666733765751421568"><ph name="TYPE" />-н төгсөл</translation>
 <translation id="867187640362843212">Гарчиг 5</translation>
+<translation id="8690400660839620419">{COUNT,plural, =1{}other{байрлуулсан түвшин #}}</translation>
 <translation id="8693391540059827073">Миний дуртай улирал</translation>
 <translation id="8696284982970258155">Бага зэргийн цайвар цэнхэр</translation>
 <translation id="8697111817566059991">{COUNT,plural, =1{ хоолой}other{ # босоо хоолой}}</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_tr.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_tr.xtb
index e077559f..10681b3 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_tr.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_tr.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">Alıştırma alanı: Açılır listeler</translation>
 <translation id="1195238899008218998">Sonsöz</translation>
 <translation id="1197088940767939838">Turuncu</translation>
+<translation id="1198865190323699001">Dokunma Hareketleri</translation>
 <translation id="1201402288615127009">İleri</translation>
 <translation id="1206619573307042055">marquee</translation>
 <translation id="1207086294218137981">Sonraki 4. düzey başlık yok</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-HK.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-HK.xtb
index 9a76733..8c89e5af8 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-HK.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-HK.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">練習區:下拉式清單</translation>
 <translation id="1195238899008218998">後記</translation>
 <translation id="1197088940767939838">橙色</translation>
+<translation id="1198865190323699001">觸控手勢</translation>
 <translation id="1201402288615127009">下一個</translation>
 <translation id="1206619573307042055">marquee</translation>
 <translation id="1207086294218137981">冇下一個第 4 級標題</translation>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
index 93487cc9..af0dd94 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-TW.xtb
@@ -30,6 +30,7 @@
 <translation id="1189258430971676908">練習區:下拉式清單</translation>
 <translation id="1195238899008218998">後記</translation>
 <translation id="1197088940767939838">橘色</translation>
+<translation id="1198865190323699001">觸控手勢</translation>
 <translation id="1201402288615127009">繼續</translation>
 <translation id="1206619573307042055">marquee</translation>
 <translation id="1207086294218137981">沒有下一個第 4 階標題</translation>
diff --git a/chrome/browser/resources/chromeos/login/test_api/test_api.js b/chrome/browser/resources/chromeos/login/test_api/test_api.js
index 380c01b8..0ca52d1 100644
--- a/chrome/browser/resources/chromeos/login/test_api/test_api.js
+++ b/chrome/browser/resources/chromeos/login/test_api/test_api.js
@@ -156,6 +156,11 @@
     super('network-selection');
     this.nextButton = new PolymerElementApi(this, '#nextButton');
   }
+
+  /** @override */
+  shouldSkip() {
+    return loadTimeData.getBoolean('testapi_shouldSkipNetworkFirstShow');
+  }
 }
 
 class EulaScreenTester extends ScreenElementApi {
diff --git a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.ts b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.ts
index ebc6c6b2..3897410 100644
--- a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.ts
+++ b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.ts
@@ -357,6 +357,11 @@
     const useAccountStore = !this.$.storePicker.hidden ?
         (this.$.storePicker.value === this.storeOptionAccountValue) :
         false;
+    if (!this.$.storePicker.hidden) {
+      chrome.metricsPrivate.recordBoolean(
+          'PasswordManager.AddCredentialFromSettings.AccountStoreUsed',
+          useAccountStore);
+    }
     PasswordManagerImpl.getInstance()
         .addPassword({
           url: this.$.websiteInput.value,
diff --git a/chrome/browser/resources/tab_search/app.ts b/chrome/browser/resources/tab_search/app.ts
index a019d0e..0536db9 100644
--- a/chrome/browser/resources/tab_search/app.ts
+++ b/chrome/browser/resources/tab_search/app.ts
@@ -653,4 +653,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'tab-search-app': TabSearchAppElement;
+  }
+}
+
 customElements.define(TabSearchAppElement.is, TabSearchAppElement);
diff --git a/chrome/browser/resources/tab_search/infinite_list.ts b/chrome/browser/resources/tab_search/infinite_list.ts
index db57b3ca..5a09d66 100644
--- a/chrome/browser/resources/tab_search/infinite_list.ts
+++ b/chrome/browser/resources/tab_search/infinite_list.ts
@@ -600,4 +600,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'infinite-list': InfiniteList;
+  }
+}
+
 customElements.define(InfiniteList.is, InfiniteList);
diff --git a/chrome/browser/resources/tab_search/tab_search_group_item.ts b/chrome/browser/resources/tab_search/tab_search_group_item.ts
index dd30d53..0de560f 100644
--- a/chrome/browser/resources/tab_search/tab_search_group_item.ts
+++ b/chrome/browser/resources/tab_search/tab_search_group_item.ts
@@ -67,4 +67,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'tab-search-group-item': TabSearchGroupItem;
+  }
+}
+
 customElements.define(TabSearchGroupItem.is, TabSearchGroupItem);
diff --git a/chrome/browser/resources/tab_search/tab_search_item.ts b/chrome/browser/resources/tab_search/tab_search_item.ts
index 7f45492f..1b206d8 100644
--- a/chrome/browser/resources/tab_search/tab_search_item.ts
+++ b/chrome/browser/resources/tab_search/tab_search_item.ts
@@ -174,4 +174,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'tab-search-item': TabSearchItem;
+  }
+}
+
 customElements.define(TabSearchItem.is, TabSearchItem);
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
index 62b6653..1e0780c 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
@@ -53,12 +53,15 @@
       "pending-text-upload-scans");
   static crash_reporter::CrashKeyString<7> pending_file_downloads(
       "pending-file-download-scans");
+  static crash_reporter::CrashKeyString<7> pending_prints(
+      "pending-print-scans");
   static crash_reporter::CrashKeyString<7> total_file_uploads(
       "total-file-upload-scans");
   static crash_reporter::CrashKeyString<7> total_text_uploads(
       "total-text-upload-scans");
   static crash_reporter::CrashKeyString<7> total_file_downloads(
       "total-file-download-scans");
+  static crash_reporter::CrashKeyString<7> total_prints("total-print-scans");
   switch (key) {
     case ScanningCrashKey::PENDING_FILE_UPLOADS:
       return &pending_file_uploads;
@@ -66,12 +69,16 @@
       return &pending_text_uploads;
     case ScanningCrashKey::PENDING_FILE_DOWNLOADS:
       return &pending_file_downloads;
+    case ScanningCrashKey::PENDING_PRINTS:
+      return &pending_prints;
     case ScanningCrashKey::TOTAL_FILE_UPLOADS:
       return &total_file_uploads;
     case ScanningCrashKey::TOTAL_TEXT_UPLOADS:
       return &total_text_uploads;
     case ScanningCrashKey::TOTAL_FILE_DOWNLOADS:
       return &total_file_downloads;
+    case ScanningCrashKey::TOTAL_PRINTS:
+      return &total_prints;
   }
 }
 
@@ -79,9 +86,11 @@
   static int pending_file_uploads = 0;
   static int pending_text_uploads = 0;
   static int pending_file_downloads = 0;
+  static int pending_prints = 0;
   static int total_file_uploads = 0;
   static int total_text_uploads = 0;
   static int total_file_downloads = 0;
+  static int total_prints = 0;
   switch (key) {
     case ScanningCrashKey::PENDING_FILE_UPLOADS:
       return &pending_file_uploads;
@@ -89,12 +98,16 @@
       return &pending_text_uploads;
     case ScanningCrashKey::PENDING_FILE_DOWNLOADS:
       return &pending_file_downloads;
+    case ScanningCrashKey::PENDING_PRINTS:
+      return &pending_prints;
     case ScanningCrashKey::TOTAL_FILE_UPLOADS:
       return &total_file_uploads;
     case ScanningCrashKey::TOTAL_TEXT_UPLOADS:
       return &total_text_uploads;
     case ScanningCrashKey::TOTAL_FILE_DOWNLOADS:
       return &total_file_downloads;
+    case ScanningCrashKey::TOTAL_PRINTS:
+      return &total_prints;
   }
 }
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
index 3c984a9..a256261 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h
@@ -156,9 +156,11 @@
   PENDING_FILE_UPLOADS,
   PENDING_TEXT_UPLOADS,
   PENDING_FILE_DOWNLOADS,
+  PENDING_PRINTS,
   TOTAL_FILE_UPLOADS,
   TOTAL_TEXT_UPLOADS,
-  TOTAL_FILE_DOWNLOADS
+  TOTAL_FILE_DOWNLOADS,
+  TOTAL_PRINTS
 };
 void IncrementCrashKey(ScanningCrashKey key, int delta = 1);
 void DecrementCrashKey(ScanningCrashKey key, int delta = 1);
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc
index 38bad54..b1610848 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc
@@ -7,6 +7,7 @@
 #include <limits>
 #include <string>
 #include <tuple>
+#include <utility>
 
 #include "base/files/file_path.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -31,6 +32,18 @@
     BinaryUploadService::Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE,
 };
 
+#if !BUILDFLAG(USE_CRASH_KEY_STUBS)
+constexpr std::pair<ScanningCrashKey, const char*> kAllCrashKeys[] = {
+    {ScanningCrashKey::PENDING_FILE_UPLOADS, "pending-file-upload-scans"},
+    {ScanningCrashKey::PENDING_FILE_DOWNLOADS, "pending-file-download-scans"},
+    {ScanningCrashKey::PENDING_TEXT_UPLOADS, "pending-text-upload-scans"},
+    {ScanningCrashKey::PENDING_PRINTS, "pending-print-scans"},
+    {ScanningCrashKey::TOTAL_FILE_UPLOADS, "total-file-upload-scans"},
+    {ScanningCrashKey::TOTAL_FILE_DOWNLOADS, "total-file-download-scans"},
+    {ScanningCrashKey::TOTAL_TEXT_UPLOADS, "total-text-upload-scans"},
+    {ScanningCrashKey::TOTAL_PRINTS, "total-print-scans"}};
+#endif  // !BUILDFLAG(USE_CRASH_KEY_STUBS)
+
 constexpr int64_t kTotalBytes = 1000;
 
 constexpr base::TimeDelta kDuration = base::Seconds(10);
@@ -272,7 +285,8 @@
 }
 
 #if !BUILDFLAG(USE_CRASH_KEY_STUBS)
-class DeepScanningUtilsCrashKeysTest : public testing::Test {
+class DeepScanningUtilsCrashKeysTest
+    : public testing::TestWithParam<std::pair<ScanningCrashKey, const char*>> {
  public:
   void SetUp() override {
     crash_reporter::ResetCrashKeysForTesting();
@@ -280,64 +294,60 @@
   }
 
   void TearDown() override { crash_reporter::ResetCrashKeysForTesting(); }
+
+  ScanningCrashKey key_enum() { return std::get<0>(GetParam()); }
+
+  const char* key_string() { return std::get<1>(GetParam()); }
 };
 
-TEST_F(DeepScanningUtilsCrashKeysTest, SmallModifications) {
+INSTANTIATE_TEST_SUITE_P(,
+                         DeepScanningUtilsCrashKeysTest,
+                         testing::ValuesIn(kAllCrashKeys));
+
+TEST_P(DeepScanningUtilsCrashKeysTest, SmallModifications) {
   // The key implicitly starts at 0.
-  IncrementCrashKey(ScanningCrashKey::PENDING_FILE_DOWNLOADS, 1);
-  EXPECT_EQ("1",
-            crash_reporter::GetCrashKeyValue("pending-file-download-scans"));
+  IncrementCrashKey(key_enum(), 1);
+  EXPECT_EQ("1", crash_reporter::GetCrashKeyValue(key_string()));
 
-  IncrementCrashKey(ScanningCrashKey::PENDING_FILE_DOWNLOADS, 1);
-  EXPECT_EQ("2",
-            crash_reporter::GetCrashKeyValue("pending-file-download-scans"));
+  IncrementCrashKey(key_enum(), 1);
+  EXPECT_EQ("2", crash_reporter::GetCrashKeyValue(key_string()));
 
-  DecrementCrashKey(ScanningCrashKey::PENDING_FILE_DOWNLOADS, 1);
-  EXPECT_EQ("1",
-            crash_reporter::GetCrashKeyValue("pending-file-download-scans"));
+  DecrementCrashKey(key_enum(), 1);
+  EXPECT_EQ("1", crash_reporter::GetCrashKeyValue(key_string()));
 
-  DecrementCrashKey(ScanningCrashKey::PENDING_FILE_DOWNLOADS, 1);
-  EXPECT_TRUE(
-      crash_reporter::GetCrashKeyValue("pending-file-download-scans").empty());
+  DecrementCrashKey(key_enum(), 1);
+  EXPECT_TRUE(crash_reporter::GetCrashKeyValue(key_string()).empty());
 }
 
-TEST_F(DeepScanningUtilsCrashKeysTest, LargeModifications) {
+TEST_P(DeepScanningUtilsCrashKeysTest, LargeModifications) {
   // The key implicitly starts at 0.
-  IncrementCrashKey(ScanningCrashKey::PENDING_FILE_UPLOADS, 100);
-  EXPECT_EQ("100",
-            crash_reporter::GetCrashKeyValue("pending-file-upload-scans"));
+  IncrementCrashKey(key_enum(), 100);
+  EXPECT_EQ("100", crash_reporter::GetCrashKeyValue(key_string()));
 
-  IncrementCrashKey(ScanningCrashKey::PENDING_FILE_UPLOADS, 100);
-  EXPECT_EQ("200",
-            crash_reporter::GetCrashKeyValue("pending-file-upload-scans"));
+  IncrementCrashKey(key_enum(), 100);
+  EXPECT_EQ("200", crash_reporter::GetCrashKeyValue(key_string()));
 
-  DecrementCrashKey(ScanningCrashKey::PENDING_FILE_UPLOADS, 100);
-  EXPECT_EQ("100",
-            crash_reporter::GetCrashKeyValue("pending-file-upload-scans"));
+  DecrementCrashKey(key_enum(), 100);
+  EXPECT_EQ("100", crash_reporter::GetCrashKeyValue(key_string()));
 
-  DecrementCrashKey(ScanningCrashKey::PENDING_FILE_UPLOADS, 100);
-  EXPECT_TRUE(
-      crash_reporter::GetCrashKeyValue("pending-file-upload-scans").empty());
+  DecrementCrashKey(key_enum(), 100);
+  EXPECT_TRUE(crash_reporter::GetCrashKeyValue(key_string()).empty());
 }
 
-TEST_F(DeepScanningUtilsCrashKeysTest, InvalidModifications) {
+TEST_P(DeepScanningUtilsCrashKeysTest, InvalidModifications) {
   // The crash key value cannot be negative.
-  DecrementCrashKey(ScanningCrashKey::PENDING_TEXT_UPLOADS, 1);
-  EXPECT_TRUE(
-      crash_reporter::GetCrashKeyValue("pending-text-upload-scans").empty());
-  DecrementCrashKey(ScanningCrashKey::PENDING_TEXT_UPLOADS, 100);
-  EXPECT_TRUE(
-      crash_reporter::GetCrashKeyValue("pending-text-upload-scans").empty());
+  DecrementCrashKey(key_enum(), 1);
+  EXPECT_TRUE(crash_reporter::GetCrashKeyValue(key_string()).empty());
+  DecrementCrashKey(key_enum(), 100);
+  EXPECT_TRUE(crash_reporter::GetCrashKeyValue(key_string()).empty());
 
   // The crash key value is restricted to 6 digits. If a modification would
   // exceed it, it is clamped so crashes will indicate that the key was set at a
   // very high value.
-  IncrementCrashKey(ScanningCrashKey::PENDING_TEXT_UPLOADS, 123456789);
-  EXPECT_EQ("999999",
-            crash_reporter::GetCrashKeyValue("pending-text-upload-scans"));
-  IncrementCrashKey(ScanningCrashKey::PENDING_TEXT_UPLOADS, 123456789);
-  EXPECT_EQ("999999",
-            crash_reporter::GetCrashKeyValue("pending-text-upload-scans"));
+  IncrementCrashKey(key_enum(), 123456789);
+  EXPECT_EQ("999999", crash_reporter::GetCrashKeyValue(key_string()));
+  IncrementCrashKey(key_enum(), 123456789);
+  EXPECT_EQ("999999", crash_reporter::GetCrashKeyValue(key_string()));
 }
 #endif  // !BUILDFLAG(USE_CRASH_KEY_STUBS)
 
diff --git a/chrome/browser/speech/speech_recognition_service_browsertest.cc b/chrome/browser/speech/speech_recognition_service_browsertest.cc
index 9201cb63..1708fff 100644
--- a/chrome/browser/speech/speech_recognition_service_browsertest.cc
+++ b/chrome/browser/speech/speech_recognition_service_browsertest.cc
@@ -223,9 +223,15 @@
       test_data_dir_.Append(base::FilePath(soda::kSodaResourcePath))
           .Append(soda::kSodaTestBinaryRelativePath);
 #else
+  base::FilePath soda_test_binary_path =
+      test_data_dir_.Append(base::FilePath(soda::kSodaResourcePath))
+          .Append(soda::kSodaTestBinaryRelativePath);
+  DVLOG(0) << "SODA test path: " << soda_test_binary_path.value().c_str();
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  ASSERT_TRUE(base::PathExists(soda_test_binary_path));
+
   soda_binary_path = GetSodaTestBinaryPath();
   DVLOG(0) << "SODA binary path: " << soda_binary_path.value().c_str();
-  base::ScopedAllowBlockingForTesting allow_blocking;
   ASSERT_TRUE(base::PathExists(soda_binary_path));
 #endif
   g_browser_process->local_state()->SetFilePath(prefs::kSodaBinaryPath,
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index d7417a3..9a6cbd4 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -85,7 +85,6 @@
 #include "components/sync/model/forwarding_model_type_controller_delegate.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_store_service.h"
-#include "components/sync/trusted_vault/standalone_trusted_vault_client.h"
 #include "components/sync_bookmarks/bookmark_sync_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/sync_sessions/session_sync_service.h"
@@ -120,6 +119,8 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/sync/trusted_vault_client_android.h"
+#else
+#include "components/sync/trusted_vault/standalone_trusted_vault_client.h"  // nogncheck
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 07ad0d8..1778101d 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2443,15 +2443,6 @@
       <message name="IDS_IPH_MESSAGE_ADD_TO_HOME_SCREEN_ACTION" desc="The Add button in the in-product help message encouraging users to add a commonly visited webpage to the home screen.">
         Add
       </message>
-      <message name="IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY" desc="The content description for the bottom sheet install UI.">
-        Install this app
-      </message>
-      <message name="IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT" desc="The content description string for a screenshot in the bottom sheet install UI.">
-        Screenshot
-      </message>
-      <message name="IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION" desc="The content description string for the screenshot in the image zoom view.">
-        Screenshot. Tap to close.
-      </message>
       <message name="IDS_IPH_MESSAGE_SHARED_HIGHLIGHTING_TITLE" desc="The title of in-product-help message encouraging users to create highlights.">
         Create a highlighted link like this one?
       </message>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
index 8087e28..df24586 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
@@ -132,6 +132,7 @@
 <translation id="1807246157184219062">밝게</translation>
 <translation id="1810845389119482123">초기 동기화 설정이 완료되지 않음</translation>
 <translation id="1829244130665387512">페이지에서 찾기</translation>
+<translation id="1832459821645506983">예</translation>
 <translation id="1843805151597803366">번역을 개선하려면 Google 검색을 통해 현재 페이지를 사용하세요.</translation>
 <translation id="1856325424225101786">라이트 모드를 재설정하시겠습니까?</translation>
 <translation id="1868024384445905608">이제 Chrome에서 파일을 더 빠르게 다운로드합니다.</translation>
@@ -289,6 +290,7 @@
 <translation id="2718846868787000099">콘텐츠를 기본 언어로 표시하기 위해 방문하는 사이트에서 기본 설정을 확인할 수 있습니다.</translation>
 <translation id="2723001399770238859">오디오</translation>
 <translation id="2728754400939377704">사이트별 정렬</translation>
+<translation id="2732063072010454421">더 나은 음성 검색 환경을 경험해 보세요</translation>
 <translation id="2739256783402597439">2G</translation>
 <translation id="2744248271121720757">단어를 탭하여 즉시 검색하거나 관련 작업을 확인하세요</translation>
 <translation id="2760989362628427051">기기의 어두운 테마 또는 절전 모드가 켜지면 어두운 테마를 사용 설정합니다.</translation>
@@ -835,6 +837,7 @@
 <translation id="587735546353481577">사이트를 팔로우하려면 사이트로 이동해서 Chrome 메뉴를 연 다음 팔로우를 탭합니다.</translation>
 <translation id="5880748256563468367">피드로 이동</translation>
 <translation id="5884076754568147479">작업 처리를 돕기 위해 내가 어시스턴트를 통해 제출한 정보뿐만 아니라 어시스턴트를 이용한 사이트의 URL과 콘텐츠가 Google에 전송됩니다.</translation>
+<translation id="5906513782029855931">사이트의 URL을 알려 주시면 Google 어시스턴트가 작업을 도와드릴 수 있습니다. Chrome 설정에서 어시스턴트를 사용 중지하실 수 있습니다.</translation>
 <translation id="5916664084637901428">사용</translation>
 <translation id="5919204609460789179"><ph name="PRODUCT_NAME" />을(를) 업데이트하여 동기화를 시작합니다.</translation>
 <translation id="5937580074298050696"><ph name="AMOUNT" /> 저장됨</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mn.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mn.xtb
index 7c6d902..7e3a98d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mn.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mn.xtb
@@ -826,6 +826,7 @@
 <translation id="5854512288214985237">Google-д илгээсэн статистик эсвэл гэмтлийн тайлан алга</translation>
 <translation id="5855546874025048181">Боловсронгуй болгох: <ph name="REFINE_TEXT" /></translation>
 <translation id="5857447844686706637">Алдаа гарлаа. Үнэ хянахыг шинэчилж чадсангүй.</translation>
+<translation id="5859968346865909126">Та үүнийг тохиргоонд асаах эсвэл унтраах боломжтой</translation>
 <translation id="5860033963881614850">Идэвхгүй байна</translation>
 <translation id="5860491529813859533">Асаах</translation>
 <translation id="5862731021271217234">Бусад төхөөрөмжөөс чихтэй хуудсаа авахын тулд синкийг асаана уу</translation>
@@ -1100,6 +1101,7 @@
 <translation id="7359002509206457351">Төлбөрийн хэрэгсэлд хандах</translation>
 <translation id="7375125077091615385">Бичих:</translation>
 <translation id="7376560087009844242">Хайхын тулд хүрэхийг ашиглаж байхдаа хуудасны текстээс илүү ихийг багтааснаар та илүү сайн илэрцүүд харж магадгүй. Та үүнийг өөрчлөхийн тулд хүссэн үедээ <ph name="BEGIN_LINK" />тохиргоонд<ph name="END_LINK" /> зочлох боломжтой.</translation>
+<translation id="7379900596734708416">Сайтуудад зориулсан Бараан загвар боломжтой байна</translation>
 <translation id="7386842512861524348">Chrome сайтын холболтыг аюултай байна гэж хэлээгүйгээс бусад тохиолдолд энэ нь аюулгүй байна.</translation>
 <translation id="7396940094317457632"><ph name="FILE_NAME" />.</translation>
 <translation id="7400418766976504921">URL</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_sk.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_sk.xtb
index eb87510..6eea7d60 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_sk.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_sk.xtb
@@ -132,6 +132,7 @@
 <translation id="1807246157184219062">Svetlý režim</translation>
 <translation id="1810845389119482123">Úvodné nastavenie synchronizácie nebolo dokončené</translation>
 <translation id="1829244130665387512">Nájsť na stránke</translation>
+<translation id="1832459821645506983">Áno, súhlasím</translation>
 <translation id="1843805151597803366">V záujme lepších prekladov umožnite Vyhľadávaniu Google používať aktuálnu stránku</translation>
 <translation id="1856325424225101786">Chcete zjednodušený režim obnoviť?</translation>
 <translation id="1868024384445905608">Chrome teraz sťahuje súbory rýchlejšie</translation>
@@ -289,6 +290,7 @@
 <translation id="2718846868787000099">Weby, ktoré navštevujete, môžu vidieť vaše predvoľby a zobrazovať tak obsah vo vašich preferovaných jazykoch.</translation>
 <translation id="2723001399770238859">zvuk</translation>
 <translation id="2728754400939377704">Zoradiť podľa webu</translation>
+<translation id="2732063072010454421">Získajte lepšie hlasové vyhľadávanie</translation>
 <translation id="2739256783402597439">2G</translation>
 <translation id="2744248271121720757">Klepnutím na slovo aktivujete dynamické vyhľadávanie alebo zobrazíte súvisiace akcie</translation>
 <translation id="2760989362628427051">Zapnúť tmavý motív, keď je v zariadení zapnutý tmavý motív alebo šetrič batérie</translation>
@@ -835,6 +837,7 @@
 <translation id="587735546353481577">Ak chcete sledovať určitý web, prejdite naň, otvorte Ponuku Chrome a klepnite na Sledovať.</translation>
 <translation id="5880748256563468367">Prejsť na feed</translation>
 <translation id="5884076754568147479">Google bude dostávať webové adresy a obsah webov, kde používate Asistenta, ako aj informácie, ktoré prostredníctvom neho odošlete, aby vám mohol pomáhať s dokončovaním úloh</translation>
+<translation id="5906513782029855931">Keď bude Asistent Google poznať webové adresy, bude vám môcť pomáhať s plnením úloh. Asistenta môžete vypnúť v nastaveniach Chromu.</translation>
 <translation id="5916664084637901428">Zapnuté</translation>
 <translation id="5919204609460789179">Ak chcete spustiť synchronizáciu, aktualizujte aplikáciu <ph name="PRODUCT_NAME" /></translation>
 <translation id="5937580074298050696">Ušetrené: <ph name="AMOUNT" /></translation>
diff --git a/chrome/browser/ui/app_list/search/files/file_result.cc b/chrome/browser/ui/app_list/search/files/file_result.cc
index 741967f..8d0433a 100644
--- a/chrome/browser/ui/app_list/search/files/file_result.cc
+++ b/chrome/browser/ui/app_list/search/files/file_result.cc
@@ -150,9 +150,16 @@
                                ash::ColorProvider::Get()->IsDarkModeEnabled();
   switch (display_type) {
     case DisplayType::kChip:
-    case DisplayType::kContinue:
       SetChipIcon(ash::GetChipIconForPath(filepath, dark_background));
       break;
+    case DisplayType::kContinue:
+      // For Continue Section, if dark/light mode is disabled, we should use
+      // dark background as default.
+      if (!ash::features::IsDarkLightModeEnabled())
+        SetChipIcon(ash::GetIconForPath(filepath, /*dark_background=*/true));
+      else
+        SetChipIcon(ash::GetChipIconForPath(filepath, dark_background));
+      break;
     case DisplayType::kList:
       SetIcon(IconInfo(ash::GetIconForPath(filepath, dark_background)));
       break;
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc
index 50bff81e..37a96f2 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc
@@ -75,7 +75,8 @@
 };
 
 // https://crbug.com/1087875: Flaky on Linux and Mac.
-#if defined(OS_MAC) || defined(OS_LINUX)
+// TODO(crbug.com/1278361): Flaky on lacros.
+#if defined(OS_MAC) || defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #define MAYBE_NotifyFullscreenAcquired DISABLED_NotifyFullscreenAcquired
 #else
 #define MAYBE_NotifyFullscreenAcquired NotifyFullscreenAcquired
diff --git a/chrome/browser/ui/hid/hid_chooser_controller.cc b/chrome/browser/ui/hid/hid_chooser_controller.cc
index 3c2f34ab..f976dcb 100644
--- a/chrome/browser/ui/hid/hid_chooser_controller.cc
+++ b/chrome/browser/ui/hid/hid_chooser_controller.cc
@@ -50,10 +50,12 @@
           IDS_HID_CHOOSER_PROMPT_EXTENSION_NAME)),
       filters_(std::move(filters)),
       callback_(std::move(callback)),
-      origin_(content::WebContents::FromRenderFrameHost(render_frame_host)
-                  ->GetMainFrame()
-                  ->GetLastCommittedOrigin()),
+      origin_(render_frame_host->GetMainFrame()->GetLastCommittedOrigin()),
       frame_tree_node_id_(render_frame_host->GetFrameTreeNodeId()) {
+  // The use above of GetMainFrame is safe as content::HidService instances are
+  // not created for fenced frames.
+  DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
+
   auto* web_contents =
       content::WebContents::FromRenderFrameHost(render_frame_host);
   auto* profile =
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 2059d1c..dc640758 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -322,8 +322,10 @@
           PageContentAnnotationsServiceFactory::GetForProfile(profile);
   if (page_content_annotations_service) {
     optimization_guide::PageContentAnnotationsWebContentsObserver::
-        CreateForWebContents(web_contents, page_content_annotations_service,
-                             TemplateURLServiceFactory::GetForProfile(profile));
+        CreateForWebContents(
+            web_contents, page_content_annotations_service,
+            TemplateURLServiceFactory::GetForProfile(profile),
+            OptimizationGuideKeyedServiceFactory::GetForProfile(profile));
   }
   OutOfMemoryReporter::CreateForWebContents(web_contents);
   chrome::InitializePageLoadMetricsForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/location_bar/permission_chip.cc b/chrome/browser/ui/views/location_bar/permission_chip.cc
index b870ac3..71142d79 100644
--- a/chrome/browser/ui/views/location_bar/permission_chip.cc
+++ b/chrome/browser/ui/views/location_bar/permission_chip.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/views/permission_bubble/permission_prompt_style.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/permissions/features.h"
@@ -123,6 +124,9 @@
   if (!should_start_open_) {
     GetViewAccessibility().AnnounceText(l10n_util::GetStringUTF16(
         IDS_PERMISSIONS_REQUESTED_SCREENREADER_ANNOUNCEMENT));
+#if defined(OS_MAC)
+    NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
+#endif
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 458666f5..fa8fdbe7 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -923,7 +923,7 @@
   cookie_manager->GetCookieList(
       GaiaUrls::GetInstance()->gaia_url(),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain::Todo(),
+      net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(&EnrollmentScreenHandler::OnGetCookiesForCompleteLogin,
                      weak_ptr_factory_.GetWeakPtr(), user));
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc b/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc
index eb8dbb6..8a749ec 100644
--- a/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc
+++ b/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc
@@ -208,7 +208,7 @@
       net::CookieOptions::MakeAllInclusive();
   cookie_manager->GetCookieList(
       GaiaUrls::GetInstance()->gaia_url(), cookie_options,
-      net::CookiePartitionKeychain::Todo(),
+      net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(&OnlineLoginHelper::OnGetCookiesForCompleteAuthentication,
                      weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/testapi/oobe_test_api_handler.cc b/chrome/browser/ui/webui/chromeos/login/testapi/oobe_test_api_handler.cc
index 561a4b5..7ee1fd8 100644
--- a/chrome/browser/ui/webui/chromeos/login/testapi/oobe_test_api_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/testapi/oobe_test_api_handler.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/testapi/oobe_test_api_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "build/branding_buildflags.h"
+#include "chrome/browser/ash/login/helper.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
+#include "chrome/browser/ash/login/screens/network_screen.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
@@ -38,6 +41,10 @@
 void OobeTestAPIHandler::Initialize() {}
 
 void OobeTestAPIHandler::GetAdditionalParameters(base::DictionaryValue* dict) {
+  login::NetworkStateHelper helper_;
+  dict->SetBoolean("testapi_shouldSkipNetworkFirstShow",
+                   features::IsOobeNetworkScreenSkipEnabled() &&
+                       helper_.IsConnectedToEthernet());
   dict->SetBoolean(
       "testapi_shouldSkipEula",
       policy::EnrollmentRequisitionManager::IsRemoraRequisition() ||
diff --git a/chrome/browser/ui/webui/settings/privacy_review_handler_unittest.cc b/chrome/browser/ui/webui/settings/privacy_review_handler_unittest.cc
index b474632..3d3cb8d 100644
--- a/chrome/browser/ui/webui/settings/privacy_review_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/privacy_review_handler_unittest.cc
@@ -89,12 +89,29 @@
   }
 };
 
-TEST_F(PrivacyReviewHandlerDisabledTest, IsPrivacyReviewAvailable) {
+// TODO(crbug.com/1277422): Flaky on Linux TSan Tests as one particular instance
+// of crbug/crbug.com/1275502.
+#if defined(THREAD_SANITIZER)
+#define MAYBE_IsDisabledPrivacyReviewAvailable \
+  DISABLED_IsDisabledPrivacyReviewAvailable
+#else
+#define MAYBE_IsDisabledPrivacyReviewAvailable IsDisabledPrivacyReviewAvailable
+#endif
+TEST_F(PrivacyReviewHandlerDisabledTest,
+       MAYBE_IsDisabledPrivacyReviewAvailable) {
   // Privacy review is not available when the experimental flag is disabled.
   ValidateIsPrivacyReviewAvailable(false);
 }
 
-TEST_F(PrivacyReviewHandlerEnabledTest, IsPrivacyReviewAvailable) {
+// TODO(crbug.com/1277422): Flaky on Linux TSan Tests as one particular instance
+// of crbug/crbug.com/1275502.
+#if defined(THREAD_SANITIZER)
+#define MAYBE_IsEnabledPrivacyReviewAvailable \
+  DISABLED_IsEnabledPrivacyReviewAvailable
+#else
+#define MAYBE_IsEnabledPrivacyReviewAvailable IsEnabledPrivacyReviewAvailable
+#endif
+TEST_F(PrivacyReviewHandlerEnabledTest, MAYBE_IsEnabledPrivacyReviewAvailable) {
   // Privacy review is available when the experimental flag is enabled.
   ValidateIsPrivacyReviewAvailable(true);
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc
index 6fa48ec..c0a2af2 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -162,7 +162,7 @@
   partition->GetCookieManagerForBrowserProcess()->GetCookieList(
       GaiaUrls::GetInstance()->gaia_url(),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain::Todo(),
+      net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(&InlineLoginHandler::HandleCompleteLoginMessageWithCookies,
                      weak_ptr_factory_.GetWeakPtr(),
                      base::ListValue(args->GetList())));
diff --git a/chrome/browser/webapps/android/BUILD.gn b/chrome/browser/webapps/android/BUILD.gn
index ed1fc75..718161f 100644
--- a/chrome/browser/webapps/android/BUILD.gn
+++ b/chrome/browser/webapps/android/BUILD.gn
@@ -5,41 +5,12 @@
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
 
-source_set("android") {
-  sources = [
-    "pwa_bottom_sheet_controller.cc",
-    "pwa_bottom_sheet_controller.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chrome/browser/webapps/android:jni_headers",
-    "//components/url_formatter:url_formatter",
-    "//components/webapps/browser",
-    "//content/public/browser:browser",
-    "//services/device/public/mojom",
-    "//skia",
-    "//third_party/blink/public/common:common",
-  ]
-}
-
 android_library("java") {
   resources_package = "org.chromium.chrome.browser.webapps"
 
-  sources = [
-    "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java",
-    "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenIPHController.java",
-    "java/src/org/chromium/chrome/browser/webapps/ImageZoomView.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java",
-  ]
+  sources = [ "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenIPHController.java" ]
 
   deps = [
-    ":java_resources",
-    ":jni_headers",
     "//base:base_java",
     "//chrome/browser/feature_engagement:java",
     "//chrome/browser/flags:java",
@@ -48,7 +19,6 @@
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//chrome/browser/user_education:java",
-    "//components/browser_ui/bottomsheet/android:java",
     "//components/browser_ui/styles/android:java_resources",
     "//components/embedder_support/android:util_java",
     "//components/feature_engagement:feature_engagement_java",
@@ -57,7 +27,6 @@
     "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
-    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/androidx:androidx_vectordrawable_vectordrawable_java",
     "//ui/android:ui_no_recycler_view_java",
     "//url:gurl_java",
@@ -65,24 +34,3 @@
 
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
-
-generate_jni("jni_headers") {
-  sources = [
-    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java",
-    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java",
-  ]
-}
-
-android_resources("java_resources") {
-  sources = [
-    "java/res/layout/image_zoom_view.xml",
-    "java/res/layout/pwa_install_bottom_sheet_content.xml",
-    "java/res/layout/pwa_install_bottom_sheet_toolbar.xml",
-    "java/res/values/dimens.xml",
-  ]
-  deps = [
-    "//chrome/android:chrome_app_java_resources",
-    "//chrome/browser/ui/android/strings:ui_strings_grd",
-    "//components/webapk/android/libs/common:splash_resources",
-  ]
-}
diff --git a/chrome/browser/webapps/android/java/res/values/dimens.xml b/chrome/browser/webapps/android/java/res/values/dimens.xml
deleted file mode 100644
index 688f457..0000000
--- a/chrome/browser/webapps/android/java/res/values/dimens.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- Copyright 2020 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources xmlns:tools="http://schemas.android.com/tools">
-    <dimen name="webapk_screenshot_margin">16dp</dimen>
-</resources>
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 87c3f351..6895834 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1639040057-52c810d54983c91d0e44692d384d033b589c8747.profdata
+chrome-win32-main-1639049961-2ff45e97ac172b985b6dac9bd6c6ad36a6153f55.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index a6b3dd1..385d6027 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1639040057-6c5ba69d141dc31c51719a6fb93a4e58e2c284a4.profdata
+chrome-win64-main-1639049961-75dbff4b1121f5cdeb9014ee500099cb917e90ed.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 6c26f0e..cf07780 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -9001,7 +9001,6 @@
     "//components/sync:test_support_model",
     "//components/sync:test_support_nigori",
     "//components/sync/test/fake_server",
-    "//components/sync/trusted_vault:test_support",
     "//content/public/browser",
     "//content/test:test_support",
     "//net",
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 2924638c..86aa8df 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -501,7 +501,7 @@
     net::CookieList cookie_list;
     storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
         url, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(GetCookieCallback, loop.QuitClosure(), &cookie_list));
     loop.Run();
 
diff --git a/chrome/test/chromedriver/support/release/README.md b/chrome/test/chromedriver/support/release/README.md
index 40343c4..ee4ea37 100644
--- a/chrome/test/chromedriver/support/release/README.md
+++ b/chrome/test/chromedriver/support/release/README.md
@@ -1,43 +1,257 @@
-This directory contains scripts used by ChromeDriver team to make public
-releases of ChromeDriver.
+# ChromeDriver Release Tools
 
-The following steps are involved:
+This directory contains scripts and templates needed for ChromeDriver release process.
+Script `nest` is an umbrella script routing user commands to the appropriate
+`nest-${command}` script.
+You don't need to execute the other scripts directly.
 
-* Go to the following URL to review bugs fixed in the release, replacing the
+TIP: Add this directory to your `PATH` environmental variable and enjoy out
+of source release process.
+Alternatively you can symlink `nest` into a directory
+that is already in your `PATH`.
+
+NOTE: The scripts can run on Linux platform only!
+
+Directory [templates](templates) contains the following templates
+used for release announcements:
+
+* [template1.html](templates/template1.html),
+  [template2.html](templates/template2.html) -
+  release announcement email templates for one or two versions of ChromeDriver respectively.
+* [parametrized_change_list.html](templates/parametrized_change_list.html) -
+  change list template parametrized with ChromeDriver version.
+  It looks as follows in the generated email:
+
+  ```
+  Changes in version 95 of ChromeDriver include:
+
+  ${LI_LIST}
+  ```
+
+  where `${LI_LIST}` is the actual release note list for the given version.
+  We use this template while announcing a release of two versions simultaneously.
+* [static_change_list.html](templates/static_change_list.html) -
+  change list template that does not mention ChromeDriver version.
+  It looks as follows in the generated email:
+
+  ```
+  Changes in this version of ChromeDriver include:
+
+  ${LI_LIST}
+  ```
+
+  where `${LI_LIST}` is the actual release note list.
+  We use this template for single version release announcement.
+* [li.html](templates/li.html) - template for release note entry in
+  release announcement email.
+  The actual release note replaces `${LI_TEXT}` macro in the template.
+* [template1.txt](templates/template1.txt),
+  [template2.txt](templates/template2.txt) -
+  templates for *text/plain* part of release announcement email.
+* [blog_home_template1.md](templates/blog_home_template1.md),
+  [blog_home_template2.md](templates/blog_home_template2.md) -
+  templates for release announcement at
+  [Home](https://chromedriver.chromium.org/)
+  page of ChromeDriver site.
+* [blog_download_template1.md](templates/blog_download_template1.md),
+  [blog_download_template2.md](templates/blog_download_template2.md) -
+  templates for release announcement at
+  [Downloads](https://chromedriver.chromium.org/downloads)
+  page of ChromeDriver site.
+
+
+## Releasing a new version of ChromeDriver
+
+NOTE: We assume that path to `nest` is in your `PATH` variable.
+
+You need to execute the following steps:
+
+1. Go to the following URL to review bug fixed in the release, replacing the
   trailing 81 with actual ChromeDriver major version number:
 
   https://crbug.com/chromedriver?can=1&sort=id&q=label:ChromeDriver-81
 
-* After reviewing the above page and making and necessary updates, click on the
-  "CSV" link near the lower-right corner to download the bug list to
-  ~/Download/chromedriver-issues.csv.
+1. After reviewing the above page and making all the necessary updates, click on the
+  `CSV` link near the lower-right corner to download the bug list to
+  `~/Download/chromedriver-issues.csv`.
 
-* Run Python script `release_notes.py` to generate release notes. It requires
-  one command line argument, which is the full
+1. Switch to any empty directory.
+
+1. Generate release notes executing
+
+  ```bash
+  nest note ${version}`
+  ```
+
+  where `${version}` is the full
   [4-part version number](https://www.chromium.org/developers/version-numbers)
   of the new release.
-  The script is hardcoded to read ~/Download/chromedriver-issues.csv,
-  and save the resulting file in notes.txt in the current directory.
+  The script reads `~/Download/chromedriver-issues.csv`,
+  and saves the resulting file in `notes\_${version}.txt` of the current directory.
 
-* Run shell script `release.sh` to copy ChromeDriver binaries and release notes
-  to the release web site. This script takes one argument, the full 4-part
-  version number of the new release.
+1. Copy ChromeDriver binaries and release notes to the release web site.
 
-* Check
+   ```bash
+  nest cut-out ${release_type} ${version}
+  ```
+
+  The first argument `${release_type}` is the release type: *stable* or *beta*.
+  The second argument `${version}` is the full 4-part version number of the new release.
+  Make sure that this command finishes with message **Success!!!**.
+
+1. In case if you want to release and announce two versions in one shot you need to repeat
+  the steps above again.
+
+1. Generate the release announcements.
+
+  ```bash
+  nest announce
+  ```
+
+  They will be written by the script to the following files:
+
+  * `./blog_home.md` - contains messages for pasting to
+    [Home](https://chromedriver.chromium.org/) page of ChromeDriver site.
+  * `./blog_downloads.md` - contains messages for pasting to
+    [Downloads](https://chromedriver.chromium.org/downloads) page of ChromeDriver site.
+  * `./announcement.eml` - announcement email.
+    You can send it via Thunderbird or copy/paste it to your email client.
+
+  This script is able to recognize whether you want to announce one or two
+  versions and it will generate the aforementioned files correctly combining
+  all the needed information.
+
+1. Check
   [chromedriver storage site](https://chromedriver.storage.googleapis.com/index.html)
-  to verify binaries have been released
+  to verify binaries have been released.
 
-Notes:
 
-* If you encounter error that gsutil can't be found, install it with:
+## Troubleshooting
 
-    sudo apt-get install google-cloud-sdk
+* If you encounter error that `gsutil` can't be found, install it with:
+
+  ```bash
+  sudo apt-get install google-cloud-sdk
+  ```
 
 * If you encounter permission errors from gsutil, run the following command and
   login with an account that has permission to update gs://chromedriver.
 
-    gcloud auth login
+  ```bash
+  gcloud auth login
+  ```
 
 * If `LATEST_RELEASE` file needs updating, it can be done manually, e.g.,
 
-    gsutil cp gs://chromedriver/LATEST_RELEASE_81 gs://chromedriver/LATEST_RELEASE
+  ```bash
+  gsutil cp gs://chromedriver/LATEST_RELEASE_81 gs://chromedriver/LATEST_RELEASE
+  ```
+
+
+## Development
+
+For convenience of development and troubleshooting `nest cut-out` can be
+executed by parts:
+
+1. Create a working directory for the release process.
+
+  ```bash
+  nest create ${release_type} ${version}
+  ```
+
+  The first argument `${release_type}` is the release type: *stable* or *beta*.
+  The second argument `${version}` is the full 4-part version number of the new release.
+  You can also use two shortcuts for this command:
+
+  ```bash
+  nest stable ${version}
+  nest beta ${version}
+  ```
+
+1. Descend to the directory created above.
+
+  ```bash
+  cd ${version}
+  ```
+
+1. Download the binaries that need to be published.
+
+  ```bash
+  nest pull
+  ```
+
+  The archives are placed into `crome-unsigned` folder.
+  In the same step they are extracted to `unzipped` folder.
+
+1. Create the archives that need to be published,
+  gather all the information needed for release in folder `packed`.
+
+  ```bash
+  nest pack [--notes=path-to-release-notes]
+  ```
+
+  If you omit `--notes` argument the script tries to find the rlease notes under
+  the release working directory, named as `${version}`, and one level above it.
+  This step also verifies that the release notes indeed refer the version being
+  prepared.
+
+1. Publish the release prepared in folder `packed`.
+
+  ```bash
+  nest push
+  ```
+
+  If the release is *stable* then this script also updates
+  gs://chromedriver/LATEST_RELEASE accordingly.
+
+1. Pull the released binaries and notes and compare their hashes
+  with the binaries in `unzipped` folder and the notes in `packed` folders.
+
+  ```bash
+  nest verify
+  ```
+
+## How to update the templates
+
+This task is performed manually as follows:
+
+1. Update the announcement letter text in
+  [ChromeDriver Release Process](http://go/chromedriver-release-process).
+1. Copy it and paste it with the command
+
+  ```bash
+  xclip -selection c -o -t text/html > templates/template2.html
+  ```
+
+1. Extract the \<li\>..\</li\> part into [templates/li.html](templates/li.html).
+  Replace it with `${LI_LIST}` in [templates/template2.html](templates/template2.html)
+
+1. Extract the block containing text *"Changes in version ${MAJOR}..."* and the
+   following \<ul\>..\</ul\> into
+   [templates/parametrized_change_list.html](templates/parametrized_change_list.html)
+   and replace them with macro `${CHANGE_LIST}` in [templates/template2.html](templates/template2.html).
+
+1. Copy [templates/parametrized_change_list.html](templates/parametrized_change_list.html)
+  to [templates/static_change_list.html](templates/static_change_list.html)
+  and change the text in the destination accordingly.
+
+1. Copy [templates/template2.html](templates/template2.html)
+  to [templates/template1.html](templates/template1.html)
+  and change the text in the destination accordingly:
+  * Remove any mentions of `${VERSION2}`, `${MAJOR2}`, `${TYPE2}`, `${KIND2}`.
+  * Give attention to replacing plural forms of words with singular forms.
+
+1. Copy [templates/template2.html](templates/template2.html)
+  as plain text into [templates/template2.txt](templates/template2.txt)
+
+1. Copy [templates/template1.html](templates/template1.html)
+  as plain text into [templates/template1.txt](templates/template1.txt)
+
+The templates in
+[templates/blog_home_template1.md](templates/blog_home_template1.md),
+[templates/blog_home_template2.md](templates/blog_home_template2.md),
+[templates/blog_download_template1.md](templates/blog_download_template1.md),
+and  [templates/blog_download_template2.md](templates/blog_download_template2.md)
+are not related to [ChromeDriver Release Process](http://go/chromedriver-release-process).
+You can update them directly without any copy/paste.
+
diff --git a/chrome/test/chromedriver/support/release/common.sh b/chrome/test/chromedriver/support/release/common.sh
new file mode 100644
index 0000000..a46f274
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/common.sh
@@ -0,0 +1,28 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Common functions to be used by ChromeDriver publishing utilities
+
+
+function ensure_linux {
+  if [[ $(uname -s) != Linux* ]]
+  then
+    echo Please run $1 on Linux
+    exit 1
+  fi
+}
+
+function ensure_release_root {
+  if [ ! -f '.version' ]
+  then
+    echo "File not found .version" >&2
+    exit 1
+  fi
+
+  if [ ! -f '.type' ]
+  then
+    echo "File not found .type" >&2
+    exit 1
+  fi
+}
diff --git a/chrome/test/chromedriver/support/release/nest b/chrome/test/chromedriver/support/release/nest
new file mode 100755
index 0000000..1dd1f0d
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Umbrella script serving as a common entry point to the other ChromeDriver
+# release related scripts.
+
+command=$1
+shift
+
+$(dirname $(realpath "$0"))/nest-$command $@
diff --git a/chrome/test/chromedriver/support/release/nest-announce b/chrome/test/chromedriver/support/release/nest-announce
new file mode 100755
index 0000000..f01ed91
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-announce
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+# 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.
+#
+# Script for preparing of new ChromeDriver release announcement.
+
+from email.generator import Generator
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+import os
+import os.path as path
+import re
+import sys
+import html
+
+
+script_dir = path.dirname(path.realpath(sys.argv[0]))
+templates_dir =  path.join(script_dir, 'templates')
+
+def version_to_intlist(version):
+  return list(map(lambda x: int(x), version.split('.')))
+
+def read_file(file_path):
+  with open(file_path, 'r') as f:
+    return f.read()
+
+def save_file(content, file_path):
+  with open(file_path, 'w') as f:
+    return f.write(content)
+
+def read_and_trim(file_path):
+  return re.sub(r'^\s+|\s+$', '', read_file(file_path))
+
+def extract_data(build_name):
+  build_path = path.join(os.curdir, build_name)
+  return {'path': build_path,
+          'version': read_and_trim(path.join(build_path, '.version')),
+          'type': read_and_trim(path.join(build_path, '.type'))
+          };
+
+def read_notes(data):
+  pub_path = path.join(data['path'], 'published')
+  notes_path = path.join(pub_path, 'notes.txt')
+  with open(notes_path, 'r') as f:
+    lines = f.readlines()
+    return list(filter(lambda line: line.startswith('Resolved'), lines))
+
+def create_html_notes(data):
+  result = ''
+  li_template = read_file(path.join(templates_dir, 'li.html'))
+  static_template = read_file(path.join(templates_dir, 'static_change_list.html'))
+  parametrized_template = read_file(path.join(templates_dir, 'parametrized_change_list.html'))
+  if (len(data) > 1):
+    for k in [0, 1]:
+      lines = read_notes(data[k])
+      if (len(lines) > 0):
+        major = version_to_intlist(data[k]['version'])[0]
+        template = parametrized_template.replace('${MAJOR}', str(major))
+        lines = map(lambda line: li_template.replace('${LI_TEXT}', html.escape(line)), lines)
+        result += template.replace('${LI_LIST}', ''.join(lines))
+  else:
+    lines = read_notes(data[0])
+    if (len(lines) > 0):
+      lines = map(lambda line: li_template.replace('${LI_TEXT}', html.escape(line)), lines)
+      result += static_template.replace('${LI_LIST}', ''.join(lines))
+  return result
+
+def create_plain_notes(data):
+  result = ''
+  if (len(data) > 1):
+    for k in [0, 1]:
+      lines = read_notes(data[k])
+      if (len(lines) > 0):
+        lines = map(lambda line: ' * ' + line, lines)
+        result += '\nChanges in version %s of ChromeDriver include:\n%s' % (data[k]['version'], '\n'.join(lines));
+  else:
+    lines = read_notes(data[0])
+    if (len(lines) > 0):
+      lines = map(lambda line: ' * ' + line, lines)
+      result += '\nChanges in this version of ChromeDriver include:\n%s' % ('\n'.join(lines));
+  return result
+
+def extract_raw_notes(data):
+  result = ''
+  lines = read_notes(data)
+  if (len(lines) > 0):
+    lines = map(lambda line: ' * ' + line, lines)
+    result += '\n'.join(lines);
+  return result
+
+
+def main(build_names):
+  data = list(map(lambda build_name: extract_data(build_name), build_names))
+  data = sorted(data, key = lambda x: version_to_intlist(x['version']))
+
+  if len(data) == 0 or len(data) > 2:
+    print("Release announcement can be written only for 1 or 2 ChromeDriver versions", file=sys.stderr)
+    exit(1)
+
+  v1 = data[0]['version']
+  t1 = data[0]['type']
+  m1 = str(version_to_intlist(v1)[0])
+  v2 = data[1]['version'] if len(data) > 1 else '???'
+  t2 = data[1]['type'] if len(data) > 1 else '???'
+  m2 = str(version_to_intlist(v2)[0]) if len(data) > 1 else '???'
+
+  substitutions = {
+      '${VERSION}': v1,
+      '${VERSION1}': v1,
+      '${VERSION2}': v2,
+      '${type}': t1,
+      '${type1}': t1,
+      '${type2}': t2,
+      '${TYPE}': 'Stable' if t1 == 'stable' else 'Beta',
+      '${TYPE1}': 'Stable' if t1 == 'stable' else 'Beta',
+      '${TYPE2}': 'Stable' if t2 == 'stable' else 'Beta',
+      '${KIND}': 'current' if t1 == 'stable' else 'upcoming',
+      '${KIND1}': 'current' if t1 == 'stable' else 'upcoming',
+      '${KIND2}': 'current' if t2 == 'stable' else 'upcoming',
+      '${MAJOR}': m1,
+      '${MAJOR1}': m1,
+      '${MAJOR2}': m2,
+      '${NOTES_LINK}': '<a href="https://chromedriver.storage.googleapis.com/%s/notes.txt">release notes %s</a>' % (v1, v1),
+      '${NOTES_LINK1}': '<a href="https://chromedriver.storage.googleapis.com/%s/notes.txt">release notes %s</a>' % (v1, v1),
+      '${NOTES_LINK2}': '<a href="https://chromedriver.storage.googleapis.com/%s/notes.txt">release notes %s</a>' % (v2, v2),
+      '${CHANGE_LIST}': create_html_notes(data),
+  }
+
+  msg = MIMEMultipart('alternative')
+  if (len(data) == 2):
+    msg['Subject'] = 'ChromeDriver %s and %s have been released' % (data[0]['version'], data[1]['version'])
+  else:
+    msg['Subject'] = 'ChromeDriver %s has been released' % (data[0]['version'])
+
+  html = read_file(path.join(templates_dir, 'template' + str(len(data)) + '.html'))
+  for key, value in substitutions.items():
+    html = html.replace(key, value)
+  htmlPart = MIMEText(html, 'html', 'utf-8')
+  msg.attach(htmlPart)
+
+  substitutions['${NOTES_LINK}'] = 'release notes %s <https://chromedriver.storage.googleapis.com/%s/notes.txt>' % (v1, v1)
+  substitutions['${NOTES_LINK1}'] = 'release notes %s <https://chromedriver.storage.googleapis.com/%s/notes.txt>' % (v1, v1)
+  substitutions['${NOTES_LINK2}'] = 'release notes %s <https://chromedriver.storage.googleapis.com/%s/notes.txt>' % (v2, v2)
+  substitutions['${CHANGE_LIST}'] = create_plain_notes(data)
+
+  plain = read_file(path.join(templates_dir, 'template' + str(len(data)) + '.txt'))
+  for key, value in substitutions.items():
+    plain = plain.replace(key, value)
+  plainPart = MIMEText(plain, 'plain', 'utf-8')
+  msg.attach(plainPart)
+
+  with open(path.join(os.curdir, 'announcement.eml'), 'w') as f:
+    gen = Generator(f)
+    gen.flatten(msg)
+
+  substitutions['${RAW_NOTES}'] = extract_raw_notes(data[0])
+  substitutions['${RAW_NOTES1}'] = extract_raw_notes(data[0])
+  if (len(data) > 1):
+    substitutions['${RAW_NOTES2}'] = extract_raw_notes(data[1])
+
+  blog_downloads = read_file(path.join(templates_dir, 'blog_downloads_template' + str(len(data)) + '.md'))
+  for key, value in substitutions.items():
+    blog_downloads = blog_downloads.replace(key, value)
+  save_file(blog_downloads, path.join(os.curdir, 'blog_downloads.md'))
+
+  blog_home = read_file(path.join(templates_dir, 'blog_home_template' + str(len(data)) + '.md'))
+  for key, value in substitutions.items():
+    blog_home = blog_home.replace(key, value)
+  save_file(blog_home, path.join(os.curdir, 'blog_home.md'))
+
+
+if __name__ == '__main__':
+  if len(sys.argv) > 1:
+    dirs = filter(lambda dir: path.exists(path.join(dir, '.version')), sys.argv[1:])
+    dirs = map(lambda dir: re.sub(r'\/+$', '', dir), dirs)
+    main(list(dirs))
+  elif path.exists(path.join(os.curdir, '.version')):
+    main([os.curdir])
+  else:
+    dirs = os.listdir(os.curdir)
+    dirs = filter(lambda dir: path.exists(path.join(dir, '.version')), dirs)
+    main(list(dirs))
diff --git a/chrome/test/chromedriver/support/release/nest-beta b/chrome/test/chromedriver/support/release/nest-beta
new file mode 100755
index 0000000..5a3c204d
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-beta
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for preparing of new ChromeDriver beta release workspace.
+
+$(dirname "$0")/nest-create beta $@
diff --git a/chrome/test/chromedriver/support/release/nest-create b/chrome/test/chromedriver/support/release/nest-create
new file mode 100755
index 0000000..a415bd0
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-create
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for preparing of new ChromeDriver release workspace.
+
+set -eu
+
+source "$(dirname "$0")/common.sh"
+ensure_linux $0
+
+this_script_name="$0"
+release_type="${1:-''}"
+version="${2:-''}"
+
+case "$release_type" in
+  'beta' | 'stable')
+    ;;
+  *)
+    echo "Usage: $this_script_name beta|stable version" >&2
+    exit 1
+    ;;
+esac
+
+mkdir "$version"
+cd "$version"
+echo "$release_type" > '.type'
+echo "$version" > '.version'
diff --git a/chrome/test/chromedriver/support/release/nest-cut-out b/chrome/test/chromedriver/support/release/nest-cut-out
new file mode 100755
index 0000000..c362360
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-cut-out
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for new ChromeDriver release cut out.
+
+set -eu
+
+notes_arg=''
+build_type=''
+version=''
+this_script_dir="$(dirname $(realpath "$0"))"
+
+while [ $# -gt 0 ]
+do
+  case "$1" in
+    stable|beta)
+      build_type="$1"
+      ;;
+    --notes=*)
+      notes_arg="$1"
+      ;;
+    *)
+      version="$1"
+      ;;
+  esac
+  shift
+done
+
+function show_usage {
+  echo "Usage: $0 [--notes=path-to-notes] build-type version" >&2
+}
+
+if [ -z "$build_type" ]
+then
+  echo "Build type is not defined" >&2
+  show_usage
+  exit 1
+fi
+
+if [ -z "$version" ]
+then
+  echo "Version is not defined" >&2
+  show_usage
+  exit 1
+fi
+
+"$this_script_dir/nest" create "$build_type" "$version"
+cd "$version"
+"$this_script_dir/nest" pull
+if [ -z "$notes_arg" ]
+then
+  "$this_script_dir/nest" pack
+else
+  "$this_script_dir/nest" pack "$notes_arg"
+fi
+"$this_script_dir/nest" push
+"$this_script_dir/nest" verify
+
+echo 'Success!!!' >&2
diff --git a/chrome/test/chromedriver/support/release/release_notes.py b/chrome/test/chromedriver/support/release/nest-notes
similarity index 83%
rename from chrome/test/chromedriver/support/release/release_notes.py
rename to chrome/test/chromedriver/support/release/nest-notes
index 41037fb..b48251554 100755
--- a/chrome/test/chromedriver/support/release/release_notes.py
+++ b/chrome/test/chromedriver/support/release/nest-notes
@@ -1,17 +1,18 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2020 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-
+#
 # Script to generate ChromeDriver release notes.
 # Before running this script, download list of fixed issues from
 # https://crbug.com/chromedriver?can=1&sort=id&q=label:ChromeDriver-81
-# to ~/Download/chromedriver-issues.csv. Output is ./notes.txt.
+# to ~/Download/chromedriver-issues.csv. Output is ./notes_${version}.txt.
 
 from __future__ import print_function
 import csv
 import datetime
 import os
+import os.path as path
 import sys
 
 if len(sys.argv) != 2:
@@ -21,10 +22,15 @@
 version = sys.argv[1]
 major_version = version.split('.')[0]
 
-notes_name = 'notes.txt'
+notes_name = 'notes_%s.txt' % version
 
 csv_file = os.path.join(os.getenv('HOME'), 'Downloads',
                         'chromedriver-issues.csv')
+
+if not path.exists(csv_file):
+  print('File not found: %s' % csv_file, file=sys.stderr)
+  exit(1)
+
 f = open(csv_file, 'r')
 lines = f.read().split('\n')
 f.close()
@@ -37,7 +43,7 @@
   if not seen_header:
     if issue[0] == 'ID':
       for i,title in enumerate(issue):
-        if title == 'Pri':
+        if title == 'Pri' or title == 'Priority':
           pri_col = i
         elif title == 'Summary':
           summary_col = i
diff --git a/chrome/test/chromedriver/support/release/nest-pack b/chrome/test/chromedriver/support/release/nest-pack
new file mode 100755
index 0000000..ca08268
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-pack
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Prepares all the data needed for new ChromeDriver release for sending to the
+# server.
+
+set -eu
+
+source "$(dirname "$0")/common.sh"
+ensure_linux $0
+ensure_release_root
+
+version=$(cat ".version")
+src=unzipped
+tgt=packed
+
+if [ ! -d "$src" -o ! -f "$src/.pulled" -o "$version" != "$(cat $src/.pulled)" ]
+then
+  echo "Nothing to pack in $0. Command 'nest pull' needs to be executed first!" >&2
+  exit 1
+fi
+
+rm -rf $tgt
+mkdir $tgt
+
+notes_paths=(
+  "../notes.txt"
+  "../notes_${version}.txt"
+  "./notes.txt"
+  "./notes_${version}.txt"
+  "${src}/notes.txt"
+  "${src}/notes_${version}.txt"
+  )
+
+path_to_notes=""
+
+for path in ${notes_paths[@]}
+do
+  if [ -f "$path" ]
+  then
+    path_to_notes="$path"
+  fi
+done
+
+while [ "$#" -gt 0 ]
+do
+  case "$1" in
+    --notes=*)
+      path_to_notes=$(echo "$1" | sed -r 's#--notes=##')
+      ;;
+  esac
+  shift
+done
+
+if [ ! -f "$path_to_notes" ]
+then
+  echo "Notes file not found: $path_to_notes" >&2
+  echo "Usage: $0 [--notes=path-to-notes]" >&2
+  exit 1
+fi
+
+if ! grep -Eq "ChromeDriver\s+$version" "$path_to_notes"
+then
+  echo "Error in $0. Notes file refers to different version than $version in $path_to_notes" >&2
+  exit 1
+fi
+
+
+zip -j $tgt/chromedriver_linux64.zip $src/chromedriver_linux64/chromedriver
+zip -j $tgt/chromedriver_mac64.zip $src/chromedriver_mac64/chromedriver
+zip -j $tgt/chromedriver_mac64_m1.zip $src/chromedriver_mac64_m1/chromedriver_mac64/chromedriver
+zip -j $tgt/chromedriver_win32.zip $src/chromedriver_win32/chromedriver.exe
+echo -n "$version" > $tgt/latest
+cp "$path_to_notes" "$tgt/notes.txt"
diff --git a/chrome/test/chromedriver/support/release/nest-pull b/chrome/test/chromedriver/support/release/nest-pull
new file mode 100755
index 0000000..54d0439
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-pull
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for copying of ChromeDriver from chrome-unsigned bucket to to the local
+# workspace.
+
+set -eu
+
+source "$(dirname "$0")/common.sh"
+ensure_linux $0
+ensure_release_root
+
+version=$(cat ".version")
+src=chrome-unsigned
+tgt=unzipped
+
+rm -rf $src
+rm -rf $tgt
+rm -rf $tgt/chromedriver_linux64
+rm -rf $tgt/chromedriver_mac64
+rm -rf $tgt/chromedriver_mac64_m1
+rm -rf $tgt/chromedriver_win32
+
+mkdir $src
+mkdir $tgt
+mkdir $tgt/chromedriver_mac64_m1
+
+gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/linux64/chromedriver_linux64.zip $src
+gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/mac64/chromedriver_mac64.zip $src
+gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/mac-arm64/chromedriver_mac64.zip $src/chromedriver_mac64_m1.zip
+gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/win-clang/chromedriver_win32.zip $src
+
+unzip $src/chromedriver_linux64.zip -d $tgt
+unzip $src/chromedriver_mac64.zip -d $tgt
+unzip $src/chromedriver_mac64_m1.zip -d $tgt/chromedriver_mac64_m1/
+unzip $src/chromedriver_win32.zip -d $tgt
+
+# TODO: Remove this line after verifying strip has no effect
+strip -p $tgt/chromedriver_linux64/chromedriver
+
+echo "$version" > $tgt/.pulled
diff --git a/chrome/test/chromedriver/support/release/nest-push b/chrome/test/chromedriver/support/release/nest-push
new file mode 100755
index 0000000..d90ac46
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-push
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for copying of ChromeDriver from local workspace to chromedriver
+# bucket.
+
+set -eu
+
+source "$(dirname "$0")/common.sh"
+ensure_linux $0
+ensure_release_root
+
+version=$(cat ".version")
+release_type=$(cat ".type")
+src=packed
+
+if [ ! -d "$src" -o ! -f "$src/latest" -o "$version" != "$(cat $src/latest)" ]
+then
+  echo "Nothing to publish in $0. Command 'nest pack' needs to be executed first!" >&2
+  exit 1
+fi
+
+
+## Uncomment this code if you wan't to debug the script without sending anything to the server
+#function gsutil {
+#  echo "gsutil $@" >&2
+#  echo "1.2.4664.45"
+#}
+#export -f gsutil
+
+gsutil cp $src/chromedriver_linux64.zip gs://chromedriver/$version/chromedriver_linux64.zip
+gsutil cp $src/chromedriver_mac64.zip gs://chromedriver/$version/chromedriver_mac64.zip
+gsutil cp $src/chromedriver_mac64_m1.zip gs://chromedriver/$version/chromedriver_mac64_m1.zip
+gsutil cp $src/chromedriver_win32.zip gs://chromedriver/$version/chromedriver_win32.zip
+
+build=`echo $version | sed -E 's/\.[0-9]+$//'`
+major=`echo $version | sed -E 's/\.[0-9.]+$//'`
+gsutil -h Content-Type:text/plain cp "$src/latest" gs://chromedriver/LATEST_RELEASE_$build
+gsutil -h Content-Type:text/plain cp "$src/latest" gs://chromedriver/LATEST_RELEASE_$major
+
+gsutil cp $src/notes.txt gs://chromedriver/$version/notes.txt
+
+function version_is_less {
+  v1="$1"
+  v2="$2"
+  build1="$(echo "$v1" | cut -f3 -d'.')"
+  build2="$(echo "$v2" | cut -f3 -d'.')"
+  patch1="${v1##*.}"
+  patch2="${v2##*.}"
+  if [ "$build1" -lt "$build2" ]
+  then
+    return 0
+  fi
+  if [ "$build1" -gt "$build2" ]
+  then
+    return 1
+  fi
+  [ "$patch1" -lt "$patch2" ]
+}
+
+if [ "$release_type" == 'stable' ]
+then
+  current_version="$(gsutil cat gs://chromedriver/LATEST_RELEASE)"
+  if version_is_less "$current_version" "$version"
+  then
+    gsutil cp gs://chromedriver/LATEST_RELEASE_$major gs://chromedriver/LATEST_RELEASE
+    new_version="$(gsutil cat gs://chromedriver/LATEST_RELEASE)"
+    if [ "$new_version" != "$version" ]
+    then
+      echo "Failed to update LATEST_RELEASE version to $version" >&2
+      exit 1
+    fi
+  fi
+fi
diff --git a/chrome/test/chromedriver/support/release/nest-stable b/chrome/test/chromedriver/support/release/nest-stable
new file mode 100755
index 0000000..cc3f3e1a
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-stable
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Script for preparing of new ChromeDriver stable release workspace.
+
+$(dirname "$0")/nest-create stable $@
diff --git a/chrome/test/chromedriver/support/release/nest-verify b/chrome/test/chromedriver/support/release/nest-verify
new file mode 100755
index 0000000..99e9818
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/nest-verify
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Verify that the package prepared for release is correct.
+
+set -eu
+
+source "$(dirname "$0")/common.sh"
+ensure_linux $0
+ensure_release_root
+
+this_script="$0"
+
+version=$(cat ".version")
+unzipped="unzipped"
+packed="packed"
+published="published"
+
+rm -rf "$published"
+mkdir "$published"
+
+if [ ! -f "$unzipped/.pulled" -o "$version" != "$(cat $unzipped/.pulled)" ]
+then
+  echo "The originals are not found by $0. Execute 'nest pull' first!" >&2
+  exit 1
+fi
+
+if [ ! -f "$packed/latest" -o "$version" != "$(cat $packed/latest)" ]
+then
+  echo "The notes are not found by $0. Execute 'nest pack' first!" >&2
+  exit 1
+fi
+
+gsutil cp gs://chromedriver/$version/chromedriver_linux64.zip $published/chromedriver_linux64.zip
+gsutil cp gs://chromedriver/$version/chromedriver_mac64.zip $published/chromedriver_mac64.zip
+gsutil cp gs://chromedriver/$version/chromedriver_mac64_m1.zip $published/chromedriver_mac64_m1.zip
+gsutil cp gs://chromedriver/$version/chromedriver_win32.zip $published/chromedriver_win32.zip
+gsutil cp gs://chromedriver/$version/notes.txt $published/notes.txt
+unzip $published/chromedriver_linux64.zip -d $published/chromedriver_linux64
+unzip $published/chromedriver_mac64.zip -d $published/chromedriver_mac64
+unzip $published/chromedriver_mac64_m1.zip -d $published/chromedriver_mac64_m1
+unzip $published/chromedriver_win32.zip -d $published/chromedriver_win32
+
+function compare_md5 {
+  path1="$1"
+  path2="$2"
+  if [ ! -f "$path1" ]
+  then
+    echo "File not found by $this_script: $path1" >&2
+    exit 1
+  fi
+  if [ ! -f "$path2" ]
+  then
+    echo "File not found by $this_script: $path2" >&2
+    exit 1
+  fi
+  s1=$(md5sum -b $path1 | cut -f1 -d' ')
+  s2=$(md5sum -b $path2 | cut -f1 -d' ')
+  if [ "$s1" != "$s2" ]
+  then
+    echo "Checksum mismatch between files $path1 and $path2" >&2
+    exit 1
+  fi
+}
+
+compare_md5 "$unzipped/chromedriver_linux64/chromedriver" "$published/chromedriver_linux64/chromedriver"
+compare_md5 "$unzipped/chromedriver_mac64/chromedriver" "$published/chromedriver_mac64/chromedriver"
+compare_md5 "$unzipped/chromedriver_mac64_m1/chromedriver_mac64/chromedriver" "$published/chromedriver_mac64_m1/chromedriver"
+compare_md5 "$unzipped/chromedriver_win32/chromedriver.exe" "$published/chromedriver_win32/chromedriver.exe"
+compare_md5 "$packed/notes.txt" "$published/notes.txt"
+
+if ! grep -Eq "ChromeDriver\s+$version" "$published/notes.txt"
+then
+  echo "Error in $0. Notes file refers to different version than $version in "$published/notes.txt"" >&2
+  exit 1
+fi
diff --git a/chrome/test/chromedriver/support/release/release.sh b/chrome/test/chromedriver/support/release/release.sh
deleted file mode 100755
index b2c44cd..0000000
--- a/chrome/test/chromedriver/support/release/release.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/bash
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Script to release ChromeDriver, by copying it from chrome-unsigned bucket to
-# chromedriver bucket.
-
-if [[ $(uname -s) != Linux* ]]
-then
-  echo Please run release.sh on Linux
-  exit 1
-fi
-
-if [[ $# -ne 1 || -z $1 ]]
-then
-  echo usage: $0 version
-  exit 1
-fi
-
-origdir=`pwd`
-workdir=`mktemp -d`
-if [[ -z $workdir ]]
-then
-  echo Unable to create working directory, exiting
-  exit 1
-fi
-echo Working directory: $workdir
-
-cd $workdir
-if [[ `pwd` != $workdir ]]
-then
-  echo Failed to chdir to working directory, exiting
-  exit 1
-fi
-
-version=$1
-src=from
-tgt=to
-
-rm -rf $src
-rm -rf $tgt
-rm -rf chromedriver_linux64
-rm -rf chromedriver_mac64
-rm -rf chromedriver_mac64_m1
-rm -rf chromedriver_win32
-
-mkdir $src
-mkdir $tgt
-mkdir chromedriver_mac64_m1
-
-gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/linux64/chromedriver_linux64.zip $src
-gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/mac64/chromedriver_mac64.zip $src
-gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/mac-arm64/chromedriver_mac64.zip $src/chromedriver_mac64_m1.zip
-gsutil cp gs://chrome-unsigned/desktop-5c0tCh/$version/win-clang/chromedriver_win32.zip $src
-
-unzip $src/chromedriver_linux64.zip
-unzip $src/chromedriver_mac64.zip
-unzip $src/chromedriver_mac64_m1.zip -d chromedriver_mac64_m1/
-unzip $src/chromedriver_win32.zip
-
-# TODO: Remove this line after verifying strip has no effect
-strip -p chromedriver_linux64/chromedriver
-
-zip -j $tgt/chromedriver_linux64.zip chromedriver_linux64/chromedriver
-zip -j $tgt/chromedriver_mac64.zip chromedriver_mac64/chromedriver
-zip -j $tgt/chromedriver_mac64_m1.zip chromedriver_mac64_m1/chromedriver_mac64/chromedriver
-zip -j $tgt/chromedriver_win32.zip chromedriver_win32/chromedriver.exe
-
-gsutil cp $tgt/chromedriver_linux64.zip gs://chromedriver/$version/chromedriver_linux64.zip
-gsutil cp $tgt/chromedriver_mac64.zip gs://chromedriver/$version/chromedriver_mac64.zip
-gsutil cp $tgt/chromedriver_mac64_m1.zip gs://chromedriver/$version/chromedriver_mac64_m1.zip
-gsutil cp $tgt/chromedriver_win32.zip gs://chromedriver/$version/chromedriver_win32.zip
-
-echo -n $version > latest
-
-build=`echo $version | sed -E 's/\.[0-9]+$//'`
-major=`echo $version | sed -E 's/\.[0-9.]+$//'`
-gsutil -h Content-Type:text/plain cp latest gs://chromedriver/LATEST_RELEASE_$build
-gsutil -h Content-Type:text/plain cp latest gs://chromedriver/LATEST_RELEASE_$major
-
-if [[ -f $origdir/notes.txt ]]
-then
-  gsutil cp $origdir/notes.txt gs://chromedriver/$version/notes.txt
-fi
diff --git a/chrome/test/chromedriver/support/release/templates/blog_downloads_template1.md b/chrome/test/chromedriver/support/release/templates/blog_downloads_template1.md
new file mode 100644
index 0000000..7abd776
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/blog_downloads_template1.md
@@ -0,0 +1,5 @@
+* [ChromeDriver ${VERSION}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION}/)
+
+Supports Chrome version ${MAJOR}
+${RAW_NOTES}
+For more details, please see the [release notes](https://chromedriver.storage.googleapis.com/${VERSION}/notes.txt)
diff --git a/chrome/test/chromedriver/support/release/templates/blog_downloads_template2.md b/chrome/test/chromedriver/support/release/templates/blog_downloads_template2.md
new file mode 100644
index 0000000..8d7f3eacf
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/blog_downloads_template2.md
@@ -0,0 +1,18 @@
+* If you are using Chrome version ${MAJOR2}, please download [ChromeDriver ${VERSION2}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION2}/)
+* If you are using Chrome version ${MAJOR1}, please download [ChromeDriver ${VERSION1}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION1}/)
+
+
+
+[ChromeDriver ${VERSION2}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION2}/)
+
+Supports Chrome version ${MAJOR2}
+${RAW_NOTES2}
+For more details, please see the [release notes](https://chromedriver.storage.googleapis.com/${VERSION2}/notes.txt)
+
+
+
+[ChromeDriver ${VERSION1}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION1}/)
+
+Supports Chrome version ${MAJOR1}
+${RAW_NOTES1}
+For more details, please see the [release notes](https://chromedriver.storage.googleapis.com/${VERSION1}/notes.txt)
diff --git a/chrome/test/chromedriver/support/release/templates/blog_home_template1.md b/chrome/test/chromedriver/support/release/templates/blog_home_template1.md
new file mode 100644
index 0000000..4722927
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/blog_home_template1.md
@@ -0,0 +1 @@
+* Latest ${type} release: [ChromeDriver ${VERSION}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION}/)
diff --git a/chrome/test/chromedriver/support/release/templates/blog_home_template2.md b/chrome/test/chromedriver/support/release/templates/blog_home_template2.md
new file mode 100644
index 0000000..d71c28c
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/blog_home_template2.md
@@ -0,0 +1,2 @@
+* Latest ${type2} release: [ChromeDriver ${VERSION2}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION2}/)
+* Latest ${type1} release: [ChromeDriver ${VERSION1}](https://chromedriver.storage.googleapis.com/index.html?path=${VERSION1}/)
diff --git a/chrome/test/chromedriver/support/release/templates/li.html b/chrome/test/chromedriver/support/release/templates/li.html
new file mode 100644
index 0000000..bda9c32
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/li.html
@@ -0,0 +1 @@
+<li dir="ltr" style="list-style-type:disc;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;" aria-level="1"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;" role="presentation"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">${LI_TEXT}</span></p></li>
diff --git a/chrome/test/chromedriver/support/release/templates/parametrized_change_list.html b/chrome/test/chromedriver/support/release/templates/parametrized_change_list.html
new file mode 100644
index 0000000..c070085b
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/parametrized_change_list.html
@@ -0,0 +1 @@
+<br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Changes in version ${MAJOR} of ChromeDriver include:</span></p><br /><ul style="margin-top:0;margin-bottom:0;padding-inline-start:48px;">${LI_LIST}</ul>
diff --git a/chrome/test/chromedriver/support/release/templates/static_change_list.html b/chrome/test/chromedriver/support/release/templates/static_change_list.html
new file mode 100644
index 0000000..4c5d0dd
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/static_change_list.html
@@ -0,0 +1 @@
+<br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Changes in this version of ChromeDriver include:</span></p><br /><ul style="margin-top:0;margin-bottom:0;padding-inline-start:48px;">${LI_LIST}</ul>
diff --git a/chrome/test/chromedriver/support/release/templates/template1.html b/chrome/test/chromedriver/support/release/templates/template1.html
new file mode 100644
index 0000000..118253d
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/template1.html
@@ -0,0 +1 @@
+<meta charset="utf-8"><b style="font-weight:normal;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Hello ChromeDriver users,</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">We are happy to announce that ChromeDriver version ${VERSION} has been released, and is now available at the </span><a href="https://chromedriver.chromium.org/downloads" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">ChromeDriver Downloads site</span></a><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">. This version of ChromeDriver is intended for users of the ${KIND} ${TYPE} release of Chrome version ${MAJOR}.</span></p>${CHANGE_LIST}<br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Please see the </span><a href="https://chromedriver.storage.googleapis.com/${VERSION}/notes.txt" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">release notes ${VERSION}</span></a><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"> for a more complete list of changes included in this release.</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Thanks for your continued support of ChromeDriver, and please let us know if you have any questions.</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Sincerely,</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">The ChromeDriver Team</span></p></b><br class="Apple-interchange-newline">
diff --git a/chrome/test/chromedriver/support/release/templates/template1.txt b/chrome/test/chromedriver/support/release/templates/template1.txt
new file mode 100644
index 0000000..bd6d3be
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/template1.txt
@@ -0,0 +1,11 @@
+Hello ChromeDriver users,
+
+We are happy to announce that ChromeDriver version ${VERSION} has been released,
+and is now available at the ChromeDriver Downloads site <https://chromedriver.chromium.org/downloads>.
+This version of ChromeDriver is intended for users of the ${KIND} ${TYPE} release of Chrome version ${MAJOR}.
+${CHANGE_LIST}
+Please see the ${NOTES_LINK} for a more complete list of changes included in this release.
+Thanks for your continued support of ChromeDriver, and please let us know if you have any questions.
+
+Sincerely,
+The ChromeDriver Team
diff --git a/chrome/test/chromedriver/support/release/templates/template2.html b/chrome/test/chromedriver/support/release/templates/template2.html
new file mode 100644
index 0000000..fe7eb33
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/template2.html
@@ -0,0 +1 @@
+<meta charset="utf-8"><b style="font-weight:normal;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Hello ChromeDriver users,</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">We are happy to announce that ChromeDriver versions ${VERSION1} and ${VERSION2} have been released, and are now available at the </span><a href="https://chromedriver.chromium.org/downloads" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">ChromeDriver Downloads site</span></a><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">. These versions of ChromeDriver are intended for users of the ${KIND1} ${TYPE1} release of Chrome version ${MAJOR1} and ${KIND2} ${TYPE2} release of version ${MAJOR2}.</span></p>${CHANGE_LIST}<br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Please see the </span><a href="https://chromedriver.storage.googleapis.com/${VERSION1}/notes.txt" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">release notes ${VERSION1}</span></a><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"> and </span><a href="https://chromedriver.storage.googleapis.com/${VERSION2}/notes.txt" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">release notes ${VERSION2}</span></a><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"> for a more complete list of changes included in this release.</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Thanks for your continued support of ChromeDriver, and please let us know if you have any questions.</span></p><br /><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Sincerely,</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">The ChromeDriver Team</span></p></b><br class="Apple-interchange-newline">
diff --git a/chrome/test/chromedriver/support/release/templates/template2.txt b/chrome/test/chromedriver/support/release/templates/template2.txt
new file mode 100644
index 0000000..9e17ce4
--- /dev/null
+++ b/chrome/test/chromedriver/support/release/templates/template2.txt
@@ -0,0 +1,10 @@
+Hello ChromeDriver users,
+
+We are happy to announce that ChromeDriver versions ${VERSION1} and ${VERSION2} have been released, and are now available at the ChromeDriver Downloads site <https://chromedriver.chromium.org/downloads>.
+These versions of ChromeDriver are intended for users of the ${KIND1} ${TYPE1} release of Chrome version ${MAJOR1} and ${KIND2} ${TYPE2} release of version ${MAJOR2}.
+${CHANGE_LIST}
+Please see the ${NOTES_LINK1} and ${NOTES_LINK2} for a more complete list of changes included in this release.
+Thanks for your continued support of ChromeDriver, and please let us know if you have any questions.
+
+Sincerely,
+The ChromeDriver Team
diff --git a/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html
new file mode 100644
index 0000000..31174e9
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html
@@ -0,0 +1 @@
+Nothing here. See .mock-http-headers.
diff --git a/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html.mock-http-headers b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html.mock-http-headers
new file mode 100644
index 0000000..62b8619e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/frame.html.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/webrequest/fencedFrames/iframe.html b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/iframe.html
new file mode 100644
index 0000000..918c1ef
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/iframe.html
@@ -0,0 +1,7 @@
+<script>
+  onload = function() {
+    var f = document.createElement('fencedframe');
+    f.src = '/server-redirect?extensions/api_test/webrequest/fencedFrames/frame.html';
+    document.body.appendChild(f);
+  }
+</script>
diff --git a/chrome/test/data/extensions/api_test/webrequest/fencedFrames/main.html b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/main.html
new file mode 100644
index 0000000..f1dbed6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/fencedFrames/main.html
@@ -0,0 +1,7 @@
+<script>
+  onload = function() {
+    var f = document.createElement('iframe');
+    f.src = 'iframe.html';
+    document.body.appendChild(f);
+  };
+</script>
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.html b/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.html
new file mode 100644
index 0000000..a520f5e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.html
@@ -0,0 +1,7 @@
+<!--
+ * 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.
+-->
+<script src="framework.js"></script>
+<script src="test_fenced_frames.js"></script>
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.js b/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.js
new file mode 100644
index 0000000..640febc17
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_fenced_frames.js
@@ -0,0 +1,320 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const kExtensionPath = 'extensions/api_test/webrequest/fencedFrames';
+
+// Constants as functions, not to be called until after runTests.
+function getURLHttpSimpleLoad() {
+  return getServerURL(`${kExtensionPath}/main.html`);
+}
+
+function getURLIntermediateIFrame() {
+  return getServerURL(`${kExtensionPath}/iframe.html`);
+}
+
+function getURLFencedFrame() {
+  return getServerURL(`${kExtensionPath}/frame.html`);
+}
+
+function getURLFencedFrameRedirect() {
+  return getServerURL(
+      `server-redirect?${kExtensionPath}/frame.html`);
+}
+
+runTests([
+  // Navigates to a page that embeds an iframe that contains a fenced frame.
+  // The fenced frame will redirect before landing on the destination fenced
+  // frame. This allows us to test that the parentFrameId is the iframe
+  // and redirection events are dispatched correctly.
+  function simpleLoadHttp() {
+    expect(
+      [
+        // events
+        { label: 'onBeforeRequest-1',
+          event: 'onBeforeRequest',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            frameUrl: getURLHttpSimpleLoad(),
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onBeforeSendHeaders-1',
+          event: 'onBeforeSendHeaders',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            requestHeadersValid: true,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onSendHeaders-1',
+          event: 'onSendHeaders',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            requestHeadersValid: true,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onHeadersReceived-1',
+          event: 'onHeadersReceived',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            statusCode: 200,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onResponseStarted-1',
+          event: 'onResponseStarted',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            statusCode: 200,
+            responseHeadersExist: true,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onCompleted-1',
+          event: 'onCompleted',
+          details: {
+            url: getURLHttpSimpleLoad(),
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED),
+          }
+        },
+        { label: 'onBeforeRequest-2',
+          event: 'onBeforeRequest',
+          details: {
+            url: getURLIntermediateIFrame(),
+            frameUrl: getURLIntermediateIFrame(),
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeSendHeaders-2',
+          event: 'onBeforeSendHeaders',
+          details: {
+            url: getURLIntermediateIFrame(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onSendHeaders-2',
+          event: 'onSendHeaders',
+          details: {
+            url: getURLIntermediateIFrame(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onHeadersReceived-2',
+          event: 'onHeadersReceived',
+          details: {
+            url: getURLIntermediateIFrame(),
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            statusCode: 200,
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onResponseStarted-2',
+          event: 'onResponseStarted',
+          details: {
+            url: getURLIntermediateIFrame(),
+            statusCode: 200,
+            responseHeadersExist: true,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onCompleted-2',
+          event: 'onCompleted',
+          details: {
+            url: getURLIntermediateIFrame(),
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            type: 'sub_frame',
+            frameId: 1,
+            parentFrameId: 0,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeRequest-3',
+          event: 'onBeforeRequest',
+          details: {
+            url: getURLFencedFrameRedirect(),
+            frameUrl: getURLFencedFrameRedirect(),
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeSendHeaders-3',
+          event: 'onBeforeSendHeaders',
+          details: {
+            url: getURLFencedFrameRedirect(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onSendHeaders-3',
+          event: 'onSendHeaders',
+          details: {
+            url: getURLFencedFrameRedirect(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onHeadersReceived-3',
+          event: 'onHeadersReceived',
+          details: {
+            url: getURLFencedFrameRedirect(),
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 301 Moved Permanently',
+            statusCode: 301,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeRedirect-3',
+          event: 'onBeforeRedirect',
+          details: {
+            url: getURLFencedFrameRedirect(),
+            redirectUrl: getURLFencedFrame(),
+            statusCode: 301,
+            responseHeadersExist: true,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 301 Moved Permanently',
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeRequest-4',
+          event: 'onBeforeRequest',
+          details: {
+            url: getURLFencedFrame(),
+            frameUrl: getURLFencedFrame(),
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onBeforeSendHeaders-4',
+          event: 'onBeforeSendHeaders',
+          details: {
+            url: getURLFencedFrame(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onSendHeaders-4',
+          event: 'onSendHeaders',
+          details: {
+            url: getURLFencedFrame(),
+            requestHeadersValid: true,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onHeadersReceived-4',
+          event: 'onHeadersReceived',
+          details: {
+            url: getURLFencedFrame(),
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            statusCode: 200,
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onResponseStarted-4',
+          event: 'onResponseStarted',
+          details: {
+            url: getURLFencedFrame(),
+            statusCode: 200,
+            responseHeadersExist: true,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+        { label: 'onCompleted-4',
+          event: 'onCompleted',
+          details: {
+            url: getURLFencedFrame(),
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            responseHeadersExist: true,
+            statusLine: 'HTTP/1.1 200 OK',
+            type: 'sub_frame',
+            frameId: 2,
+            parentFrameId: 1,
+            initiator: getServerDomain(initiators.WEB_INITIATED),
+          }
+        },
+      ],
+      [  // event order
+        ['onBeforeRequest-1', 'onBeforeSendHeaders-1', 'onSendHeaders-1',
+         'onHeadersReceived-1', 'onResponseStarted-1', 'onCompleted-1',
+         'onBeforeRequest-2', 'onBeforeSendHeaders-2',  'onSendHeaders-2',
+         'onHeadersReceived-2', 'onResponseStarted-2', 'onCompleted-2',
+         'onBeforeRequest-3', 'onBeforeSendHeaders-3',  'onSendHeaders-3',
+         'onHeadersReceived-3', 'onBeforeRedirect-3',
+         'onBeforeRequest-4', 'onBeforeSendHeaders-4',  'onSendHeaders-4',
+         'onHeadersReceived-4', 'onResponseStarted-4', 'onCompleted-4' ] ],
+      {urls: ['<all_urls>']},  // filter
+      ['requestHeaders', 'responseHeaders']);
+    navigateAndWait(getURLHttpSimpleLoad());
+  },
+]);
diff --git a/chrome/test/data/webui/tab_search/BUILD.gn b/chrome/test/data/webui/tab_search/BUILD.gn
index 0401591..27c11b4 100644
--- a/chrome/test/data/webui/tab_search/BUILD.gn
+++ b/chrome/test/data/webui/tab_search/BUILD.gn
@@ -29,10 +29,10 @@
   in_files = [
     "bimap_test.ts",
     "fuzzy_search_test.ts",
-    "infinite_list_test.js",
-    "tab_search_app_focus_test.js",
-    "tab_search_app_test.js",
-    "tab_search_item_test.js",
+    "infinite_list_test.ts",
+    "tab_search_app_focus_test.ts",
+    "tab_search_app_test.ts",
+    "tab_search_item_test.ts",
     "tab_search_test_data.ts",
     "tab_search_test_helper.ts",
     "test_tab_search_api_proxy.ts",
diff --git a/chrome/test/data/webui/tab_search/fuzzy_search_test.ts b/chrome/test/data/webui/tab_search/fuzzy_search_test.ts
index 18e3a3b..b7f8c4a 100644
--- a/chrome/test/data/webui/tab_search/fuzzy_search_test.ts
+++ b/chrome/test/data/webui/tab_search/fuzzy_search_test.ts
@@ -4,9 +4,11 @@
 
 import 'chrome://webui-test/mojo_webui_test_support.js';
 
-import {fuzzySearch, FuzzySearchOptions, Tab, TabData, TabGroup, TabItemType} from 'chrome://tab-search.top-chrome/tab_search.js';
+import {fuzzySearch, FuzzySearchOptions, TabData, TabGroup, TabItemType} from 'chrome://tab-search.top-chrome/tab_search.js';
 import {assertDeepEquals, assertEquals} from 'chrome://webui-test/chai_assert.js';
 
+import {createTab} from './tab_search_test_data.js';
+
 /**
  * Assert search results return in specific order.
  */
@@ -36,27 +38,6 @@
   });
 }
 
-function createTab(overrides: Partial<Tab>): Tab {
-  return Object.assign(
-      {
-        active: false,
-        alertStates: [],
-        faviconUrl: undefined,
-        groupId: undefined,
-        index: 0,
-        isDefaultFavicon: false,
-        lastActiveElapsedText: '',
-        lastActiveTimeTicks: {internalValue: BigInt(5)},
-        pinned: false,
-        showIcon: false,
-        tabId: 1,
-        title: 'Google',
-        url: {url: 'https://www.google.com'},
-
-      },
-      overrides);
-}
-
 suite('FuzzySearchTest', () => {
   test('fuzzySearch', () => {
     const records: TabData[] = [
diff --git a/chrome/test/data/webui/tab_search/infinite_list_test.js b/chrome/test/data/webui/tab_search/infinite_list_test.ts
similarity index 82%
rename from chrome/test/data/webui/tab_search/infinite_list_test.js
rename to chrome/test/data/webui/tab_search/infinite_list_test.ts
index b94e711..6e92143 100644
--- a/chrome/test/data/webui/tab_search/infinite_list_test.js
+++ b/chrome/test/data/webui/tab_search/infinite_list_test.ts
@@ -5,7 +5,7 @@
 import 'chrome://webui-test/mojo_webui_test_support.js';
 
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {InfiniteList, TabData, TabSearchItem, TitleItem} from 'chrome://tab-search.top-chrome/tab_search.js';
+import {InfiniteList, TabData, TabItemType, TabSearchItem, TitleItem} from 'chrome://tab-search.top-chrome/tab_search.js';
 
 import {assertEquals, assertGT, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js';
@@ -20,7 +20,6 @@
 class TestApp extends PolymerElement {
   static get properties() {
     return {
-      /** @private {number} */
       maxHeight_: {
         type: Number,
         value: SAMPLE_AVAIL_HEIGHT,
@@ -30,7 +29,7 @@
 
   static get template() {
     return html`
-    <infinite-list id="list" max-height="[[maxHeight_]]">
+    <infinite-list max-height="[[maxHeight_]]">
       <template data-type="TitleItem">
         <div class="section-title">[[item.title]]</div>
       </template>
@@ -47,52 +46,33 @@
 customElements.define('test-app', TestApp);
 
 suite('InfiniteListTest', () => {
-  /** @type {!InfiniteList} */
-  let infiniteList;
+  let infiniteList: InfiniteList;
 
   disableAnimationBehavior(InfiniteList, 'scrollTo');
   disableAnimationBehavior(TabSearchItem, 'scrollIntoView');
 
-  /**
-   * @param {!Array<!TabData>} sampleData
-   */
-  async function setupTest(sampleData) {
+  async function setupTest(sampleData: Array<TabData|TitleItem>) {
     const testApp = document.createElement('test-app');
     document.body.innerHTML = '';
     document.body.appendChild(testApp);
 
-    infiniteList = /** @type {!InfiniteList} */ (
-        testApp.shadowRoot.querySelector('#list'));
+    infiniteList = testApp.shadowRoot!.querySelector('infinite-list')!;
     infiniteList.items = sampleData;
     await flushTasks();
   }
 
-  /**
-   * @return {!NodeList<!HTMLElement>}
-   */
-  function queryRows() {
-    return /** @type {!NodeList<!HTMLElement>} */ (
-        infiniteList.querySelectorAll('tab-search-item'));
+  function queryRows(): NodeListOf<HTMLElement> {
+    return infiniteList.querySelectorAll('tab-search-item');
   }
 
-  /**
-   * @param {string} className
-   * @return {!NodeList<!HTMLElement>}
-   */
-  function queryClassElements(className) {
-    return /** @type {!NodeList<!HTMLElement>} */ (
-        infiniteList.querySelectorAll('.' + className));
+  function queryClassElements(className: string): NodeListOf<HTMLElement> {
+    return infiniteList.querySelectorAll('.' + className);
   }
 
-  /**
-   * @param {!Array<string>} siteNames
-   * @return {!Array<!TabData>}
-   */
-  function sampleTabItems(siteNames) {
+  function sampleTabItems(siteNames: string[]): TabData[] {
     return generateSampleTabsFromSiteNames(siteNames).map(tab => {
-      const tabData = {hostname: new URL(tab.url.url).hostname, tab};
-      Object.setPrototypeOf(tabData, TabData.prototype);
-      return tabData;
+      return new TabData(
+          tab, TabItemType.OPEN_TAB, new URL(tab.url.url).hostname);
     });
   }
 
@@ -184,9 +164,8 @@
     const tabItems = sampleTabItems(sampleSiteNames(10));
     await setupTest(tabItems);
 
-    const tabsDiv = /** @type {!HTMLElement} */ (infiniteList);
     // Assert that the tabs are in a overflowing state.
-    assertGT(tabsDiv.scrollHeight, tabsDiv.clientHeight);
+    assertGT(infiniteList.scrollHeight, infiniteList.clientHeight);
 
     infiniteList.selected = 0;
     for (let i = 0; i < tabItems.length; i++) {
@@ -196,7 +175,7 @@
       const selectedIndex = ((i + 1) % tabItems.length);
       assertEquals(selectedIndex, infiniteList.selected);
       assertTabItemAndNeighborsInViewBounds(
-          tabsDiv, queryRows(), selectedIndex);
+          infiniteList, queryRows(), selectedIndex);
     }
   });
 
@@ -204,9 +183,8 @@
     const tabItems = sampleTabItems(sampleSiteNames(10));
     await setupTest(tabItems);
 
-    const tabsDiv = /** @type {!HTMLElement} */ (infiniteList);
     // Assert that the tabs are in a overflowing state.
-    assertGT(tabsDiv.scrollHeight, tabsDiv.clientHeight);
+    assertGT(infiniteList.scrollHeight, infiniteList.clientHeight);
 
     infiniteList.selected = 0;
     for (let i = tabItems.length; i > 0; i--) {
@@ -215,7 +193,8 @@
 
       const selectIndex = (i - 1 + tabItems.length) % tabItems.length;
       assertEquals(selectIndex, infiniteList.selected);
-      assertTabItemAndNeighborsInViewBounds(tabsDiv, queryRows(), selectIndex);
+      assertTabItemAndNeighborsInViewBounds(
+          infiniteList, queryRows(), selectIndex);
     }
   });
 
diff --git a/chrome/test/data/webui/tab_search/tab_search_app_focus_test.js b/chrome/test/data/webui/tab_search/tab_search_app_focus_test.js
deleted file mode 100644
index 4affae89..0000000
--- a/chrome/test/data/webui/tab_search/tab_search_app_focus_test.js
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
-import {InfiniteList, ProfileData, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchItem, TabSearchSearchField, TabsRemovedInfo} from 'chrome://tab-search.top-chrome/tab_search.js';
-
-import {assertEquals, assertGT, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js';
-
-import {generateSampleDataFromSiteNames, sampleData, sampleSiteNames} from './tab_search_test_data.js';
-import {assertTabItemAndNeighborsInViewBounds, disableAnimationBehavior, initLoadTimeDataWithDefaults} from './tab_search_test_helper.js';
-import {TestTabSearchApiProxy} from './test_tab_search_api_proxy.js';
-
-suite('TabSearchAppFocusTest', () => {
-  /** @type {!TabSearchAppElement} */
-  let tabSearchApp;
-  /** @type {!TestTabSearchApiProxy} */
-  let testProxy;
-
-  disableAnimationBehavior(InfiniteList, 'scrollTo');
-  disableAnimationBehavior(TabSearchItem, 'scrollIntoView');
-
-  /**
-   * @param {ProfileData} sampleData
-   * @param {Object=} loadTimeOverriddenData
-   */
-  async function setupTest(sampleData, loadTimeOverriddenData) {
-    testProxy = new TestTabSearchApiProxy();
-    testProxy.setProfileData(sampleData);
-    TabSearchApiProxyImpl.setInstance(testProxy);
-
-    initLoadTimeDataWithDefaults(loadTimeOverriddenData);
-
-    tabSearchApp = /** @type {!TabSearchAppElement} */
-        (document.createElement('tab-search-app'));
-
-    document.body.innerHTML = '';
-    document.body.appendChild(tabSearchApp);
-    await flushTasks();
-  }
-
-  /**
-   * @return {!NodeList<!HTMLElement>}
-   */
-  function queryRows() {
-    return /** @type {!NodeList<!HTMLElement>} */ (
-        tabSearchApp.shadowRoot.querySelector('#tabsList')
-            .querySelectorAll('tab-search-item'));
-  }
-
-  test('KeyNavigation', async () => {
-    await setupTest(sampleData());
-
-    // Initially, the search input should have focus.
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
-    const searchInput = /** @type {!HTMLInputElement} */
-        (searchField.shadowRoot.querySelector('#searchInput'));
-    assertEquals(searchInput, getDeepActiveElement());
-
-    const tabSearchItems = queryRows();
-    tabSearchItems[0].focus();
-    // Once an item is focused, arrow keys should change focus too.
-    keyDownOn(tabSearchItems[0], 0, [], 'ArrowDown');
-    assertEquals(tabSearchItems[1], getDeepActiveElement());
-
-    keyDownOn(tabSearchItems[1], 0, [], 'ArrowUp');
-    assertEquals(tabSearchItems[0], getDeepActiveElement());
-
-    keyDownOn(tabSearchItems[1], 0, [], 'End');
-    assertEquals(
-        tabSearchItems[tabSearchItems.length - 1], getDeepActiveElement());
-
-    keyDownOn(tabSearchItems[tabSearchItems.length - 1], 0, [], 'Home');
-    assertEquals(tabSearchItems[0], getDeepActiveElement());
-
-    // On restoring focus to the search field, a list item should be selected if
-    // available.
-    searchInput.focus();
-    assertEquals(0, tabSearchApp.getSelectedIndex());
-  });
-
-  test('KeyPress', async () => {
-    await setupTest(sampleData());
-
-    const tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item'));
-    tabSearchItem.focus();
-
-    keyDownOn(tabSearchItem, 0, [], 'Enter');
-    keyDownOn(tabSearchItem, 0, [], ' ');
-    assertEquals(2, testProxy.getCallCount('switchToTab'));
-
-    const closeButton = /** @type {!HTMLElement} */ (
-        tabSearchItem.shadowRoot.querySelector('#closeButton'));
-    keyDownOn(closeButton, 0, [], 'Enter');
-    assertEquals(1, testProxy.getCallCount('closeTab'));
-  });
-
-  test('ListItemFocusRetainedOnItemChanges', async () => {
-    const numTabItems = 5;
-    await setupTest(
-        generateSampleDataFromSiteNames(sampleSiteNames(numTabItems)));
-
-    await waitAfterNextRender(tabSearchApp);
-    assertEquals(numTabItems, queryRows().length);
-
-    const tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item'));
-    tabSearchItem.focus();
-
-    const closeButton = /** @type {!HTMLElement} */ (
-        tabSearchItem.shadowRoot.querySelector('#closeButton'));
-    closeButton.focus();
-
-    for (let i = 0; i < numTabItems - 1; i++) {
-      testProxy.getCallbackRouterRemote().tabsRemoved(
-          /** @type {!TabsRemovedInfo} */ ({
-            tabIds: [(i + 1)],
-            recentlyClosedTabs: [],
-          }));
-      await waitAfterNextRender(tabSearchApp);
-      assertEquals(numTabItems - 1 - i, queryRows().length);
-      assertEquals('tab-search-item', getDeepActiveElement().localName);
-    }
-  });
-
-  test('ViewScrolling', async () => {
-    await setupTest(generateSampleDataFromSiteNames(sampleSiteNames(10)));
-
-    const tabsDiv = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList'));
-    // Assert that the tabs are in a overflowing state.
-    assertGT(tabsDiv.scrollHeight, tabsDiv.clientHeight);
-
-    const tabItems = /** @type {!NodeList<HTMLElement>} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelectorAll('tab-search-item'));
-    for (let i = 0; i < tabItems.length; i++) {
-      tabItems[i].focus();
-
-      assertEquals(i, tabSearchApp.getSelectedIndex());
-      assertTabItemAndNeighborsInViewBounds(tabsDiv, tabItems, i);
-    }
-  });
-
-  test('Search field input element focused when revealed ', async () => {
-    await setupTest(sampleData());
-
-    // Set the current focus to the search input element.
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
-    const searchInput = /** @type {!HTMLInputElement} */
-        (searchField.shadowRoot.querySelector('#searchInput'));
-    searchInput.focus();
-    assertEquals(searchInput, getDeepActiveElement());
-
-    // Focus an item in the list, search input should not be focused.
-    const tabSearchItem = /** @type {!HTMLElement} */ (
-        tabSearchApp.shadowRoot.querySelector('#tabsList')
-            .querySelector('tab-search-item'));
-    tabSearchItem.focus();
-    assertEquals(tabSearchItem, getDeepActiveElement());
-    assertNotEquals(searchInput, getDeepActiveElement());
-
-    // When hidden visibilitychange should revert focus to the search input.
-    Object.defineProperty(
-        document, 'visibilityState', {value: 'hidden', writable: true});
-    document.dispatchEvent(new Event('visibilitychange'));
-    await flushTasks();
-    assertEquals(searchInput, getDeepActiveElement());
-
-    // When visible the focused element should still be the search input.
-    Object.defineProperty(
-        document, 'visibilityState', {value: 'visible', writable: true});
-    document.dispatchEvent(new Event('visibilitychange'));
-    await flushTasks();
-    assertEquals(searchInput, getDeepActiveElement());
-  });
-
-});
diff --git a/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts b/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts
new file mode 100644
index 0000000..8a6fc3fa
--- /dev/null
+++ b/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts
@@ -0,0 +1,161 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
+import {InfiniteList, ProfileData, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js';
+import {assertEquals, assertGT, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js';
+
+import {createProfileData, generateSampleDataFromSiteNames, sampleSiteNames} from './tab_search_test_data.js';
+import {assertTabItemAndNeighborsInViewBounds, disableAnimationBehavior, initLoadTimeDataWithDefaults} from './tab_search_test_helper.js';
+import {TestTabSearchApiProxy} from './test_tab_search_api_proxy.js';
+
+suite('TabSearchAppFocusTest', () => {
+  let tabSearchApp: TabSearchAppElement;
+  let testProxy: TestTabSearchApiProxy;
+
+  disableAnimationBehavior(InfiniteList, 'scrollTo');
+  disableAnimationBehavior(TabSearchItem, 'scrollIntoView');
+
+  async function setupTest(
+      sampleData: ProfileData,
+      loadTimeOverriddenData?: {[key: string]: string}) {
+    testProxy = new TestTabSearchApiProxy();
+    testProxy.setProfileData(sampleData);
+    TabSearchApiProxyImpl.setInstance(testProxy);
+
+    initLoadTimeDataWithDefaults(loadTimeOverriddenData);
+
+    tabSearchApp = document.createElement('tab-search-app');
+
+    document.body.innerHTML = '';
+    document.body.appendChild(tabSearchApp);
+    await flushTasks();
+  }
+
+  function queryRows() {
+    return tabSearchApp.$.tabsList.querySelectorAll('tab-search-item');
+  }
+
+  test('KeyNavigation', async () => {
+    await setupTest(createProfileData());
+
+    // Initially, the search input should have focus.
+    const searchInput = tabSearchApp.$.searchField.$.searchInput;
+    assertEquals(searchInput, getDeepActiveElement());
+
+    const tabSearchItems = queryRows();
+    tabSearchItems[0]!.focus();
+    // Once an item is focused, arrow keys should change focus too.
+    keyDownOn(tabSearchItems[0]!, 0, [], 'ArrowDown');
+    assertEquals(tabSearchItems[1], getDeepActiveElement());
+
+    keyDownOn(tabSearchItems[1]!, 0, [], 'ArrowUp');
+    assertEquals(tabSearchItems[0], getDeepActiveElement());
+
+    keyDownOn(tabSearchItems[1]!, 0, [], 'End');
+    assertEquals(
+        tabSearchItems[tabSearchItems.length - 1], getDeepActiveElement());
+
+    keyDownOn(tabSearchItems[tabSearchItems.length - 1]!, 0, [], 'Home');
+    assertEquals(tabSearchItems[0], getDeepActiveElement());
+
+    // On restoring focus to the search field, a list item should be selected if
+    // available.
+    searchInput.focus();
+    assertEquals(0, tabSearchApp.getSelectedIndex());
+  });
+
+  test('KeyPress', async () => {
+    await setupTest(createProfileData());
+
+    const tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-item')!;
+    tabSearchItem.focus();
+
+    keyDownOn(tabSearchItem, 0, [], 'Enter');
+    keyDownOn(tabSearchItem, 0, [], ' ');
+    assertEquals(2, testProxy.getCallCount('switchToTab'));
+
+    const closeButton =
+        tabSearchItem.shadowRoot!.querySelector('#closeButton')!;
+    keyDownOn(closeButton, 0, [], 'Enter');
+    assertEquals(1, testProxy.getCallCount('closeTab'));
+  });
+
+  test('ListItemFocusRetainedOnItemChanges', async () => {
+    const numTabItems = 5;
+    await setupTest(
+        generateSampleDataFromSiteNames(sampleSiteNames(numTabItems)));
+
+    await waitAfterNextRender(tabSearchApp);
+    assertEquals(numTabItems, queryRows().length);
+
+    const tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-item')!;
+    tabSearchItem.focus();
+
+    const closeButton =
+        tabSearchItem.shadowRoot!.querySelector<HTMLElement>('#closeButton')!;
+    closeButton.focus();
+
+    for (let i = 0; i < numTabItems - 1; i++) {
+      testProxy.getCallbackRouterRemote().tabsRemoved({
+        tabIds: [(i + 1)],
+        recentlyClosedTabs: [],
+      });
+      await waitAfterNextRender(tabSearchApp);
+      assertEquals(numTabItems - 1 - i, queryRows().length);
+      assertEquals('tab-search-item', getDeepActiveElement()!.localName);
+    }
+  });
+
+  test('ViewScrolling', async () => {
+    await setupTest(generateSampleDataFromSiteNames(sampleSiteNames(10)));
+
+    const tabsDiv = tabSearchApp.$.tabsList;
+    // Assert that the tabs are in a overflowing state.
+    assertGT(tabsDiv.scrollHeight, tabsDiv.clientHeight);
+
+    const tabItems =
+        tabSearchApp.$.tabsList.querySelectorAll('tab-search-item');
+    for (let i = 0; i < tabItems.length; i++) {
+      tabItems[i]!.focus();
+
+      assertEquals(i, tabSearchApp.getSelectedIndex());
+      assertTabItemAndNeighborsInViewBounds(tabsDiv, tabItems, i);
+    }
+  });
+
+  test('Search field input element focused when revealed ', async () => {
+    await setupTest(createProfileData());
+
+    // Set the current focus to the search input element.
+    const searchInput = tabSearchApp.$.searchField.$.searchInput;
+    searchInput.focus();
+    assertEquals(searchInput, getDeepActiveElement());
+
+    // Focus an item in the list, search input should not be focused.
+    const tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-item')!;
+    tabSearchItem.focus();
+    assertEquals(tabSearchItem, getDeepActiveElement());
+    assertNotEquals(searchInput, getDeepActiveElement());
+
+    // When hidden visibilitychange should revert focus to the search input.
+    Object.defineProperty(
+        document, 'visibilityState', {value: 'hidden', writable: true});
+    document.dispatchEvent(new Event('visibilitychange'));
+    await flushTasks();
+    assertEquals(searchInput, getDeepActiveElement());
+
+    // When visible the focused element should still be the search input.
+    Object.defineProperty(
+        document, 'visibilityState', {value: 'visible', writable: true});
+    document.dispatchEvent(new Event('visibilitychange'));
+    await flushTasks();
+    assertEquals(searchInput, getDeepActiveElement());
+  });
+});
diff --git a/chrome/test/data/webui/tab_search/tab_search_app_test.js b/chrome/test/data/webui/tab_search/tab_search_app_test.ts
similarity index 65%
rename from chrome/test/data/webui/tab_search/tab_search_app_test.js
rename to chrome/test/data/webui/tab_search/tab_search_app_test.ts
index bf4142c..c55697b 100644
--- a/chrome/test/data/webui/tab_search/tab_search_app_test.js
+++ b/chrome/test/data/webui/tab_search/tab_search_app_test.ts
@@ -5,55 +5,44 @@
 import 'chrome://webui-test/mojo_webui_test_support.js';
 
 import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
-import {ProfileData, RecentlyClosedTab, Tab, TabGroup, TabGroupColor, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchSearchField, TabsRemovedInfo, TabUpdateInfo} from 'chrome://tab-search.top-chrome/tab_search.js';
-
+import {ProfileData, RecentlyClosedTab, Tab, TabGroupColor, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js';
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js';
 
-import {generateSampleDataFromSiteNames, generateSampleRecentlyClosedTabs, generateSampleTabsFromSiteNames, SAMPLE_RECENTLY_CLOSED_DATA, SAMPLE_WINDOW_DATA, SAMPLE_WINDOW_HEIGHT, sampleData, sampleToken} from './tab_search_test_data.js';
-import {initLoadTimeDataWithDefaults, initProfileDataWithDefaults} from './tab_search_test_helper.js';
+import {createProfileData, createTab, generateSampleDataFromSiteNames, generateSampleRecentlyClosedTabs, generateSampleRecentlyClosedTabsFromSiteNames, generateSampleTabsFromSiteNames, SAMPLE_RECENTLY_CLOSED_DATA, SAMPLE_WINDOW_HEIGHT, sampleToken} from './tab_search_test_data.js';
+import {initLoadTimeDataWithDefaults} from './tab_search_test_helper.js';
 import {TestTabSearchApiProxy} from './test_tab_search_api_proxy.js';
 
 suite('TabSearchAppTest', () => {
-  /** @type {!TabSearchAppElement} */
-  let tabSearchApp;
-  /** @type {!TestTabSearchApiProxy} */
-  let testProxy;
+  let tabSearchApp: TabSearchAppElement;
+  let testProxy: TestTabSearchApiProxy;
 
-  /**
-   * @param {!NodeList<!Element>} rows
-   * @param {!Array<number>} ids
-   */
-  function verifyTabIds(rows, ids) {
+  function verifyTabIds(rows: NodeListOf<HTMLElement>, ids: number[]) {
     assertEquals(ids.length, rows.length);
     rows.forEach((row, index) => {
-      assertEquals(ids[index].toString(), row.getAttribute('id'));
+      assertEquals(ids[index]!.toString(), row.getAttribute('id'));
     });
   }
 
-  /**
-   * @return {!NodeList<!Element>}
-   */
-  function queryRows() {
-    return tabSearchApp.shadowRoot.querySelector('#tabsList')
-        .querySelectorAll('tab-search-item, tab-search-group-item');
+  function queryRows(): NodeListOf<HTMLElement> {
+    return tabSearchApp.$.tabsList.querySelectorAll(
+        'tab-search-item, tab-search-group-item');
   }
 
   /**
-   * @param {!Object} sampleData A mock data object containing relevant profile
-   *     data for the test.
-   * @param {Object=} loadTimeOverriddenData
+   * @param sampleData A mock data object containing relevant profile data for
+   *     the test.
    */
-  async function setupTest(sampleData, loadTimeOverriddenData) {
-    initProfileDataWithDefaults(/** @type {ProfileData} */ (sampleData));
+  async function setupTest(
+      sampleData: ProfileData,
+      loadTimeOverriddenData?: {[key: string]: number|string|boolean}) {
     initLoadTimeDataWithDefaults(loadTimeOverriddenData);
 
     testProxy = new TestTabSearchApiProxy();
-    testProxy.setProfileData(/** @type {ProfileData} */ (sampleData));
+    testProxy.setProfileData(sampleData);
     TabSearchApiProxyImpl.setInstance(testProxy);
 
-    tabSearchApp = /** @type {!TabSearchAppElement} */
-        (document.createElement('tab-search-app'));
+    tabSearchApp = document.createElement('tab-search-app');
 
     document.body.innerHTML = '';
     document.body.appendChild(tabSearchApp);
@@ -61,7 +50,7 @@
   }
 
   test('return all tabs', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
   });
 
@@ -76,10 +65,11 @@
             tabs: generateSampleTabsFromSiteNames(['OpenTab1'], true),
           }],
           recentlyClosedTabs: generateSampleRecentlyClosedTabs(
-              'Sample Tab', sampleTabCount, sampleToken(0, 1)),
+              'Sample Tab', sampleTabCount, sampleToken(0n, 1n)),
+          tabGroups: [],
           recentlyClosedTabGroups: [{
             sessionId: sampleSessionId,
-            id: sampleToken(0, 1),
+            id: sampleToken(0n, 1n),
             color: 1,
             title: 'Reading List',
             tabCount: sampleTabCount,
@@ -92,8 +82,7 @@
           recentlyClosedDefaultItemDisplayCount: 5,
         });
 
-    tabSearchApp.shadowRoot.querySelector('#tabsList')
-        .ensureAllDomItemsAvailable();
+    tabSearchApp.$.tabsList.ensureAllDomItemsAvailable();
 
     // Assert the recently closed tab group is included in the recently closed
     // items section and that the recently closed tabs belonging to it are
@@ -102,29 +91,27 @@
   });
 
   test('return all open and recently closed tabs', async () => {
-    await setupTest({
-      windows: SAMPLE_WINDOW_DATA,
+    await setupTest(createProfileData({
       recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA,
       recentlyClosedSectionExpanded: true,
-    });
-    tabSearchApp.shadowRoot.querySelector('#tabsList')
-        .ensureAllDomItemsAvailable();
+    }));
+    tabSearchApp.$.tabsList.ensureAllDomItemsAvailable();
 
     assertEquals(8, queryRows().length);
   });
 
   test('Limit recently closed tabs to the default display count', async () => {
     await setupTest(
-        {
+        createProfileData({
           windows: [{
             active: true,
             height: SAMPLE_WINDOW_HEIGHT,
             tabs: generateSampleTabsFromSiteNames(['OpenTab1'], true),
           }],
-          recentlyClosedTabs: generateSampleTabsFromSiteNames(
-              ['RecentlyClosedTab1', 'RecentlyClosedTab2'], false),
+          recentlyClosedTabs: generateSampleRecentlyClosedTabsFromSiteNames(
+              ['RecentlyClosedTab1', 'RecentlyClosedTab2']),
           recentlyClosedSectionExpanded: true
-        },
+        }),
         {
           recentlyClosedDefaultItemDisplayCount: 1,
         });
@@ -133,19 +120,18 @@
   });
 
   test('Default tab selection when data is present', async () => {
-    await setupTest(sampleData());
-    assertNotEquals(-1, tabSearchApp.getSelectedIndex(),
+    await setupTest(createProfileData());
+    assertNotEquals(
+        -1, tabSearchApp.getSelectedIndex(),
         'No default selection in the presence of data');
   });
 
   test('Search text changes tab items', async () => {
-    await setupTest({
-      windows: SAMPLE_WINDOW_DATA,
+    await setupTest(createProfileData({
       recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA,
       recentlyClosedSectionExpanded: true,
-    });
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    }));
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('bing');
     await flushTasks();
     verifyTabIds(queryRows(), [2]);
@@ -161,17 +147,17 @@
     const sampleSessionId = 101;
     const sampleTabCount = 5;
     await setupTest(
-        {
+        createProfileData({
           windows: [{
             active: true,
             height: SAMPLE_WINDOW_HEIGHT,
             tabs: generateSampleTabsFromSiteNames(['Open sample tab'], true),
           }],
           recentlyClosedTabs: generateSampleRecentlyClosedTabs(
-              'Sample Tab', sampleTabCount, sampleToken(0, 1)),
+              'Sample Tab', sampleTabCount, sampleToken(0n, 1n)),
           recentlyClosedTabGroups: [({
             sessionId: sampleSessionId,
-            id: sampleToken(0, 1),
+            id: sampleToken(0n, 1n),
             color: 1,
             title: 'Reading List',
             tabCount: sampleTabCount,
@@ -179,13 +165,12 @@
             lastActiveElapsedText: ''
           })],
           recentlyClosedSectionExpanded: true,
-        },
+        }),
         {
           recentlyClosedDefaultItemDisplayCount: 5,
         });
 
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('sample');
     await flushTasks();
 
@@ -196,9 +181,8 @@
   });
 
   test('No tab selected when there are no search matches', async () => {
-    await setupTest(sampleData());
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    await setupTest(createProfileData());
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('Twitter');
     await flushTasks();
     assertEquals(0, queryRows().length);
@@ -206,25 +190,23 @@
   });
 
   test('Click on tab item triggers actions', async () => {
-    const tabData = {
-      index: 0,
-      tabId: 1,
+    const tabData = createTab({
       title: 'Google',
       url: {url: 'https://www.google.com'},
-    };
-    await setupTest({
-      windows: [{active: true, tabs: [tabData]}],
+      lastActiveTimeTicks: {internalValue: BigInt(4)},
     });
+    await setupTest(createProfileData({
+      windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs: [tabData]}],
+    }));
 
-    const tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item'));
+    const tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-item')!;
     tabSearchItem.click();
     const [tabInfo] = await testProxy.whenCalled('switchToTab');
     assertEquals(tabData.tabId, tabInfo.tabId);
 
-    const tabSearchItemCloseButton = /** @type {!HTMLElement} */ (
-        tabSearchItem.shadowRoot.querySelector('cr-icon-button'));
+    const tabSearchItemCloseButton =
+        tabSearchItem.shadowRoot!.querySelector('cr-icon-button')!;
     tabSearchItemCloseButton.click();
     const [tabId, withSearch, closedTabIndex] =
         await testProxy.whenCalled('closeTab');
@@ -234,32 +216,31 @@
   });
 
   test('Click on recently closed tab item triggers action', async () => {
-    const tabData = {
+    const tabData: RecentlyClosedTab = {
       tabId: 100,
       title: 'PayPal',
       url: {url: 'https://www.paypal.com'},
-      lastActiveTimeTicks: {internalValue: BigInt(11)},
       lastActiveElapsedText: '',
+      groupId: undefined,
+      lastActiveTime: {internalValue: BigInt(11)},
     };
 
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{
         active: true,
         height: SAMPLE_WINDOW_HEIGHT,
-        tabs: [{
-          index: 0,
-          tabId: 1,
+        tabs: [createTab({
           title: 'Google',
           url: {url: 'https://www.google.com'},
-        }]
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })]
       }],
       recentlyClosedTabs: [tabData],
       recentlyClosedSectionExpanded: true
-    });
+    }));
 
-    let tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="100"]'));
+    let tabSearchItem = tabSearchApp.$.tabsList.querySelector<HTMLElement>(
+        'tab-search-item[id="100"]')!;
     tabSearchItem.click();
     const [tabId, withSearch, isTab, index] =
         await testProxy.whenCalled('openRecentlyClosedEntry');
@@ -272,7 +253,7 @@
   test('Click on recently closed tab group item triggers action', async () => {
     const tabGroupData = {
       sessionId: 101,
-      id: sampleToken(0, 1),
+      id: sampleToken(0n, 1n),
       title: 'My Favorites',
       color: TabGroupColor.kBlue,
       tabCount: 1,
@@ -280,24 +261,22 @@
       lastActiveElapsedText: '',
     };
 
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{
         active: true,
         height: SAMPLE_WINDOW_HEIGHT,
-        tabs: [{
-          index: 0,
-          tabId: 1,
+        tabs: [createTab({
           title: 'Google',
           url: {url: 'https://www.google.com'},
-        }]
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })]
       }],
       recentlyClosedTabGroups: [tabGroupData],
       recentlyClosedSectionExpanded: true
-    });
+    }));
 
-    let tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-group-item'));
+    let tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-group-item')!;
     tabSearchItem.click();
     const [id, withSearch, isTab, index] =
         await testProxy.whenCalled('openRecentlyClosedEntry');
@@ -308,12 +287,11 @@
   });
 
   test('Keyboard navigation on an empty list', async () => {
-    await setupTest({
-      windows: [{active: true, tabs: []}],
-    });
+    await setupTest(createProfileData({
+      windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs: []}],
+    }));
 
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector("#searchField"));
+    const searchField = tabSearchApp.$.searchField;
 
     keyDownOn(searchField, 0, [], 'ArrowUp');
     assertEquals(-1, tabSearchApp.getSelectedIndex());
@@ -329,13 +307,12 @@
   });
 
   test('Keyboard navigation abides by item list range boundaries', async () => {
-    const testData = sampleData();
+    const testData = createProfileData();
     await setupTest(testData);
 
     const numTabs =
         testData.windows.reduce((total, w) => total + w.tabs.length, 0);
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector("#searchField"));
+    const searchField = tabSearchApp.$.searchField;
 
     keyDownOn(searchField, 0, [], 'ArrowUp');
     assertEquals(numTabs - 1, tabSearchApp.getSelectedIndex());
@@ -363,10 +340,7 @@
         const testData = generateSampleDataFromSiteNames(siteNames);
         await setupTest(testData);
 
-        const numTabs =
-            testData.windows.reduce((total, w) => total + w.tabs.length, 0);
-        const searchField = /** @type {!TabSearchSearchField} */
-            (tabSearchApp.shadowRoot.querySelector('#searchField'));
+        const searchField = tabSearchApp.$.searchField;
 
         keyDownOn(searchField, 0, ['shift'], 'Tab');
         await waitAfterNextRender(tabSearchApp);
@@ -378,10 +352,9 @@
       });
 
   test('Key with modifiers should not affect selected item', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
 
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
 
     for (const key of ['ArrowUp', 'ArrowDown', 'Home', 'End']) {
       keyDownOn(searchField, 0, ['shift'], key);
@@ -390,103 +363,83 @@
   });
 
   test('refresh on tabs changed', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
-    testProxy.getCallbackRouterRemote().tabsChanged({
-      windows: [],
-      recentlyClosedTabs: [],
-      tabGroups: [],
-      recentlyClosedTabGroups: [],
-    });
+    testProxy.getCallbackRouterRemote().tabsChanged(
+        createProfileData({windows: []}));
     await flushTasks();
     verifyTabIds(queryRows(), []);
     assertEquals(-1, tabSearchApp.getSelectedIndex());
   });
 
   test('On tabs changed, tab item selection preserved or updated', async () => {
-    const testData = sampleData();
+    const testData = createProfileData();
     await setupTest(testData);
 
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
     keyDownOn(searchField, 0, [], 'ArrowDown');
     assertEquals(1, tabSearchApp.getSelectedIndex());
 
-    testProxy.getCallbackRouterRemote().tabsChanged({
-      windows: [testData.windows[0]],
-      recentlyClosedTabs: [],
-      tabGroups: [],
-      recentlyClosedTabGroups: [],
-    });
+    testProxy.getCallbackRouterRemote().tabsChanged(createProfileData({
+      windows: [testData.windows[0]!],
+    }));
     await flushTasks();
     assertEquals(1, tabSearchApp.getSelectedIndex());
 
-    testProxy.getCallbackRouterRemote().tabsChanged({
-      windows: [{active: true, tabs: [testData.windows[0].tabs[0]]}],
-      recentlyClosedTabs: [],
-      tabGroups: [],
-      recentlyClosedTabGroups: [],
-    });
+    testProxy.getCallbackRouterRemote().tabsChanged(createProfileData({
+      windows: [{
+        active: true,
+        height: SAMPLE_WINDOW_HEIGHT,
+        tabs: [testData.windows[0]!.tabs[0]!]
+      }],
+    }));
     await flushTasks();
     assertEquals(0, tabSearchApp.getSelectedIndex());
   });
 
   test('refresh on tab updated', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
-    let tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="1"]'));
+    let tabSearchItem = tabSearchApp.$.tabsList.querySelector<TabSearchItem>(
+        'tab-search-item[id="1"]')!;
     assertEquals('Google', tabSearchItem.data.tab.title);
     assertEquals('https://www.google.com', tabSearchItem.data.tab.url.url);
-    const updatedTab = /** @type {!Tab} */ ({
-      alertStates: [],
-      index: 0,
-      tabId: 1,
-      title: 'Example',
-      url: {url: 'https://example.com'},
+    const updatedTab: Tab = createTab({
       lastActiveTimeTicks: {internalValue: BigInt(5)},
-      lastActiveElapsedText: '',
     });
-    const tabUpdateInfo = /** @type {!TabUpdateInfo} */ ({
+    const tabUpdateInfo = {
       inActiveWindow: true,
       tab: updatedTab,
-    });
+    };
     testProxy.getCallbackRouterRemote().tabUpdated(tabUpdateInfo);
     await flushTasks();
     // tabIds are not changed after tab updated.
     verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
-    tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="1"]'));
+    tabSearchItem =
+        tabSearchApp.$.tabsList.querySelector('tab-search-item[id="1"]')!;
     assertEquals(updatedTab.title, tabSearchItem.data.tab.title);
     assertEquals(updatedTab.url.url, tabSearchItem.data.tab.url.url);
-    assertEquals('example.com', tabSearchItem.data.hostname);
+    assertEquals('www.example.com', tabSearchItem.data.hostname);
   });
 
   test('tab update for tab not in profile data adds tab to list', async () => {
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{
         active: true,
         height: SAMPLE_WINDOW_HEIGHT,
         tabs: generateSampleTabsFromSiteNames(['OpenTab1'], true),
       }],
-    });
+    }));
     verifyTabIds(queryRows(), [1]);
 
-    const updatedTab = /** @type {!Tab} */ ({
-      alertStates: [],
-      index: 1,
+    const updatedTab: Tab = createTab({
       tabId: 2,
-      title: 'Example',
-      url: {url: 'https://example.com'},
       lastActiveTimeTicks: {internalValue: BigInt(5)},
-      lastActiveElapsedText: '',
     });
-    const tabUpdateInfo = /** @type {!TabUpdateInfo} */ ({
+    const tabUpdateInfo = {
       inActiveWindow: true,
       tab: updatedTab,
-    });
+    };
     testProxy.getCallbackRouterRemote().tabUpdated(tabUpdateInfo);
     await flushTasks();
     verifyTabIds(queryRows(), [2, 1]);
@@ -496,55 +449,53 @@
     // Simulates a scenario where there is no tab restore service available for
     // the current profile and thus, on removing a tab, there are no associated
     // recently closed tabs created, such as in a OTR case.
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
 
-    testProxy.getCallbackRouterRemote().tabsRemoved(
-        /** @type {!TabsRemovedInfo} */ ({
-          tabIds: [1, 2],
-          recentlyClosedTabs: [],
-        }));
+    testProxy.getCallbackRouterRemote().tabsRemoved({
+      tabIds: [1, 2],
+      recentlyClosedTabs: [],
+    });
     await flushTasks();
     verifyTabIds(queryRows(), [5, 6, 3, 4]);
 
     // Assert that on removing all items, we display the no-results div.
     testProxy.getCallbackRouterRemote().tabsRemoved(
-        /** @type {!TabsRemovedInfo} */ (
-            {tabIds: [3, 4, 5, 6], recentlyClosedTabs: []}));
+        {tabIds: [3, 4, 5, 6], recentlyClosedTabs: []});
     await flushTasks();
-    assertNotEquals(null, tabSearchApp.shadowRoot.querySelector('#no-results'));
+    assertNotEquals(
+        null, tabSearchApp.shadowRoot!.querySelector('#no-results'));
   });
 
   test('Closed tab appears in recently closed section', async () => {
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{
         active: true,
         height: SAMPLE_WINDOW_HEIGHT,
         tabs:
             generateSampleTabsFromSiteNames(['SampleTab', 'SampleTab2'], true),
       }],
-      recentlyClosedTabs: [],
       recentlyClosedSectionExpanded: true,
-    });
+    }));
     verifyTabIds(queryRows(), [1, 2]);
 
-    testProxy.getCallbackRouterRemote().tabsRemoved(
-        /** @type {!TabsRemovedInfo} */ ({
-          tabIds: [1],
-          recentlyClosedTabs: [/** @type {RecentlyClosedTab} */ ({
-            tabId: 3,
-            title: `SampleTab`,
-            url: {url: 'https://www.sampletab.com'},
-            lastActiveTime: {internalValue: BigInt(3)},
-            lastActiveElapsedText: '',
-          })],
-        }));
+    testProxy.getCallbackRouterRemote().tabsRemoved({
+      tabIds: [1],
+      recentlyClosedTabs: [{
+        tabId: 3,
+        title: `SampleTab`,
+        url: {url: 'https://www.sampletab.com'},
+        lastActiveTime: {internalValue: BigInt(3)},
+        lastActiveElapsedText: '',
+        groupId: undefined,
+      }],
+    });
     await flushTasks();
     verifyTabIds(queryRows(), [2, 3]);
   });
 
   test('Verify visibilitychange triggers data fetch', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     assertEquals(1, testProxy.getCallCount('getProfileData'));
 
     // When hidden visibilitychange should not trigger the data callback.
@@ -563,11 +514,10 @@
   });
 
   test('Verify hiding document resets selection and search text', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     assertEquals(1, testProxy.getCallCount('getProfileData'));
 
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('Apple');
     await flushTasks();
     verifyTabIds(queryRows(), [6, 4]);
@@ -595,14 +545,13 @@
   });
 
   test('Verify tab switch is logged correctly', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     // Make sure that tab data has been recieved.
-    verifyTabIds(queryRows(), [ 1, 5, 6, 2, 3, 4 ]);
+    verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
 
     // Click the first element with tabId 1.
-    let tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="1"]'));
+    let tabSearchItem = tabSearchApp.$.tabsList.querySelector<HTMLElement>(
+        'tab-search-item[id="1"]')!;
     tabSearchItem.click();
 
     // Assert switchToTab() was called appropriately for an unfiltered tab list.
@@ -615,9 +564,8 @@
 
     testProxy.reset();
     // Click the first element with tabId 6.
-    tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="6"]'));
+    tabSearchItem = tabSearchApp.$.tabsList.querySelector<HTMLElement>(
+        'tab-search-item[id="6"]')!;
     tabSearchItem.click();
 
     // Assert switchToTab() was called appropriately for an unfiltered tab list.
@@ -630,17 +578,15 @@
 
     // Force a change to filtered tab data that would result in a
     // re-render.
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('bing');
     await flushTasks();
-    verifyTabIds(queryRows(), [ 2 ]);
+    verifyTabIds(queryRows(), [2]);
 
     testProxy.reset();
     // Click the only remaining element with tabId 2.
-    tabSearchItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelector('tab-search-item[id="2"]'));
+    tabSearchItem = tabSearchApp.$.tabsList.querySelector<HTMLElement>(
+        'tab-search-item[id="2"]')!;
     tabSearchItem.click();
 
     // Assert switchToTab() was called appropriately for a tab list fitlered by
@@ -654,11 +600,11 @@
   });
 
   test('Verify showUI() is called correctly', async () => {
-    await setupTest(sampleData());
+    await setupTest(createProfileData());
     await waitAfterNextRender(tabSearchApp);
 
     // Make sure that tab data has been received.
-    verifyTabIds(queryRows(), [ 1, 5, 6, 2, 3, 4 ]);
+    verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]);
 
     // Ensure that showUI() has been called after the initial data has been
     // rendered.
@@ -666,12 +612,11 @@
 
     // Force a change to filtered tab data that would result in a
     // re-render.
-    const searchField = /** @type {!TabSearchSearchField} */
-        (tabSearchApp.shadowRoot.querySelector('#searchField'));
+    const searchField = tabSearchApp.$.searchField;
     searchField.setValue('bing');
     await flushTasks();
     await waitAfterNextRender(tabSearchApp);
-    verifyTabIds(queryRows(), [ 2 ]);
+    verifyTabIds(queryRows(), [2]);
 
     // |showUI()| should still have only been called once.
     assertEquals(1, testProxy.getCallCount('showUI'));
@@ -679,80 +624,73 @@
 
   test('Sort by most recent active tabs', async () => {
     const tabs = [
-      {
+      createTab({
         index: 0,
         tabId: 1,
         title: 'Google',
         url: {url: 'https://www.google.com'},
         lastActiveTimeTicks: {internalValue: BigInt(2)},
-        lastActiveElapsedText: '',
-      },
-      {
+      }),
+      createTab({
         index: 1,
         tabId: 2,
         title: 'Bing',
         url: {url: 'https://www.bing.com'},
         lastActiveTimeTicks: {internalValue: BigInt(4)},
-        lastActiveElapsedText: '',
         active: true,
-      },
-      {
+      }),
+      createTab({
         index: 2,
         tabId: 3,
         title: 'Yahoo',
         url: {url: 'https://www.yahoo.com'},
         lastActiveTimeTicks: {internalValue: BigInt(3)},
-        lastActiveElapsedText: '',
-      }
+      }),
     ];
 
     // Move active tab to the bottom of the list.
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}],
-    });
+    }));
     verifyTabIds(queryRows(), [3, 1, 2]);
 
     await setupTest(
-        {
+        createProfileData({
           windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}],
-        },
-        {'moveActiveTabToBottom': false});
+        }),
+        {moveActiveTabToBottom: false});
     verifyTabIds(queryRows(), [2, 3, 1]);
   });
 
   test('Tab associated with TabGroup data', async () => {
-    const token = sampleToken(1, 1);
+    const token = sampleToken(1n, 1n);
     const tabs = [
-      {
-        index: 0,
-        tabId: 1,
+      createTab({
         groupId: token,
         title: 'Google',
         url: {url: 'https://www.google.com'},
         lastActiveTimeTicks: {internalValue: BigInt(2)},
-        lastActiveElapsedText: '',
-      },
+      }),
     ];
-    const tabGroup = /** @type {!TabGroup} */ ({
+    const tabGroup = {
       id: token,
       color: TabGroupColor.kBlue,
       title: 'Search Engines',
-    });
+    };
 
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}],
       tabGroups: [tabGroup],
-    });
+    }));
 
-    let tabSearchItem = /** @type {!HTMLElement} */ (
-        tabSearchApp.shadowRoot.querySelector('#tabsList')
-            .querySelector('tab-search-item[id="1"]'));
+    let tabSearchItem = tabSearchApp.$.tabsList.querySelector<TabSearchItem>(
+        'tab-search-item[id="1"]')!;
     assertEquals('Google', tabSearchItem.data.tab.title);
-    assertEquals('Search Engines', tabSearchItem.data.tabGroup.title);
+    assertEquals('Search Engines', tabSearchItem.data.tabGroup!.title);
   });
 
   test('Recently closed section collapse and expand', async () => {
-    await setupTest({
+    await setupTest(createProfileData({
       windows: [{
         active: true,
         height: SAMPLE_WINDOW_HEIGHT,
@@ -760,27 +698,26 @@
       }],
       recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA,
       recentlyClosedSectionExpanded: true,
-    });
+    }));
     assertEquals(3, queryRows().length);
 
-    const recentlyClosedTitleItem = /** @type {!HTMLElement} */
-        (tabSearchApp.shadowRoot.querySelector('#tabsList')
-             .querySelectorAll('.list-section-title')[1]);
-    assertNotEquals(null, recentlyClosedTitleItem);
+    const recentlyClosedTitleItem =
+        tabSearchApp.$.tabsList.querySelectorAll('.list-section-title')[1];
+    assertTrue(!!recentlyClosedTitleItem);
 
-    const recentlyClosedTitleExpandButton = /** @type {!HTMLElement} */
-        (recentlyClosedTitleItem.querySelector('cr-expand-button'));
-    assertNotEquals(null, recentlyClosedTitleExpandButton);
+    const recentlyClosedTitleExpandButton =
+        recentlyClosedTitleItem!.querySelector('cr-expand-button');
+    assertTrue(!!recentlyClosedTitleExpandButton);
 
     // Collapse the `Recently Closed` section and assert item count.
-    recentlyClosedTitleExpandButton.click();
+    recentlyClosedTitleExpandButton!.click();
     const [expanded] =
         await testProxy.whenCalled('saveRecentlyClosedExpandedPref');
     assertFalse(expanded);
     assertEquals(1, queryRows().length);
 
     // Expand the `Recently Closed` section and assert item count.
-    recentlyClosedTitleExpandButton.click();
+    recentlyClosedTitleExpandButton!.click();
     assertEquals(2, testProxy.getCallCount('saveRecentlyClosedExpandedPref'));
     assertEquals(3, queryRows().length);
   });
diff --git a/chrome/test/data/webui/tab_search/tab_search_item_test.js b/chrome/test/data/webui/tab_search/tab_search_item_test.js
deleted file mode 100644
index ec4a7fd..0000000
--- a/chrome/test/data/webui/tab_search/tab_search_item_test.js
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {Tab, TabAlertState, TabData, TabGroup, TabGroupColor, TabItemType, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js';
-
-import {assertDeepEquals, assertEquals, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-import {sampleToken} from './tab_search_test_data.js';
-
-suite('TabSearchItemTest', () => {
-  /** @type {!TabSearchItem} */
-  let tabSearchItem;
-
-  /** @param {!TabData} data */
-  async function setupTest(data) {
-    tabSearchItem = /** @type {!TabSearchItem} */ (
-        document.createElement('tab-search-item'));
-    tabSearchItem.data = data;
-    document.body.innerHTML = '';
-    document.body.appendChild(tabSearchItem);
-    await flushTasks();
-  }
-
-  /**
-   * @param {string} text
-   * @param {?Array<{start:number, length:number}>} fieldHighlightRanges
-   * @param {!Array<string>} expected
-   */
-  async function assertTabSearchItemHighlights(
-      text, fieldHighlightRanges, expected) {
-    const data = new TabData(
-        {
-          active: true,
-          index: 0,
-          isDefaultFavicon: true,
-          lastActiveTimeTicks: {internalValue: BigInt(0)},
-          pinned: false,
-          showIcon: true,
-          tabId: 0,
-          url: {url: 'https://example.com'},
-          title: text,
-        },
-        TabItemType.OPEN_TAB, text);
-    data.highlightRanges = {
-      'tab.title': fieldHighlightRanges,
-      hostname: fieldHighlightRanges,
-    };
-    await setupTest(data);
-
-    assertHighlight(
-        /** @type {!HTMLElement} */ (tabSearchItem.$['primaryText']), expected);
-    assertHighlight(
-        /** @type {!HTMLElement} */ (tabSearchItem.$['secondaryText']),
-        expected);
-  }
-
-  /**
-   * @param {!HTMLElement} node
-   * @param {!Array<string>} expected
-   */
-  function assertHighlight(node, expected) {
-    assertDeepEquals(
-        expected,
-        [].slice.call(node.querySelectorAll('.search-highlight-hit'))
-            .map(e => e ? e.textContent : ''));
-  }
-
-  test('Highlight', async () => {
-    const text = 'Make work better';
-    await assertTabSearchItemHighlights(text, null, []);
-    await assertTabSearchItemHighlights(
-        text, [{start: 0, length: text.length}], ['Make work better']);
-    await assertTabSearchItemHighlights(
-        text, [{start: 0, length: 4}], ['Make']);
-    await assertTabSearchItemHighlights(
-        text, [{start: 0, length: 4}, {start: 10, length: 6}],
-        ['Make', 'better']);
-    await assertTabSearchItemHighlights(
-        text, [{start: 5, length: 4}], ['work']);
-  });
-
-  test('CloseButtonPresence', async () => {
-    await setupTest(new TabData(
-        {
-          active: true,
-          alertStates: [],
-          index: 0,
-          isDefaultFavicon: true,
-          lastActiveTimeTicks: {internalValue: BigInt(0)},
-          pinned: false,
-          showIcon: true,
-          tabId: 0,
-          url: {url: 'https://example.com'},
-          title: 'Example.com site',
-        },
-        TabItemType.OPEN_TAB, 'example'));
-
-    let tabSearchItemCloseButton = /** @type {!HTMLElement} */ (
-        tabSearchItem.shadowRoot.querySelector('cr-icon-button'));
-    assertNotEquals(null, tabSearchItemCloseButton);
-
-    await setupTest(new TabData(
-        {
-          tabId: 0,
-          title: 'Example.com site',
-          url: {url: 'https://example.com'},
-          lastActiveTimeTicks: {internalValue: BigInt(0)},
-        },
-        TabItemType.RECENTLY_CLOSED_TAB, 'example'));
-
-    tabSearchItemCloseButton = /** @type {!HTMLElement} */ (
-        tabSearchItem.shadowRoot.querySelector('cr-icon-button'));
-    assertEquals(null, tabSearchItemCloseButton);
-  });
-
-  test('GroupDetailsPresence', async () => {
-    const token = sampleToken(1, 1);
-    const tab = /** @type {!Tab} */ ({
-      active: true,
-      alertStates: [],
-      index: 0,
-      isDefaultFavicon: true,
-      lastActiveTimeTicks: {internalValue: BigInt(0)},
-      pinned: false,
-      showIcon: true,
-      tabId: 0,
-      groupId: token,
-      url: {url: 'https://example.com'},
-      title: 'Example.com site',
-    });
-
-    const tabGroup = /** @type {!TabGroup} */ ({
-      id: token,
-      color: TabGroupColor.kBlue,
-      title: 'Examples',
-    });
-
-    const tabData = new TabData(tab, TabItemType.OPEN_TAB, 'example');
-    tabData.tabGroup = tabGroup;
-    await setupTest(tabData);
-
-    const groupDotElement = tabSearchItem.shadowRoot.querySelector('#groupDot');
-    assertNotEquals(null, groupDotElement);
-    const groupDotComputedStyle = getComputedStyle(groupDotElement);
-    assertEquals(
-        groupDotComputedStyle.getPropertyValue('--tab-group-color-blue'),
-        groupDotComputedStyle.getPropertyValue('--group-dot-color'));
-
-    assertNotEquals(
-        null, tabSearchItem.shadowRoot.querySelector('#groupTitle'));
-  });
-
-  test('MediaAlertIndicatorPresence', async () => {
-    const token = sampleToken(1, 1);
-    const tab = /** @type {!Tab} */ ({
-      active: true,
-      alertStates: [TabAlertState.kMediaRecording, TabAlertState.kAudioPlaying],
-      index: 0,
-      isDefaultFavicon: true,
-      lastActiveTimeTicks: {internalValue: BigInt(0)},
-      pinned: false,
-      showIcon: true,
-      tabId: 0,
-      groupId: token,
-      url: {url: 'https://example.com'},
-      title: 'Example.com site',
-    });
-
-    await setupTest(new TabData(tab, TabItemType.OPEN_TAB, 'example'));
-
-    const recordingMediaAlert =
-        tabSearchItem.shadowRoot.querySelector('#mediaAlert');
-    assertNotEquals(null, recordingMediaAlert);
-    assertEquals('media-recording', recordingMediaAlert.getAttribute('class'));
-  });
-
-  test('MediaAlertIndicatorPresenceWithUnsupportedAlert', async () => {
-    /* Since we currently don't consider DesktopCapturing, the AudioPlaying
-     * should be displayed */
-    const token = sampleToken(1, 1);
-    const tab = /** @type {!Tab} */ ({
-      active: true,
-      alertStates:
-          [TabAlertState.kDesktopCapturing, TabAlertState.kAudioPlaying],
-      index: 0,
-      isDefaultFavicon: true,
-      lastActiveTimeTicks: {internalValue: BigInt(0)},
-      pinned: false,
-      showIcon: true,
-      tabId: 0,
-      groupId: token,
-      url: {url: 'https://example.com'},
-      title: 'Example.com site',
-    });
-
-    await setupTest(new TabData(tab, TabItemType.OPEN_TAB, 'example'));
-
-    const audioMediaAlert =
-        tabSearchItem.shadowRoot.querySelector('#mediaAlert');
-    assertNotEquals(null, audioMediaAlert);
-    assertEquals('audio-playing', audioMediaAlert.getAttribute('class'));
-  });
-
-});
diff --git a/chrome/test/data/webui/tab_search/tab_search_item_test.ts b/chrome/test/data/webui/tab_search/tab_search_item_test.ts
new file mode 100644
index 0000000..1f6202c
--- /dev/null
+++ b/chrome/test/data/webui/tab_search/tab_search_item_test.ts
@@ -0,0 +1,168 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {RecentlyClosedTab, Tab, TabAlertState, TabData, TabGroup, TabGroupColor, TabItemType, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js';
+
+import {assertDeepEquals, assertEquals, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
+
+import {createTab, sampleToken} from './tab_search_test_data.js';
+
+suite('TabSearchItemTest', () => {
+  let tabSearchItem: TabSearchItem;
+
+  async function setupTest(data: TabData) {
+    tabSearchItem = document.createElement('tab-search-item');
+    tabSearchItem.data = data;
+    document.body.innerHTML = '';
+    document.body.appendChild(tabSearchItem);
+    await flushTasks();
+  }
+
+  async function assertTabSearchItemHighlights(
+      text: string,
+      fieldHighlightRanges: Array<{start: number, length: number}>|null,
+      expected: string[]) {
+    const data = new TabData(
+        createTab({
+          active: true,
+          isDefaultFavicon: true,
+          showIcon: true,
+          title: text,
+        }),
+        TabItemType.OPEN_TAB, text);
+    if (fieldHighlightRanges !== null) {
+      data.highlightRanges = {
+        'tab.title': fieldHighlightRanges,
+        hostname: fieldHighlightRanges,
+      };
+    }
+    await setupTest(data);
+
+    assertHighlight(tabSearchItem.$['primaryText'], expected);
+    assertHighlight(tabSearchItem.$['secondaryText'], expected);
+  }
+
+  function assertHighlight(node: HTMLElement, expected: string[]) {
+    assertDeepEquals(
+        expected,
+        Array.from(node.querySelectorAll('.search-highlight-hit'))
+            .map(e => e ? e.textContent : ''));
+  }
+
+  test('Highlight', async () => {
+    const text = 'Make work better';
+    await assertTabSearchItemHighlights(text, null, []);
+    await assertTabSearchItemHighlights(
+        text, [{start: 0, length: text.length}], ['Make work better']);
+    await assertTabSearchItemHighlights(
+        text, [{start: 0, length: 4}], ['Make']);
+    await assertTabSearchItemHighlights(
+        text, [{start: 0, length: 4}, {start: 10, length: 6}],
+        ['Make', 'better']);
+    await assertTabSearchItemHighlights(
+        text, [{start: 5, length: 4}], ['work']);
+  });
+
+  test('CloseButtonPresence', async () => {
+    await setupTest(new TabData(
+        createTab({
+          active: true,
+          isDefaultFavicon: true,
+          showIcon: true,
+        }),
+        TabItemType.OPEN_TAB, 'example'));
+
+    let tabSearchItemCloseButton =
+        tabSearchItem.shadowRoot!.querySelector('cr-icon-button');
+    assertNotEquals(null, tabSearchItemCloseButton);
+
+    await setupTest(new TabData(
+        {
+          tabId: 0,
+          title: 'Example.com site',
+          url: {url: 'https://example.com'},
+          groupId: undefined,
+          lastActiveTime: {internalValue: BigInt(0)},
+          lastActiveElapsedText: '',
+        } as RecentlyClosedTab,
+        TabItemType.RECENTLY_CLOSED_TAB, 'example'));
+
+    tabSearchItemCloseButton =
+        tabSearchItem.shadowRoot!.querySelector('cr-icon-button');
+    assertEquals(null, tabSearchItemCloseButton);
+  });
+
+  test('GroupDetailsPresence', async () => {
+    const token = sampleToken(1n, 1n);
+    const tab: Tab = createTab({
+      active: true,
+      isDefaultFavicon: true,
+      showIcon: true,
+      groupId: token,
+    });
+
+    const tabGroup: TabGroup = {
+      id: token,
+      color: TabGroupColor.kBlue,
+      title: 'Examples',
+    };
+
+    const tabData = new TabData(tab, TabItemType.OPEN_TAB, 'example');
+    tabData.tabGroup = tabGroup;
+    await setupTest(tabData);
+
+    const groupDotElement =
+        tabSearchItem.shadowRoot!.querySelector('#groupDot')!;
+    assertNotEquals(null, groupDotElement);
+    const groupDotComputedStyle = getComputedStyle(groupDotElement!);
+    assertEquals(
+        groupDotComputedStyle.getPropertyValue('--tab-group-color-blue'),
+        groupDotComputedStyle.getPropertyValue('--group-dot-color'));
+
+    assertNotEquals(
+        null, tabSearchItem.shadowRoot!.querySelector('#groupTitle'));
+  });
+
+  test('MediaAlertIndicatorPresence', async () => {
+    const token = sampleToken(1n, 1n);
+    const tab: Tab = createTab({
+      active: true,
+      alertStates: [TabAlertState.kMediaRecording, TabAlertState.kAudioPlaying],
+      isDefaultFavicon: true,
+      showIcon: true,
+      groupId: token,
+    });
+
+    await setupTest(new TabData(tab, TabItemType.OPEN_TAB, 'example'));
+
+    const recordingMediaAlert =
+        tabSearchItem.shadowRoot!.querySelector<HTMLElement>('#mediaAlert');
+    assertNotEquals(null, recordingMediaAlert);
+    assertEquals('media-recording', recordingMediaAlert!.getAttribute('class'));
+  });
+
+  test('MediaAlertIndicatorPresenceWithUnsupportedAlert', async () => {
+    /* Since we currently don't consider DesktopCapturing, the AudioPlaying
+     * should be displayed */
+    const token = sampleToken(1n, 1n);
+    const tab: Tab = createTab({
+      active: true,
+      alertStates:
+          [TabAlertState.kDesktopCapturing, TabAlertState.kAudioPlaying],
+      isDefaultFavicon: true,
+      showIcon: true,
+      groupId: token,
+    });
+
+    await setupTest(new TabData(tab, TabItemType.OPEN_TAB, 'example'));
+
+    const audioMediaAlert =
+        tabSearchItem.shadowRoot!.querySelector<HTMLElement>('#mediaAlert');
+    assertNotEquals(null, audioMediaAlert);
+    assertEquals('audio-playing', audioMediaAlert!.getAttribute('class'));
+  });
+});
diff --git a/chrome/test/data/webui/tab_search/tab_search_test_data.ts b/chrome/test/data/webui/tab_search/tab_search_test_data.ts
index c101cde2..2090e26 100644
--- a/chrome/test/data/webui/tab_search/tab_search_test_data.ts
+++ b/chrome/test/data/webui/tab_search/tab_search_test_data.ts
@@ -7,107 +7,76 @@
 
 export const SAMPLE_WINDOW_HEIGHT: number = 448;
 
+export function createTab(overrides: Partial<Tab>): Tab {
+  return Object.assign(
+      {
+        active: false,
+        alertStates: [],
+        faviconUrl: undefined,
+        groupId: undefined,
+        index: 0,
+        isDefaultFavicon: false,
+        lastActiveElapsedText: '',
+        lastActiveTimeTicks: {internalValue: BigInt(0)},
+        pinned: false,
+        showIcon: false,
+        tabId: 1,
+        title: 'Example',
+        url: {url: 'https://www.example.com'},
+      },
+      overrides);
+}
+
 export const SAMPLE_WINDOW_DATA: Window[] = [
   {
     active: true,
     height: SAMPLE_WINDOW_HEIGHT,
     tabs: [
-      {
-        alertStates: [],
-        index: 0,
-        tabId: 1,
+      createTab({
         title: 'Google',
         url: {url: 'https://www.google.com'},
         lastActiveTimeTicks: {internalValue: BigInt(5)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
-      {
-        alertStates: [],
+      }),
+      createTab({
         index: 1,
         tabId: 5,
         title: 'Amazon',
         url: {url: 'https://www.amazon.com'},
         lastActiveTimeTicks: {internalValue: BigInt(4)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
-      {
-        alertStates: [],
+      }),
+      createTab({
         index: 2,
         tabId: 6,
         title: 'Apple',
         url: {url: 'https://www.apple.com'},
         lastActiveTimeTicks: {internalValue: BigInt(3)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
+      }),
     ],
   },
   {
     active: false,
     height: SAMPLE_WINDOW_HEIGHT,
     tabs: [
-      {
-        alertStates: [],
+      createTab({
         index: 0,
         tabId: 2,
         title: 'Bing',
         url: {url: 'https://www.bing.com/'},
         lastActiveTimeTicks: {internalValue: BigInt(2)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
-      {
-        alertStates: [],
+      }),
+      createTab({
         index: 1,
         tabId: 3,
         title: 'Yahoo',
         url: {url: 'https://www.yahoo.com'},
         lastActiveTimeTicks: {internalValue: BigInt(1)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
-      {
-        alertStates: [],
+      }),
+      createTab({
         index: 2,
         tabId: 4,
         title: 'Apple',
         url: {url: 'https://www.apple.com/'},
-        lastActiveTimeTicks: {internalValue: BigInt(0)},
-        lastActiveElapsedText: '',
-        active: false,
-        faviconUrl: undefined,
-        groupId: undefined,
-        isDefaultFavicon: false,
-        pinned: false,
-        showIcon: false,
-      },
+      }),
     ],
   }
 ];
@@ -131,16 +100,20 @@
   },
 ];
 
-export function sampleData(): ProfileData {
-  return {
-    windows: SAMPLE_WINDOW_DATA,
-    recentlyClosedTabs: [],
-    tabGroups: [],
-    recentlyClosedTabGroups: [],
-    recentlyClosedSectionExpanded: false,
-  };
+export function createProfileData(overrides?: Partial<ProfileData>):
+    ProfileData {
+  return Object.assign(
+      {
+        windows: SAMPLE_WINDOW_DATA,
+        tabGroups: [],
+        recentlyClosedTabGroups: [],
+        recentlyClosedTabs: [],
+        recentlyClosedSectionExpanded: false,
+      },
+      overrides || {});
 }
 
+
 export function sampleSiteNames(count: number): string[] {
   return Array.from({length: count}, (_, i) => (i + 1).toString());
 }
@@ -152,24 +125,28 @@
 export function generateSampleTabsFromSiteNames(
     siteNames: string[], hasIndex: boolean = true): Tab[] {
   return siteNames.map((siteName, i) => {
-    const tab: Tab = {
-      alertStates: [],
+    return createTab({
       tabId: i + 1,
       title: siteName,
       url: {url: 'https://www.' + siteName.toLowerCase() + '.com'},
       lastActiveTimeTicks: {internalValue: BigInt(siteNames.length - i)},
-      lastActiveElapsedText: '',
-
-      active: false,
-      faviconUrl: undefined,
-      groupId: undefined,
       index: hasIndex ? i : 0,
-      isDefaultFavicon: false,
-      pinned: false,
-      showIcon: false,
-    };
+    });
+  });
+}
 
-    return tab;
+export function generateSampleRecentlyClosedTabsFromSiteNames(
+    siteNames: string[]): RecentlyClosedTab[] {
+  return siteNames.map((siteName, i) => {
+    return {
+      tabId: i + 1,
+      groupId: undefined,
+      title: siteName,
+      url: {url: 'https://www.' + siteName.toLowerCase() + '.com'},
+      lastActiveTimeTicks: {internalValue: BigInt(siteNames.length - i)},
+      lastActiveTime: {internalValue: BigInt(siteNames.length - i)},
+      lastActiveElapsedText: '',
+    };
   });
 }
 
diff --git a/chrome/test/data/webui/tab_search/tab_search_test_helper.ts b/chrome/test/data/webui/tab_search/tab_search_test_helper.ts
index 88be0b4..f650e3d 100644
--- a/chrome/test/data/webui/tab_search/tab_search_test_helper.ts
+++ b/chrome/test/data/webui/tab_search/tab_search_test_helper.ts
@@ -3,13 +3,11 @@
 // found in the LICENSE file.
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {ProfileData} from 'chrome://tab-search.top-chrome/tab_search.js';
 import {assertGE, assertLE} from 'chrome://webui-test/chai_assert.js';
 
 /**
  * Override the specified function and parameters for the given class to avoid
  * scroll animations that delay the scrollTop property updates.
- * @param {!Object} klass
  */
 export function disableAnimationBehavior(klass: any, functionName: string) {
   const originalFunction = klass.prototype[functionName];
@@ -57,26 +55,10 @@
 }
 
 /**
- * Initialize a mock ProfileData object with defaults that would be set
- * by the Mojo IPC logic.
- */
-export function initProfileDataWithDefaults(profileData: ProfileData) {
-  ['tabGroups', 'recentlyClosedTabs', 'recentlyClosedTabGroups'].forEach(
-      (arrayProp) => {
-        if (!profileData.hasOwnProperty(arrayProp)) {
-          (profileData as {[key: string]: any})[arrayProp] = [];
-        }
-      });
-  if (!profileData.hasOwnProperty('recentlyClosedSectionExpanded')) {
-    profileData.recentlyClosedSectionExpanded = false;
-  }
-}
-
-/**
  * Initialize the loadTimeData with the provided data and defaults.
  */
 export function initLoadTimeDataWithDefaults(
-    loadTimeOverriddenData: {[key: string]: string} = {}) {
+    loadTimeOverriddenData: {[key: string]: number|string|boolean} = {}) {
   loadTimeData.overrideValues(Object.assign(
       {
         shortcutText: '',
diff --git a/chrome/test/data/webui/tab_search/tsconfig_base.json b/chrome/test/data/webui/tab_search/tsconfig_base.json
index eeddfb3..371e43b 100644
--- a/chrome/test/data/webui/tab_search/tsconfig_base.json
+++ b/chrome/test/data/webui/tab_search/tsconfig_base.json
@@ -1,7 +1,6 @@
 {
   "extends": "../../../../../tools/typescript/tsconfig_base.json",
   "compilerOptions": {
-    "allowJs": true,
     "typeRoots": [
        "./../../../../../third_party/node/node_modules/@types"
     ]
diff --git a/chromecast/cast_core/streaming_runtime_application.cc b/chromecast/cast_core/streaming_runtime_application.cc
index f38e956..b41661ad 100644
--- a/chromecast/cast_core/streaming_runtime_application.cc
+++ b/chromecast/cast_core/streaming_runtime_application.cc
@@ -9,6 +9,7 @@
 #include "components/cast/message_port/platform_message_port.h"
 #include "components/cast_streaming/browser/public/receiver_session.h"
 #include "components/cast_streaming/public/cast_streaming_url.h"
+#include "components/cast_streaming/public/constants.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -19,7 +20,6 @@
 namespace chromecast {
 namespace {
 
-const char kCastTransportBindingName[] = "cast.__platform__.cast_transport";
 const char kMediaCapabilitiesBindingName[] = "cast.__platform__.canDisplayType";
 
 const char kStreamingPageUrlTemplate[] =
@@ -84,8 +84,8 @@
   std::unique_ptr<cast_api_bindings::MessagePort> server_port;
   std::unique_ptr<cast_api_bindings::MessagePort> client_port;
   cast_api_bindings::CreatePlatformMessagePortPair(&client_port, &server_port);
-  message_port_service_->ConnectToPort(kCastTransportBindingName,
-                                       std::move(client_port));
+  message_port_service_->ConnectToPort(
+      cast_streaming::kCastTransportBindingName, std::move(client_port));
 
   // Allow for capturing of the renderer controls mojo pipe.
   Observe(cast_web_contents);
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 586d7a2..3f85bdc 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -70,7 +70,7 @@
     content::WebContents* web_contents,
     Client* client,
     const base::TickClock* tick_clock,
-    base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+    base::WeakPtr<RuntimeManager> runtime_manager,
     std::unique_ptr<Service> service,
     std::unique_ptr<AutofillAssistantTtsController> tts_controller,
     ukm::UkmRecorder* ukm_recorder,
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index d8c95aa..15d40ef3 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -19,7 +19,7 @@
 #include "components/autofill_assistant/browser/element_area.h"
 #include "components/autofill_assistant/browser/event_handler.h"
 #include "components/autofill_assistant/browser/metrics.h"
-#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
+#include "components/autofill_assistant/browser/public/runtime_manager.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
 #include "components/autofill_assistant/browser/script_tracker.h"
@@ -66,7 +66,7 @@
   Controller(content::WebContents* web_contents,
              Client* client,
              const base::TickClock* tick_clock,
-             base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+             base::WeakPtr<RuntimeManager> runtime_manager,
              std::unique_ptr<Service> service,
              std::unique_ptr<AutofillAssistantTtsController> tts_controller,
              ukm::UkmRecorder* ukm_recorder,
@@ -456,7 +456,7 @@
   ClientSettings settings_;
   const raw_ptr<Client> client_;
   const raw_ptr<const base::TickClock> tick_clock_;
-  base::WeakPtr<RuntimeManagerImpl> runtime_manager_;
+  base::WeakPtr<RuntimeManager> runtime_manager_;
 
   // Lazily instantiate in GetWebController().
   std::unique_ptr<WebController> web_controller_;
diff --git a/components/autofill_assistant/browser/public/mock_runtime_manager.cc b/components/autofill_assistant/browser/public/mock_runtime_manager.cc
index 473a1d9..f6829daa5 100644
--- a/components/autofill_assistant/browser/public/mock_runtime_manager.cc
+++ b/components/autofill_assistant/browser/public/mock_runtime_manager.cc
@@ -7,4 +7,9 @@
 namespace autofill_assistant {
 MockRuntimeManager::MockRuntimeManager() = default;
 MockRuntimeManager::~MockRuntimeManager() = default;
+
+base::WeakPtr<RuntimeManager> MockRuntimeManager::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/public/mock_runtime_manager.h b/components/autofill_assistant/browser/public/mock_runtime_manager.h
index a916a22d..e254f41 100644
--- a/components/autofill_assistant/browser/public/mock_runtime_manager.h
+++ b/components/autofill_assistant/browser/public/mock_runtime_manager.h
@@ -5,20 +5,26 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_MOCK_RUNTIME_MANAGER_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_MOCK_RUNTIME_MANAGER_H_
 
-#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/public/runtime_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
 
-class MockRuntimeManager : public RuntimeManagerImpl {
+class MockRuntimeManager : public RuntimeManager {
  public:
   MockRuntimeManager();
-  ~MockRuntimeManager() override;
+  virtual ~MockRuntimeManager();
 
   MOCK_METHOD1(AddObserver, void(RuntimeObserver*));
   MOCK_METHOD1(RemoveObserver, void(RuntimeObserver*));
   MOCK_CONST_METHOD0(GetState, UIState());
   MOCK_METHOD1(SetUIState, void(UIState));
+
+  base::WeakPtr<RuntimeManager> GetWeakPtr() final;
+
+ private:
+  base::WeakPtrFactory<MockRuntimeManager> weak_ptr_factory_{this};
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/public/runtime_manager.h b/components/autofill_assistant/browser/public/runtime_manager.h
index 7eb9d251..acacfbd 100644
--- a/components/autofill_assistant/browser/public/runtime_manager.h
+++ b/components/autofill_assistant/browser/public/runtime_manager.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_H_
 
+#include "base/memory/weak_ptr.h"
 #include "components/autofill_assistant/browser/public/runtime_observer.h"
 #include "components/autofill_assistant/browser/public/ui_state.h"
 #include "content/public/browser/web_contents.h"
@@ -31,6 +32,10 @@
 
   // Return Autofill Assistant state.
   virtual UIState GetState() const = 0;
+
+  virtual void SetUIState(UIState state) = 0;
+
+  virtual base::WeakPtr<RuntimeManager> GetWeakPtr() = 0;
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/public/runtime_manager_impl.cc b/components/autofill_assistant/browser/public/runtime_manager_impl.cc
index e05c45f..7b316e2 100644
--- a/components/autofill_assistant/browser/public/runtime_manager_impl.cc
+++ b/components/autofill_assistant/browser/public/runtime_manager_impl.cc
@@ -16,8 +16,6 @@
 
 RuntimeManagerImpl::RuntimeManagerImpl(content::WebContents* web_contents) {}
 
-RuntimeManagerImpl::RuntimeManagerImpl() = default;
-
 RuntimeManagerImpl::~RuntimeManagerImpl() = default;
 
 void RuntimeManagerImpl::AddObserver(RuntimeObserver* observer) {
@@ -41,7 +39,7 @@
   }
 }
 
-base::WeakPtr<RuntimeManagerImpl> RuntimeManagerImpl::GetWeakPtr() {
+base::WeakPtr<RuntimeManager> RuntimeManagerImpl::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
diff --git a/components/autofill_assistant/browser/public/runtime_manager_impl.h b/components/autofill_assistant/browser/public/runtime_manager_impl.h
index 8980d30..52a009d 100644
--- a/components/autofill_assistant/browser/public/runtime_manager_impl.h
+++ b/components/autofill_assistant/browser/public/runtime_manager_impl.h
@@ -31,16 +31,12 @@
   void AddObserver(RuntimeObserver* observer) override;
   void RemoveObserver(RuntimeObserver* observer) override;
   UIState GetState() const override;
-
-  virtual void SetUIState(UIState state);
-
-  base::WeakPtr<RuntimeManagerImpl> GetWeakPtr();
+  void SetUIState(UIState state) override;
+  base::WeakPtr<RuntimeManager> GetWeakPtr() override;
 
  private:
   friend class content::WebContentsUserData<RuntimeManagerImpl>;
-  friend class MockRuntimeManager;
 
-  RuntimeManagerImpl();
   explicit RuntimeManagerImpl(content::WebContents* web_contents);
 
   // Holds the state of Autofill Assistant.
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc
index d1e33cd..d573cc68 100644
--- a/components/autofill_assistant/browser/starter.cc
+++ b/components/autofill_assistant/browser/starter.cc
@@ -168,7 +168,7 @@
 Starter::Starter(content::WebContents* web_contents,
                  StarterPlatformDelegate* platform_delegate,
                  ukm::UkmRecorder* ukm_recorder,
-                 base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+                 base::WeakPtr<RuntimeManager> runtime_manager,
                  const base::TickClock* tick_clock)
     : content::WebContentsObserver(web_contents),
       current_ukm_source_id_(
diff --git a/components/autofill_assistant/browser/starter.h b/components/autofill_assistant/browser/starter.h
index e9a537c3..acb531d3 100644
--- a/components/autofill_assistant/browser/starter.h
+++ b/components/autofill_assistant/browser/starter.h
@@ -16,7 +16,7 @@
 #include "base/time/time.h"
 #include "components/autofill_assistant/browser/controller.h"
 #include "components/autofill_assistant/browser/metrics.h"
-#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
+#include "components/autofill_assistant/browser/public/runtime_manager.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/starter_heuristic.h"
 #include "components/autofill_assistant/browser/starter_platform_delegate.h"
@@ -35,7 +35,7 @@
   explicit Starter(content::WebContents* web_contents,
                    StarterPlatformDelegate* platform_delegate,
                    ukm::UkmRecorder* ukm_recorder,
-                   base::WeakPtr<RuntimeManagerImpl> runtime_manager,
+                   base::WeakPtr<RuntimeManager> runtime_manager,
                    const base::TickClock* tick_clock);
   ~Starter() override;
   Starter(const Starter&) = delete;
@@ -173,7 +173,7 @@
   bool is_custom_tab_ = false;
   const raw_ptr<StarterPlatformDelegate> platform_delegate_;
   raw_ptr<ukm::UkmRecorder> ukm_recorder_ = nullptr;
-  base::WeakPtr<RuntimeManagerImpl> runtime_manager_;
+  base::WeakPtr<RuntimeManager> runtime_manager_;
   bool fetch_trigger_scripts_on_navigation_ = false;
   std::unique_ptr<TriggerContext> pending_trigger_context_;
   std::unique_ptr<TriggerScriptCoordinator> trigger_script_coordinator_;
diff --git a/components/cast_streaming/browser/BUILD.gn b/components/cast_streaming/browser/BUILD.gn
index f8512cdb..27f18a2 100644
--- a/components/cast_streaming/browser/BUILD.gn
+++ b/components/cast_streaming/browser/BUILD.gn
@@ -11,7 +11,9 @@
 source_set("core") {
   deps = [
     "//base",
+    "//chromecast/bindings/shared:proto_serializer",
     "//media",
+    "//third_party/cast_core/public/src/proto/bindings:cast_channel_proto",
   ]
   public_deps = [
     "//components/cast/message_port",
diff --git a/components/cast_streaming/browser/DEPS b/components/cast_streaming/browser/DEPS
index 0376433a..3ea1f73 100644
--- a/components/cast_streaming/browser/DEPS
+++ b/components/cast_streaming/browser/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chromecast/bindings/shared",
   "+components/cast/message_port",
   "+components/openscreen_platform",
   "+media/base",
@@ -7,4 +8,5 @@
   "+mojo/public",
   "+net/base",
   "+third_party/openscreen/src",
+  "+third_party/cast_core/public/src",
 ]
diff --git a/components/cast_streaming/browser/message_serialization.cc b/components/cast_streaming/browser/message_serialization.cc
index 10a7095..aa7e5669 100644
--- a/components/cast_streaming/browser/message_serialization.cc
+++ b/components/cast_streaming/browser/message_serialization.cc
@@ -4,10 +4,12 @@
 
 #include "components/cast_streaming/browser/message_serialization.h"
 
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/values.h"
+#include "base/base64.h"
+#include "chromecast/bindings/shared/proto_serializer.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/cast_core/public/src/proto/bindings/cast_channel.pb.h"
+
+using CastChannelMessage = cast::bindings::CastChannelMessage;
 
 namespace cast_streaming {
 
@@ -17,8 +19,6 @@
 const char kInjectNamespace[] = "urn:x-cast:com.google.cast.inject";
 const char kMediaNamespace[] = "urn:x-cast:com.google.cast.media";
 
-const char kKeySenderId[] = "senderId";
-const char kKeyNamespace[] = "namespace";
 const char kKeyData[] = "data";
 const char kKeyType[] = "type";
 const char kKeyRequestId[] = "requestId";
@@ -55,29 +55,20 @@
                             std::string* sender_id,
                             std::string* message_namespace,
                             std::string* message) {
-  absl::optional<base::Value> converted_value = base::JSONReader::Read(buffer);
-  if (!converted_value)
+  absl::optional<CastChannelMessage> proto =
+      chromecast::bindings::ProtoSerializer<CastChannelMessage>::Deserialize(
+          buffer);
+  if (!proto) {
     return false;
+  }
 
-  if (!converted_value->is_dict())
+  if (proto->payload_case() != CastChannelMessage::PayloadCase::kPayloadUtf8) {
     return false;
+  }
 
-  const std::string* sender_id_value =
-      converted_value->FindStringPath(kKeySenderId);
-  if (!sender_id_value)
-    return false;
-  *sender_id = *sender_id_value;
-
-  const std::string* message_namespace_value =
-      converted_value->FindStringPath(kKeyNamespace);
-  if (!message_namespace_value)
-    return false;
-  *message_namespace = *message_namespace_value;
-
-  const std::string* message_value = converted_value->FindStringPath(kKeyData);
-  if (!message_value)
-    return false;
-  *message = *message_value;
+  *sender_id = proto->sender_id();
+  *message_namespace = proto->ns();
+  *message = proto->payload_utf8();
 
   return true;
 }
@@ -85,14 +76,13 @@
 std::string SerializeCastMessage(const std::string& sender_id,
                                  const std::string& message_namespace,
                                  const std::string& message) {
-  base::Value value(base::Value::Type::DICTIONARY);
-  value.SetStringKey(kKeyNamespace, message_namespace);
-  value.SetStringKey(kKeySenderId, sender_id);
-  value.SetStringKey(kKeyData, message);
+  CastChannelMessage proto;
+  proto.set_sender_id(sender_id);
+  proto.set_ns(message_namespace);
+  proto.set_payload_utf8(message);
 
-  std::string json_message;
-  CHECK(base::JSONWriter::Write(value, &json_message));
-  return json_message;
+  return chromecast::bindings::ProtoSerializer<CastChannelMessage>::Serialize(
+      proto);
 }
 
 }  // namespace cast_streaming
diff --git a/components/cast_streaming/browser/message_serialization.h b/components/cast_streaming/browser/message_serialization.h
index 1f2673c..2217787 100644
--- a/components/cast_streaming/browser/message_serialization.h
+++ b/components/cast_streaming/browser/message_serialization.h
@@ -19,8 +19,6 @@
 extern const char kInjectNamespace[];
 extern const char kMediaNamespace[];
 
-extern const char kKeySenderId[];
-extern const char kKeyNamespace[];
 extern const char kKeyData[];
 extern const char kKeyType[];
 extern const char kKeyRequestId[];
diff --git a/components/cast_streaming/public/BUILD.gn b/components/cast_streaming/public/BUILD.gn
index 95602d8c..5affc2d 100644
--- a/components/cast_streaming/public/BUILD.gn
+++ b/components/cast_streaming/public/BUILD.gn
@@ -10,6 +10,8 @@
   sources = [
     "cast_streaming_url.cc",
     "cast_streaming_url.h",
+    "constants.cc",
+    "constants.h",
   ]
 }
 
diff --git a/components/cast_streaming/public/constants.cc b/components/cast_streaming/public/constants.cc
new file mode 100644
index 0000000..b96ba0c
--- /dev/null
+++ b/components/cast_streaming/public/constants.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cast_streaming/public/constants.h"
+
+namespace cast_streaming {
+
+const char kCastTransportBindingName[] =
+    "cast.__platform__.proto_cast_transport";
+
+}  // namespace cast_streaming
diff --git a/components/cast_streaming/public/constants.h b/components/cast_streaming/public/constants.h
new file mode 100644
index 0000000..29e4661d
--- /dev/null
+++ b/components/cast_streaming/public/constants.h
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CAST_STREAMING_PUBLIC_CONSTANTS_H_
+#define COMPONENTS_CAST_STREAMING_PUBLIC_CONSTANTS_H_
+
+namespace cast_streaming {
+
+// Name of the binding with which |ReceiverSession| communicates. Used for
+// setting up the MessagePort.
+extern const char kCastTransportBindingName[];
+
+}  // namespace cast_streaming
+
+#endif  // COMPONENTS_CAST_STREAMING_PUBLIC_CONSTANTS_H_
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 05f2d09a..d2f5f59e 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "4.52",
-  "log_list_timestamp": "2021-12-08T01:34:10Z",
+  "version": "4.53",
+  "log_list_timestamp": "2021-12-09T01:35:04Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/enterprise/content/copy_prevention_settings_policy_handler.cc b/components/enterprise/content/copy_prevention_settings_policy_handler.cc
index c4e2ad00..ad7066b4 100644
--- a/components/enterprise/content/copy_prevention_settings_policy_handler.cc
+++ b/components/enterprise/content/copy_prevention_settings_policy_handler.cc
@@ -38,6 +38,13 @@
   if (!SchemaValidatingPolicyHandler::CheckPolicySettings(policies, errors))
     return false;
 
+  const policy::PolicyMap::Entry* policy = policies.Get(policy_name());
+  if (policy->source != policy::POLICY_SOURCE_CLOUD &&
+      policy->source != policy::POLICY_SOURCE_CLOUD_FROM_ASH) {
+    errors->AddError(policy_name(), IDS_POLICY_CLOUD_SOURCE_ONLY_ERROR);
+    return false;
+  }
+
   const base::Value* enable = value->FindListKey(
       enterprise::content::kCopyPreventionSettingsEnableFieldName);
   const base::Value* disable = value->FindListKey(
diff --git a/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc b/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc
index 80fe0799..db005f51 100644
--- a/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc
+++ b/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc
@@ -135,6 +135,24 @@
 }
 
 TEST_F(CopyPreventionSettingsPolicyHandlerTest,
+       TestValidPolicyNotAppliedIfNotFromCloud) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(
+      kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+      policy::PolicyScope::POLICY_SCOPE_MACHINE,
+      policy::PolicySource::POLICY_SOURCE_PLATFORM,
+      base::JSONReader::Read(kValidPolicy, base::JSON_ALLOW_TRAILING_COMMAS),
+      nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_FALSE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_FALSE(errors.empty());
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest,
        TestValidPolicyWithoutMinDataSizeDefaultsTo100) {
   policy::PolicyMap policy_map;
   policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
diff --git a/components/optimization_guide/content/browser/page_content_annotations_service.cc b/components/optimization_guide/content/browser/page_content_annotations_service.cc
index e3e0e1b..213c2d5 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_service.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_service.cc
@@ -264,6 +264,18 @@
 #endif
 }
 
+void PageContentAnnotationsService::PersistRemotePageEntities(
+    const HistoryVisit& history_visit,
+    const std::vector<history::VisitContentModelAnnotations::Category>&
+        entities) {
+  history::VisitContentModelAnnotations annotations;
+  annotations.entities = entities;
+  QueryURL(history_visit,
+           base::BindOnce(
+               &history::HistoryService::AddContentModelAnnotationsForVisit,
+               history_service_->AsWeakPtr(), annotations));
+}
+
 // static
 HistoryVisit PageContentAnnotationsService::CreateHistoryVisitFromWebContents(
     content::WebContents* web_contents,
diff --git a/components/optimization_guide/content/browser/page_content_annotations_service.h b/components/optimization_guide/content/browser/page_content_annotations_service.h
index f88c4342..45a08445 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_service.h
+++ b/components/optimization_guide/content/browser/page_content_annotations_service.h
@@ -144,6 +144,14 @@
       continuous_search::SearchResultExtractorClientStatus status,
       continuous_search::mojom::CategoryResultsPtr results);
 
+  // Persist |entities| for |visit| in |history_service_|.
+  //
+  // Virtualized for testing.
+  virtual void PersistRemotePageEntities(
+      const HistoryVisit& visit,
+      const std::vector<history::VisitContentModelAnnotations::Category>&
+          entities);
+
   using PersistAnnotationsCallback = base::OnceCallback<void(history::VisitID)>;
   // Queries |history_service| for all the visits to the visited URL of |visit|.
   // |callback| will be invoked to write the bound content annotations to
diff --git a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
index 30fd351..8eea9f27 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
@@ -8,8 +8,10 @@
 #include "base/i18n/case_conversion.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/google/core/common/google_util.h"
+#include "components/optimization_guide/content/browser/optimization_guide_decider.h"
 #include "components/optimization_guide/content/browser/page_content_annotations_service.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/proto/page_entities_metadata.pb.h"
 #include "components/search_engines/template_url_service.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
@@ -72,12 +74,14 @@
     PageContentAnnotationsWebContentsObserver(
         content::WebContents* web_contents,
         PageContentAnnotationsService* page_content_annotations_service,
-        TemplateURLService* template_url_service)
+        TemplateURLService* template_url_service,
+        OptimizationGuideDecider* optimization_guide_decider)
     : content::WebContentsObserver(web_contents),
       content::WebContentsUserData<PageContentAnnotationsWebContentsObserver>(
           *web_contents),
       page_content_annotations_service_(page_content_annotations_service),
       template_url_service_(template_url_service),
+      optimization_guide_decider_(optimization_guide_decider),
       max_size_for_text_dump_(features::MaxSizeForPageContentTextDump()) {
   DCHECK(page_content_annotations_service_);
 
@@ -88,6 +92,11 @@
         PageTextObserver::GetOrCreateForWebContents(web_contents);
     observer->AddConsumer(this);
   }
+
+  if (features::RemotePageEntitiesEnabled() && optimization_guide_decider_) {
+    optimization_guide_decider_->RegisterOptimizationTypes(
+        {proto::PAGE_ENTITIES});
+  }
 }
 
 PageContentAnnotationsWebContentsObserver::
@@ -123,6 +132,14 @@
       PageContentAnnotationsService::CreateHistoryVisitFromWebContents(
           web_contents(), navigation_handle->GetNavigationId());
 
+  if (features::RemotePageEntitiesEnabled() && optimization_guide_decider_) {
+    optimization_guide_decider_->CanApplyOptimizationAsync(
+        navigation_handle, proto::PAGE_ENTITIES,
+        base::BindOnce(&PageContentAnnotationsWebContentsObserver::
+                           OnRemotePageEntitiesReceived,
+                       weak_ptr_factory_.GetWeakPtr(), history_visit));
+  }
+
   if (google_util::IsGoogleSearchUrl(navigation_handle->GetURL())) {
     // Extract related searches.
     if (optimization_guide::features::ShouldExtractRelatedSearches()) {
@@ -232,6 +249,33 @@
       visit, *result.GetMainFrameTextContent());
 }
 
+void PageContentAnnotationsWebContentsObserver::OnRemotePageEntitiesReceived(
+    const HistoryVisit& history_visit,
+    OptimizationGuideDecision decision,
+    const OptimizationMetadata& metadata) {
+  if (decision != OptimizationGuideDecision::kTrue)
+    return;
+
+  absl::optional<proto::PageEntitiesMetadata> page_entities_metadata =
+      metadata.ParsedMetadata<proto::PageEntitiesMetadata>();
+  if (!page_entities_metadata || page_entities_metadata->entities().size() == 0)
+    return;
+
+  std::vector<history::VisitContentModelAnnotations::Category> entities;
+  for (const auto& entity : page_entities_metadata->entities()) {
+    if (entity.entity_id().empty())
+      continue;
+
+    if (entity.score() < 0 || entity.score() > 100)
+      continue;
+
+    entities.emplace_back(history::VisitContentModelAnnotations::Category(
+        entity.entity_id(), entity.score()));
+  }
+  page_content_annotations_service_->PersistRemotePageEntities(history_visit,
+                                                               entities);
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(PageContentAnnotationsWebContentsObserver);
 
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
index 0f32498..c041782 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
+++ b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
@@ -19,7 +19,10 @@
 
 namespace optimization_guide {
 
+enum class OptimizationGuideDecision;
 struct HistoryVisit;
+class OptimizationGuideDecider;
+class OptimizationMetadata;
 class PageContentAnnotationsService;
 
 // This class is used to dispatch page content to the
@@ -41,7 +44,8 @@
   PageContentAnnotationsWebContentsObserver(
       content::WebContents* web_contents,
       PageContentAnnotationsService* page_content_annotations_service,
-      TemplateURLService* template_url_service);
+      TemplateURLService* template_url_service,
+      OptimizationGuideDecider* optimization_guide_decider);
 
  private:
   friend class content::WebContentsUserData<
@@ -61,12 +65,21 @@
   void OnTextDumpReceived(const HistoryVisit& visit,
                           const PageTextDumpResult& result);
 
+  // Callback invoked when the page entities have been received from
+  // |optimization_guide_decider_| for |visit|.
+  void OnRemotePageEntitiesReceived(const HistoryVisit& visit,
+                                    OptimizationGuideDecision decision,
+                                    const OptimizationMetadata& metadata);
+
   // Not owned. Guaranteed to outlive |this|.
   raw_ptr<PageContentAnnotationsService> page_content_annotations_service_;
 
   // Not owned. Guaranteed to outlive |this|.
   raw_ptr<const TemplateURLService> template_url_service_;
 
+  // Not owned. Guaranteed to outlive |this|.
+  raw_ptr<OptimizationGuideDecider> optimization_guide_decider_;
+
   // The max size to request for text dump.
   const uint64_t max_size_for_text_dump_;
 
diff --git a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
index 8e561d6..5bc6b7b 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
@@ -12,8 +12,10 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/optimization_guide/content/browser/page_content_annotations_service.h"
 #include "components/optimization_guide/content/browser/page_text_dump_result.h"
+#include "components/optimization_guide/content/browser/test_optimization_guide_decider.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/core/test_optimization_guide_model_provider.h"
+#include "components/optimization_guide/proto/page_entities_metadata.pb.h"
 #include "components/search_engines/template_url_service.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/navigation_simulator.h"
@@ -22,6 +24,12 @@
 
 namespace optimization_guide {
 
+namespace {
+
+using ::testing::UnorderedElementsAre;
+
+}  // namespace
+
 const TemplateURLService::Initializer kTemplateURLData[] = {
     {"default-engine.com", "http://default-engine.com/search?q={searchTerms}",
      "Default"},
@@ -80,10 +88,88 @@
     return last_related_searches_extraction_request_;
   }
 
+  void PersistRemotePageEntities(
+      const HistoryVisit& visit,
+      const std::vector<history::VisitContentModelAnnotations::Category>&
+          entities) override {
+    last_entities_persistence_request_.emplace(std::make_pair(visit, entities));
+  }
+
+  absl::optional<
+      std::pair<HistoryVisit,
+                std::vector<history::VisitContentModelAnnotations::Category>>>
+  last_entities_persistence_request() const {
+    return last_entities_persistence_request_;
+  }
+
  private:
   absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request_;
   absl::optional<std::pair<HistoryVisit, content::WebContents*>>
       last_related_searches_extraction_request_;
+  absl::optional<
+      std::pair<HistoryVisit,
+                std::vector<history::VisitContentModelAnnotations::Category>>>
+      last_entities_persistence_request_;
+};
+
+class FakeOptimizationGuideDecider : public TestOptimizationGuideDecider {
+ public:
+  void RegisterOptimizationTypes(
+      const std::vector<proto::OptimizationType>& optimization_types) override {
+    registered_optimization_types_ = optimization_types;
+  }
+
+  std::vector<proto::OptimizationType> registered_optimization_types() {
+    return registered_optimization_types_;
+  }
+
+  void CanApplyOptimizationAsync(
+      content::NavigationHandle* navigation_handle,
+      proto::OptimizationType optimization_type,
+      OptimizationGuideDecisionCallback callback) override {
+    DCHECK(optimization_type == proto::PAGE_ENTITIES);
+
+    std::string url_spec = navigation_handle->GetURL().spec();
+    if (navigation_handle->GetURL() == GURL("http://hasentities.com/")) {
+      proto::PageEntitiesMetadata page_entities_metadata;
+      proto::Entity* entity = page_entities_metadata.add_entities();
+      entity->set_entity_id("entity1");
+      entity->set_score(50);
+
+      // The following entities should be skipped.
+      proto::Entity* entity2 = page_entities_metadata.add_entities();
+      entity2->set_score(50);
+      proto::Entity* entity3 = page_entities_metadata.add_entities();
+      entity3->set_entity_id("scoretoohigh");
+      entity3->set_score(105);
+      proto::Entity* entity4 = page_entities_metadata.add_entities();
+      entity4->set_entity_id("scoretoolow");
+      entity4->set_score(-1);
+
+      OptimizationMetadata metadata;
+      metadata.SetAnyMetadataForTesting(page_entities_metadata);
+      std::move(callback).Run(OptimizationGuideDecision::kTrue, metadata);
+      return;
+    }
+    if (navigation_handle->GetURL() == GURL("http://noentities.com/")) {
+      proto::PageEntitiesMetadata page_entities_metadata;
+      OptimizationMetadata metadata;
+      metadata.SetAnyMetadataForTesting(page_entities_metadata);
+      std::move(callback).Run(OptimizationGuideDecision::kTrue, metadata);
+      return;
+    }
+    if (navigation_handle->GetURL() == GURL("http://wrongmetadata.com/")) {
+      OptimizationMetadata metadata;
+      proto::Entity entity;
+      metadata.SetAnyMetadataForTesting(entity);
+      std::move(callback).Run(OptimizationGuideDecision::kTrue, metadata);
+      return;
+    }
+    std::move(callback).Run(OptimizationGuideDecision::kFalse, {});
+  }
+
+ private:
+  std::vector<proto::OptimizationType> registered_optimization_types_;
 };
 
 class PageContentAnnotationsWebContentsObserverTest
@@ -93,7 +179,8 @@
     scoped_feature_list_.InitAndEnableFeatureWithParameters(
         features::kPageContentAnnotations,
         {{"extract_related_searches", "false"},
-         {"annotate_title_instead_of_page_content", "false"}});
+         {"annotate_title_instead_of_page_content", "false"},
+         {"fetch_remote_page_entities", "false"}});
   }
 
   void SetUp() override {
@@ -113,13 +200,16 @@
         kDefaultTemplateURLKeyword);
     template_url_service_->SetUserSelectedDefaultSearchProvider(template_url_);
 
+    optimization_guide_decider_ =
+        std::make_unique<FakeOptimizationGuideDecider>();
+
     page_text_observer_ = new TestPageTextObserver(web_contents());
     web_contents()->SetUserData(TestPageTextObserver::UserDataKey(),
                                 base::WrapUnique(page_text_observer_.get()));
 
     PageContentAnnotationsWebContentsObserver::CreateForWebContents(
         web_contents(), page_content_annotations_service_.get(),
-        template_url_service_.get());
+        template_url_service_.get(), optimization_guide_decider_.get());
 
     // Overwrite Google base URL.
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -131,6 +221,7 @@
     page_content_annotations_service_.reset();
     optimization_guide_model_provider_.reset();
     template_url_service_.reset();
+    optimization_guide_decider_.reset();
 
     content::RenderViewHostTestHarness::TearDown();
   }
@@ -146,6 +237,10 @@
 
   TestPageTextObserver* page_text_observer() { return page_text_observer_; }
 
+  FakeOptimizationGuideDecider* optimization_guide_decider() {
+    return optimization_guide_decider_.get();
+  }
+
   std::unique_ptr<PageTextObserver::ConsumerTextDumpRequest>
   RequestTextDumpForUrl(const GURL& url, bool is_same_document = false) {
     content::MockNavigationHandle navigation_handle(url, main_rfh());
@@ -167,8 +262,14 @@
   std::unique_ptr<TemplateURLService> template_url_service_;
   raw_ptr<TemplateURL> template_url_;
   raw_ptr<TestPageTextObserver> page_text_observer_;
+  std::unique_ptr<FakeOptimizationGuideDecider> optimization_guide_decider_;
 };
 
+TEST_F(PageContentAnnotationsWebContentsObserverTest, DoesNotRegisterType) {
+  EXPECT_TRUE(
+      optimization_guide_decider()->registered_optimization_types().empty());
+}
+
 TEST_F(PageContentAnnotationsWebContentsObserverTest,
        HooksIntoPageTextObserver) {
   EXPECT_TRUE(page_text_observer()->add_consumer_called());
@@ -402,4 +503,70 @@
   EXPECT_FALSE(service()->last_annotation_request());
 }
 
+class PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest
+    : public PageContentAnnotationsWebContentsObserverTest {
+ public:
+  PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest() {
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        features::kPageContentAnnotations,
+        {{"fetch_remote_page_entities", "true"}});
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest,
+       RegistersTypeWhenFeatureEnabled) {
+  std::vector<proto::OptimizationType> registered_optimization_types =
+      optimization_guide_decider()->registered_optimization_types();
+  EXPECT_EQ(registered_optimization_types.size(), 1u);
+  EXPECT_EQ(registered_optimization_types[0], proto::PAGE_ENTITIES);
+}
+
+TEST_F(PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest,
+       DoesNotPersistIfServerHasNoData) {
+  // Navigate.
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("http://www.nohints.com/"));
+
+  EXPECT_FALSE(service()->last_entities_persistence_request());
+}
+
+TEST_F(PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest,
+       DoesNotPersistIfNoEntities) {
+  // Navigate.
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("http://noentities.com/"));
+
+  EXPECT_FALSE(service()->last_entities_persistence_request());
+}
+
+TEST_F(PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest,
+       DoesNotPersistIfServerReturnsWrongMetadata) {
+  // Navigate.
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("http://wrongmetadata.com/"));
+
+  EXPECT_FALSE(service()->last_entities_persistence_request());
+}
+
+TEST_F(PageContentAnnotationsWebContentsObserverRemotePageEntitiesTest,
+       RequestsToPersistIfHasEntities) {
+  // Navigate.
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("http://hasentities.com/"));
+
+  absl::optional<
+      std::pair<HistoryVisit,
+                std::vector<history::VisitContentModelAnnotations::Category>>>
+      request = service()->last_entities_persistence_request();
+  ASSERT_TRUE(request);
+  EXPECT_EQ(request->first.url, GURL("http://hasentities.com/"));
+  EXPECT_THAT(
+      request->second,
+      UnorderedElementsAre(
+          history::VisitContentModelAnnotations::Category("entity1", 50)));
+}
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/hints_processing_util.cc b/components/optimization_guide/core/hints_processing_util.cc
index f6cf69e7..29a873a 100644
--- a/components/optimization_guide/core/hints_processing_util.cc
+++ b/components/optimization_guide/core/hints_processing_util.cc
@@ -61,6 +61,8 @@
       return "AboutThisSite";
     case proto::OptimizationType::MERCHANT_TRUST_SIGNALS_V2:
       return "MerchantTrustSignalsV2";
+    case proto::OptimizationType::PAGE_ENTITIES:
+      return "PageEntities";
   }
 
   // The returned string is used to record histograms for the optimization type.
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc
index 2efc012..9f8d8191 100644
--- a/components/optimization_guide/core/optimization_guide_features.cc
+++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -413,6 +413,11 @@
   return model_targets.vector();
 }
 
+bool RemotePageEntitiesEnabled() {
+  return GetFieldTrialParamByFeatureAsBool(kPageContentAnnotations,
+                                           "fetch_remote_page_entities", false);
+}
+
 base::TimeDelta GetOnloadDelayForHintsFetching() {
   return base::Milliseconds(GetFieldTrialParamByFeatureAsInt(
       kRemoteOptimizationGuideFetching, "onload_delay_for_hints_fetching_ms",
diff --git a/components/optimization_guide/core/optimization_guide_features.h b/components/optimization_guide/core/optimization_guide_features.h
index 6603f327..25467fba 100644
--- a/components/optimization_guide/core/optimization_guide_features.h
+++ b/components/optimization_guide/core/optimization_guide_features.h
@@ -219,6 +219,10 @@
 std::vector<optimization_guide::proto::OptimizationTarget>
 GetPageContentModelsToExecute();
 
+// Returns whether page entities should be retrieved from the remote
+// Optimization Guide service.
+bool RemotePageEntitiesEnabled();
+
 // The time to wait beyond the onload event before sending the hints request for
 // link predictions.
 base::TimeDelta GetOnloadDelayForHintsFetching();
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn
index 05d0cc0f..288e9fd 100644
--- a/components/optimization_guide/proto/BUILD.gn
+++ b/components/optimization_guide/proto/BUILD.gn
@@ -16,6 +16,7 @@
     "hints.proto",
     "loading_predictor_metadata.proto",
     "models.proto",
+    "page_entities_metadata.proto",
     "page_topics_model_metadata.proto",
     "performance_hints_metadata.proto",
     "public_image_metadata.proto",
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto
index 7a54fb4..4fe715e 100644
--- a/components/optimization_guide/proto/hints.proto
+++ b/components/optimization_guide/proto/hints.proto
@@ -157,6 +157,8 @@
   // Provides key information about the merchant represented by the current
   // host -- VERSION 2.
   MERCHANT_TRUST_SIGNALS_V2 = 21;
+  // Provides the entities that are present on the page.
+  PAGE_ENTITIES = 22;
 }
 
 // Presents semantics for how page load URLs should be matched.
diff --git a/components/optimization_guide/proto/page_entities_metadata.proto b/components/optimization_guide/proto/page_entities_metadata.proto
new file mode 100644
index 0000000..96a8479f1
--- /dev/null
+++ b/components/optimization_guide/proto/page_entities_metadata.proto
@@ -0,0 +1,30 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "org.chromium.components.optimization_guide.proto";
+option java_outer_classname = "PageEntitiesMetadataProto";
+
+package optimization_guide.proto;
+
+message Entity {
+  // The ID of the entity expected to be present on the page.
+  optional string entity_id = 1;
+
+  // The confidence that the entity, as expressed by entity_id, is on the page.
+  //
+  // It is expected that this score be between 0 and 100, inclusive.
+  optional int32 score = 2;
+}
+
+// Optimization metadata associated with providing information about the
+// entities on the page.
+//
+// It is only populated for the PAGE_ENTITIES optimization type.
+message PageEntitiesMetadata {
+  // A set of entities that are expected to be present on the page.
+  repeated Entity entities = 1;
+}
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 3d88fc3..45b7ab3 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -28988,6 +28988,7 @@
         'minimum_data_size': 100
       },
       'features': {
+        'cloud_only': True,
         'dynamic_refresh': True,
         'per_profile': True,
       },
diff --git a/components/policy/resources/policy_templates_id.xtb b/components/policy/resources/policy_templates_id.xtb
index 4e75b1c..a047353 100644
--- a/components/policy/resources/policy_templates_id.xtb
+++ b/components/policy/resources/policy_templates_id.xtb
@@ -211,6 +211,7 @@
       Jika kebijakan tidak disetel atau jika nilai setelah substitusi bukan berupa hostname yang valid, tidak ada hostname yang akan disetel dalam permintaan DHCP.</translation>
 <translation id="1257550411839719984">Setel direktori download default</translation>
 <translation id="1265053460044691532">Batasi waktu bagi pengguna yang diautentikasi melalui SAML untuk dapat masuk saat offline.</translation>
+<translation id="1268548671627260798">Daftar URL yang dikecualikan dari notifikasi layar penuh</translation>
 <translation id="127264587838521316">Mengaktifkan permintaan penginstalan ekstensi <ph name="PRODUCT_NAME" /></translation>
 <translation id="1272798957154751008">Mengaktifkan migrasi perangkat Chromad ke pengelolaan cloud</translation>
 <translation id="1274997165432133392">Cookie dan data situs lainnya</translation>
@@ -381,6 +382,18 @@
 
       Catatan: Kebijakan ini juga berlaku untuk ekstensi komponen, seperti ekstensi Layanan Hangout.</translation>
 <translation id="148194404518916594">Izinkan pengguna menggunakan fitur Sentuh untuk Menelusuri</translation>
+<translation id="1485570394283692769">Mengontrol apakah situs diizinkan untuk membuat permintaan ke endpoint jaringan yang lebih pribadi dengan cara yang tidak aman.
+
+          Kebijakan ini berkaitan dengan spesifikasi Akses Jaringan Pribadi. Lihat https://wicg.github.io/private-network-access/ untuk detail selengkapnya.
+
+          Endpoint jaringan bersifat lebih pribadi dibanding endpoint lain jika:
+          1) Alamat IP-nya adalah localhost sedangkan yang lain bukan.
+          2) Alamat IP-nya bersifat pribadi, sedangkan yang lain bersifat publik.
+          Di masa mendatang, tergantung pada evolusi spesifikasi, kebijakan ini dapat berlaku untuk semua permintaan lintas asal yang ditujukan ke IP pribadi atau localhost.
+
+          Jika kebijakan ini tidak disetel atau disetel ke salah (false), perilaku default untuk permintaan ke endpoint jaringan yang lebih pribadi akan bergantung pada konfigurasi pribadi pengguna untuk tombol fitur <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />, <ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" />, dan <ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" /> yang dapat disetel berdasarkan uji coba kolom atau command line.
+
+          Jika kebijakan ini disetel ke benar (true), situs akan diizinkan untuk membuat permintaan ke endpoint jaringan mana saja, bergantung pada pemeriksaan lintas asal lainnya.</translation>
 <translation id="1486021504508098388">Melaporkan info lampu latar</translation>
 <translation id="1487916040416013623">Menyetel kebijakan akan menentukan server mana yang diizinkan untuk autentikasi terintegrasi. Autentikasi terintegrasi hanya aktif jika <ph name="PRODUCT_NAME" /> mendapat pernyataan autentikasi dari proxy atau dari server yang ada di daftar yang diizinkan.
 
@@ -2745,6 +2758,11 @@
       Jika kebijakan disetel ke Nonaktif atau tidak disetel, pengguna akan dapat mentransfer file ke Drive melalui koneksi seluler.</translation>
 <translation id="4248277954659222481">Izinkan pemutaran otomatis media pada pola URL yang diizinkan</translation>
 <translation id="4250680216510889253">Tidak</translation>
+<translation id="4257545866869267519">Mengonfigurasi daftar URL yang dikecualikan dari notifikasi layar penuh. Notifikasi ditampilkan saat perangkat keluar dari mode tidur, kecerahan rendah, atau layar kunci dan memiliki jendela dalam mode layar penuh. Setelan ini memastikan pengguna mengetahui bahwa mereka sedang dalam mode layar penuh, yang mengurangi risiko serangan phishing.
+
+          Kebijakan ini memungkinkan penonaktifan notifikasi untuk URL tertentu yang akan dianggap sebagai sumber tepercaya. Kebijakan ini disetel dengan menentukan daftar pola URL yang diformat sesuai dengan format berikut ( https://www.chromium.org/administrators/url-blocklist-filter-format ). Misalnya, penonaktifan semua notifikasi dapat dilakukan dengan menentukan karakter pengganti <ph name="WILDCARD_VALUE" /> agar cocok dengan semua URL.
+
+          Jika kebijakan ini disetel ke daftar kosong atau tidak disetel, tidak ada URL yang akan dikecualikan dari notifikasi layar penuh.</translation>
 <translation id="4260027436474745627">Jika kebijakan ini disetel, setiap asal bernama dalam daftar yang dipisahkan koma akan berjalan dalam proses khusus. Setiap proses asal bernama hanya akan diizinkan untuk memuat dokumen dari asal tersebut dan subdomainnya. Misalnya, menentukan https://a1.example.com/ akan mengizinkan https://a2.a1.example.com/ dalam proses yang sama, tetapi tidak mengizinkan https://example.com atau https://b.example.com.
 
       Sejak <ph name="PRODUCT_NAME" /> 77, Anda juga dapat menentukan rentang asal yang akan diisolasi menggunakan karakter pengganti. Misalnya, menentukan https://[*.]corp.example.com akan memberi setiap asal di bawah https://corp.example.com proses khususnya sendiri, termasuk https://corp.example.com itu sendiri, https://a1.corp.example.com, dan https://a2.a1.corp.example.com.
@@ -4271,6 +4289,7 @@
       Jika tidak, alamat IP lokal akan disembunyikan dengan hostname mDNS.
       Perlu diingat bahwa kebijakan ini akan melemahkan perlindungan IP lokal jika dibutuhkan oleh administrator.</translation>
 <translation id="614662973812186053">Kebijakan ini juga mengontrol pengumpulan data diagnostik dan penggunaan Android.</translation>
+<translation id="614665605501218241">Mengizinkan situs yang terdaftar untuk membuat permintaan ke endpoint jaringan yang lebih pribadi dengan cara yang tidak aman.</translation>
 <translation id="6154509171634387825">Peringatan: 3DES akan dihapus sepenuhnya dari <ph name="PRODUCT_NAME" /> versi 95 (sekitar Oktober 2021) dan kebijakan ini akan berhenti berfungsi.
 
       Jika kebijakan disetel ke benar (true), cipher suite 3DES di TLS akan diaktifkan. Jika kebijakan disetel ke salah (false), cipher suite 3DES di TLS akan dinonaktifkan. Jika kebijakan tidak disetel, cipher suite 3DES akan dinonaktifkan secara default. Kebijakan ini dapat digunakan untuk sementara waktu mempertahankan kompatibilitas dengan server yang sudah tidak berlaku. Ini adalah tindakan sementara dan server harus dikonfigurasi ulang.
@@ -4285,6 +4304,13 @@
       Jika kebijakan tidak disetel, pengguna akan dapat mengaktifkan atau menonaktifkan fitur ini.</translation>
 <translation id="6174065452773547810">Jika kebijakan disetel ke Aktif atau tidak disetel, perangkat akan diizinkan menerima kontrol pelaporan terperinci.
       Jika kebijakan disetel ke Nonaktif, perangkat terdaftar tidak akan menerima kontrol pelaporan terperinci.</translation>
+<translation id="6174187836314350835">Daftar Pola URL. Permintaan yang dimulai dari situs yang ditayangkan dengan pencocokan asal tidak tunduk pada pemeriksaan Akses Jaringan Pribadi.
+
+          Jika tidak disetel, kebijakan ini berperilaku sebagaimana jika disetel ke daftar kosong.
+
+          Untuk asal yang tidak tercakup oleh pola yang ditentukan di sini, nilai default global akan digunakan dari kebijakan <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" /> jika disetel, atau dari konfigurasi pribadi pengguna jika kebijakan tersebut tidak disetel.
+
+          Untuk informasi selengkapnya tentang pola URL yang valid, lihat https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.</translation>
 <translation id="6178075938488052838">Kebijakan ini mengontrol siapa yang dapat memulai sesi <ph name="PRODUCT_OS_NAME" />. Kebijakan ini tidak mencegah pengguna login ke akun Google lain dalam Android. Jika Anda ingin mencegah tindakan ini, konfigurasikan kebijakan <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> khusus Android sebagai bagian dari <ph name="ARC_POLICY_POLICY_NAME" />.</translation>
 <translation id="6181304954168534748">Hash SHA-256 template desktop.</translation>
 <translation id="6181618732396778048">Jangan izinkan situs apa pun meminta akses tulis ke file atau direktori</translation>
@@ -4747,6 +4773,7 @@
       Catatan: Meskipun kebijakan dapat menerima beberapa item dalam <ph name="ENTRIES_FIELD_NAME" />, semua item kecuali yang pertama akan diabaikan.
       Peringatan: Jika kebijakan ini disetel, penerapan update software mungkin tertunda.</translation>
 <translation id="6698632841807204978">Aktifkan pencetakan monokrom</translation>
+<translation id="6699740789657890714">Menentukan apakah akan mengizinkan situs untuk membuat permintaan ke endpoint jaringan yang lebih pribadi dengan cara yang tidak aman</translation>
 <translation id="6699880231565102694">Mengaktifkan autentikasi dua faktor untuk hosting akses jarak jauh</translation>
 <translation id="6703251016607733593">Jika kebijakan ditetapkan, penerapan persyaratan pengungkapan Transparansi Sertifikat akan dinonaktifkan untuk daftar hash <ph name="SUBJECT_PUBLIC_KEY_INFO" />. Host perusahaan tetap dapat menggunakan sertifikat yang tidak tepercaya (karena tidak diungkapkan secara publik dengan sesuai). Untuk menonaktifkan penerapan, hash harus memenuhi salah satu ketentuan berikut:
 
diff --git a/components/policy/resources/policy_templates_ja.xtb b/components/policy/resources/policy_templates_ja.xtb
index 1485597..268f797 100644
--- a/components/policy/resources/policy_templates_ja.xtb
+++ b/components/policy/resources/policy_templates_ja.xtb
@@ -207,6 +207,7 @@
       このポリシーを未設定のままにした場合、または置き換えた後の値が有効なホスト名ではない場合、DHCP リクエストにホスト名は設定されません。</translation>
 <translation id="1257550411839719984">デフォルトのダウンロード ディレクトリを設定する</translation>
 <translation id="1265053460044691532">SAML 経由で認証されたユーザーがオフラインでログインできる時間を制限する</translation>
+<translation id="1268548671627260798">全画面表示の通知から除外する URL のリスト</translation>
 <translation id="127264587838521316"><ph name="PRODUCT_NAME" /> 拡張機能のインストールのリクエストを有効にする</translation>
 <translation id="1272798957154751008">Chromad デバイスのクラウド管理への移行を有効にします</translation>
 <translation id="1274997165432133392">Cookie と他のサイトデータ</translation>
@@ -378,6 +379,18 @@
 
       注: このポリシーは、ハングアウト サービス拡張機能のようなコンポーネント型拡張機能にも適用されます。</translation>
 <translation id="148194404518916594">ユーザーは「タップして検索」を使用できる</translation>
+<translation id="1485570394283692769">より限定されたプライベート ネットワークのエンドポイントに対して、ウェブサイトからの安全でない方法でのリクエストを許可するかどうかを制御します。
+
+          このポリシーはプライベート ネットワーク アクセスの仕様に関連したものです。詳しくは https://wicg.github.io/private-network-access/ をご覧ください。
+
+          次に該当するネットワーク エンドポイントは、アクセスがより限定されます。
+          1)IP アドレスがローカルホストである(ローカルホストでないエンドポイントと比較して)。
+          2)IP アドレスがプライベートである(パブリックなエンドポイントと比較して)。
+          仕様の発展に応じて、このポリシーは将来的にプライベート IP またはローカルホストに対するすべてのクロスオリジンのリクエストに適用される可能性があります。
+
+          このポリシーを設定しない場合や False に設定した場合、より限定されたプライベート ネットワーク エンドポイントに送信されたリクエストがデフォルトで許可またはブロックされるかは、ユーザーの個人設定で <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />、<ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" />、<ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" /> の機能フラグがどのように設定されているかによって決まります。なお、これらのフラグは、フィールド トライアルまたはコマンドラインで設定できます。
+
+          このポリシーを True に設定した場合は、他のクロスオリジン チェックに合格することを条件として、ウェブサイトから任意のネットワーク エンドポイントにリクエストを送信できます。</translation>
 <translation id="1486021504508098388">バックライト情報を報告する</translation>
 <translation id="1487916040416013623">このポリシーでは、統合認証を許可するサーバーを指定できます。統合認証は、<ph name="PRODUCT_NAME" /> がこの許可されたリストに含まれているプロキシやサーバーから認証チャレンジを取得するときにのみ有効になります。
 
@@ -2668,6 +2681,11 @@
       このポリシーを無効に設定するか未設定のままにした場合、ユーザーはモバイル接続時にドライブにファイルを転送できます。</translation>
 <translation id="4248277954659222481">メディアの自動再生を許可する URL パターンのリストを指定する</translation>
 <translation id="4250680216510889253">いいえ</translation>
+<translation id="4257545866869267519">全画面表示の通知から除外する URL のリストを設定します。この通知は、デバイスがスリープ画面、暗い画面、またはロック画面から復帰するときに、ウィンドウが全画面モードになっていると表示されます。これは全画面モードになっていることをユーザーに知らせるためのもので、これによりフィッシング攻撃のリスクを軽減します。
+
+          このポリシーを使用すると、信頼できる提供元と判断される特定の URL の通知を無効にできます。URL パターンのリストは、https://www.chromium.org/administrators/url-blocklist-filter-format で定められている形式で指定します。たとえば、すべての URL に一致するワイルドカード文字「<ph name="WILDCARD_VALUE" />」を指定すると、通知を一切無効にすることができます。
+
+          このポリシーを空のリストに設定するか未設定のままにした場合は、どの URL も全画面表示の通知から除外されません。</translation>
 <translation id="4260027436474745627">このポリシーを設定した場合、カンマ区切りのリストで指定した発行元はそれぞれ独自のプロセスで実行されます。指定した発行元のプロセスで使用できるのは、発行元およびそのサブドメインのドキュメントだけです。たとえば、https://a1.example.com/ を指定した場合、https://a2.a1.example.com/ は同一のプロセスで実行されますが、https://example.com や https://b.example.com はこの限りではありません。
 
       <ph name="PRODUCT_NAME" /> 77 以降であれば、ワイルドカードを使用し、分離する発行元の範囲を指定できます。たとえば、https://[*.]corp.example.com を指定した場合、https://corp.example.com 以下の発行元に対して同じ独自プロセスが適用されます。これには https://corp.example.com 自体が該当するほか、https://a1.corp.example.com や https://a2.a1.corp.example.com も含まれます。
@@ -2782,6 +2800,23 @@
 
       このポリシーが false の場合、OS のアップグレード後に初めてブラウザを起動したときにウェルカム ページは再表示されません。</translation>
 <translation id="441686537793821907">外部の拡張機能のインストールを許可しない</translation>
+<translation id="4420613474328461583"><ph name="ON_FILE_DOWNLOADED_ENTERPRISE_CONNECTOR" /> Enterprise コネクタに適用する Chrome Enterprise コネクタ サービス設定のリストで、Chrome でファイルがダウンロードされた場合に呼び出されます。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> フィールドは、特定のページからダウンロードされるファイルを分析のためコネクタが送信すべきかどうかと、そのファイルの分析リクエストにどのタグを含めるかをコネクタで判別する際に使用されます。「有効」パターンに該当するタグは、ページの URL がそのタグに関連付けられているパターンと一致し、同じタグの「無効」パターンとは一致しない場合に分析リクエストに含められます。分析は、リクエストにタグが少なくとも 1 つ含まれる場合に行われます。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> フィールドでは、この設定が対応している分析サービス プロバイダを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> フィールドを 1 に設定した場合、Chrome は分析サービスからの応答を待ってから、ダウンロードされたファイルへのユーザーのアクセスを許可します。その他の整数値を設定した場合、Chrome はユーザーにファイルへのアクセスを直ちに許可します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_PASSWORD_PROTECTED_FIELD" /> フィールドでは、パスワードで保護されているファイルをブロックするか許可するかを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> フィールドでは、分析可能なサイズより大きいファイルをブロックするか許可するかを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> フィールドでは、分析リクエストに含まれるタグのうち、「バイパス可能」警告が表示された時点でユーザーがスキャン チェックのバイパスを選択した場合に、その理由を入力するよう求めるタグを指定します。このフィールドを設定しない場合、理由は不要とみなされます。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> フィールドでは、スキャンの結果に問題がある場合に、ユーザーに表示する警告メッセージを設定します。message フィールドでは、ユーザーに表示するテキストを半角 200 文字以内で指定します。learn_more_url フィールドでは、管理者が提供する URL を指定します。ユーザーはこの URL をクリックして、操作がブロックされた理由について、お客様から提供された情報を確認できます。language フィールドでは、メッセージの言語を指定します(省略可)。このフィールドを空白にするか、「default」の値を指定した場合、ユーザーの言語のメッセージがないときは、デフォルトのメッセージが使用されます。tag フィールドでは、メッセージを表示するスキャンの種類を指定します。custom_messages リストには、0 以上のエントリを指定できます。各エントリには、空白以外のメッセージと tag フィールドを含める必要があります。
+
+      このポリシーは <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" /> からのみ設定できます。</translation>
 <translation id="4423597592074154136">プロキシ設定を手動で指定する</translation>
 <translation id="4424004842303301809">データ漏洩防止イベントのレポートを無効にする</translation>
 <translation id="4427173305799125784">PDF ビューアで PDF に注釈を追加できない</translation>
@@ -2902,6 +2937,7 @@
       詳しくは、https://www.chromestatus.com/feature/5675755719622656 をご覧ください。
       このポリシーが有効な場合、サイトでは移動と同時に新しいウィンドウやタブを開くことができます。
       このポリシーが無効または未設定の場合、サイトでは移動と同時に新しいウィンドウやタブを開くことはできません。</translation>
+<translation id="457430673056611745">OnPrint <ph name="PRODUCT_NAME" /> Enterprise コネクタの設定ポリシー</translation>
 <translation id="4578265298946081589">ユーザーのログアウト時に再起動しません。</translation>
 <translation id="4581507927311097234">ユーザー入力が行われなくなってから画面をオフにするまでの時間(ミリ秒)</translation>
 <translation id="4582338216073557489">このポリシーを None に設定した場合、<ph name="PRODUCT_NAME" /> は、キャッシュされたファイルをディスクに保存する際に、デフォルトのキャッシュ サイズを使用します。ユーザーはこの設定を変更できません。
@@ -4124,6 +4160,7 @@
       それ以外の場合、ローカル IP アドレスは mDNS のホスト名で隠されます。
       管理者がこのポリシーを有効にした場合、ローカル IP の保護が弱まることに注意してください。</translation>
 <translation id="614662973812186053">このポリシーでは Android の使用状況と診断データの収集も管理できます。</translation>
+<translation id="614665605501218241">ウェブサイトがリストに指定されている場合、より限定されたプライベート ネットワークのエンドポイントに対して、そのサイトからの安全でない方法でのリクエストを許可する。</translation>
 <translation id="6154509171634387825">警告: 3DES は <ph name="PRODUCT_NAME" /> バージョン 95(2021 年 10 月頃公開)で完全に削除され、それ以後、このポリシーも機能しなくなります。
 
       このポリシーを true に設定した場合は、TLS の 3DES 暗号スイートが有効になります。false に設定した場合は無効になります。このポリシーを未設定のままにした場合は、デフォルトで 3DES 暗号スイートが無効になります。このポリシーは、古いサーバーとの一時的な互換性の保持に使用できます。これは暫定的な措置であり、サーバーの再設定が必要です。
@@ -4137,6 +4174,13 @@
 
       このポリシーを未設定のままにした場合、ユーザーはこの機能をオンまたはオフに指定できます。</translation>
 <translation id="6174065452773547810">このポリシーを有効に設定するか未設定のままにした場合、デバイスで詳細なレポート コントロールを受けることができます。このポリシーを無効に設定した場合、登録済みデバイスは詳細なレポート コントロールを受けません。</translation>
+<translation id="6174187836314350835">URL パターンのリスト。このリストのパターンと一致するオリジンのウェブサイトから送信されたリクエストは、プライベート ネットワーク アクセスのチェック対象外となります。
+
+          リストを指定しない場合、このポリシーは空のリストを指定したときと同様に動作します。
+
+          ここで指定したパターンに含まれていないオリジンについては、グローバル デフォルト値として、<ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" /> ポリシーで値が設定されていればその値、設定されていなければユーザーの個人設定の値が使用されます。
+
+          有効な URL パターンについて詳しくは、https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns をご覧ください。</translation>
 <translation id="6178075938488052838">このポリシーでは、<ph name="PRODUCT_OS_NAME" /> セッションを開始できるユーザーを管理します。このポリシーを設定しても、ユーザーが Android で他の Google アカウントにログインすることを防ぐことはできません。ログインを防ぐには、<ph name="ARC_POLICY_POLICY_NAME" /> の一部として Android 用の <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> ポリシーを設定してください。</translation>
 <translation id="6181304954168534748">デスク テンプレートの SHA-256 ハッシュです。</translation>
 <translation id="6181618732396778048">どのサイトにもファイルとディレクトリへの書き込みアクセスの要求を許可しない</translation>
@@ -4544,6 +4588,7 @@
       注: ポリシーの <ph name="ENTRIES_FIELD_NAME" /> には複数の項目を指定できますが、最初の項目以外は無視されます。
       警告: このポリシーを設定した場合、ソフトウェア更新の適用が遅れる可能性があります。</translation>
 <translation id="6698632841807204978">白黒印刷を有効にする</translation>
+<translation id="6699740789657890714">より限定されたプライベート ネットワークのエンドポイントに対して、ウェブサイトからの安全でない方法でのリクエストを許可するかどうかを指定する</translation>
 <translation id="6699880231565102694">リモート アクセス ホストの 2 段階認証プロセスを有効にする</translation>
 <translation id="6703251016607733593">このポリシーを設定した場合、リストで指定された <ph name="SUBJECT_PUBLIC_KEY_INFO" /> ハッシュに対して、Certificate Transparency(証明書の透明性)の開示要件の適用が無効になります。企業のホストでは、適切に公開されていないことを理由に通常であれば信頼できないものとして扱われる証明書を、引き続き使用できるようになります。適用を無効にするには、ハッシュが次のいずれかの条件を満たしている必要があります。
 
@@ -5759,6 +5804,23 @@
 
       このポリシーを無効にするか、未設定のままにすると、パケットは送信されません。</translation>
 <translation id="816783746144552109">デバイスでの使用を許可する Chrome の最小バージョンを設定する。</translation>
+<translation id="8169492352330154095"><ph name="ON_FILE_ATTACHED_ENTERPRISE_CONNECTOR" /> Enterprise コネクタに適用する Chrome Enterprise コネクタ サービス設定のリストで、Chrome にファイルが添付されている場合に呼び出されます。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> フィールドは、特定のページに添付されるファイルを分析のためコネクタが送信すべきかどうかと、そのファイルの分析リクエストにどのタグを含めるかをコネクタで判別する際に使用されます。「有効」パターンに該当するタグは、ページの URL がそのタグに関連付けられているパターンと一致し、同じタグの「無効」パターンとは一致しない場合に分析リクエストに含められます。分析は、リクエストにタグが少なくとも 1 つ含まれる場合に行われます。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> フィールドでは、この設定が対応している分析サービス プロバイダを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> フィールドを 1 に設定した場合、Chrome は分析サービスからの応答を待ってから、ページにファイルへのアクセスを許可します。その他の整数値を設定した場合、Chrome はページにファイルへのアクセスをただちに許可します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_PASSWORD_PROTECTED_FIELD" /> フィールドでは、パスワードで保護されているファイルをブロックするか許可するかを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> フィールドでは、分析可能なサイズより大きいファイルをブロックするか許可するかを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> フィールドでは、分析リクエストに含まれるタグのうち、「バイパス可能」警告が表示された時点でユーザーがスキャン チェックのバイパスを選択した場合に、その理由を入力するよう求めるタグを指定します。このフィールドを設定しない場合、理由は不要とみなされます。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> フィールドでは、スキャンの結果に問題がある場合に、ユーザーに表示する警告メッセージを設定します。message フィールドでは、ユーザーに表示するテキストを半角 200 文字以内で指定します。learn_more_url フィールドでは、管理者が提供する URL を指定します。ユーザーはこの URL をクリックして、操作がブロックされた理由について、お客様から提供された情報を確認できます。language フィールドでは、メッセージの言語を指定します(省略可)。このフィールドを空白にするか、「default」の値を指定した場合、ユーザーの言語のメッセージがないときは、デフォルトのメッセージが使用されます。tag フィールドでは、メッセージを表示するスキャンの種類を指定します。custom_messages リストには、0 以上のエントリを指定できます。各エントリには、空白以外のメッセージと tag フィールドを含める必要があります。
+
+      このポリシーは <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" /> からのみ設定できます。</translation>
 <translation id="8171924760436219650">ログイン画面でマウスのメインボタンを右に切り替える</translation>
 <translation id="8173864651667424191">「画像として印刷する」オプションが使用可能な場合、「画像として印刷する」オプションは PDF ドキュメントの印刷プレビューでデフォルトで設定されます。</translation>
 <translation id="8176035528522326671">企業ユーザーがメインのマルチプロフィール ユーザーとしてのみ操作できるようにする(企業の管理対象ユーザーに対するデフォルトの動作)</translation>
@@ -6007,6 +6069,11 @@
       このポリシーを設定しない場合は、デフォルト値の 3 が使用されます。
 
       このポリシーを設定した場合は、制限を超えないように、古いスナップショットが必要に応じて削除されます。このポリシーを 0 に設定した場合、スナップショットは作成されません。</translation>
+<translation id="8447347049334673364">このポリシーを設定することで、既存の拡張機能関連ポリシーで管理されている設定もすべて含め、<ph name="PRODUCT_NAME" /> の拡張機能の設定を管理できます。このポリシーは、設定済みの以前のポリシーよりも優先されます。
+
+      このポリシーでは、特定の設定のみを指定するには拡張機能 ID または更新 URL を使用します。また、「<ph name="DEFAULT_SCOPE" />」という特別な ID でデフォルトの設定を指定できます。デフォルトの設定は、このポリシーでカスタムの設定が指定されていないすべての拡張機能に適用されます。更新 URL を使用すると、拡張機能マニフェストにその更新 URL が指定された拡張機能に対して設定が適用されます(http://support.google.com/chrome/a?p=Configure_ExtensionSettings_policy)。「override_update_url」フラグが true に設定されている場合、拡張機能は、<ph name="EXTENSION_INSTALL_FORCELIST_POLICY_NAME" /> ポリシーまたはこのポリシーの「update_url」フィールドで指定された「更新」URL を使用してインストールおよび更新されます。「update_url」が Chrome ウェブストアの URL の場合、「override_update_url」フラグは無視されます。
+
+      注: <ph name="MS_AD_NAME" /> ドメインに登録されていない <ph name="MS_WIN_NAME" /> インスタンスと、MDM 経由で管理されていない、または MCX 経由でドメインに登録されていない <ph name="MAC_OS_NAME" /> インスタンスの場合、強制的にインストールされるのは Chrome ウェブストアに公開されているアプリと拡張機能のみとなります。</translation>
 <translation id="8451988835943702790">新しいタブ ページをホームページとして使用する</translation>
 <translation id="8455529558077979314">プライバシー スクリーン設定</translation>
 <translation id="8455551509936646199">再起動する曜日(デバイスのローカル タイムゾーン)です。frequency が「WEEKLY」に指定されている場合にのみ使用されます。</translation>
@@ -6217,6 +6284,21 @@
       有効な <ph name="URL_LABEL" /> パターンについて詳しくは、https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns をご覧ください。このポリシーの値に「<ph name="WILDCARD_VALUE" />」は使用できません。</translation>
 <translation id="8703488928438047864">ボードの状態を報告する</translation>
 <translation id="8704831857353097849">無効なプラグインのリスト</translation>
+<translation id="8704915028294851978"><ph name="ON_PRINT_ENTERPRISE_CONNECTOR" /> Enterprise コネクタに適用する <ph name="PRODUCT_NAME" /> Enterprise Connectors サービス設定のリストです。これは <ph name="PRODUCT_NAME" /> からページまたはファイルが印刷された場合に呼び出されます。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> フィールドは、特定のページで印刷が呼び出されたときに、分析のためデータを送信すべきかどうかと、分析リクエストにどのタグを含めるかをコネクタで判別する際に使用されます。分析は、リクエストにタグが少なくとも 1 つ含まれる場合に行われます。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> フィールドでは、この設定が対応している分析サービス プロバイダを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> フィールドを 1 に設定した場合、<ph name="PRODUCT_NAME" /> は分析サービスからの応答を待ってから、印刷ページの印刷プレビュー ダイアログの表示を許可します。その他の整数値を設定した場合、<ph name="PRODUCT_NAME" /> は印刷プレビュー ダイアログをただちに表示します。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> フィールドでは、<ph name="PRODUCT_NAME" /> で分析可能なサイズより大きいファイルまたはページをブロックするか許可するかを指定します。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> フィールドでは、分析リクエストに含まれるタグのうち、「バイパス可能」警告が表示された時点でユーザーがスキャン チェックのバイパスを選択した場合に、その理由を入力するよう求めるタグを指定します。このフィールドを設定しない場合、理由は不要とみなされます。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> フィールドでは、スキャンの結果に問題がある場合に、ユーザーに表示する警告メッセージを設定します。管理者は、200 文字以内でメッセージを設定できます。
+
+      このポリシーは <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" /> からのみ設定できます。</translation>
 <translation id="8705895771006864851">このポリシーを True に設定した場合、<ph name="PRODUCT_NAME" /> に組み込みの翻訳ツールバーを表示し、右クリックのコンテキスト メニューに翻訳オプションを表示して、ユーザーが必要な場面で翻訳機能を使用できるようにします。このポリシーを False に設定した場合、組み込みの翻訳機能はすべて使用できなくなります。
 
       このポリシーを設定した場合、ユーザーはこの機能を変更できません。このポリシーを未設定のままにした場合、ユーザーは設定を変更できます。</translation>
diff --git a/components/policy/resources/policy_templates_ko.xtb b/components/policy/resources/policy_templates_ko.xtb
index 823c0c9b..68b6da5c 100644
--- a/components/policy/resources/policy_templates_ko.xtb
+++ b/components/policy/resources/policy_templates_ko.xtb
@@ -211,6 +211,7 @@
       정책을 설정하지 않거나 대체 값이 유효한 호스트 이름이 아닌 경우 DHCP 요청에서 호스트 이름이 설정되지 않습니다.</translation>
 <translation id="1257550411839719984">기본 다운로드 디렉터리 설정</translation>
 <translation id="1265053460044691532">SAML을 통해 인증한 사용자가 오프라인에서 로그인할 수 있는 기간을 제한</translation>
+<translation id="1268548671627260798">전체 화면 알림에서 제외되는 URL 목록</translation>
 <translation id="127264587838521316"><ph name="PRODUCT_NAME" /> 확장 프로그램 설치 요청 사용</translation>
 <translation id="1272798957154751008">Chromad 기기를 클라우드 관리로 이전할 수 있도록 합니다.</translation>
 <translation id="1274997165432133392">쿠키 및 기타 사이트 데이터</translation>
@@ -382,6 +383,18 @@
 
       참고: 이 정책은 행아웃 서비스 확장 프로그램과 같은 구성요소 확장 프로그램에도 적용됩니다.</translation>
 <translation id="148194404518916594">사용자가 터치하여 검색을 사용하도록 허용</translation>
+<translation id="1485570394283692769">웹사이트가 안전하지 않은 방식으로 더 높은 수준의 비공개 네트워크 엔드포인트에 요청할 수 있도록 허용할지 제어합니다.
+
+          이 정책은 비공개 네트워크 액세스 사양과 관련이 있습니다. 자세한 내용은 https://wicg.github.io/private-network-access/ 페이지를 참고하세요.
+
+          네트워크 엔드포인트는 다음의 경우 다른 엔드포인트보다 비공개 수준이 더 높습니다.
+          1) 네트워크 엔드포인트의 IP 주소가 localhost이고 다른 엔드포인트의 IP 주소는 아닌 경우
+          2) 네트워크 엔드포인트의 IP 주소가 비공개이고 다른 엔드포인트의 IP 주소는 공개인 경우
+          향후 사양 변경에 따라 정책이 비공개 IP 또는 localhost를 대상으로 하는 모든 교차 도메인 요청에 적용될 수 있습니다.
+
+          정책을 설정하지 않거나 False로 설정하면 비공개 수준이 더 높은 네트워크 엔드포인트로 전송되는 요청의 기본 동작이 <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />, <ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" />, <ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" /> 기능 플래그에 관한 사용자의 개인 구성에 따라 달라지며, 이러한 구성은 공개 실험이나 명령줄에서 설정할 수 있습니다.
+
+          정책을 True로 설정하면 웹사이트에서 모든 네트워크 엔드포인트에 요청할 수 있게 되며, 이 요청에는 다른 교차 도메인 확인이 적용됩니다.</translation>
 <translation id="1486021504508098388">백라이트 정보 보고</translation>
 <translation id="1487916040416013623">정책을 설정하면 통합 인증에 허용되어야 하는 서버가 지정됩니다. 통합 인증은 <ph name="PRODUCT_NAME" />이 허용 목록에 있는 서버 또는 프록시에서 인증 요청을 받은 경우에만 사용 설정됩니다.
 
@@ -2743,6 +2756,11 @@
       정책을 '사용 안함'으로 설정하거나 설정하지 않으면 모바일 데이터에 연결되어 있을 때도 사용자가 드라이브로 파일을 전송하도록 허용합니다.</translation>
 <translation id="4248277954659222481">URL 패턴의 허용 목록에서 미디어 자동 재생 허용</translation>
 <translation id="4250680216510889253">아니요</translation>
+<translation id="4257545866869267519">전체 화면 알림에서 제외되는 URL 목록을 구성합니다. 기기의 절전 모드 또는 잠금 화면이 해제되거나 밝기 수준이 낮음에서 높음으로 변경되었을 때, 전체 화면 모드로 창이 열려 있을 때 알림이 표시됩니다. 이는 사용자에게 피싱 공격 위험을 낮추는 전체 화면 모드를 사용하고 있음을 알리기 위함입니다.
+
+          이 정책은 신뢰할 수 있는 출처라고 생각되는 특정 URL에서 알림을 사용 중지할 수 있도록 허용합니다. 정책은 https://www.chromium.org/administrators/url-blocklist-filter-format 형식을 사용하는 URL 패턴의 목록을 지정하여 설정합니다. 예를 들어 모든 URL과 매칭되도록 와일드 카드 문자(<ph name="WILDCARD_VALUE" />)를 지정하면 알림을 완전히 사용 중지할 수도 있습니다.
+
+          정책을 빈 목록으로 두거나 설정하지 않으면 전체 화면 알림에서 제외되는 URL이 없다는 의미입니다.</translation>
 <translation id="4260027436474745627">정책을 설정하면 쉼표로 구분된 목록의 이름이 지정된 각 출처가 전용 프로세스로 실행됩니다. 이름이 지정된 각 출처의 프로세스에는 해당 출처와 하위 도메인의 문서만 포함될 수 있습니다. 예를 들어 https://a1.example.com/을 지정하면 동일한 프로세스에는 https://a2.a1.example.com/만 허용되며 https://example.com 또는 https://b.example.com은 허용되지 않습니다.
 
       <ph name="PRODUCT_NAME" /> 77부터 와일드 카드를 사용해 격리할 출처의 범위를 지정할 수도 있습니다. 예를 들어 https://[*.]corp.example.com을 지정하면 https://corp.example.com 자체와 https://a1.corp.example.com, https://a2.a1.corp.example.com 등 https://corp.example.com에 속한 모든 출처에 전용 프로세스가 제공됩니다.
@@ -4267,6 +4285,7 @@
       그러지 않으면 로컬 IP 주소가 mDNS 호스트 이름으로 숨겨집니다.
       관리자가 필요로 하는 경우 이 정책은 로컬 IP의 보안 수준을 낮춥니다.</translation>
 <translation id="614662973812186053">이 정책은 Android 사용 및 진단 데이터 수집도 제어합니다.</translation>
+<translation id="614665605501218241">목록에 포함된 사이트가 안전하지 않은 방식으로 더 높은 수준의 비공개 네트워크 엔드포인트에 요청할 수 있도록 허용</translation>
 <translation id="6154509171634387825">경고: 3DES는 버전 95(2021년 10월경)부터 <ph name="PRODUCT_NAME" />에서 완전히 삭제되고 그 이후에는 정책이 작동하지 않습니다.
 
       정책이 true로 설정되면 TLS의 3DES 암호화 스위트가 사용 설정됩니다. false로 설정되면 사용 중지됩니다. 설정되지 않으면 3DES 암호화 스위트가 기본적으로 사용 중지됩니다. 정책은 오래된 서버와 일시적으로 호환성을 유지하는 데 사용될 수 있습니다. 임시방편이므로 서버를 다시 구성해야 합니다.
@@ -4281,6 +4300,13 @@
       정책을 설정하지 않으면 사용자가 이 기능을 사용 또는 사용 중지할 수 있습니다.</translation>
 <translation id="6174065452773547810">정책을 사용으로 설정하거나 설정하지 않은 채로 두면 기기가 상세 보고 제어 권한을 받을 수 있습니다.
       정책을 사용 안함으로 설정하면 등록된 기기가 상세 보고 제어 권한을 받을 수 없습니다.</translation>
+<translation id="6174187836314350835">URL 패턴 목록입니다. 일치하는 출처에 의해 게재된 웹사이트에서 시작한 요청은 비공개 네트워크 액세스 확인 대상이 아닙니다.
+
+          정책을 설정하지 않으면 빈 목록일 때와 동일하게 적용됩니다.
+
+          여기 명시된 패턴에 해당하지 않는 원본에는 <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" /> 정책(설정된 경우) 또는 사용자 개인 구성의 전체 기본값이 사용됩니다.
+
+          유효한 URL 패턴을 자세히 알아보려면 https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns 페이지를 참고하세요.</translation>
 <translation id="6178075938488052838">이 정책은 누가 <ph name="PRODUCT_OS_NAME" /> 세션을 시작할지 제어합니다. 이 정책은 사용자가 Android 내에서 추가 Google 계정에 로그인하지 못하도록 막지 않습니다. 사용자가 추가 Google 계정으로 로그인하지 못하게 하려면 <ph name="ARC_POLICY_POLICY_NAME" />의 일환으로 Android <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> 정책을 구성하세요.</translation>
 <translation id="6181304954168534748">데스크 템플릿의 SHA-256 해시입니다.</translation>
 <translation id="6181618732396778048">모든 사이트에서 파일 및 디렉터리 쓰기 액세스 권한을 요청하지 못하도록 차단</translation>
@@ -4743,6 +4769,7 @@
       참고: 정책에서 <ph name="ENTRIES_FIELD_NAME" />에 있는 여러 항목을 수용할 수 있지만, 첫 번째 항목을 제외한 모든 항목은 무시됩니다.
       경고: 정책을 설정하면 소프트웨어 업데이트 적용이 늦어질 수 있습니다.</translation>
 <translation id="6698632841807204978">단색 인쇄 사용 설정</translation>
+<translation id="6699740789657890714">웹사이트가 안전하지 않은 방식으로 더 높은 수준의 비공개 네트워크 엔드포인트에 요청할 수 있도록 허용할지 지정</translation>
 <translation id="6699880231565102694">원격 액세스 호스트를 위한 2단계 인증 사용</translation>
 <translation id="6703251016607733593">정책을 설정하면 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 해시 목록에 대해 인증서 투명성 공개 요구사항의 시행이 사용 중지됩니다. 이에 따라 적절하게 공개되지 않아 신뢰할 수 없던 인증서를 엔터프라이즈 호스트에서 계속해서 사용할 수 있습니다. 시행을 사용 중지하려면 해시는 다음 조건 중 하나를 만족해야 합니다.
 
diff --git a/components/policy/resources/policy_templates_pt-BR.xtb b/components/policy/resources/policy_templates_pt-BR.xtb
index 6555a26..cf5caff1 100644
--- a/components/policy/resources/policy_templates_pt-BR.xtb
+++ b/components/policy/resources/policy_templates_pt-BR.xtb
@@ -207,6 +207,7 @@
       Se a política não for definida ou se o valor pós-substituição não for um nome de host válido, nenhum nome de host será definido na solicitação de DHCP.</translation>
 <translation id="1257550411839719984">Definir diretório de download padrão</translation>
 <translation id="1265053460044691532">Limite o tempo pelo qual um usuário autenticado via SAML pode fazer login off-line</translation>
+<translation id="1268548671627260798">Lista de URLs isentos de notificações sobre a tela cheia</translation>
 <translation id="127264587838521316">Ativa as solicitações de instalação de extensões do <ph name="PRODUCT_NAME" /></translation>
 <translation id="1272798957154751008">Ativar a migração de dispositivos Chromad no gerenciamento de nuvem.</translation>
 <translation id="1274997165432133392">Cookies e outros dados do site</translation>
@@ -378,6 +379,18 @@
 
       Observação: essa política também se aplica a extensões de componentes, como a extensão do Hangout Services.</translation>
 <translation id="148194404518916594">Permitir que os usuários usem o recurso Pesquisa por toque</translation>
+<translation id="1485570394283692769">Controla se os sites têm permissão para fazer solicitações para endpoints de rede mais particulares de forma não segura.
+
+          Esta política está relacionada à especificação Private Network Access. Para ver mais detalhes, acesse https://wicg.github.io/private-network-access/ (link em inglês).
+
+          Um endpoint de rede é mais particular que outro se:
+          1) o endereço IP dele for localhost e o do outro não for;
+          2) o endereço IP dele for particular e o do outro for público.
+          No futuro, dependendo da evolução das especificações, esta política poderá ser aplicada a todas as solicitações de origem cruzada direcionadas ao localhost ou a IPs particulares.
+
+          Quando esta política for deixada sem definição ou for definida como falsa, o comportamento padrão para solicitações para endpoints de rede mais particulares vai depender da configuração pessoal do usuário para as sinalizações de recurso <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />, <ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" /> e <ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" />, que podem ser definidas por versões de teste ou na linha de comando.
+
+          Quando a política for definida como verdadeira, os sites terão permissão para fazer solicitações para qualquer endpoint de rede, sujeito a outras verificações de origem cruzada.</translation>
 <translation id="1486021504508098388">Enviar informações sobre as luzes de fundo</translation>
 <translation id="1487916040416013623">Definir a política especifica quais servidores devem ter permissão para a autenticação integrada, que só é ativada quando o <ph name="PRODUCT_NAME" /> recebe um desafio de autenticação de um proxy ou de um servidor nessa lista permitida.
 
@@ -2735,6 +2748,11 @@
       Se a política for definida como desativada ou não for definida, o usuário poderá transferir arquivos para o Drive mesmo em conexões celulares.</translation>
 <translation id="4248277954659222481">Permitir reprodução automática de mídia em uma lista de permissões de padrões de URL</translation>
 <translation id="4250680216510889253">Não</translation>
+<translation id="4257545866869267519">Configurar uma lista de URLs isentos de notificação sobre a tela cheia. A notificação é mostrada quando o dispositivo retorna da suspensão, do modo de baixo brilho ou da tela de bloqueio e tem uma janela em tela cheia. Ela informa aos usuários que eles estão no modo de tela cheia, o que reduz o risco de ataques de phishing.
+
+          Esta política permite desativar a notificação para URLs específicos que serão considerados como fontes confiáveis. A definição dela é feita especificando uma lista de padrões de URL no formato explicado em https://www.chromium.org/administrators/url-blocklist-filter-format. Por exemplo, é possível desativar as notificações por completo especificando o caractere curinga <ph name="WILDCARD_VALUE" />, que corresponde a todos os URLs.
+
+           Se a política for definida como uma lista vazia ou for deixada sem definição, nenhum URL estará isento da notificação sobre a tela cheia.</translation>
 <translation id="4260027436474745627">Se a política for definida, cada uma das origens indicadas em uma lista separada por vírgulas será executada no próprio processo. Cada processo de uma origem indicada só poderá conter documentos da origem em questão e dos subdomínios dela. Por exemplo, se https://a1.example.com/ for especificada, https://a2.a1.example.com/ será permitida no mesmo processo, mas https://example.com ou https://b.example.com não serão.
 
       Desde o <ph name="PRODUCT_NAME" /> 77, também é possível especificar um intervalo de origens isoladas usando um caractere curinga. Por exemplo, se https://[*.]corp.example.com for especificada, todas as origens abaixo de https://corp.example.com ganharão um processo dedicado, incluindo a própria https://corp.example.com, a https://a1.corp.example.com e a https://a2.a1.corp.example.com.
@@ -4271,6 +4289,7 @@
       Caso contrário, os endereços IP locais serão ocultos com os nomes de host de mDNS.
       Observe que, se exigida pelos administradores, esta política enfraquece a proteção dos IPs locais.</translation>
 <translation id="614662973812186053">Esta política também controla a coleta de dados de uso e diagnóstico do Android.</translation>
+<translation id="614665605501218241">Permitir que os sites da lista façam solicitações para endpoints de rede mais particulares de forma não segura.</translation>
 <translation id="6154509171634387825">Aviso: o padrão 3DES será completamente removido na versão 95 do <ph name="PRODUCT_NAME" /> por volta de outubro de 2021, e esta política só funcionará até essa data.
 
       Se esta política for definida como verdadeira, os pacotes de criptografia 3DES em TLS serão ativados. Se ela for definida como falsa, eles serão desativados. Se for deixada sem definição, os pacotes de criptografia 3DES serão desativados por padrão. Esta política pode ser usada para manter temporariamente a compatibilidade com um servidor desatualizado. Esta é uma medida provisória e o servidor precisará ser reconfigurado.
@@ -4285,6 +4304,13 @@
       Se a política não for definida, o usuário poderá escolher ativar ou desativar esse recurso.</translation>
 <translation id="6174065452773547810">Se a política for ativada ou deixada sem definição, o dispositivo poderá receber controles de geração de relatórios granulares.
       Se a política for desativada, os dispositivos registrados não receberão controles de geração de relatórios granulares.</translation>
+<translation id="6174187836314350835">Lista de padrões de URL. As solicitações iniciadas em sites veiculados por origens correspondentes não estão sujeitas a verificações de Private Network Access.
+
+          Se esta política for deixada sem definição, ela se comportará como se a lista tivesse sido definida como vazia.
+
+          No caso de origens não cobertas pelos padrões especificados aqui, o valor padrão geral usado será o da política <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" />, se ela estiver definida, ou o da configuração pessoal do usuário.
+
+          Para ver informações detalhadas sobre padrões de URL válidos, consulte https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.</translation>
 <translation id="6178075938488052838">Esta política controla quem pode iniciar uma sessão do <ph name="PRODUCT_OS_NAME" />. Ela não impede que os usuários façam login em outras Contas do Google no Android. Para impedir essa ação, configure a política <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> específica para Android como parte da <ph name="ARC_POLICY_POLICY_NAME" />.</translation>
 <translation id="6181304954168534748">A hash SHA-256 do modelo de espaço de trabalho.</translation>
 <translation id="6181618732396778048">Não permitir que qualquer site solicite acesso de gravação de arquivos ou diretórios</translation>
@@ -4743,6 +4769,7 @@
       Observação: ainda que a política possa aceitar vários itens em <ph name="ENTRIES_FIELD_NAME" />, todos eles serão ignorados, com exceção do primeiro.
       Aviso: a configuração dessa política pode atrasar as atualizações de software.</translation>
 <translation id="6698632841807204978">Ativar impressão monocromática</translation>
+<translation id="6699740789657890714">Especifica se os sites têm permissão para fazer solicitações para endpoints de rede mais particulares de forma não segura</translation>
 <translation id="6699880231565102694">Ativar autenticação de dois fatores para hosts de acesso remoto</translation>
 <translation id="6703251016607733593">A definição da política desativa a aplicação dos requisitos de divulgação da Transparência dos certificados para uma lista de hashes <ph name="SUBJECT_PUBLIC_KEY_INFO" />. Os hosts comerciais podem continuar usando certificados que, de outro modo, não seriam confiáveis, já que eles não foram divulgados publicamente de maneira adequada. Para desativar a aplicação, o hash precisa atender a uma destas condições:
 
diff --git a/components/policy/resources/policy_templates_tr.xtb b/components/policy/resources/policy_templates_tr.xtb
index 6e56271..f14d60a 100644
--- a/components/policy/resources/policy_templates_tr.xtb
+++ b/components/policy/resources/policy_templates_tr.xtb
@@ -211,6 +211,7 @@
       Politika ayarlanmadan bırakılırsa veya değişiklikten sonraki değer geçerli bir ana makine adı değilse DHCP isteğinde ana makine adı ayarlanmaz.</translation>
 <translation id="1257550411839719984">Varsayılan indirme dizinini ayarlama</translation>
 <translation id="1265053460044691532">SAML kullanarak kimlik doğrulaması yapmış kullanıcının çevrimdışı olarak giriş yapabileceği süreyi sınırla</translation>
+<translation id="1268548671627260798">Tam ekran bildiriminden muaf olan URL'lerin listesi</translation>
 <translation id="127264587838521316"><ph name="PRODUCT_NAME" /> uzantı yükleme isteklerini etkinleştirir</translation>
 <translation id="1272798957154751008">Chromad cihazların bulut yönetimine taşınmasını etkinleştir</translation>
 <translation id="1274997165432133392">Çerezler ve diğer site verileri</translation>
@@ -381,6 +382,18 @@
 
       Bu politika, Hangout Hizmetleri uzantısı gibi bileşen uzantıları için de geçerlidir.</translation>
 <translation id="148194404518916594">Kullanıcıların Dokun ve Ara özelliğini kullanmalarına izin ver</translation>
+<translation id="1485570394283692769">Web sitelerinin daha özel ağ uç noktalarına güvenli olmayan bir şekilde istekte bulunmasına izin verilip verilmediğini kontrol eder.
+
+          Bu politika Özel Ağ Erişimi spesifikasyonuyla alakalıdır. Daha fazla ayrıntı için https://wicg.github.io/private-network-access/ sayfasına bakabilirsiniz.
+
+          Bir ağ uç noktası aşağıdaki koşullarda diğerinden daha gizlidir:
+          1) IP adresi localhost iken diğerininki değilse.
+          2) IP adresi özelken diğerininki herkese açıksa.
+          Bu politika ileride spesifikasyonların değişimine bağlı olarak, özel IP'lere veya localhost'a yönelik tüm çapraz kaynak istekleri için geçerli olabilir.
+
+          Bu politika ayarlanmadığında veya yanlış değerine ayarlandığında daha özel ağ uç noktalarına yapılan istekler için varsayılan davranış, kullanıcının <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />, <ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" /> ve <ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" /> özellik bayraklarıyla ilgili kişisel yapılandırmasına bağlıdır. Bu özellik bayrakları, saha denemeleri tarafından veya komut satırında ayarlanmış olabilir.
+
+          Bu politika, Doğru değerine ayarlandığında, güvenli olmayan web sitelerinin, diğer çapraz kaynak kontrollerine tabi olarak herhangi bir ağ uç noktasına istekte bulunmasına izin verilir.</translation>
 <translation id="1486021504508098388">Arka ışık bilgilerini raporla</translation>
 <translation id="1487916040416013623">Politikanın ayarlanması, entegre kimlik doğrulama için hangi sunuculara izin verileceğini belirtir. Entegre kimlik doğrulaması yalnızca <ph name="PRODUCT_NAME" /> bir proxy veya söz konusu izin verilenler listesindeki bir sunucudan kimlik doğrulaması daveti aldığında etkinleşir.
 
@@ -2729,6 +2742,11 @@
       Politika Devre dışı değerine ayarlanır veya ayarlanmadan bırakılırsa kullanıcılar hücresel bağlantı kullanırken Drive'a dosya aktarabilir.</translation>
 <translation id="4248277954659222481">URL kalıpları izin verilenler listesinde medyanın otomatik olarak oynatılmasına izin ver</translation>
 <translation id="4250680216510889253">Hayır</translation>
+<translation id="4257545866869267519">Tam ekran bildiriminden muaf olan URL'lerin listesini yapılandırır. Bildirim, cihaz uykudan, düşük parlaklıktan veya kilit ekranından döndüğünde ve tam ekran modunda penceresi varken gösterilir. Bunun nedeni kullanıcıların tam ekran modunda olduklarını anlamalarını sağlayıp kimlik avı saldırıları riskini azaltmaktır.
+
+          Bu politika sayesinde güvenilir kaynak olarak kabul edilecek belirli URL'ler için bildirimin devre dışı bırakılması sağlanır. Politika bu biçime (https://www.chromium.org/administrators/url-blocklist-filter-format) göre biçimlendirilmiş bir URL kalıpları listesi belirtilerek ayarlanır. Örneğin, tüm URL'lerle eşleşen <ph name="WILDCARD_VALUE" /> joker karakterini belirterek bildirimleri tamamen devre dışı bırakmak mümkündür.
+
+          Bu politikanın boş bir listeye ayarlanması veya ayarlamadan bırakılması hiçbir URL'nin tam ekran bildiriminden muaf olmadığı anlamına gelir.</translation>
 <translation id="4260027436474745627">Bu politika ayarlanırsa virgülle ayrılmış listede adı verilen her kaynak özel işlem içinde çalışır. Adı verilen her kaynağın işleminde yalnızca o kaynaktan ve kaynağın alt alan adlarından dokümanlar bulunabilir. Örneğin, https://a1.example.com/ alan adı tanımlandığında aynı işlem içerisinde https://a2.a1.example.com/ bulunabilir ancak https://example.com veya https://b.example.com bulunamaz.
 
       77. <ph name="PRODUCT_NAME" /> sürümünden itibaren, joker karakter kullanarak izole edilecek bir kaynak aralığı belirlemek mümkündür. Örneğin, https://[*.]corp.example.com alan adı belirlenirse, https://corp.example.com alan adının kendisi, https://a1.corp.example.com ve https://a2.a1.corp.example.com dahil olmak üzere https://corp.example.com alan adının altında bulunan her bir kaynak kendi özel işlemi içinde çalışır.
@@ -4240,6 +4258,7 @@
       Aksi takdirde, yerel IP adresleri mDNS ana makine adlarıyla gizlenir.
       Bu politikanın, yöneticilerin ihtiyaç duyması halinde yerel IP'lerin korunmasını zayıflattığını lütfen unutmayın.</translation>
 <translation id="614662973812186053">Bu politika, Android kullanımını ve teşhis verilerini toplama çalışmalarını da kontrol eder.</translation>
+<translation id="614665605501218241">Listelenen sitelerin, daha özel ağ uç noktalarına güvenli olmayan bir şekilde istekte bulunmasına izin ver.</translation>
 <translation id="6154509171634387825">Uyarı: 3DES, 95 sürümünde (Ekim 2021 civarında) <ph name="PRODUCT_NAME" /> ürününden tamamen kaldırılacak ve bu politika artık kullanılamayacaktır.
 
       Politika doğru değerine ayarlanırsa TLS'de 3DES şifre paketleri etkinleştirilir. Politika yanlış değerine ayarlanırsa bunlar devre dışı bırakılır. Politika ayarlanmazsa 3DES şifre paketleri varsayılan olarak devre dışı bırakılır. Bu politika eski bir sunucuyla uyumluluğu sürdürmek için geçici olarak kullanılabilir. Bu geçici bir tedbir olup sunucu yeniden yapılandırılmalıdır.
@@ -4254,6 +4273,13 @@
       Politika ayarlanmadan bırakılırsa kullanıcılar bu özelliğin etkinleştirilip etkineştirilmeyeceğine kendileri karar verebilir.</translation>
 <translation id="6174065452773547810">Politika, Etkin değerine ayarlanır veya ayarlanmadan bırakılırsa cihaz, ayrıntılı raporlama kontrolleri alabilir.
       Politika, Devre Dışı değerine ayarlanırsa kayıtlı cihazlar ayrıntılı raporlama kontrolleri alamaz.</translation>
+<translation id="6174187836314350835">URL kalıpları listesi. Eşleşen kaynakların sunduğu web sitelerinden başlatılan istekler, özel ağ erişimi kontrollerine tabi değildir.
+
+          Bu politika ayarlanmazsa boş listeye ayarlanmış gibi davranır.
+
+          Burada belirtilen kalıpların dışında kalan kaynaklar için <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" /> politikası ayarlandıysa buradaki değer, aksi takdirde kullanıcının kişisel yapılandırması genel varsayılan değer olarak kullanılır.
+
+          Geçerli URL kalıpları hakkında ayrıntılı bilgi için https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns adresine bakabilirsiniz.</translation>
 <translation id="6178075938488052838">Bu politika, kimin bir <ph name="PRODUCT_OS_NAME" /> oturumu başlatabileceğini kontrol eder. Kullanıcıların Android'de başka Google hesapları ile oturum açmalarını engellemez. Bunu engellemek isterseniz Android'e özgü <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> politikasını <ph name="ARC_POLICY_POLICY_NAME" /> politikası kapsamında yapılandırın.</translation>
 <translation id="6181304954168534748">Masa şablonunun SHA-256 karması.</translation>
 <translation id="6181618732396778048">Hiçbir sitenin dosya ve dizinlere yazma erişimi istemesine izin verme</translation>
@@ -4698,6 +4724,7 @@
       Not: Politika <ph name="ENTRIES_FIELD_NAME" /> alanında birden çok öğe kabul edebilir, ancak birinci öğe hariç diğerleri yok sayılır.
       Uyarı: Bu politikayı ayarlamak, yazılım güncellemelerinin uygulanmasını geciktirebilir.</translation>
 <translation id="6698632841807204978">Tek renk yazdırmayı etkinleştir</translation>
+<translation id="6699740789657890714">Web sitelerinin, daha özel ağ uç noktalarına güvenli olmayan bir şekilde istekte bulunmasına izin verilip verilmeyeceğini belirtir</translation>
 <translation id="6699880231565102694">Uzaktan erişim ana makineleri için iki öğeli kimlik doğrulamayı etkinleştir</translation>
 <translation id="6703251016607733593">Politikanın ayarlanması, <ph name="SUBJECT_PUBLIC_KEY_INFO" /> karmaları listesi için Sertifika Şeffaflığı açıklama gereksinimlerinin uygulanmasını kapatır. Kurumsal ana makineler, aksi halde güvenilmeyecek olan (uygun bir şekilde herkese açık olarak açıklanmadığından) sertifikaları kullanmaya devam edebilir. Uygulamanın kapatılması için karmanın aşağıdaki koşullardan birini karşılaması gerekir:
 
diff --git a/components/policy/resources/policy_templates_zh-CN.xtb b/components/policy/resources/policy_templates_zh-CN.xtb
index 57840426..8a90a4d6 100644
--- a/components/policy/resources/policy_templates_zh-CN.xtb
+++ b/components/policy/resources/policy_templates_zh-CN.xtb
@@ -2840,6 +2840,23 @@
 
       如果将此政策设置为 false,在操作系统升级后,该浏览器首次启动时将不会重新显示欢迎页面。</translation>
 <translation id="441686537793821907">阻止安装外部扩展程序</translation>
+<translation id="4420613474328461583">让您能够以列表形式指定要应用于 <ph name="ON_FILE_DOWNLOADED_ENTERPRISE_CONNECTOR" /> 企业版接口的 Chrome 企业版接口服务设置,以供系统在有人通过 Chrome 下载文件时调用。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> 字段用于确定当用户从特定网页下载某个文件时,该接口是否应将此文件发送给系统进行分析,以及要将哪些标记添加到此文件的分析请求中。如果相应的网页网址与某个标记关联的“enable”格式相匹配,但不与此标记关联的任何“disable”格式匹配,该接口便会将这个标记添加到分析请求中。如果该接口向分析请求中添加了至少 1 个标记,系统便会分析此文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> 字段用于确定您指定的设置是与哪个分析服务提供商对应。
+
+      如果您将 <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> 字段设为 1,Chrome 需要先等到分析服务做出响应,再确定是否要授权相应用户访问所下载的文件。如果您将该字段设为任何其他整数值,Chrome 就会立即授权相应用户访问此文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_PASSWORD_PROTECTED_FIELD" /> 字段用于控制 Chrome 是会禁止访问还是会允许访问受密码保护的文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> 字段用于控制 Chrome 是会禁止访问还是会允许访问因过大而无法分析的文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> 字段用于确定该接口应要求用户为哪些标记输入理由,以绕过那些触发了可绕过式警告的扫描。如果该字段未设置,系统会假设不需要输入理由。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> 字段用于配置系统在扫描完毕并判定文件有问题后向用户显示的警告消息。message 字段包含要向用户显示的文字,最多只能有 200 个字符。learn_more_url 字段包含管理员提供的网址,用户可点击该网址以从客户提供的信息中详细了解相应操作被禁止的原因。language 字段是可选字段,包含消息所用的语言。空 language 字段或“default”值用于指明要显示的消息不是以用户所用语言设定的。tag 字段用于指定要针对哪类扫描显示消息。custom_messages 列表可包含零个或多个条目,每个条目都必须具有非空的 message 和 tag 字段。
+
+      此政策只能通过 <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" />进行设置。</translation>
 <translation id="4423597592074154136">手动指定代理设置</translation>
 <translation id="4424004842303301809">停用关于数据泄露预防事件的报告</translation>
 <translation id="4427173305799125784">PDF 查看器无法在 PDF 文件中添加注释</translation>
@@ -2961,6 +2978,7 @@
       如需查看完整说明,请访问 https://www.chromestatus.com/feature/5675755719622656。
       如果您启用了此政策,网站将可以在导航的同时打开新窗口/新标签页。
       如果您停用了或未设置此政策,网站将无法在导航的同时打开新窗口/新标签页。</translation>
+<translation id="457430673056611745">OnPrint <ph name="PRODUCT_NAME" /> 企业版接口的配置政策</translation>
 <translation id="4578265298946081589">不要在用户退出后重新启动。</translation>
 <translation id="4581507927311097234">系统应在设备闲置多久(以毫秒为单位)后关闭屏幕</translation>
 <translation id="4582338216073557489">当此政策设为 None 时,<ph name="PRODUCT_NAME" /> 会使用默认的缓存大小在磁盘中存储缓存文件。用户无法更改此设置。
@@ -5944,6 +5962,23 @@
 
       如果此政策已停用或未设置,系统将不会发送任何数据包。</translation>
 <translation id="816783746144552109">为设备配置允许使用的最低 Chrome 操作系统版本。</translation>
+<translation id="8169492352330154095">让您能够以列表形式指定要应用于 <ph name="ON_FILE_ATTACHED_ENTERPRISE_CONNECTOR" /> 企业版接口的 Chrome 企业版接口服务设置,以供系统在有人向 Chrome 附加文件时调用。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> 字段用于确定当用户向特定网页附加文件时,该接口是否应将此文件发送给系统进行分析,以及要将哪些标记添加到此文件的分析请求中。如果相应的网页网址与某个标记关联的“enable”格式相匹配,但不与此标记关联的任何“disable”格式匹配,该接口便会将这个标记添加到分析请求中。如果该接口向分析请求中添加了至少 1 个标记,系统便会分析此文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> 字段用于确定您指定的设置是与哪个分析服务提供商对应。
+
+      如果您将 <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> 字段设为 1,Chrome 需要先等到分析服务做出响应,再确定是否要授权相应网页访问此文件。如果您将该字段设为任何其他整数值,Chrome 就会立即授权相应网页访问此文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_PASSWORD_PROTECTED_FIELD" /> 字段用于控制 Chrome 是会禁止访问还是会允许访问受密码保护的文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> 字段用于控制 Chrome 是会禁止访问还是会允许访问因过大而无法分析的文件。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> 字段用于确定该接口应要求用户为哪些标记输入理由,以绕过那些触发了可绕过式警告的扫描。如果该字段未设置,系统会假设不需要输入理由。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> 字段用于配置系统在扫描完毕并判定文件有问题后向用户显示的警告消息。message 字段包含要向用户显示的文字,最多只能有 200 个字符。learn_more_url 字段包含管理员提供的网址,用户可点击该网址以从客户提供的信息中详细了解相应操作被禁止的原因。language 字段是可选字段,包含消息所用的语言。空 language 字段或“default”值用于指明要显示的消息不是以用户所用语言设定的。tag 字段用于指定要针对哪类扫描显示消息。custom_messages 列表可包含零个或多个条目,每个条目都必须具有非空的 message 和 tag 字段。
+
+      此政策只能通过 <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" />进行设置。</translation>
 <translation id="8171924760436219650">将在登录屏幕上使用的鼠标主按钮切换成右键</translation>
 <translation id="8173864651667424191">在 PDF 文档的打印预览中,“以图片形式打印”选项(若有)默认处于选中状态。</translation>
 <translation id="8176035528522326671">当设定了多份个人资料时,只有企业用户才可以作为主用户(受企业管理的用户的默认行为)</translation>
@@ -6192,6 +6227,11 @@
       如果此政策未设置,系统将会使用默认值(即 3)
 
       如果设置了此政策,系统便会酌情删除旧快照以遵守此限制。如果此政策设为 0,系统将不会创建任何快照</translation>
+<translation id="8447347049334673364">通过设置此政策,您可以控制 <ph name="PRODUCT_NAME" /> 的扩展程序管理设置,其中包括由现有的扩展程序相关政策控制的设置。此政策会取代任何可能已设置的旧版政策。
+
+      此政策仅会将某个扩展程序 ID 或某个更新网址映射至其特定的设置。您可为特殊 ID<ph name="DEFAULT_SCOPE" />设定默认配置,该配置会应用于未在此政策中设定自定义配置的所有扩展程序。对于更新网址,相应配置会应用于具有在扩展程序清单 ( http://support.google.com/chrome/a?p=Configure_ExtensionSettings_policy ) 中注明的确切更新网址的扩展程序。如果“override_update_url”标记设为 true,系统会根据 <ph name="EXTENSION_INSTALL_FORCELIST_POLICY_NAME" /> 政策中或此政策的“update_url”字段中指定的“更新”网址来安装并更新扩展程序。如果“update_url”是 Chrome 网上应用店网址,“override_update_url”标记会被忽略。
+
+      注意:对于未加入 <ph name="MS_AD_NAME" /> 网域的 <ph name="MS_WIN_NAME" /> 实例,以及未通过 MDM 进行管理或未通过 MCX 加入网域的 <ph name="MAC_OS_NAME" /> 实例,强制安装仅限于 Chrome 网上应用店中列出的应用和扩展程序。</translation>
 <translation id="8451988835943702790">使用“新标签页”作为主页</translation>
 <translation id="8455529558077979314">隐私保护屏设置</translation>
 <translation id="8455551509936646199">应在每周的哪一天(以设备的本地时区表示)重新启动设备。仅在“频率”设为“WEEKLY”时使用。</translation>
@@ -6399,6 +6439,21 @@
       如需详细了解有效的<ph name="URL_LABEL" />格式,请访问 https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns。<ph name="WILDCARD_VALUE" /> 不是此政策可接受的值。</translation>
 <translation id="8703488928438047864">报告主板状态</translation>
 <translation id="8704831857353097849">已停用插件的列表</translation>
+<translation id="8704915028294851978">让您能够以列表形式指定要应用于 <ph name="ON_PRINT_ENTERPRISE_CONNECTOR" /> 企业版接口的 <ph name="PRODUCT_NAME" /> 企业版接口服务设置,以供系统在有人通过 <ph name="PRODUCT_NAME" /> 打印网页或文件时调用。
+
+      <ph name="ENTERPRISE_CONNECTOR_URL_LIST_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_TAGS_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> 字段用于确定当用户在特定网页中触发打印操作时,该接口是否应将数据发送给系统进行分析,以及要将哪些标记添加到分析请求中。如果该接口向分析请求中添加了至少 1 个标记,系统便会分析相应数据。
+
+      <ph name="ENTERPRISE_CONNECTOR_SERVICE_PROVIDER_FIELD" /> 字段用于确定您指定的设置是与哪个分析服务提供商对应。
+
+      如果您将 <ph name="ENTERPRISE_CONNECTOR_BLOCK_UNTIL_VERDICT_FIELD" /> 字段设为 1,<ph name="PRODUCT_NAME" /> 需要先等到分析服务做出响应,再确定是否要为打印的网页显示“打印预览”对话框。如果您将该字段设为任何其他整数值,<ph name="PRODUCT_NAME" /> 就会立即显示“打印预览”对话框。
+
+      <ph name="ENTERPRISE_CONNECTOR_BLOCK_LARGE_FILES_FIELD" /> 字段用于控制 <ph name="PRODUCT_NAME" /> 是会禁止访问还是会允许访问因过大而无法分析的文件/网页。
+
+      <ph name="ENTERPRISE_CONNECTOR_REQUIRE_JUSTIFICATION_TAGS_FIELD" /> 字段用于确定该接口应要求用户为哪些标记输入理由,以绕过那些触发了可绕过式警告的扫描。如果该字段未设置,系统会假设不需要输入理由。
+
+      <ph name="ENTERPRISE_CONNECTOR_CUSTOM_MESSAGES_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_MESSAGE_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LEARN_MORE_URL_FIELD" />、<ph name="ENTERPRISE_CONNECTOR_LANGUAGE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_TAG_FIELD" /> 字段用于配置系统在扫描完毕并判定数据有问题后向用户显示的警告消息。管理员能够配置最多 200 个字符的消息。
+
+      此政策只能通过 <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME" />进行设置。</translation>
 <translation id="8705895771006864851">如果此政策设为 True,<ph name="PRODUCT_NAME" /> 将会显示一个集成式翻译工具栏,并且在用户点击鼠标右键时,出现的上下文菜单中会显示翻译选项,以便适时地向用户提供翻译功能。将此政策设为 False 会关闭所有内置的翻译功能。
 
       如果您设置了此政策,用户将无法更改这项功能。如果此政策未设置,用户便可以更改此设置。</translation>
diff --git a/components/policy/resources/policy_templates_zh-TW.xtb b/components/policy/resources/policy_templates_zh-TW.xtb
index 0bd6596..b4d1069 100644
--- a/components/policy/resources/policy_templates_zh-TW.xtb
+++ b/components/policy/resources/policy_templates_zh-TW.xtb
@@ -210,6 +210,7 @@
       如果不設定這項政策,或是替換後的值不是有效的主機名稱,則系統不會在 DHCP 要求中設定主機名稱。</translation>
 <translation id="1257550411839719984">設定預設的下載目錄</translation>
 <translation id="1265053460044691532">限制透過 SAML 驗證的使用者可離線登入的時間</translation>
+<translation id="1268548671627260798">排除全螢幕通知的網址清單</translation>
 <translation id="127264587838521316">啟用 <ph name="PRODUCT_NAME" /> 擴充功能安裝要求</translation>
 <translation id="1272798957154751008">允許將 Chromad 裝置遷移至雲端管理服務</translation>
 <translation id="1274997165432133392">Cookie 和其他網站資料</translation>
@@ -380,6 +381,16 @@
 
       注意:這項政策也適用於元件擴充功能,例如 Hangout Services 擴充功能。</translation>
 <translation id="148194404518916594">允許使用「輕觸搜尋」功能</translation>
+<translation id="1485570394283692769">控制是否允許網站以不安全的方式,向更私密的網路端點傳送要求。這項政策與私人網路存取權規格有關。詳情請參閱 https://wicg.github.io/private-network-access/。
+
+          當網路端點符合以下條件時,私密程度較高:
+          1) 其 IP 位址為 localhost,且其他網路端點的 IP 位址不是 localhost。
+          2) 其 IP 位址為私人位址,且其他網路端點的 IP 位址為公開位址。
+          根據未來的規格演進而定,這項政策可能會套用至所有導向私人 IP 或 localhost 的跨來源要求。
+
+          如果不設定這項政策或設為 False,向更私密的網路端點傳送要求的預設行為將取決於使用者對 <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME" />、<ph name="PRIVATE_NETWORK_ACCESS_SEND_PREFLIGHTS_FEATURE_NAME" /> 和 <ph name="PRIVATE_NETWORK_ACCESS_RESPECT_PREFLIGHT_RESULTS_FEATURE_NAME" /> 功能旗標的個人設定,使用者可以透過實際測試或指令列來進行設定。
+
+          如果將這項政策設為 True,網站即可向任何網路端點傳送要求,並且需經過其他跨來源檢查。</translation>
 <translation id="1486021504508098388">回報背光資訊</translation>
 <translation id="1487916040416013623">你可以透過這項政策指定允許整合驗證的伺服器。只有當 Proxy 或這份許可清單中的伺服器傳送驗證要求給 <ph name="PRODUCT_NAME" /> 時,系統才會啟用整合驗證。
 
@@ -2711,6 +2722,11 @@
       如果將這項政策設為停用或不設定,使用者可在使用行動網路連線時,將檔案傳輸至雲端硬碟。</translation>
 <translation id="4248277954659222481">允許符合網址模式許可清單的網頁自動播放媒體</translation>
 <translation id="4250680216510889253">否</translation>
+<translation id="4257545866869267519">設定要從全螢幕通知排除的網址清單。當裝置從休眠、低亮度或螢幕鎖定回到一般使用狀態,且視窗處於全螢幕模式時,系統將會顯示通知。這是為了讓使用者意識到自己處於全螢幕模式,用以減少網路詐騙攻擊的風險。
+
+          這項政策允許將特定網址視為信任來源時,為其停用通知。設定方式為根據這個格式 (https://www.chromium.org/administrators/url-blocklist-filter-format) 指定網址模式格式的清單。例如,可以透過指定萬用字元 <ph name="WILDCARD_VALUE" /> 比對所有網址,一併停用通知。
+
+          將這項政策設為空白清單或不設定,則表示不會從全螢幕通知排除任何網址。</translation>
 <translation id="4260027436474745627">如果設定這項政策,逗號分隔清單中指定的每個來源就會在獨立程序中執行。每個指定來源的程序都只能容納來自相同來源及其子網域的文件。舉例來說,如果指定 https://a1.example.com/,https://a2.a1.example.com/ 就能使用同一個程序,但是 https://example.com 和 https://b.example.com 並不能使用同一個程序。
 
       自 <ph name="PRODUCT_NAME" /> 第 77 版起,你也可以使用萬用字元來指定要隔離的來源範圍。舉例來說,如果指定 https://[*.]corp.example.com,則 https://corp.example.com 底下的每個來源都會在獨立程序中執行,其中包括 https://corp.example.com 本身、https://a1.corp.example.com 和 https://a2.a1.corp.example.com。
@@ -4219,6 +4235,7 @@
       否則系統會透過 mDNS 主機名稱隱藏本機 IP 位址。
       請注意,如果系統管理員必須使用此政策,此政策將降低系統對本機 IP 的保護程度。</translation>
 <translation id="614662973812186053">這項政策也可以控制 Android 使用資料和診斷資料的收集設定。</translation>
+<translation id="614665605501218241">允許列出的網站譯不安全的方式,向更私密的網路端點傳送要求。</translation>
 <translation id="6154509171634387825">警告:我們將從 <ph name="PRODUCT_NAME" /> 第 95 版中 (約在 2021 年 10 月推出) 完全移除 3DES,屆時這項政策也會停止運作。
       如果將這項政策設為 True,系統會啟用傳輸層安全標準 (TLS) 中的 3DES 加密套件。如果設為 False,系統將停用這些加密套件。如果不設定這項政策,3DES 加密套件會預設為停用。這項政策可以暫時維持與過時伺服器的相容性。這種做法是權宜之計,正確的做法是重新設定伺服器。
       </translation>
@@ -4232,6 +4249,13 @@
       如果未設定這項政策,使用者可自行決定要啟用或停用這項功能。</translation>
 <translation id="6174065452773547810">如果將這項政策設為 Enabled 或不設定,裝置就能取得精細回報控制項。
       如果將這項政策設為 Disabled,表示已註冊的裝置不會取得精細回報控制項。</translation>
+<translation id="6174187836314350835">網址模式清單。來自相符來源提供的網站所傳送的要求,不受私人網路存取權檢查應響。
+
+          如果不設定,這項政策的運作方式會如同已設為空白清單。
+
+          如果來源不符合此處指定的模式,系統會根據 <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME" /> 政策 (如有設定) 或使用者的個人設定套用全域預設值。
+
+          如果想進一步瞭解有效的網址模式,請參閱 https://chromeenterprise.google/intl/zh_tw/policies/url-patterns。</translation>
 <translation id="6178075938488052838">這項政策可控管哪些使用者能夠啟動 <ph name="PRODUCT_OS_NAME" />工作階段,但不會禁止使用者在 Android 應用程式中登入其他 Google 帳戶。如要禁止使用者登入其他 Google 帳戶,你可以在 <ph name="ARC_POLICY_POLICY_NAME" /> 中設定 Android 專屬的 <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> 政策。</translation>
 <translation id="6181304954168534748">桌面範本的 SHA-256 雜湊。</translation>
 <translation id="6181618732396778048">不允許任何網站要求檔案和目錄的寫入權限。</translation>
@@ -4677,6 +4701,7 @@
       注意:雖然這項政策可接受 <ph name="ENTRIES_FIELD_NAME" /> 中的多個項目,但除了第一個項目外,其他項目都會遭到忽略。
       警告:設定這項政策可能導致軟體更新延遲套用。</translation>
 <translation id="6698632841807204978">啟用單色列印</translation>
+<translation id="6699740789657890714">指定是否允許網站以不安全的方式,向更私密的網路端點傳送要求</translation>
 <translation id="6699880231565102694">為遠端存取主機啟用雙重驗證機制</translation>
 <translation id="6703251016607733593">設定這項政策後,系統不會強制要求列出的 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊依憑證透明化規定公開憑證。此外,因為未依規定對外公開而不受信任的憑證,企業主機也可以繼續使用。雜湊必須符合以下其中一項條件,才能不強制要求公開憑證:
 
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index db9b818f..9a768a8 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -359,7 +359,7 @@
     cookie_manager->GetCookieList(
         GaiaUrls::GetInstance()->secure_google_url(),
         net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain::Todo(),
+        net::CookiePartitionKeyCollection::Todo(),
         base::BindOnce(
             &AccountConsistencyService::TriggerGaiaCookieChangeIfDeleted,
             base::Unretained(this), std::move(cookies_restored_callback)));
diff --git a/components/strings/components_strings_mn.xtb b/components/strings/components_strings_mn.xtb
index 0e3cdd7..77b3de5 100644
--- a/components/strings/components_strings_mn.xtb
+++ b/components/strings/components_strings_mn.xtb
@@ -176,6 +176,7 @@
 <translation id="1472675084647422956">Дэлгэрэнгүй харуулах</translation>
 <translation id="1473183651233018052">JIS B10</translation>
 <translation id="147358896496811705">2A0</translation>
+<translation id="1475299637784133125">Хөтчийн хувилбарыг хайж байна уу? Зочлох</translation>
 <translation id="1476595624592550506">Нууц үгээ өөрчилнө үү</translation>
 <translation id="1483493594462132177">Илгээх</translation>
 <translation id="1484290072879560759">Тээвэрлэлтийн хаяг сонгох</translation>
@@ -1886,6 +1887,7 @@
 <translation id="7118618213916969306">Түр санах ойн URL болох <ph name="SHORT_URL" />-г хайх</translation>
 <translation id="7119414471315195487">Бусад таб, эсвэл программыг хаах</translation>
 <translation id="7129409597930077180">Энэ хаяг руу хүргэх боломжгүй тул өөр хаяг сонгоно уу.</translation>
+<translation id="7132939140423847331">Таны админ энэ өгөгдлийг хуулахыг хориглосон.</translation>
 <translation id="7135130955892390533">Төлөвийг харуулах</translation>
 <translation id="7138472120740807366">Хүргэлтийн арга</translation>
 <translation id="7139724024395191329">Эмират улс</translation>
@@ -2444,6 +2446,7 @@
 <translation id="8987245424886630962"><ph name="VIEW_CHROME_HISTORY_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome-д хөтчийн түүхээ үзэхийн тулд эхлээд tab, дараа нь Enter дээр дарна уу</translation>
 <translation id="8987927404178983737">Сар</translation>
 <translation id="8989148748219918422"><ph name="ORGANIZATION" /> [ <ph name="COUNTRY" /> ]</translation>
+<translation id="8992061558343343009">Системийн хувилбарыг хайж байна уу? Зочлох</translation>
 <translation id="899688752321268742"><ph name="URL" /> таныг энэ төхөөрөмжийг хэзээ идэвхтэй ашиглаж буйг мэдэхийг хүсэж байна</translation>
 <translation id="8996941253935762404">Таны сонгосон сайт гэмтэл учруулж болох программыг агуулж байна</translation>
 <translation id="8997023839087525404">Сертификатын ил тод байдлаар ил тод болгоогүй сертификатыг серверээс санал болгосон. Энэ нь зарим сертификатад итгэх итгэл, халдагчдын эсрэг хамгаалалтыг бий болгох үүднээс шаардлагатай байдаг.</translation>
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index aced853..e854b83e 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -12,8 +12,10 @@
     "//components/sync/engine",
     "//components/sync/model",
     "//components/sync/nigori",
-    "//components/sync/trusted_vault",
   ]
+  if (!is_android) {
+    public_deps += [ "//components/sync/trusted_vault" ]
+  }
 }
 
 group("test_support") {
@@ -26,6 +28,9 @@
     "//components/sync/base:test_support",
     "//components/sync/driver:test_support",
   ]
+  if (!is_android) {
+    public_deps += [ "//components/sync/trusted_vault:test_support" ]
+  }
 }
 
 static_library("test_support_engine") {
@@ -199,16 +204,21 @@
     "nigori/nigori_unittest.cc",
     "protocol/proto_enum_conversions_unittest.cc",
     "protocol/proto_value_conversions_unittest.cc",
-    "trusted_vault/download_keys_response_handler_unittest.cc",
-    "trusted_vault/proto_string_bytes_conversion_unittest.cc",
-    "trusted_vault/securebox_unittest.cc",
-    "trusted_vault/standalone_trusted_vault_backend_unittest.cc",
-    "trusted_vault/trusted_vault_access_token_fetcher_frontend_unittest.cc",
-    "trusted_vault/trusted_vault_connection_impl_unittest.cc",
-    "trusted_vault/trusted_vault_crypto_unittest.cc",
-    "trusted_vault/trusted_vault_request_unittest.cc",
   ]
 
+  if (!is_android) {
+    sources += [
+      "trusted_vault/download_keys_response_handler_unittest.cc",
+      "trusted_vault/proto_string_bytes_conversion_unittest.cc",
+      "trusted_vault/securebox_unittest.cc",
+      "trusted_vault/standalone_trusted_vault_backend_unittest.cc",
+      "trusted_vault/trusted_vault_access_token_fetcher_frontend_unittest.cc",
+      "trusted_vault/trusted_vault_connection_impl_unittest.cc",
+      "trusted_vault/trusted_vault_crypto_unittest.cc",
+      "trusted_vault/trusted_vault_request_unittest.cc",
+    ]
+  }
+
   configs += [ "//build/config:precompiled_headers" ]
 
   data = [
diff --git a/components/sync/trusted_vault/BUILD.gn b/components/sync/trusted_vault/BUILD.gn
index d2914d7ec..3ada626 100644
--- a/components/sync/trusted_vault/BUILD.gn
+++ b/components/sync/trusted_vault/BUILD.gn
@@ -2,62 +2,64 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-static_library("trusted_vault") {
-  sources = [
-    "download_keys_response_handler.cc",
-    "download_keys_response_handler.h",
-    "proto_string_bytes_conversion.cc",
-    "proto_string_bytes_conversion.h",
-    "securebox.cc",
-    "securebox.h",
-    "standalone_trusted_vault_backend.cc",
-    "standalone_trusted_vault_backend.h",
-    "standalone_trusted_vault_client.cc",
-    "standalone_trusted_vault_client.h",
-    "trusted_vault_access_token_fetcher.h",
-    "trusted_vault_access_token_fetcher_frontend.cc",
-    "trusted_vault_access_token_fetcher_frontend.h",
-    "trusted_vault_access_token_fetcher_impl.cc",
-    "trusted_vault_access_token_fetcher_impl.h",
-    "trusted_vault_connection.cc",
-    "trusted_vault_connection.h",
-    "trusted_vault_connection_impl.cc",
-    "trusted_vault_connection_impl.h",
-    "trusted_vault_crypto.cc",
-    "trusted_vault_crypto.h",
-    "trusted_vault_request.cc",
-    "trusted_vault_request.h",
-    "trusted_vault_server_constants.cc",
-    "trusted_vault_server_constants.h",
-    "trusted_vault_switches.cc",
-    "trusted_vault_switches.h",
-  ]
-  public_deps = [
-    "//base",
-    "//components/sync/driver",
-  ]
-  deps = [
-    "//components/os_crypt",
-    "//components/signin/public/identity_manager",
-    "//components/sync/base",
-    "//components/sync/protocol",
-    "//crypto",
-    "//net",
-    "//services/network/public/cpp:cpp",
-    "//third_party/boringssl",
-  ]
-}
+if (!is_android) {
+  static_library("trusted_vault") {
+    sources = [
+      "download_keys_response_handler.cc",
+      "download_keys_response_handler.h",
+      "proto_string_bytes_conversion.cc",
+      "proto_string_bytes_conversion.h",
+      "securebox.cc",
+      "securebox.h",
+      "standalone_trusted_vault_backend.cc",
+      "standalone_trusted_vault_backend.h",
+      "standalone_trusted_vault_client.cc",
+      "standalone_trusted_vault_client.h",
+      "trusted_vault_access_token_fetcher.h",
+      "trusted_vault_access_token_fetcher_frontend.cc",
+      "trusted_vault_access_token_fetcher_frontend.h",
+      "trusted_vault_access_token_fetcher_impl.cc",
+      "trusted_vault_access_token_fetcher_impl.h",
+      "trusted_vault_connection.cc",
+      "trusted_vault_connection.h",
+      "trusted_vault_connection_impl.cc",
+      "trusted_vault_connection_impl.h",
+      "trusted_vault_crypto.cc",
+      "trusted_vault_crypto.h",
+      "trusted_vault_request.cc",
+      "trusted_vault_request.h",
+      "trusted_vault_server_constants.cc",
+      "trusted_vault_server_constants.h",
+      "trusted_vault_switches.cc",
+      "trusted_vault_switches.h",
+    ]
+    public_deps = [
+      "//base",
+      "//components/sync/driver",
+    ]
+    deps = [
+      "//components/os_crypt",
+      "//components/signin/public/identity_manager",
+      "//components/sync/base",
+      "//components/sync/protocol",
+      "//crypto",
+      "//net",
+      "//services/network/public/cpp:cpp",
+      "//third_party/boringssl",
+    ]
+  }
 
-static_library("test_support") {
-  testonly = true
-  sources = [
-    "fake_security_domains_server.cc",
-    "fake_security_domains_server.h",
-  ]
+  static_library("test_support") {
+    testonly = true
+    sources = [
+      "fake_security_domains_server.cc",
+      "fake_security_domains_server.h",
+    ]
 
-  deps = [
-    "//components/sync/protocol",
-    "//components/sync/trusted_vault",
-    "//net:test_support",
-  ]
+    deps = [
+      "//components/sync/protocol",
+      "//components/sync/trusted_vault",
+      "//net:test_support",
+    ]
+  }
 }
diff --git a/components/viz/service/display_embedder/output_presenter.cc b/components/viz/service/display_embedder/output_presenter.cc
index 7a59842..9f696373 100644
--- a/components/viz/service/display_embedder/output_presenter.cc
+++ b/components/viz/service/display_embedder/output_presenter.cc
@@ -9,7 +9,6 @@
 #include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_factory.h"
-#include "skia/ext/legacy_display_globals.h"
 #include "third_party/skia/include/gpu/GrBackendSemaphore.h"
 #include "third_party/skia/include/gpu/GrDirectContext.h"
 
@@ -53,8 +52,7 @@
   DCHECK(end_semaphores_.empty());
 
   std::vector<GrBackendSemaphore> begin_semaphores;
-  SkSurfaceProps surface_props =
-      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
 
   // Buffer queue is internal to GPU proc and handles texture initialization,
   // so allow uncleared access.
diff --git a/components/viz/service/display_embedder/skia_output_device_dawn.cc b/components/viz/service/display_embedder/skia_output_device_dawn.cc
index 6cb9212..00f1b85 100644
--- a/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -9,7 +9,6 @@
 #include "base/check_op.h"
 #include "base/notreached.h"
 #include "components/viz/common/gpu/dawn_context_provider.h"
-#include "skia/ext/legacy_display_globals.h"
 #include "third_party/dawn/src/include/dawn_native/D3D12Backend.h"
 #include "ui/gfx/presentation_feedback.h"
 #include "ui/gfx/vsync_provider.h"
@@ -123,8 +122,7 @@
   GrBackendRenderTarget backend_target(
       size_.width(), size_.height(), /*sampleCnt=*/0, /*stencilBits=*/0, info);
   DCHECK(backend_target.isValid());
-  SkSurfaceProps surface_props =
-      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
   sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
       context_provider_->GetGrContext(), backend_target,
       capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc
index 7e0bf33..6453f7f 100644
--- a/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -233,8 +233,7 @@
     base::debug::Alias(nullptr);
     return false;
   }
-  SkSurfaceProps surface_props =
-      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
 
   GrGLFramebufferInfo framebuffer_info;
   framebuffer_info.fFBOID = 0;
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index 4237369..8fcc2ba 100644
--- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "gpu/command_buffer/service/skia_utils.h"
-#include "skia/ext/legacy_display_globals.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
 namespace viz {
@@ -140,8 +139,7 @@
   DCHECK(!allocate_frame_buffer);
   DCHECK(backend_texture_.isValid());
   if (!sk_surface_) {
-    SkSurfaceProps surface_props =
-        skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
     sk_surface_ = SkSurface::MakeFromBackendTexture(
         context_state_->gr_context(), backend_texture_,
         capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index 75415347..bbef3973 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -18,7 +18,6 @@
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_implementation.h"
 #include "gpu/vulkan/vulkan_surface.h"
-#include "skia/ext/legacy_display_globals.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrBackendSemaphore.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
@@ -182,8 +181,7 @@
       sk_surface_size_pairs_[scoped_write_->image_index()].sk_surface;
 
   if (UNLIKELY(!sk_surface)) {
-    SkSurfaceProps surface_props =
-        skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
     const auto surface_format = vulkan_surface_->surface_format().format;
     DCHECK(surface_format == VK_FORMAT_B8G8R8A8_UNORM ||
            surface_format == VK_FORMAT_R8G8B8A8_UNORM);
diff --git a/components/viz/service/display_embedder/skia_output_device_webview.cc b/components/viz/service/display_embedder/skia_output_device_webview.cc
index 3b1457d..964450d 100644
--- a/components/viz/service/display_embedder/skia_output_device_webview.cc
+++ b/components/viz/service/display_embedder/skia_output_device_webview.cc
@@ -101,9 +101,6 @@
 void SkiaOutputDeviceWebView::InitSkiaSurface(unsigned int fbo) {
   last_frame_buffer_object_ = fbo;
 
-  SkSurfaceProps surface_props =
-      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
-
   GrGLFramebufferInfo framebuffer_info;
   framebuffer_info.fFBOID = fbo;
   framebuffer_info.fFormat = GL_RGBA8;
@@ -115,6 +112,8 @@
   auto origin = (gl_surface_->GetOrigin() == gfx::SurfaceOrigin::kTopLeft)
                     ? kTopLeft_GrSurfaceOrigin
                     : kBottomLeft_GrSurfaceOrigin;
+
+  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
   sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
       context_state_->gr_context(), render_target, origin, color_type,
       color_space_.ToSkColorSpace(), &surface_props);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 4ad1a24..841230b 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -930,8 +930,7 @@
   }
 
   auto cache_max_resource_bytes = impl_on_gpu_->max_resource_cache_bytes();
-  SkSurfaceProps surface_props =
-      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
   if (is_root_render_pass) {
     const auto format_index = static_cast<int>(format);
     const auto& color_type = capabilities_.sk_color_types[format_index];
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index b1f728b1..4b5d61e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -1120,10 +1120,11 @@
         mailbox, context_state_.get());
     DCHECK(backing_representation);
 
+    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
     // TODO(https://crbug.com/1226672): Use BeginScopedReadAccess instead
     scoped_access = backing_representation->BeginScopedWriteAccess(
-        /*final_msaa_count=*/0, skia::LegacyDisplayGlobals::GetSkSurfaceProps(),
-        &begin_semaphores, &end_semaphores,
+        /*final_msaa_count=*/0, surface_props, &begin_semaphores,
+        &end_semaphores,
         gpu::SharedImageRepresentation::AllowUnclearedAccess::kNo);
     surface = scoped_access->surface();
     if (!begin_semaphores.empty()) {
diff --git a/components/viz/service/transitions/transferable_resource_tracker.h b/components/viz/service/transitions/transferable_resource_tracker.h
index 72c8b87..8e6843d 100644
--- a/components/viz/service/transitions/transferable_resource_tracker.h
+++ b/components/viz/service/transitions/transferable_resource_tracker.h
@@ -118,7 +118,7 @@
 
     TransferableResource resource;
     ResourceReleaseCallback release_callback;
-    uint8_t ref_count = 0u;
+    int ref_count = 0;
   };
 
   std::map<ResourceId, TransferableResourceHolder> managed_resources_;
diff --git a/components/viz/service/transitions/transferable_resource_tracker_unittest.cc b/components/viz/service/transitions/transferable_resource_tracker_unittest.cc
index 30127ed0..92827c9f 100644
--- a/components/viz/service/transitions/transferable_resource_tracker_unittest.cc
+++ b/components/viz/service/transitions/transferable_resource_tracker_unittest.cc
@@ -94,14 +94,14 @@
 TEST_F(TransferableResourceTrackerTest, UnrefWithCount) {
   TransferableResourceTracker tracker(&shared_bitmap_manager_);
   auto frame = tracker.ImportResources(CreateFrameWithResult());
-  for (int i = 0; i < 100; ++i)
+  for (int i = 0; i < 1000; ++i)
     tracker.RefResource(frame.root.resource.id);
   ASSERT_FALSE(tracker.is_empty());
   tracker.UnrefResource(frame.root.resource.id, 1);
   EXPECT_FALSE(tracker.is_empty());
   tracker.UnrefResource(frame.root.resource.id, 1);
   EXPECT_FALSE(tracker.is_empty());
-  tracker.UnrefResource(frame.root.resource.id, 99);
+  tracker.UnrefResource(frame.root.resource.id, 999);
   EXPECT_TRUE(tracker.is_empty());
 }
 
diff --git a/components/webapps/browser/BUILD.gn b/components/webapps/browser/BUILD.gn
index e7f79e0..59b38761 100644
--- a/components/webapps/browser/BUILD.gn
+++ b/components/webapps/browser/BUILD.gn
@@ -62,6 +62,8 @@
       "android/add_to_homescreen_params.h",
       "android/app_banner_manager_android.cc",
       "android/app_banner_manager_android.h",
+      "android/bottomsheet/pwa_bottom_sheet_controller.cc",
+      "android/bottomsheet/pwa_bottom_sheet_controller.h",
       "android/features.cc",
       "android/features.h",
       "android/installable/installable_ambient_badge_client.h",
diff --git a/components/webapps/browser/android/BUILD.gn b/components/webapps/browser/android/BUILD.gn
index 883b45b..094d561 100644
--- a/components/webapps/browser/android/BUILD.gn
+++ b/components/webapps/browser/android/BUILD.gn
@@ -22,16 +22,25 @@
     "java/src/org/chromium/components/webapps/AppDetailsDelegate.java",
     "java/src/org/chromium/components/webapps/WebappsIconUtils.java",
     "java/src/org/chromium/components/webapps/WebappsUtils.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/AddToHomescreenBottomSheetViewBinder.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/ImageZoomView.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetController.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerFactory.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerProvider.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetContent.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetView.java",
     "java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java",
   ]
   deps = [
     ":java_resources",
     "//base:base_java",
+    "//components/browser_ui/bottomsheet/android:java",
     "//components/browser_ui/widget/android:java",
     "//components/infobars/android:java",
     "//components/webapk/android/libs/client:java",
     "//content/public/android:content_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//ui/android:ui_no_recycler_view_java",
     "//url:gurl_java",
   ]
@@ -47,6 +56,8 @@
     "java/src/org/chromium/components/webapps/AppBannerManager.java",
     "java/src/org/chromium/components/webapps/WebappsIconUtils.java",
     "java/src/org/chromium/components/webapps/WebappsUtils.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetController.java",
+    "java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerProvider.java",
     "java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java",
   ]
 }
@@ -79,6 +90,9 @@
     "java/res/drawable-xxxhdpi/star_green.png",
     "java/res/drawable/rating_bar.xml",
     "java/res/layout/add_to_homescreen_dialog.xml",
+    "java/res/layout/image_zoom_view.xml",
+    "java/res/layout/pwa_install_bottom_sheet_content.xml",
+    "java/res/layout/pwa_install_bottom_sheet_toolbar.xml",
     "java/res/mipmap-hdpi/shortcut_icon_shadow.png",
     "java/res/mipmap-mdpi/shortcut_icon_shadow.png",
     "java/res/mipmap-xhdpi/shortcut_icon_shadow.png",
diff --git a/components/webapps/browser/android/DEPS b/components/webapps/browser/android/DEPS
index 7e61c2f..0701f3b 100644
--- a/components/webapps/browser/android/DEPS
+++ b/components/webapps/browser/android/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/browser_ui/widget/android",
+  "+components/browser_ui/bottomsheet/android",
   "+components/dom_distiller",
   "+components/favicon/content",
   "+components/favicon/core",
diff --git a/components/webapps/browser/android/android_webapps_strings.grd b/components/webapps/browser/android/android_webapps_strings.grd
index 36b228b..de75346 100644
--- a/components/webapps/browser/android/android_webapps_strings.grd
+++ b/components/webapps/browser/android/android_webapps_strings.grd
@@ -187,6 +187,15 @@
       <message name="IDS_ADDED_TO_HOMESCREEN" desc="Text in a toast indicating that the website with the specified name was added to the user's Home screen.">
         <ph name="NAME">%1$s<ex>Google</ex></ph> was added to your Home screen
       </message>
+      <message name="IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY" desc="The content description for the bottom sheet install UI.">
+        Install this app
+      </message>
+      <message name="IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT" desc="The content description string for a screenshot in the bottom sheet install UI.">
+        Screenshot
+      </message>
+      <message name="IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION" desc="The content description string for the screenshot in the image zoom view.">
+        Screenshot. Tap to close.
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION.png.sha1 b/components/webapps/browser/android/android_webapps_strings_grd/IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION.png.sha1
similarity index 100%
rename from chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION.png.sha1
rename to components/webapps/browser/android/android_webapps_strings_grd/IDS_IMAGE_ZOOM_CONTENT_DESCRIPTION.png.sha1
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY.png.sha1 b/components/webapps/browser/android/android_webapps_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY.png.sha1
similarity index 100%
rename from chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY.png.sha1
rename to components/webapps/browser/android/android_webapps_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_ACCESSIBILITY.png.sha1
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT.png.sha1 b/components/webapps/browser/android/android_webapps_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT.png.sha1
similarity index 100%
rename from chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT.png.sha1
rename to components/webapps/browser/android/android_webapps_strings_grd/IDS_PWA_INSTALL_BOTTOM_SHEET_SCREENSHOT.png.sha1
diff --git a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc b/components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.cc
similarity index 95%
rename from chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc
rename to components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.cc
index f3da859..947bdf4b 100644
--- a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc
+++ b/components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/webapps/android/pwa_bottom_sheet_controller.h"
+#include "components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h"
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/webapps/android/jni_headers/PwaBottomSheetControllerProvider_jni.h"
-#include "chrome/browser/webapps/android/jni_headers/PwaBottomSheetController_jni.h"
 #include "components/url_formatter/elide_url.h"
 #include "components/webapps/browser/android/app_banner_manager_android.h"
+#include "components/webapps/browser/android/webapps_jni_headers/PwaBottomSheetControllerProvider_jni.h"
+#include "components/webapps/browser/android/webapps_jni_headers/PwaBottomSheetController_jni.h"
 #include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/android/java_bitmap.h"
diff --git a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h b/components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h
similarity index 94%
rename from chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
rename to components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h
index 58e14f7..01110ae 100644
--- a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
+++ b/components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
-#define CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_BOTTOMSHEET_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_BOTTOMSHEET_PWA_BOTTOM_SHEET_CONTROLLER_H_
 
 #include <memory>
 #include <vector>
@@ -115,4 +115,4 @@
 
 }  // namespace webapps
 
-#endif  // CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_BOTTOMSHEET_PWA_BOTTOM_SHEET_CONTROLLER_H_
diff --git a/chrome/browser/webapps/android/java/res/layout/image_zoom_view.xml b/components/webapps/browser/android/java/res/layout/image_zoom_view.xml
similarity index 100%
rename from chrome/browser/webapps/android/java/res/layout/image_zoom_view.xml
rename to components/webapps/browser/android/java/res/layout/image_zoom_view.xml
diff --git a/chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_content.xml b/components/webapps/browser/android/java/res/layout/pwa_install_bottom_sheet_content.xml
similarity index 100%
rename from chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_content.xml
rename to components/webapps/browser/android/java/res/layout/pwa_install_bottom_sheet_content.xml
diff --git a/chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml b/components/webapps/browser/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
similarity index 100%
rename from chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
rename to components/webapps/browser/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
diff --git a/components/webapps/browser/android/java/res/values/dimens.xml b/components/webapps/browser/android/java/res/values/dimens.xml
index 8887412e..d623509 100644
--- a/components/webapps/browser/android/java/res/values/dimens.xml
+++ b/components/webapps/browser/android/java/res/values/dimens.xml
@@ -21,4 +21,5 @@
 
     <dimen name="webapk_monochrome_icon_size">24dp</dimen>
     <dimen name="webapk_prompt_ui_icon_radius">16dp</dimen>
+    <dimen name="webapk_screenshot_margin">16dp</dimen>
 </resources>
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/AddToHomescreenBottomSheetViewBinder.java
similarity index 96%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/AddToHomescreenBottomSheetViewBinder.java
index 4de1beec..f5b869a 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/AddToHomescreenBottomSheetViewBinder.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.graphics.Bitmap;
 import android.util.Pair;
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/ImageZoomView.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/ImageZoomView.java
similarity index 89%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/ImageZoomView.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/ImageZoomView.java
index bfd6f4c5..88371acb 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/ImageZoomView.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/ImageZoomView.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.app.AlertDialog;
 import android.content.Context;
@@ -11,6 +11,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import org.chromium.components.webapps.R;
+
 /**
  * UI for the zoomed image view used for screenshots in the bottom-sheet UI for PWA installs.
  */
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetController.java
similarity index 98%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetController.java
index 55cb66c..0c3a3d5 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetController.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.app.Activity;
 import android.content.Context;
@@ -28,6 +28,7 @@
 import org.chromium.components.webapps.AddToHomescreenProperties;
 import org.chromium.components.webapps.AddToHomescreenViewDelegate;
 import org.chromium.components.webapps.InstallTrigger;
+import org.chromium.components.webapps.R;
 import org.chromium.components.webapps.WebappInstallSource;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.Visibility;
@@ -122,6 +123,7 @@
             mScreenshots = new ArrayList<Bitmap>();
         }
 
+        @SuppressWarnings("NotifyDataSetChanged")
         public void addScreenshot(Bitmap screenshot) {
             mScreenshots.add(screenshot);
             notifyDataSetChanged();
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerFactory.java
similarity index 93%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerFactory.java
index fd669d5..f0837d5d 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerFactory.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.app.Activity;
 
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerProvider.java
similarity index 98%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerProvider.java
index e8f3807..e51773aa 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaBottomSheetControllerProvider.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.graphics.Bitmap;
 
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetContent.java
similarity index 95%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetContent.java
index 539d6ff1..96ab9f1 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetContent.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.view.View;
 
@@ -11,6 +11,7 @@
 
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.webapps.AddToHomescreenViewDelegate;
+import org.chromium.components.webapps.R;
 
 /**
  * The class handling the bottom sheet install for PWA installs. The UI is shown on construction
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetView.java
similarity index 97%
rename from chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetView.java
index e4d90fe..b9c68fd6 100644
--- a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/bottomsheet/PwaInstallBottomSheetView.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.webapps;
+package org.chromium.components.webapps.bottomsheet;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -14,6 +14,7 @@
 
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.components.webapps.R;
 import org.chromium.components.webapps.WebappsIconUtils;
 
 /**
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index c60528e..34fbe09 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1697,10 +1697,17 @@
 }
 
 // internal
-- (NSRect)rectInScreen:(gfx::Rect)rect {
+- (NSRect)rectInScreen:(gfx::Rect)layout_rect {
   if (![self instanceActive])
     return NSZeroRect;
 
+  // Convert to DIPs if UseZoomForDSF is enabled.
+  auto rect =
+      IsUseZoomForDSFEnabled()
+          ? ScaleToRoundedRect(layout_rect,
+                               1.f / _owner->manager()->device_scale_factor())
+          : layout_rect;
+
   // Get the delegate for the topmost BrowserAccessibilityManager, because
   // that's the only one that can convert points to their origin in the screen.
   BrowserAccessibilityDelegate* delegate =
diff --git a/content/browser/attribution_reporting/attribution_host_utils_unittest.cc b/content/browser/attribution_reporting/attribution_host_utils_unittest.cc
index 899bb0c..58df1b3 100644
--- a/content/browser/attribution_reporting/attribution_host_utils_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_host_utils_unittest.cc
@@ -15,8 +15,6 @@
 
 namespace {
 
-class AttributionHostUtilsTest : public ::testing::Test {};
-
 TEST(AttributionHostUtilsTest, AppImpression_Valid) {
   absl::optional<blink::Impression> impression =
       ParseImpressionFromApp("9223372036854775807", "https://example.com",
diff --git a/content/browser/attribution_reporting/attribution_policy_unittest.cc b/content/browser/attribution_reporting/attribution_policy_unittest.cc
index 131a15b..646fca5 100644
--- a/content/browser/attribution_reporting/attribution_policy_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_policy_unittest.cc
@@ -34,14 +34,9 @@
   bool should_noise_;
 };
 
-class AttributionPolicyTest : public testing::Test {
- public:
-  AttributionPolicyTest() = default;
-};
-
 }  // namespace
 
-TEST_F(AttributionPolicyTest, HighEntropyTriggerData_StrippedToLowerBits) {
+TEST(AttributionPolicyTest, HighEntropyTriggerData_StrippedToLowerBits) {
   std::unique_ptr<AttributionPolicy> policy =
       std::make_unique<ConfigurableAttributionPolicy>(/*should_noise=*/false);
 
@@ -56,7 +51,7 @@
             policy->SanitizeTriggerData(3, StorableSource::SourceType::kEvent));
 }
 
-TEST_F(AttributionPolicyTest, SanitizeHighEntropySourceEventId_Unchanged) {
+TEST(AttributionPolicyTest, SanitizeHighEntropySourceEventId_Unchanged) {
   uint64_t source_event_id = 256LU;
 
   // The policy should not alter the impression data, and return the base 10
@@ -64,7 +59,7 @@
   EXPECT_EQ(256LU, AttributionPolicy().SanitizeSourceEventId(source_event_id));
 }
 
-TEST_F(AttributionPolicyTest, LowEntropyTriggerData_Unchanged) {
+TEST(AttributionPolicyTest, LowEntropyTriggerData_Unchanged) {
   std::unique_ptr<AttributionPolicy> policy =
       std::make_unique<ConfigurableAttributionPolicy>(/*should_noise=*/false);
 
@@ -80,7 +75,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, SanitizeTriggerData_OutputHasNoise) {
+TEST(AttributionPolicyTest, SanitizeTriggerData_OutputHasNoise) {
   // The policy should include noise when sanitizing data.
   for (auto source_type : kSourceTypes) {
     EXPECT_EQ(1LU, ConfigurableAttributionPolicy(/*should_noise=*/true)
@@ -89,7 +84,7 @@
 }
 
 // This test will fail flakily if noise is used.
-TEST_F(AttributionPolicyTest, DebugMode_TriggerDataNotNoised) {
+TEST(AttributionPolicyTest, DebugMode_TriggerDataNotNoised) {
   const uint64_t trigger_data = 0UL;
   for (auto source_type : kSourceTypes) {
     for (int i = 0; i < 100; i++) {
@@ -100,7 +95,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, NoExpiryForImpression_DefaultUsed) {
+TEST(AttributionPolicyTest, NoExpiryForImpression_DefaultUsed) {
   const base::Time impression_time = base::Time::Now();
 
   for (auto source_type : kSourceTypes) {
@@ -111,7 +106,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, LargeImpressionExpirySpecified_ClampedTo30Days) {
+TEST(AttributionPolicyTest, LargeImpressionExpirySpecified_ClampedTo30Days) {
   constexpr base::TimeDelta declared_expiry = base::Days(60);
   const base::Time impression_time = base::Time::Now();
 
@@ -122,7 +117,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, SmallImpressionExpirySpecified_ClampedTo1Day) {
+TEST(AttributionPolicyTest, SmallImpressionExpirySpecified_ClampedTo1Day) {
   const struct {
     base::TimeDelta declared_expiry;
     base::TimeDelta want_expiry;
@@ -143,7 +138,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, NonWholeDayImpressionExpirySpecified_Rounded) {
+TEST(AttributionPolicyTest, NonWholeDayImpressionExpirySpecified_Rounded) {
   const struct {
     StorableSource::SourceType source_type;
     base::TimeDelta declared_expiry;
@@ -170,7 +165,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, ImpressionExpirySpecified_ExpiryOverrideDefault) {
+TEST(AttributionPolicyTest, ImpressionExpirySpecified_ExpiryOverrideDefault) {
   constexpr base::TimeDelta declared_expiry = base::Days(10);
   const base::Time impression_time = base::Time::Now();
 
@@ -181,7 +176,7 @@
   }
 }
 
-TEST_F(AttributionPolicyTest, GetFailedReportDelay) {
+TEST(AttributionPolicyTest, GetFailedReportDelay) {
   const struct {
     int failed_send_attempts;
     absl::optional<base::TimeDelta> expected;
diff --git a/content/browser/attribution_reporting/attribution_storage_delegate_impl_unittest.cc b/content/browser/attribution_reporting/attribution_storage_delegate_impl_unittest.cc
index ba0255ce..a43e675b 100644
--- a/content/browser/attribution_reporting/attribution_storage_delegate_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_storage_delegate_impl_unittest.cc
@@ -32,13 +32,7 @@
 
 }  // namespace
 
-class AttributionStorageDelegateImplTest : public testing::Test {
- public:
-  AttributionStorageDelegateImplTest() = default;
-};
-
-TEST_F(AttributionStorageDelegateImplTest,
-       ImmediateConversion_FirstWindowUsed) {
+TEST(AttributionStorageDelegateImplTest, ImmediateConversion_FirstWindowUsed) {
   base::Time impression_time = base::Time::Now();
   const AttributionReport report =
       GetReport(impression_time, /*conversion_time=*/impression_time);
@@ -47,8 +41,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       ConversionImmediatelyBeforeWindow_NextWindowUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     ConversionImmediatelyBeforeWindow_NextWindowUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time =
       impression_time + base::Days(2) - base::Minutes(1);
@@ -58,8 +52,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       ConversionBeforeWindowDelay_WindowUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     ConversionBeforeWindowDelay_WindowUsed) {
   base::Time impression_time = base::Time::Now();
 
   // The deadline for a window is 1 hour before the window. Use a time just
@@ -72,8 +66,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       ImpressionExpiryBeforeTwoDayWindow_TwoDayWindowUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     ImpressionExpiryBeforeTwoDayWindow_TwoDayWindowUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time = impression_time + base::Hours(1);
 
@@ -85,8 +79,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       ImpressionExpiryBeforeSevenDayWindow_ExpiryWindowUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     ImpressionExpiryBeforeSevenDayWindow_ExpiryWindowUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time = impression_time + base::Days(3);
 
@@ -100,8 +94,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       ImpressionExpiryAfterSevenDayWindow_ExpiryWindowUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     ImpressionExpiryAfterSevenDayWindow_ExpiryWindowUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time = impression_time + base::Days(7);
 
@@ -115,8 +109,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       SourceTypeEvent_ExpiryLessThanTwoDays_TwoDaysUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     SourceTypeEvent_ExpiryLessThanTwoDays_TwoDaysUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time = impression_time + base::Days(3);
   const AttributionReport report =
@@ -127,8 +121,8 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest,
-       SourceTypeEvent_ExpiryGreaterThanTwoDays_ExpiryUsed) {
+TEST(AttributionStorageDelegateImplTest,
+     SourceTypeEvent_ExpiryGreaterThanTwoDays_ExpiryUsed) {
   base::Time impression_time = base::Time::Now();
   base::Time conversion_time = impression_time + base::Days(3);
   const AttributionReport report =
@@ -139,7 +133,7 @@
                 report.impression, report.conversion_time));
 }
 
-TEST_F(AttributionStorageDelegateImplTest, NewReportID_IsValidGUID) {
+TEST(AttributionStorageDelegateImplTest, NewReportID_IsValidGUID) {
   EXPECT_TRUE(AttributionStorageDelegateImpl().NewReportID().is_valid());
 }
 
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index ed8e5e6..dbd96452 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -1337,7 +1337,7 @@
           should_treat_as_first_party));
 
   cookie_manager_->GetCookieList(request.url, options,
-                                 net::CookiePartitionKeychain::Todo(),
+                                 net::CookiePartitionKeyCollection::Todo(),
                                  std::move(callback));
 }
 
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 145fe854..aaa61e2 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -224,7 +224,7 @@
     for (const auto& url : urls) {
       cookie_manager->GetCookieList(
           url, cookie_options,
-          net::CookiePartitionKeychain::FromOptional(
+          net::CookiePartitionKeyCollection::FromOptional(
               net::CookiePartitionKey::FromNetworkIsolationKey(
                   network_isolation_key)),
           base::BindOnce(&CookieRetrieverNetworkService::GotCookies, self));
diff --git a/content/browser/hid/hid_browsertest.cc b/content/browser/hid/hid_browsertest.cc
index 7a1c4e5..04de1757 100644
--- a/content/browser/hid/hid_browsertest.cc
+++ b/content/browser/hid/hid_browsertest.cc
@@ -18,6 +18,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/fenced_frame_test_util.h"
 #include "content/shell/browser/shell.h"
 #include "services/device/public/cpp/hid/fake_hid_manager.h"
 #include "services/device/public/mojom/hid.mojom.h"
@@ -182,4 +183,66 @@
              })())"));
 }
 
+class HidFencedFramesBrowserTest : public HidTest {
+ public:
+  HidFencedFramesBrowserTest() = default;
+  HidFencedFramesBrowserTest(const HidFencedFramesBrowserTest&) = delete;
+  HidFencedFramesBrowserTest& operator=(const HidFencedFramesBrowserTest&) =
+      delete;
+  ~HidFencedFramesBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    HidTest::SetUpOnMainThread();
+
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
+    return fenced_frame_helper_;
+  }
+
+  WebContents* GetWebContents() { return shell()->web_contents(); }
+
+ private:
+  content::test::FencedFrameTestHelper fenced_frame_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(HidFencedFramesBrowserTest, BlockFromFencedFrame) {
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("/simple_page.html")));
+
+  // Three devices are added but only two will have permission granted.
+  for (int i = 0; i < 3; i++) {
+    auto device = CreateTestDeviceWithInputAndOutputReports();
+    device->guid = base::StringPrintf("test-guid-%02d", i);
+    hid_manager()->AddDevice(std::move(device));
+  }
+
+  EXPECT_CALL(delegate(), HasDevicePermission)
+      .WillOnce(Return(true))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+
+  EXPECT_EQ(
+      2,
+      EvalJs(shell(),
+             R"(navigator.hid.getDevices().then(devices => devices.length))"));
+
+  // Loads a fenced frame
+  const GURL kFencedFrameUrl =
+      embedded_test_server()->GetURL("/fenced_frames/empty.html");
+  content::RenderFrameHost* render_frame_host =
+      fenced_frame_test_helper().CreateFencedFrame(
+          GetWebContents()->GetMainFrame(), kFencedFrameUrl);
+  ASSERT_NE(nullptr, render_frame_host);
+
+  // Tries to request a device from the fenced frame, which must cause an error.
+  constexpr char kFencedFrameError[] =
+      "Access to the feature \"hid\" is disallowed by permissions policy.";
+  auto result = content::EvalJs(
+      render_frame_host,
+      R"(navigator.hid.getDevices().then(devices => devices.length))");
+  EXPECT_THAT(result.error, ::testing::HasSubstr(kFencedFrameError));
+}
+
 }  // namespace content
diff --git a/content/browser/hid/hid_service.cc b/content/browser/hid/hid_service.cc
index 36328e6..93c9a478 100644
--- a/content/browser/hid/hid_service.cc
+++ b/content/browser/hid/hid_service.cc
@@ -115,6 +115,14 @@
   if (!GetContentClient()->browser()->GetHidDelegate())
     return;
 
+  if (render_frame_host->IsNestedWithinFencedFrame()) {
+    // The renderer is supposed to disallow the use of hid services when inside
+    // a fenced frame. Anything getting past the renderer checks must be marked
+    // as a bad request.
+    mojo::ReportBadMessage("WebHID is not allowed in a fenced frame tree.");
+    return;
+  }
+
   // HidService owns itself. It will self-destruct when a mojo interface error
   // occurs, the render frame host is deleted, or the render frame host
   // navigates to a new document.
diff --git a/content/browser/renderer_host/cookie_browsertest.cc b/content/browser/renderer_host/cookie_browsertest.cc
index 3e06d86a..789e131a 100644
--- a/content/browser/renderer_host/cookie_browsertest.cc
+++ b/content/browser/renderer_host/cookie_browsertest.cc
@@ -89,7 +89,7 @@
       ->GetDefaultStoragePartition()
       ->GetCookieManagerForBrowserProcess()
       ->GetCookieList(
-          url, options, net::CookiePartitionKeychain(),
+          url, options, net::CookiePartitionKeyCollection(),
           base::BindLambdaForTesting(
               [&](const net::CookieAccessResultList& cookie_list,
                   const net::CookieAccessResultList& excluded_cookies) {
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 5eca688..a54ba98 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -167,7 +167,7 @@
     get_cookie_success_ = false;
     storage_partition_->GetCookieManagerForBrowserProcess()->GetCookieList(
         origin.GetURL(), net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain(),
+        net::CookiePartitionKeyCollection(),
         base::BindOnce(&RemoveCookieTester::GetCookieListCallback,
                        base::Unretained(this)));
     await_completion_.BlockUntilNotified();
diff --git a/content/common/partition_alloc_support.cc b/content/common/partition_alloc_support.cc
index 608a862..81da7fc0 100644
--- a/content/common/partition_alloc_support.cc
+++ b/content/common/partition_alloc_support.cc
@@ -19,6 +19,7 @@
 #include "base/callback.h"
 #include "base/feature_list.h"
 #include "base/location.h"
+#include "base/memory/nonscannable_memory.h"
 #include "base/no_destructor.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -58,6 +59,25 @@
   }
 }
 
+bool IsPCScanEnabled(const std::string& process_type) {
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN)
+  DCHECK(base::FeatureList::GetInstance());
+  bool enabled =
+      base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan);
+  // No specified process type means this is the Browser process.
+  if (process_type.empty()) {
+    enabled = enabled || base::FeatureList::IsEnabled(
+                             base::features::kPartitionAllocPCScanBrowserOnly);
+  } else if (process_type == switches::kRendererProcess) {
+    enabled = enabled || base::FeatureList::IsEnabled(
+                             base::features::kPartitionAllocPCScanRendererOnly);
+  }
+  return enabled;
+#else  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN)
+  return false;
+#endif
+}
+
 bool EnablePCScanForMallocPartitionsIfNeeded() {
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN)
   using Config = base::internal::PCScan::InitConfig;
@@ -224,15 +244,22 @@
   if (base::FeatureList::IsEnabled(
           base::features::kPartitionAllocBackupRefPtr)) {
     // No specified process type means this is the Browser process.
-    process_affected_by_brp_flag = process_type.empty();
-    if (base::features::kBackupRefPtrEnabledProcessesParam.Get() ==
-        base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer) {
-      process_affected_by_brp_flag |=
-          process_type == switches::kRendererProcess;
-    }
-    if (base::features::kBackupRefPtrEnabledProcessesParam.Get() ==
-        base::features::BackupRefPtrEnabledProcesses::kAllProcesses) {
-      process_affected_by_brp_flag = true;
+    switch (base::features::kBackupRefPtrEnabledProcessesParam.Get()) {
+      case base::features::BackupRefPtrEnabledProcesses::kBrowserOnly:
+        process_affected_by_brp_flag = process_type.empty();
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer:
+        process_affected_by_brp_flag =
+            process_type.empty() ||
+            (process_type == switches::kRendererProcess);
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kNonRenderer:
+        process_affected_by_brp_flag =
+            (process_type != switches::kRendererProcess);
+        break;
+      case base::features::BackupRefPtrEnabledProcesses::kAllProcesses:
+        process_affected_by_brp_flag = true;
+        break;
     }
   }
 
@@ -269,9 +296,25 @@
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
   // If BRP is not enabled, check if any of PCScan flags is enabled.
-  bool scan_enabled = false;
-  if (!enable_brp) {
-    scan_enabled = EnablePCScanForMallocPartitionsIfNeeded();
+  bool enable_scan = !enable_brp && IsPCScanEnabled(process_type);
+
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+  const bool enable_thread_cache_on_v8_partition =
+      enable_scan && process_type == switches::kRendererProcess;
+  base::allocator::ConfigurePartitions(
+      base::allocator::EnableBrp(enable_brp),
+      base::allocator::SplitMainPartition(split_main_partition),
+      base::allocator::UseDedicatedAlignedPartition(
+          use_dedicated_aligned_partition),
+      base::allocator::ThreadCacheOnNonQuarantinablePartition(
+          enable_thread_cache_on_v8_partition));
+#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+
+  if (enable_scan) {
+    // Even though we already know the PCScan should be enabled, we go through
+    // the logic of querying Finch (in the callees) again, to determine, which
+    // function should be called to enable PCScan.
+    bool scan_enabled = EnablePCScanForMallocPartitionsIfNeeded();
     // No specified process type means this is the Browser process.
     if (process_type.empty()) {
       scan_enabled = scan_enabled ||
@@ -281,40 +324,35 @@
       scan_enabled = scan_enabled ||
                      EnablePCScanForMallocPartitionsInRendererProcessIfNeeded();
     }
-    if (scan_enabled) {
-      if (base::FeatureList::IsEnabled(
-              base::features::kPartitionAllocPCScanStackScanning)) {
+    DCHECK(scan_enabled);
+    if (base::FeatureList::IsEnabled(
+            base::features::kPartitionAllocPCScanStackScanning)) {
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-        base::internal::PCScan::EnableStackScanning();
-        // Notify PCScan about the main thread.
-        base::internal::PCScan::NotifyThreadCreated(
-            base::internal::GetStackTop());
+      base::internal::PCScan::EnableStackScanning();
+      // Notify PCScan about the main thread.
+      base::internal::PCScan::NotifyThreadCreated(
+          base::internal::GetStackTop());
 #endif
-      }
-      if (base::FeatureList::IsEnabled(
-              base::features::kPartitionAllocPCScanImmediateFreeing)) {
-        base::internal::PCScan::EnableImmediateFreeing();
-      }
-      if (base::FeatureList::IsEnabled(
-              base::features::kPartitionAllocPCScanEagerClearing)) {
-        base::internal::PCScan::SetClearType(
-            base::internal::PCScan::ClearType::kEager);
-      }
-      SetProcessNameForPCScan(process_type);
     }
-  }
+    if (base::FeatureList::IsEnabled(
+            base::features::kPartitionAllocPCScanImmediateFreeing)) {
+      base::internal::PCScan::EnableImmediateFreeing();
+    }
+    if (base::FeatureList::IsEnabled(
+            base::features::kPartitionAllocPCScanEagerClearing)) {
+      base::internal::PCScan::SetClearType(
+          base::internal::PCScan::ClearType::kEager);
+    }
+    SetProcessNameForPCScan(process_type);
 
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  const bool enable_thread_cache_on_v8_partition =
-      scan_enabled && process_type == switches::kRendererProcess;
-  base::allocator::ConfigurePartitions(
-      base::allocator::EnableBrp(enable_brp),
-      base::allocator::SplitMainPartition(split_main_partition),
-      base::allocator::UseDedicatedAlignedPartition(
-          use_dedicated_aligned_partition),
-      base::allocator::ThreadCacheOnNonQuarantinablePartition(
-          enable_thread_cache_on_v8_partition));
-#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+    if (enable_thread_cache_on_v8_partition) {
+      base::internal::NonQuarantinableAllocator::Instance()
+          .root()
+          ->EnableThreadCacheIfSupported();
+    }
+#endif
+  }
 }
 
 void PartitionAllocSupport::ReconfigureAfterTaskRunnerInit(
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index b7268b7..f205fd77 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1993,7 +1993,7 @@
   net::CookieOptions options;
   options.set_same_site_cookie_context(context);
   cookie_manager->GetCookieList(
-      url, options, net::CookiePartitionKeychain(),
+      url, options, net::CookiePartitionKeyCollection(),
       base::BindOnce(
           [](std::string* cookies_out, base::RunLoop* run_loop,
              const net::CookieAccessResultList& cookies,
@@ -2020,7 +2020,7 @@
   options.set_same_site_cookie_context(
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
   cookie_manager->GetCookieList(
-      url, options, net::CookiePartitionKeychain(),
+      url, options, net::CookiePartitionKeyCollection(),
       base::BindOnce(
           [](base::RunLoop* run_loop,
              std::vector<net::CanonicalCookie>* cookies_out,
diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc
index bab0bb2..8b265d1 100644
--- a/content/renderer/service_worker/navigation_preload_request.cc
+++ b/content/renderer/service_worker/navigation_preload_request.cc
@@ -6,17 +6,17 @@
 
 #include <utility>
 
-#include "content/renderer/service_worker/service_worker_context_client.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/public/mojom/early_hints.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
 
 namespace content {
 
 NavigationPreloadRequest::NavigationPreloadRequest(
-    ServiceWorkerContextClient* owner,
+    blink::WebServiceWorkerContextClient* owner,
     int fetch_event_id,
     const blink::WebURL& url,
     mojo::PendingReceiver<network::mojom::URLLoaderClient>
diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h
index 36a25a1..4875ff4 100644
--- a/content/renderer/service_worker/navigation_preload_request.h
+++ b/content/renderer/service_worker/navigation_preload_request.h
@@ -18,20 +18,22 @@
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 
+namespace blink {
+class WebServiceWorkerContextClient;
+}  // namespace blink
+
 namespace content {
 
-class ServiceWorkerContextClient;
-
 // The URLLoaderClient for receiving a navigation preload response. It reports
-// the response back to ServiceWorkerContextClient.
+// the response back to blink::WebServiceWorkerContextClient.
 //
 // This class lives on the service worker thread and is owned by
-// ServiceWorkerContextClient.
+// blink::WebServiceWorkerContextClient.
 class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
  public:
   // |owner| must outlive |this|.
   NavigationPreloadRequest(
-      ServiceWorkerContextClient* owner,
+      blink::WebServiceWorkerContextClient* owner,
       int fetch_event_id,
       const blink::WebURL& url,
       mojo::PendingReceiver<network::mojom::URLLoaderClient>
@@ -59,7 +61,7 @@
   void ReportErrorToOwner(const blink::WebString& message,
                           blink::WebServiceWorkerError::Mode error_mode);
 
-  ServiceWorkerContextClient* owner_ = nullptr;
+  blink::WebServiceWorkerContextClient* owner_ = nullptr;
 
   const int fetch_event_id_ = -1;
   const blink::WebURL url_;
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index dc943b1..66df79e 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -168,31 +168,18 @@
   void RequestTermination(RequestTerminationCallback callback) override;
   scoped_refptr<blink::WebServiceWorkerFetchContext>
   CreateWorkerFetchContextOnInitiatorThread() override;
-
-  /////////////////////////////////////////////////////////////////////////////
-  // The following are for use by NavigationPreloadRequest.
-  //
-  // Called to resolve the FetchEvent.preloadResponse promise.
   void OnNavigationPreloadResponse(
       int fetch_event_id,
       std::unique_ptr<blink::WebURLResponse> response,
-      mojo::ScopedDataPipeConsumerHandle data_pipe);
-
-  // Called when the navigation preload request completed. Either
-  // OnNavigationPreloadComplete() or OnNavigationPreloadError() must be
-  // called to release the preload related resources.
+      mojo::ScopedDataPipeConsumerHandle data_pipe) override;
   void OnNavigationPreloadComplete(int fetch_event_id,
                                    base::TimeTicks completion_time,
                                    int64_t encoded_data_length,
                                    int64_t encoded_body_length,
-                                   int64_t decoded_body_length);
-
-  // Called when an error occurred while receiving the response of the
-  // navigation preload request.
+                                   int64_t decoded_body_length) override;
   void OnNavigationPreloadError(
       int fetch_event_id,
-      std::unique_ptr<blink::WebServiceWorkerError> error);
-  /////////////////////////////////////////////////////////////////////////////
+      std::unique_ptr<blink::WebServiceWorkerError> error) override;
 
  private:
   struct WorkerContextData;
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index 76a8497b..4e2b7f2b 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -230,7 +230,10 @@
   void PostV8Callback(v8::Local<v8::Function> v8_callback,
                       std::vector<v8::Local<v8::Value>> args = {});
 
-  blink::WebLocalFrame* GetWebFrame() { return frame_->GetWebFrame(); }
+  blink::WebLocalFrame* GetWebFrame() {
+    CHECK(!invalid_);
+    return frame_->GetWebFrame();
+  }
 
  private:
   // Watches for the RenderFrame that the TestRunnerBindings is attached to
@@ -870,6 +873,8 @@
 void TestRunnerBindings::PostV8Callback(
     v8::Local<v8::Function> v8_callback,
     std::vector<v8::Local<v8::Value>> args) {
+  if (invalid_)
+    return;
   const auto& task_runner =
       GetWebFrame()->GetTaskRunner(blink::TaskType::kInternalTest);
   task_runner->PostTask(FROM_HERE,
@@ -880,6 +885,8 @@
     v8::UniquePersistent<v8::Function> callback,
     std::vector<v8::UniquePersistent<v8::Value>> bound_args,
     const std::vector<v8::Local<v8::Value>>& runtime_args) {
+  if (invalid_)
+    return;
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
 
@@ -1952,6 +1959,8 @@
 void TestRunnerBindings::CopyImageThen(int x,
                                        int y,
                                        v8::Local<v8::Function> v8_callback) {
+  if (invalid_)
+    return;
   mojo::Remote<blink::mojom::ClipboardHost> remote_clipboard;
   frame_->GetBrowserInterfaceBroker()->GetInterface(
       remote_clipboard.BindNewPipeAndPassReceiver());
diff --git a/fuchsia/engine/browser/cookie_manager_impl.cc b/fuchsia/engine/browser/cookie_manager_impl.cc
index 8c04f58d..cd05291 100644
--- a/fuchsia/engine/browser/cookie_manager_impl.cc
+++ b/fuchsia/engine/browser/cookie_manager_impl.cc
@@ -217,7 +217,7 @@
           net::CookieOptions::SameSiteCookieContext::MakeInclusive());
 
       cookie_manager_->GetCookieList(
-          GURL(*url), options, net::CookiePartitionKeychain::Todo(),
+          GURL(*url), options, net::CookiePartitionKeyCollection::Todo(),
           base::BindOnce(&OnCookiesAndExcludedReceived, std::move(iterator)));
     } else {
       // TODO(858853): Support filtering by name.
diff --git a/fuchsia/runners/BUILD.gn b/fuchsia/runners/BUILD.gn
index a7be37d..69fd167 100644
--- a/fuchsia/runners/BUILD.gn
+++ b/fuchsia/runners/BUILD.gn
@@ -82,6 +82,7 @@
     "//components/cast/common:constants",
     "//components/cast/message_port",
     "//components/cast/named_message_port_connector:named_message_port_connector",
+    "//components/cast_streaming/public",
     "//fuchsia/base",
     "//fuchsia/base:modular",
     "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.diagnostics",
diff --git a/fuchsia/runners/cast/DEPS b/fuchsia/runners/cast/DEPS
index 993c074..17aae4dc 100644
--- a/fuchsia/runners/cast/DEPS
+++ b/fuchsia/runners/cast/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/cast",
+  "+components/cast_streaming/public",
   "+content/public/test",
   "+fuchsia/fidl/chromium/cast/cpp/fidl.h",
   "+net",
diff --git a/fuchsia/runners/cast/cast_component.cc b/fuchsia/runners/cast/cast_component.cc
index 7e10b890..1cea7825 100644
--- a/fuchsia/runners/cast/cast_component.cc
+++ b/fuchsia/runners/cast/cast_component.cc
@@ -18,11 +18,12 @@
 #include "base/task/current_thread.h"
 #include "components/cast/message_port/fuchsia/message_port_fuchsia.h"
 #include "components/cast/message_port/platform_message_port.h"
+#include "components/cast_streaming/public/constants.h"
 #include "fuchsia/base/agent_manager.h"
-#include "fuchsia/runners/cast/fidl/fidl/chromium/cast/cpp/fidl.h"
 #include "fuchsia/runners/cast/cast_runner.h"
 #include "fuchsia/runners/cast/cast_streaming.h"
 #include "fuchsia/runners/cast/create_web_message.h"
+#include "fuchsia/runners/cast/fidl/fidl/chromium/cast/cpp/fidl.h"
 #include "fuchsia/runners/common/web_component.h"
 
 namespace {
@@ -172,8 +173,9 @@
                              fuchsia::sys::TerminationReason::INTERNAL_ERROR);
           }
         });
-    api_bindings_client_->OnPortConnected(kCastStreamingMessagePortName,
-                                          std::move(message_port_for_agent));
+    api_bindings_client_->OnPortConnected(
+        cast_streaming::kCastTransportBindingName,
+        std::move(message_port_for_agent));
   }
 
   api_bindings_client_->AttachToFrame(
diff --git a/fuchsia/runners/cast/cast_streaming.cc b/fuchsia/runners/cast/cast_streaming.cc
index a6e6630..708282f 100644
--- a/fuchsia/runners/cast/cast_streaming.cc
+++ b/fuchsia/runners/cast/cast_streaming.cc
@@ -42,8 +42,6 @@
 const char kCastStreamingWebUrl[] =
     "fuchsia-dir://cast-streaming/receiver.html";
 
-const char kCastStreamingMessagePortName[] = "cast.__platform__.cast_transport";
-
 bool IsAppConfigForCastStreaming(
     const chromium::cast::ApplicationConfig& application_config) {
   return application_config.web_url() == kCastStreamingAppUrl;
diff --git a/fuchsia/runners/cast/cast_streaming.h b/fuchsia/runners/cast/cast_streaming.h
index d55dbc9f..3055ccd 100644
--- a/fuchsia/runners/cast/cast_streaming.h
+++ b/fuchsia/runners/cast/cast_streaming.h
@@ -17,9 +17,6 @@
 // URL for the Cast Streaming application.
 extern const char kCastStreamingWebUrl[];
 
-// Name of the Cast Streaming MessagePort.
-extern const char kCastStreamingMessagePortName[];
-
 // Returns true if |application_config| is a cast streaming application.
 bool IsAppConfigForCastStreaming(
     const chromium::cast::ApplicationConfig& application_config);
diff --git a/headless/test/headless_devtools_client_browsertest.cc b/headless/test/headless_devtools_client_browsertest.cc
index be6e4d7..fd1f881 100644
--- a/headless/test/headless_devtools_client_browsertest.cc
+++ b/headless/test/headless_devtools_client_browsertest.cc
@@ -856,8 +856,7 @@
           base::ListValue inline_text_nodes;
           for (const std::unique_ptr<dom_snapshot::InlineTextBox>&
                    inline_text_box : *layout_node->GetInlineTextNodes()) {
-            size_t index = inline_text_nodes.GetList().size();
-            inline_text_nodes.Set(index, inline_text_box->Serialize());
+            inline_text_nodes.Append(inline_text_box->Serialize());
           }
           node_dict->SetKey("inlineTextNodes", std::move(inline_text_nodes));
         }
diff --git a/infra/config/generated/builders/ci/GPU Linux Builder/properties.textpb b/infra/config/generated/builders/ci/GPU Linux Builder/properties.textpb
index 94f3cb4..5cdd4ae1 100644
--- a/infra/config/generated/builders/ci/GPU Linux Builder/properties.textpb
+++ b/infra/config/generated/builders/ci/GPU Linux Builder/properties.textpb
@@ -1,9 +1,8 @@
 {
-  "$build/goma": {
-    "enable_ats": true,
-    "rpc_extra_params": "?prod",
-    "server_host": "goma.chromium.org",
-    "use_luci_auth": true
+  "$build/reclient": {
+    "instance": "rbe-chromium-trusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
diff --git a/infra/config/generated/builders/ci/Linux Builder/properties.textpb b/infra/config/generated/builders/ci/Linux Builder/properties.textpb
index 21fcce96..e859202 100644
--- a/infra/config/generated/builders/ci/Linux Builder/properties.textpb
+++ b/infra/config/generated/builders/ci/Linux Builder/properties.textpb
@@ -1,10 +1,8 @@
 {
-  "$build/goma": {
-    "enable_ats": true,
+  "$build/reclient": {
+    "instance": "rbe-chromium-trusted",
     "jobs": 500,
-    "rpc_extra_params": "?prod",
-    "server_host": "goma.chromium.org",
-    "use_luci_auth": true
+    "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 2c1c7b8c..0cc2ec09 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -17947,7 +17947,7 @@
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "luci.recipes.use_python3"
-        value: 20
+        value: 100
       }
       experiments {
         key: "luci.use_realms"
@@ -18620,7 +18620,7 @@
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "luci.recipes.use_python3"
-        value: 20
+        value: 100
       }
       experiments {
         key: "luci.use_realms"
@@ -19552,7 +19552,7 @@
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "luci.recipes.use_python3"
-        value: 20
+        value: 100
       }
       experiments {
         key: "luci.use_realms"
diff --git a/infra/config/recipes.star b/infra/config/recipes.star
index 0f39127fb..f83877d 100644
--- a/infra/config/recipes.star
+++ b/infra/config/recipes.star
@@ -160,9 +160,7 @@
 
 build_recipe(
     name = "recipe:chromium_clang_coverage_tot",
-    experiments = {
-        "luci.recipes.use_python3": 20,
-    },
+    use_python3 = True,
 )
 
 build_recipe(
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index d231fa67..15f0d7c 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -4774,6 +4774,9 @@
     ),
     cq_mirrors_console_view = "mirrors",
     main_console_view = main_console_if_on_branch(),
+    goma_backend = None,
+    reclient_instance = rbe_instance.DEFAULT,
+    reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
 )
 
 ci.gpu_linux_builder(
@@ -5641,6 +5644,9 @@
     ),
     cq_mirrors_console_view = "mirrors",
     main_console_view = "main",
+    goma_backend = None,
+    reclient_instance = rbe_instance.DEFAULT,
+    reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
 )
 
 ci.linux_builder(
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 41a1093..a334e35 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1565,6 +1565,9 @@
       <message name="IDS_IOS_PAGE_LOADED_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement when a page has loaded. [Length: unlimited] [iOS only]">
         Webpage loaded
       </message>
+      <message name="IDS_IOS_PASSWORD_LEAK_CHANGE_CREDENTIALS" desc="The text of the OK button in the dialog for credentials leaked on the current site.">
+        Got It
+      </message>
       <message name="IDS_IOS_PASSWORD_MANAGER_BLOCK_BUTTON" desc="Button text for the 'Save Password' infobar's 'Never remember for this site' option [Length: 10em]">
         Never
       </message>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_id.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_id.xtb
index 92ed88a3..192ace17 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_id.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_id.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578">Pilih <ph name="BEGIN_BOLD" />Chromium<ph name="END_BOLD" /></translation>
 <translation id="2567507405773541360">Tingkatkan produktivitas dengan Chromium yang lebih praktis, aman, dan cepat</translation>
 <translation id="2590893390871230428">Sinkronkan Data Chromium Anda</translation>
+<translation id="259094968798709429">Sandi disimpan ke <ph name="BEGIN_LINK" />Pengelola Sandi<ph name="END_LINK" /> agar Anda dapat menggunakannya di perangkat mana pun.</translation>
 <translation id="2650312721222849884">Untuk melihat tab Chromium Anda dari perangkat lain, aktifkan sinkronisasi</translation>
 <translation id="2684230048001240293">Setel Chromium sebagai browser default untuk menyinkronkan tab, sandi, dan info pembayaran di semua perangkat Anda</translation>
 <translation id="2730884209570016437">Chromium tidak dapat menggunakan kamera karena sedang digunakan aplikasi lain</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">Chromium dapat memeriksa sandi saat Anda login dengan Akun Google.</translation>
 <translation id="3805899903892079518">Chromium tidak memiliki akses ke foto atau video Anda. Izinkan akses di iOS Settings &gt; Privacy &gt; Photos.</translation>
 <translation id="3946918322491238254">Anda tetap dapat melihat semua bookmark, histori, sandi, dan setelan lain di perangkat ini. Jika Anda membuat perubahan, perubahan tersebut tidak akan disinkronkan ke akun Anda.</translation>
+<translation id="4043291146360695975">Sandi hanya disimpan ke Pengelola Sandi di perangkat ini.</translation>
 <translation id="4099085513035183040">Tidak didukung di Chromium Beta</translation>
 <translation id="4555020257205549924">Saat fitur ini diaktifkan, Chromium akan menawarkan untuk menerjemahkan halaman yang ditulis dalam bahasa lain menggunakan Google Terjemahan. <ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">Anda sekarang dapat menggunakan Chromium kapan saja dengan mengetuk link di pesan, dokumen, dan aplikasi lainnya.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_ja.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_ja.xtb
index 7ac27e03..1204e41 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_ja.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_ja.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578">[<ph name="BEGIN_BOLD" />Chromium<ph name="END_BOLD" />] を選択する</translation>
 <translation id="2567507405773541360">シンプル、安全で、さらに高速になった Chromium をご活用ください</translation>
 <translation id="2590893390871230428">Chromium のデータを同期する</translation>
+<translation id="259094968798709429">パスワードは<ph name="BEGIN_LINK" />パスワード マネージャー<ph name="END_LINK" />に保存され、どのデバイスからでも使用できます。</translation>
 <translation id="2650312721222849884">どのデバイスからでも Chromium で自分のタブにアクセスするには、同期をオンにしてください</translation>
 <translation id="2684230048001240293">Chromium を既定に設定すると、タブ、パスワード、お支払い情報をすべてのデバイスで同期できるようになります</translation>
 <translation id="2730884209570016437">カメラは別のアプリが使用中のため、Chromium では使用できません</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">Google アカウントでログインすると、Chromium でパスワードを確認できるようになります。</translation>
 <translation id="3805899903892079518">Chromium で写真または動画にアクセスできません。iOS の [設定] &gt; [プライバシー] &gt; [写真] でアクセスを有効にしてください。</translation>
 <translation id="3946918322491238254">このデバイスのブックマーク、履歴、パスワードなどの設定は、引き続き使用できます。これらの設定に変更を加えた場合、変更内容はアカウントと同期されません。</translation>
+<translation id="4043291146360695975">パスワードは、このデバイスのパスワード マネージャーにのみ保存されます。</translation>
 <translation id="4099085513035183040">Chromium ベータ版ではサポートされていません</translation>
 <translation id="4555020257205549924">この機能を有効にすると、外国語のページを開いたときに翻訳ツールが表示されます。<ph name="BEGIN_LINK" />詳細<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">メッセージ、ドキュメント、他のアプリでタップしたリンクが常に Chromium で開かれるようになります。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_ko.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_ko.xtb
index fbc64644..83d6f6f 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_ko.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_ko.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578"><ph name="BEGIN_BOLD" />Chromium<ph name="END_BOLD" />을 선택합니다.</translation>
 <translation id="2567507405773541360">더욱 심플하고 안전하며 그 어느 때보다도 빠른 Chromium을 더욱 다양하게 활용하세요</translation>
 <translation id="2590893390871230428">Chromium 데이터 동기화</translation>
+<translation id="259094968798709429">비밀번호가 <ph name="BEGIN_LINK" />비밀번호 관리자<ph name="END_LINK" />에 저장되므로 모든 기기에서 비밀번호를 사용할 수 있습니다</translation>
 <translation id="2650312721222849884">Chromium을 사용하는 어느 곳에서나 탭을 확인하려면 동기화를 사용 설정하세요.</translation>
 <translation id="2684230048001240293">Chromium을 모든 기기에서 탭, 비밀번호, 결제 정보를 동기화할 기본값으로 설정합니다.</translation>
 <translation id="2730884209570016437">다른 애플리케이션에서 카메라를 사용하고 있으므로 Chromium에서 카메라를 사용할 수 없습니다.</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">Google 계정으로 로그인하면 Chromium에서 비밀번호를 확인할 수 있습니다.</translation>
 <translation id="3805899903892079518">Chromium에서 사진 또는 동영상에 액세스할 수 없습니다. 'iOS 설정 &gt; 개인정보 보호 &gt; 사진'에서 액세스를 허용하세요.</translation>
 <translation id="3946918322491238254">북마크, 방문 기록, 비밀번호 및 기타 설정은 모두 이 기기에서 계속 확인할 수 있습니다. 변경할 경우 변경사항이 내 계정에 동기화되지는 않습니다.</translation>
+<translation id="4043291146360695975">비밀번호가 이 기기의 비밀번호 관리자에만 저장됩니다</translation>
 <translation id="4099085513035183040">Chromium 베타에서는 지원되지 않습니다.</translation>
 <translation id="4555020257205549924">이 기능을 사용하면 Chromium에서 Google 번역을 사용하여 외국어로 작성된 페이지를 번역합니다. <ph name="BEGIN_LINK" />자세히 알아보기<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">이제 언제든 메시지, 문서 및 다른 앱에서 링크를 탭하여 Chromium을 사용할 수 있습니다.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_tr.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_tr.xtb
index e06b22128..5cd4efd0 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_tr.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_tr.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578"><ph name="BEGIN_BOLD" />Chromium<ph name="END_BOLD" />'u seçin</translation>
 <translation id="2567507405773541360">Basit, güvenli ve her zamankinden daha hızlı Chromium ile daha fazlasını yapın</translation>
 <translation id="2590893390871230428">Chromium Verilerimi Senkronize Et</translation>
+<translation id="259094968798709429">Şifreler herhangi bir cihazda kullanabilmeniz için <ph name="BEGIN_LINK" />Şifre Yöneticisi<ph name="END_LINK" />'ne kaydedilir.</translation>
 <translation id="2650312721222849884">Chromium kullandığınız her yerde sekmelerinizi görmek için senkronizasyonu açın.</translation>
 <translation id="2684230048001240293">Tüm cihazlarınızdaki sekmelerinizi, parolalarınızı ve ödeme bilgilerinizi senkronize etmek için Chromium'u varsayılan olarak ayarlayın</translation>
 <translation id="2730884209570016437">Kameranız başka bir uygulama tarafından kullanıldığından Chromium, kameranızı kullanamıyor.</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">Chromium, Google Hesabınızla oturum açtığınızda şifrelerinizi kontrol edebilir.</translation>
 <translation id="3805899903892079518">Chromium, fotoğraflarınıza veya videolarınıza erişemiyor. iOS Ayarlar &gt; Gizlilik &gt; Fotoğraflar'dan erişimi etkinleştirin.</translation>
 <translation id="3946918322491238254">Yer işaretlerinizi, geçmişinizi, şifrelerinizi ve diğer ayarlarınızı bu cihazda görmeye devam edebilirsiniz. Değişiklik yaparsanız bu değişiklikler hesabınızla senkronize edilmez.</translation>
+<translation id="4043291146360695975">Şifreler yalnızca bu cihazda Şifre Yöneticisi'ne kaydedilir.</translation>
 <translation id="4099085513035183040">Chromium Beta'da desteklenmiyor</translation>
 <translation id="4555020257205549924">Bu özellik açık durumdayken Chromium, diğer dillerde yazılmış sayfaları Google Çeviri'yi kullanarak çevirmeyi teklif eder. <ph name="BEGIN_LINK" />Daha fazla bilgi<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">Artık mesajlardaki, dokümanlardaki ve diğer uygulamalardaki bağlantıları tıkladığınızda Chromium'u kullanabilirsiniz.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-HK.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-HK.xtb
index d288e34..877f48d 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-HK.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-HK.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578">選取 [Chromium]<ph name="BEGIN_BOLD" /><ph name="END_BOLD" /></translation>
 <translation id="2567507405773541360">Chromium 比以前更簡便、安全而快速,讓您事半功倍</translation>
 <translation id="2590893390871230428">同步處理 Chromium 資料</translation>
+<translation id="259094968798709429">密碼已儲存至<ph name="BEGIN_LINK" />密碼管理員<ph name="END_LINK" />,你可以在任何裝置上使用。</translation>
 <translation id="2650312721222849884">如要在任何使用 Chromium 的裝置上查看分頁,請開啟同步處理功能</translation>
 <translation id="2684230048001240293">將 Chromium 設定為預設瀏覽器,即可在所有裝置上同步分頁、密碼和付款資料</translation>
 <translation id="2730884209570016437">由於另一個應用程式正在使用相機,因此 Chromium 暫時無法使用</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">Chromium 可在您使用 Google 帳戶登入時檢查密碼。</translation>
 <translation id="3805899903892079518">Chromium 沒有存取相片或影片的權限。請前往「iOS 設定」&gt;「私隱」&gt;「相片」開放權限。</translation>
 <translation id="3946918322491238254">您仍可在此裝置上查看自己的所有書籤、記錄、密碼和其他設定,但您作出的變更將不會同步到 Google 帳戶。</translation>
+<translation id="4043291146360695975">密碼只會儲存至這部裝置上的密碼管理員。</translation>
 <translation id="4099085513035183040">Chromium Beta 版本上不支援此功能</translation>
 <translation id="4555020257205549924">開啟這項功能後,Chromium 會使用「Google 翻譯」來翻譯其他語言的網頁。<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">您現在只要在訊息、文件或其他應用程式中輕按連結,即可使用 Chromium。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-TW.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-TW.xtb
index 80c60852..17d1966 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-TW.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-TW.xtb
@@ -31,6 +31,7 @@
 <translation id="2478931088402984578">選取 [Chromium]<ph name="BEGIN_BOLD" /><ph name="END_BOLD" /></translation>
 <translation id="2567507405773541360">運用簡便、安全且速度遠勝以往的 Chromium 讓你事半功倍</translation>
 <translation id="2590893390871230428">同步處理你的 Chromium 資料</translation>
+<translation id="259094968798709429">密碼已儲存至<ph name="BEGIN_LINK" />密碼管理員<ph name="END_LINK" />,你可以在任何裝置上使用。</translation>
 <translation id="2650312721222849884">開啟同步功能後,不論從何處使用 Chromium 都能查看你的分頁</translation>
 <translation id="2684230048001240293">將 Chromium 設為預設瀏覽器,即可在你的所有裝置上同步處理分頁、密碼和付款資訊</translation>
 <translation id="2730884209570016437">另一個應用程式正在使用你的相機,因此 Chromium 無法使用</translation>
@@ -44,6 +45,7 @@
 <translation id="3639997914391704523">如果你使用 Google 帳戶登入,Chromium 可以檢查你的密碼。</translation>
 <translation id="3805899903892079518">Chromium 無法存取您的相片或影片,請前往「iOS 設定」中的 [隱私權] &gt; [相片] 啟用存取權。</translation>
 <translation id="3946918322491238254">你仍然可以在這部裝置上查看自己的所有書籤、歷史記錄、密碼和其他設定,但你所做的變更將不會同步到帳戶。</translation>
+<translation id="4043291146360695975">密碼只會儲存至這部裝置上的密碼管理員。</translation>
 <translation id="4099085513035183040">Chromium Beta 版不支援這項功能</translation>
 <translation id="4555020257205549924">開啟這項功能後,Chromium 會使用 Google 翻譯來翻譯其他語言的網頁。<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
 <translation id="4585809515399340748">現在只要在訊息、文件和其他應用程式中輕觸連結,即可透過 Chromium 開啟。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_id.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_id.xtb
index fb588bce..34ac78bc 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_id.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_id.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">Login ke situs ini dan Chrome. Anda dapat mengaktifkan sinkronisasi nanti.</translation>
 <translation id="424864128008805179">Logout dari Chrome?</translation>
 <translation id="4249068189593983585">Tips Chrome. Untuk opsi tab lainnya, sentuh lama tombol Tampilkan Tab di toolbar, yang terdapat di bagian bawah atau atas layar.</translation>
+<translation id="4267862249323750454">Sandi disimpan ke <ph name="BEGIN_LINK" />Pengelola Sandi Google<ph name="END_LINK" /> agar Anda dapat menggunakannya di perangkat mana pun.</translation>
 <translation id="4523886039239821078">Beberapa pengaya (pengaya) menyebabkan Chrome mogok. Uninstal:</translation>
 <translation id="4633328489441962921">Chrome tidak dapat memeriksa update</translation>
 <translation id="4698415050768537821">Chrome tidak dapat memeriksa semua sandi. Coba lagi besok atau <ph name="BEGIN_LINK" />periksa sandi di Akun Google Anda<ph name="END_LINK" />.</translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">Izinkan Login Chrome</translation>
 <translation id="6181930887571472871">Beralih ke Chrome</translation>
 <translation id="6238746320622508509">Izinkan Chrome mengunci tab Samaran Anda.</translation>
+<translation id="6387994324662817823">Sandi hanya disimpan ke Pengelola Sandi Google di perangkat ini.</translation>
 <translation id="6427126399757991875">Organisasi Anda sedang menyiapkan Chrome ...</translation>
 <translation id="6600954340915313787">Disalin ke Chrome</translation>
 <translation id="6634107063912726160">Jika Anda logout, Chrome tidak akan menyinkronkan data baru apa pun ke Akun Google Anda. Data yang sebelumnya disinkronkan tetap tersimpan di akun.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_ja.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_ja.xtb
index bdf31b06..c69912b 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_ja.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_ja.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">このサイトと Chrome にログインしてください。同期は後でオンにできます。</translation>
 <translation id="424864128008805179">Chrome からログアウトしますか?</translation>
 <translation id="4249068189593983585">Chrome の使い方のヒント: タブのオプションをさらに表示するには、画面の下部または上部のツールバーにある [タブを表示] を長押しします。</translation>
+<translation id="4267862249323750454">パスワードは <ph name="BEGIN_LINK" />Google パスワード マネージャー<ph name="END_LINK" />に保存され、どのデバイスからでも使用できます。</translation>
 <translation id="4523886039239821078">アドオンが原因でChromeがクラッシュしました。次をアンインストールしてください:</translation>
 <translation id="4633328489441962921">Chrome でアップデートを確認できません</translation>
 <translation id="4698415050768537821">Chrome ですべてのパスワードを確認できませんでした。明日もう一度お試しいただくか、<ph name="BEGIN_LINK" />Google アカウント内のパスワードをご確認ください<ph name="END_LINK" />。</translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">Chrome へのログインを許可する</translation>
 <translation id="6181930887571472871">Chrome に切り替え</translation>
 <translation id="6238746320622508509">Chrome でシークレット タブをロックできるようにします。</translation>
+<translation id="6387994324662817823">パスワードは、このデバイスの Google パスワード マネージャーにのみ保存されます。</translation>
 <translation id="6427126399757991875">組織で Chrome を設定しています...</translation>
 <translation id="6600954340915313787">Chrome にコピー済み</translation>
 <translation id="6634107063912726160">ログアウトすると、Chrome で新しいデータが Google アカウントと同期されなくなります。これまでに同期されたデータはアカウントに残ります。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_ko.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_ko.xtb
index 1e54a4d..90c9fcd 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_ko.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_ko.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">이 사이트 및 Chrome에 로그인하세요. 나중에 동기화를 사용 설정할 수 있습니다.</translation>
 <translation id="424864128008805179">Chrome에서 로그아웃하시겠습니까?</translation>
 <translation id="4249068189593983585">Chrome 도움말. 더 많은 탭 옵션을 보려면 화면 하단이나 상단에 있는 툴바에서 탭 표시 버튼을 길게 터치하세요.</translation>
+<translation id="4267862249323750454">비밀번호가 <ph name="BEGIN_LINK" />Google 비밀번호 관리자<ph name="END_LINK" />에 저장되므로 모든 기기에서 비밀번호를 사용할 수 있습니다</translation>
 <translation id="4523886039239821078">일부 부가기능이 Chrome을 비정상 종료시킵니다. 다음 항목을 제거하세요.</translation>
 <translation id="4633328489441962921">Chrome에서 업데이트를 확인할 수 없습니다.</translation>
 <translation id="4698415050768537821">Chrome에서 일부 비밀번호를 확인할 수 없습니다. 내일 다시 시도하거나 <ph name="BEGIN_LINK" />Google 계정에서 비밀번호를 확인<ph name="END_LINK" />하세요.</translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">Chrome 로그인 허용</translation>
 <translation id="6181930887571472871">Chrome으로 전환</translation>
 <translation id="6238746320622508509">Chrome에서 시크릿 탭을 잠그도록 허용합니다.</translation>
+<translation id="6387994324662817823">비밀번호가 이 기기의 Google 비밀번호 관리자에만 저장됩니다</translation>
 <translation id="6427126399757991875">조직에서 Chrome을 설정하는 중...</translation>
 <translation id="6600954340915313787">Chrome에 복사됨</translation>
 <translation id="6634107063912726160">로그아웃하면 Chrome에서 더 이상 새로운 데이터를 내 Google 계정에 동기화하지 않습니다. 이전에 동기화된 데이터는 계정에 그대로 유지됩니다.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_tr.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_tr.xtb
index 49a71b46..71494e3f 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_tr.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_tr.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">Bu sitede ve Chrome'da oturum açın. Senkronizasyonu daha sonra açabilirsiniz.</translation>
 <translation id="424864128008805179">Chrome oturumu kapatılsın mı?</translation>
 <translation id="4249068189593983585">Chrome için ipucu. Sekmelerle ilgili daha fazla seçenek görmek için ekranınızın altında veya üstünde görünen araç çubuğunda Sekmeleri Göster düğmesine dokunup basılı tutun.</translation>
+<translation id="4267862249323750454">Şifreler herhangi bir cihazda kullanabilmeniz için <ph name="BEGIN_LINK" />Google Şifre Yöneticisi<ph name="END_LINK" />'ne kaydedilir.</translation>
 <translation id="4523886039239821078">Bazı eklentiler Chrome'un kilitlenmesine neden oluyor. Lütfen şunların yüklemelerini kaldırın:</translation>
 <translation id="4633328489441962921">Chrome, güncellemeleri denetleyemiyor</translation>
 <translation id="4698415050768537821">Chrome, şifrelerin tümünü kontrol edemedi. Yarın tekrar deneyin veya <ph name="BEGIN_LINK" />Google Hesabınızdaki şifreleri kontrol edin<ph name="END_LINK" />.</translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">Chrome'da oturum açmaya izin ver</translation>
 <translation id="6181930887571472871">Chrome'a Geçin</translation>
 <translation id="6238746320622508509">Chrome'un Gizli sekmeleri kilitlemesine izin verin.</translation>
+<translation id="6387994324662817823">Şifreler yalnızca bu cihazda Google Şifre Yöneticisi'ne kaydedilir.</translation>
 <translation id="6427126399757991875">Kuruluşunuz, Chrome'u kuruyor...</translation>
 <translation id="6600954340915313787">Chrome'a kopyalandı</translation>
 <translation id="6634107063912726160">Oturumu kapattığınızda Chrome, hiçbir yeni veriyi Google Hesabınızla senkronize etmez. Önceden senkronize edilmiş veriler hesapta kalır.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-HK.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-HK.xtb
index 6f7b309..fbb90c2 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-HK.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-HK.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">登入此網站和 Chrome。您可稍後再開啟同步功能。</translation>
 <translation id="424864128008805179">要登出 Chrome 嗎?</translation>
 <translation id="4249068189593983585">Chrome 提示。如果要多啲標籤選項,請㩒住螢幕底部或者頂部工具列入面中嘅 [顯示分頁] 掣。</translation>
+<translation id="4267862249323750454">密碼已儲存至 <ph name="BEGIN_LINK" />Google 密碼管理員<ph name="END_LINK" />,你可以在任何裝置上使用。</translation>
 <translation id="4523886039239821078">部分外掛程式造成 Chrome 當機,請解除安裝這些外掛程式:</translation>
 <translation id="4633328489441962921">Chrome 無法檢查更新</translation>
 <translation id="4698415050768537821">Chrome 無法檢查所有密碼。請明天再試,或<ph name="BEGIN_LINK" />檢查 Google 帳戶中的密碼<ph name="END_LINK" />。</translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">允許登入 Chrome</translation>
 <translation id="6181930887571472871">切換至 Chrome</translation>
 <translation id="6238746320622508509">讓 Chrome 鎖定您的無痕式分頁。</translation>
+<translation id="6387994324662817823">密碼只會儲存至這部裝置上的 Google 密碼管理員。</translation>
 <translation id="6427126399757991875">您的機構正在設定 Chrome…</translation>
 <translation id="6600954340915313787">已複製至 Chrome</translation>
 <translation id="6634107063912726160">登出時,Chrome 將不會同步任何新資料至您的 Google 帳戶。不過,先前已同步處理的資料仍會保存在帳戶中。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-TW.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-TW.xtb
index 6866e99..ae5de5e0 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-TW.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-TW.xtb
@@ -50,6 +50,7 @@
 <translation id="4214277427269650960">登入這個網站和 Chrome。你可以稍後再開啟同步功能。</translation>
 <translation id="424864128008805179">要登出 Chrome 嗎?</translation>
 <translation id="4249068189593983585">Chrome 提示。如需更多分頁選項,請輕觸並按住工具列 (位於畫面底部或頂端) 中的 [顯示分頁] 按鈕。</translation>
+<translation id="4267862249323750454">密碼已儲存至 <ph name="BEGIN_LINK" />Google 密碼管理員<ph name="END_LINK" />,你可以在任何裝置上使用。</translation>
 <translation id="4523886039239821078">部分外掛程式造成 Chrome 當機,請解除安裝這些外掛程式:</translation>
 <translation id="4633328489441962921">Chrome 無法檢查更新</translation>
 <translation id="4698415050768537821">Chrome 無法檢查所有密碼,請明天再試,或<ph name="BEGIN_LINK" />檢查 Google 帳戶中的密碼。<ph name="END_LINK" /></translation>
@@ -70,6 +71,7 @@
 <translation id="6063091872902370735">允許登入 Chrome</translation>
 <translation id="6181930887571472871">改為使用 Chrome</translation>
 <translation id="6238746320622508509">讓 Chrome 鎖定你的無痕分頁。</translation>
+<translation id="6387994324662817823">密碼只會儲存至這部裝置上的 Google 密碼管理員。</translation>
 <translation id="6427126399757991875">貴機構正在設定 Chrome...</translation>
 <translation id="6600954340915313787">已複製到 Chrome</translation>
 <translation id="6634107063912726160">登出帳戶後,Chrome 就不會將任何新資料同步到你的 Google 帳戶。不過,先前已同步處理的資料仍會保存在帳戶中。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_az.xtb b/ios/chrome/app/strings/resources/ios_strings_az.xtb
index 33f0e02..11e1f7b5 100644
--- a/ios/chrome/app/strings/resources/ios_strings_az.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_az.xtb
@@ -168,6 +168,7 @@
 <translation id="2584132361465095047">Hesab əlavə edin...</translation>
 <translation id="2600682495497606169">Sayt Kukilərini Silin</translation>
 <translation id="2625189173221582860">Parol kopyalandı</translation>
+<translation id="2626236249646841566">Bağlantını yoxlayın və yenidən daxil olmağa cəhd edin.</translation>
 <translation id="2647269890314209800">İstifadə edilən kukilər</translation>
 <translation id="2648803196158606475">Oxunmuşları Silin</translation>
 <translation id="2653659639078652383">Təqdim edin</translation>
@@ -363,6 +364,7 @@
 <translation id="4508750114462689118">Giriş reklamını bağlayın</translation>
 <translation id="4526249700380860531"><ph name="BEGIN_LINK" />passwords.google.com<ph name="END_LINK" /> linkində yadda saxlanılmış parollarınıza baxın və idarə edin</translation>
 <translation id="4536418791685807335">Yenidən daxil olmağa cəhd edin.</translation>
+<translation id="4540780316273593836">Xəta baş verdi</translation>
 <translation id="457386861538956877">Digər...</translation>
 <translation id="4592368184551360546">Klaviatura</translation>
 <translation id="461440297010471931">Google ilə axtarın</translation>
@@ -478,6 +480,7 @@
 <translation id="5669528293118408608">www</translation>
 <translation id="567881659373499783">Versiya <ph name="PRODUCT_VERSION" /></translation>
 <translation id="5690398455483874150">{count,plural, =1{İndi 1 Chrome pəncərəsi göstərilir}other{İndi {count} Chrome pəncərəsi göstərilir}}</translation>
+<translation id="5704908597376970822">Daxil olmaq mümkün deyil.</translation>
 <translation id="5706552126692816153">1 Gün Əvvəl Aktiv Olub</translation>
 <translation id="5711039611392265845">Məxfilik, təhlükəsizlik və datanın toplanması ilə bağlı daha çox ayarlar üçün <ph name="BEGIN_LINK" />Sinxronizasiya və Google Xidmətləri<ph name="END_LINK" /> səhifəsinə daxil olun.</translation>
 <translation id="5724941645893276623">Vebdə məxfi axtarış etmək üçün yeni tab açın</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_it.xtb b/ios/chrome/app/strings/resources/ios_strings_it.xtb
index 8c52a99..d4af7a1 100644
--- a/ios/chrome/app/strings/resources/ios_strings_it.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_it.xtb
@@ -168,6 +168,7 @@
 <translation id="2584132361465095047">Aggiungi account…</translation>
 <translation id="2600682495497606169">Cancella cookie del sito</translation>
 <translation id="2625189173221582860">Password copiata</translation>
+<translation id="2626236249646841566">Controlla la connessione e riprova ad accedere.</translation>
 <translation id="2647269890314209800">Cookie in uso</translation>
 <translation id="2648803196158606475">Elimina voci lette</translation>
 <translation id="2653659639078652383">Invia</translation>
@@ -363,6 +364,7 @@
 <translation id="4508750114462689118">Chiudi promo accesso</translation>
 <translation id="4526249700380860531">Controlla e gestisci le password salvate all'indirizzo <ph name="BEGIN_LINK" />passwords.google.com<ph name="END_LINK" /></translation>
 <translation id="4536418791685807335">Prova ad accedere nuovamente.</translation>
+<translation id="4540780316273593836">Si è verificato un problema</translation>
 <translation id="457386861538956877">Altro...</translation>
 <translation id="4592368184551360546">Tastiera</translation>
 <translation id="461440297010471931">Ricerca con Google</translation>
@@ -478,6 +480,7 @@
 <translation id="5669528293118408608">www</translation>
 <translation id="567881659373499783">Versione <ph name="PRODUCT_VERSION" /></translation>
 <translation id="5690398455483874150">{count,plural, =1{1 finestra di Chrome visualizzata}one{{count} finestre di Chrome visualizzate}other{{count} finestre di Chrome visualizzate}}</translation>
+<translation id="5704908597376970822">Impossibile eseguire l'accesso.</translation>
 <translation id="5706552126692816153">Attivo 1 giorno fa</translation>
 <translation id="5711039611392265845">Per altre impostazioni relative a privacy, sicurezza e raccolta dei dati, consulta la sezione <ph name="BEGIN_LINK" />Sincronizzazione e servizi Google<ph name="END_LINK" />.</translation>
 <translation id="5724941645893276623">Per navigare sul Web in privato, aggiungi una nuova scheda</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ja.xtb b/ios/chrome/app/strings/resources/ios_strings_ja.xtb
index 60a705f..44c6640 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ja.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ja.xtb
@@ -168,6 +168,7 @@
 <translation id="2584132361465095047">アカウントを追加...</translation>
 <translation id="2600682495497606169">サイトの Cookie を削除</translation>
 <translation id="2625189173221582860">パスワードがコピーされました</translation>
+<translation id="2626236249646841566">接続を確認して、もう一度お試しください。</translation>
 <translation id="2647269890314209800">使用中の Cookie</translation>
 <translation id="2648803196158606475">既読を削除</translation>
 <translation id="2653659639078652383">送信</translation>
@@ -363,6 +364,7 @@
 <translation id="4508750114462689118">ログイン プロモーションを閉じる</translation>
 <translation id="4526249700380860531"><ph name="BEGIN_LINK" />passwords.google.com<ph name="END_LINK" /> での保存パスワードの表示と管理</translation>
 <translation id="4536418791685807335">もう一度ログインしてみてください。</translation>
+<translation id="4540780316273593836">エラーが発生しました</translation>
 <translation id="457386861538956877">その他...</translation>
 <translation id="4592368184551360546">キーボード</translation>
 <translation id="461440297010471931">Google 検索エンジンを使用</translation>
@@ -478,6 +480,7 @@
 <translation id="5669528293118408608">www</translation>
 <translation id="567881659373499783">バージョン <ph name="PRODUCT_VERSION" /></translation>
 <translation id="5690398455483874150">{count,plural, =1{現在 1 個の Chrome ウィンドウを表示しています}other{現在 {count} 個の Chrome ウィンドウを表示しています}}</translation>
+<translation id="5704908597376970822">ログインできません。</translation>
 <translation id="5706552126692816153">最終同期: 1 日前</translation>
 <translation id="5711039611392265845">プライバシー、セキュリティ、データ収集に関連するその他の設定については、<ph name="BEGIN_LINK" />同期と Google サービス<ph name="END_LINK" />をご覧ください。</translation>
 <translation id="5724941645893276623">ウェブをプライベートに閲覧するには、新しいタブを追加してください</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_mk.xtb b/ios/chrome/app/strings/resources/ios_strings_mk.xtb
index e83ab7e..92dc26b 100644
--- a/ios/chrome/app/strings/resources/ios_strings_mk.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_mk.xtb
@@ -168,6 +168,7 @@
 <translation id="2584132361465095047">Додајте сметка</translation>
 <translation id="2600682495497606169">Избриши ги колачињата од сајтот</translation>
 <translation id="2625189173221582860">Лозинката е копирана</translation>
+<translation id="2626236249646841566">Проверете ја врската и обидете се повторно да се најавите.</translation>
 <translation id="2647269890314209800">Колачиња во употреба</translation>
 <translation id="2648803196158606475">Избриши ги прочитаните</translation>
 <translation id="2653659639078652383">Испрати</translation>
@@ -363,6 +364,7 @@
 <translation id="4508750114462689118">Затвори ја промоцијата за најавување</translation>
 <translation id="4526249700380860531">Прикажи и управувај зачувани лозинки на <ph name="BEGIN_LINK" />passwords.google.com<ph name="END_LINK" /></translation>
 <translation id="4536418791685807335">Обидете се да се најавите повторно.</translation>
+<translation id="4540780316273593836">Нешто тргна наопаку</translation>
 <translation id="457386861538956877">Повеќе…</translation>
 <translation id="4592368184551360546">Тастатура</translation>
 <translation id="461440297010471931">Се пребарува со Google</translation>
@@ -478,6 +480,7 @@
 <translation id="5669528293118408608">www</translation>
 <translation id="567881659373499783">Верзија <ph name="PRODUCT_VERSION" /></translation>
 <translation id="5690398455483874150">{count,plural, =1{Сега се прикажува 1 прозорец на Chrome}one{Сега се прикажува {count} прозорец на Chrome}other{Сега се прикажуваат {count} прозорци на Chrome}}</translation>
+<translation id="5704908597376970822">Не може да се најавите.</translation>
 <translation id="5706552126692816153">Активен пред 1 ден</translation>
 <translation id="5711039611392265845">За повеќе поставки што се однесуваат на приватноста, безбедноста и собирањето податоци, одете на <ph name="BEGIN_LINK" />Синхронизација и услуги на Google<ph name="END_LINK" />.</translation>
 <translation id="5724941645893276623">За приватно прелистување на интернет, додајте нова картичка</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_mn.xtb b/ios/chrome/app/strings/resources/ios_strings_mn.xtb
index 7ba8752..cbc05ed 100644
--- a/ios/chrome/app/strings/resources/ios_strings_mn.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_mn.xtb
@@ -169,6 +169,7 @@
 <translation id="2600682495497606169">Сайтын күүкиг арилгах</translation>
 <translation id="2625189173221582860">Нууц үгийг хуулсан</translation>
 <translation id="2626236249646841566">Холболтоо шалгаад, нэвтрэхээр дахин оролдоно уу.</translation>
+<translation id="2637313651144986786">Табуудыг хайх...</translation>
 <translation id="2647269890314209800">Ашиглаж буй күүки</translation>
 <translation id="2648803196158606475">Уншсаныг устгах</translation>
 <translation id="2653659639078652383">Илгээх</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb b/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
index 881ce49..9f2abe8 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
@@ -168,6 +168,7 @@
 <translation id="2584132361465095047">添加帐号…</translation>
 <translation id="2600682495497606169">清除网站 Cookie</translation>
 <translation id="2625189173221582860">已复制密码</translation>
+<translation id="2626236249646841566">请检查网络连接状况并尝试重新登录。</translation>
 <translation id="2647269890314209800">正在使用的 Cookie</translation>
 <translation id="2648803196158606475">删除已读项</translation>
 <translation id="2653659639078652383">提交</translation>
@@ -363,6 +364,7 @@
 <translation id="4508750114462689118">关闭登录推广元素</translation>
 <translation id="4526249700380860531">通过 <ph name="BEGIN_LINK" />passwords.google.com<ph name="END_LINK" /> 查看和管理已保存的密码</translation>
 <translation id="4536418791685807335">请尝试重新登录。</translation>
+<translation id="4540780316273593836">出了点问题</translation>
 <translation id="457386861538956877">更多...</translation>
 <translation id="4592368184551360546">键盘</translation>
 <translation id="461440297010471931">目前所用的搜索引擎是 Google</translation>
@@ -478,6 +480,7 @@
 <translation id="5669528293118408608">www</translation>
 <translation id="567881659373499783">版本 <ph name="PRODUCT_VERSION" /></translation>
 <translation id="5690398455483874150">{count,plural, =1{目前显示了 1 个 Chrome 窗口}other{目前显示了 {count} 个 Chrome 窗口}}</translation>
+<translation id="5704908597376970822">无法登录。</translation>
 <translation id="5706552126692816153">1 天前曾有活动</translation>
 <translation id="5711039611392265845">若要了解更多与隐私、安全和数据收集相关的设置,请参阅<ph name="BEGIN_LINK" />同步功能和 Google 服务<ph name="END_LINK" />。</translation>
 <translation id="5724941645893276623">若要私密地浏览网页,请添加新标签页</translation>
diff --git a/ios/chrome/browser/download/BUILD.gn b/ios/chrome/browser/download/BUILD.gn
index bd21570..cfe7a77 100644
--- a/ios/chrome/browser/download/BUILD.gn
+++ b/ios/chrome/browser/download/BUILD.gn
@@ -29,6 +29,9 @@
     "pass_kit_tab_helper.h",
     "pass_kit_tab_helper.mm",
     "pass_kit_tab_helper_delegate.h",
+    "vcard_tab_helper.h",
+    "vcard_tab_helper.mm",
+    "vcard_tab_helper_delegate.h",
   ]
 
   public_deps = [ ":mime_types" ]
@@ -82,12 +85,15 @@
     "download_manager_tab_helper_unittest.mm",
     "google_drive_app_util_unittest.mm",
     "pass_kit_tab_helper_unittest.mm",
+    "vcard_tab_helper_unittest.mm",
   ]
   deps = [
     ":test_support",
     "//base/test:test_support",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/download",
+    "//ios/chrome/browser/ui/download:features",
+    "//ios/chrome/browser/web_state_list:test_support",
     "//ios/chrome/test/fakes",
     "//ios/web/public",
     "//ios/web/public/download",
diff --git a/ios/chrome/browser/download/browser_download_service.mm b/ios/chrome/browser/download/browser_download_service.mm
index f303b16..e8c56c8 100644
--- a/ios/chrome/browser/download/browser_download_service.mm
+++ b/ios/chrome/browser/download/browser_download_service.mm
@@ -12,6 +12,7 @@
 #include "ios/chrome/browser/download/mime_type_util.h"
 #import "ios/chrome/browser/download/mobileconfig_tab_helper.h"
 #import "ios/chrome/browser/download/pass_kit_tab_helper.h"
+#import "ios/chrome/browser/download/vcard_tab_helper.h"
 #import "ios/chrome/browser/ui/download/features.h"
 #import "ios/web/public/download/download_controller.h"
 #import "ios/web/public/download/download_task.h"
@@ -136,7 +137,7 @@
     }
   } else if (task->GetMimeType() == kVcardMimeType &&
              base::FeatureList::IsEnabled(kDownloadVcard)) {
-    // TODO(crbug.com/1244002): Implement a VcardTabHelper.
+    VcardTabHelper::FromWebState(web_state)->Download(std::move(task));
   } else {
     DownloadManagerTabHelper* tab_helper =
         DownloadManagerTabHelper::FromWebState(web_state);
diff --git a/ios/chrome/browser/download/download_test_util.cc b/ios/chrome/browser/download/download_test_util.cc
index 2ac137d1..c1ab89a 100644
--- a/ios/chrome/browser/download/download_test_util.cc
+++ b/ios/chrome/browser/download/download_test_util.cc
@@ -16,6 +16,7 @@
 const char kPkPassFilePath[] =
     "ios/testing/data/http_server_files/generic.pkpass";
 const char kUsdzFilePath[] = "ios/testing/data/http_server_files/redchair.usdz";
+const char kVcardFilePath[] = "ios/testing/data/http_server_files/vcard.vcf";
 
 std::string GetTestFileContents(const char* file_path) {
   base::FilePath path;
diff --git a/ios/chrome/browser/download/download_test_util.h b/ios/chrome/browser/download/download_test_util.h
index 47dc5b53..d43e703a 100644
--- a/ios/chrome/browser/download/download_test_util.h
+++ b/ios/chrome/browser/download/download_test_util.h
@@ -12,6 +12,7 @@
 extern const char kMobileConfigFilePath[];
 extern const char kPkPassFilePath[];
 extern const char kUsdzFilePath[];
+extern const char kVcardFilePath[];
 
 // Returns contents of the test file at the given relative path in the chrome
 // test directory.
diff --git a/ios/chrome/browser/download/vcard_tab_helper.h b/ios/chrome/browser/download/vcard_tab_helper.h
new file mode 100644
index 0000000..1cd41da5
--- /dev/null
+++ b/ios/chrome/browser/download/vcard_tab_helper.h
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_H_
+
+#import <Foundation/Foundation.h>
+#include <set>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "ios/web/public/download/download_task_observer.h"
+#import "ios/web/public/web_state_user_data.h"
+
+@protocol VcardTabHelperDelegate;
+namespace web {
+class DownloadTask;
+class WebState;
+}  // namespace web
+
+// TabHelper which manages Vcard.
+class VcardTabHelper : public web::DownloadTaskObserver,
+                       public web::WebStateUserData<VcardTabHelper> {
+ public:
+  explicit VcardTabHelper(web::WebState* web_state);
+
+  VcardTabHelper(const VcardTabHelper&) = delete;
+  VcardTabHelper& operator=(const VcardTabHelper&) = delete;
+
+  ~VcardTabHelper() override;
+
+  id<VcardTabHelperDelegate> delegate() { return delegate_; }
+
+  // |delegate| is not retained by this instance.
+  void set_delegate(id<VcardTabHelperDelegate> delegate) {
+    delegate_ = delegate;
+  }
+
+  // Asynchronously downloads the Vcard file using the given |task|. Asks
+  // delegate to open the Vcard when the download is complete.
+  virtual void Download(std::unique_ptr<web::DownloadTask> task);
+
+ private:
+  friend class web::WebStateUserData<VcardTabHelper>;
+
+  // web::DownloadTaskObserver overrides:
+  void OnDownloadUpdated(web::DownloadTask* task) override;
+
+  __weak id<VcardTabHelperDelegate> delegate_ = nil;
+
+  // Set of unfinished download tasks.
+  std::set<std::unique_ptr<web::DownloadTask>, base::UniquePtrComparator>
+      tasks_;
+
+  WEB_STATE_USER_DATA_KEY_DECL();
+};
+
+#endif  // IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_H_
diff --git a/ios/chrome/browser/download/vcard_tab_helper.mm b/ios/chrome/browser/download/vcard_tab_helper.mm
new file mode 100644
index 0000000..a9494bf2
--- /dev/null
+++ b/ios/chrome/browser/download/vcard_tab_helper.mm
@@ -0,0 +1,56 @@
+// 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 "ios/chrome/browser/download/vcard_tab_helper.h"
+
+#include "base/strings/sys_string_conversions.h"
+#include "ios/chrome/browser/download/mime_type_util.h"
+#import "ios/chrome/browser/download/vcard_tab_helper_delegate.h"
+#import "ios/web/public/download/download_task.h"
+#import "net/base/mac/url_conversions.h"
+#include "net/url_request/url_fetcher_response_writer.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+VcardTabHelper::VcardTabHelper(web::WebState* web_state) {
+  DCHECK(web_state);
+}
+
+VcardTabHelper::~VcardTabHelper() {
+  for (auto& task : tasks_) {
+    task->RemoveObserver(this);
+  }
+}
+
+void VcardTabHelper::Download(std::unique_ptr<web::DownloadTask> task) {
+  DCHECK_EQ(task->GetMimeType(), kVcardMimeType);
+  web::DownloadTask* task_ptr = task.get();
+
+  // Add the task to the set of unfinished tasks before calling
+  // Start() because the download may make progress synchronously
+  // and OnDownloadUpdated called immediately.
+  tasks_.insert(std::move(task));
+  task_ptr->AddObserver(this);
+  task_ptr->Start(base::FilePath(), web::DownloadTask::Destination::kToMemory);
+}
+
+void VcardTabHelper::OnDownloadUpdated(web::DownloadTask* updated_task) {
+  auto it = tasks_.find(updated_task);
+  DCHECK(it != tasks_.end());
+
+  if (!updated_task->IsDone())
+    return;
+
+  NSData* vcardData = updated_task->GetResponseData();
+  if (vcardData) {
+    [delegate_ openVcardFromData:vcardData];
+  }
+
+  updated_task->RemoveObserver(this);
+  tasks_.erase(it);
+}
+
+WEB_STATE_USER_DATA_KEY_IMPL(VcardTabHelper)
diff --git a/ios/chrome/browser/download/vcard_tab_helper_delegate.h b/ios/chrome/browser/download/vcard_tab_helper_delegate.h
new file mode 100644
index 0000000..6ec1aac
--- /dev/null
+++ b/ios/chrome/browser/download/vcard_tab_helper_delegate.h
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_DELEGATE_H_
+
+// TabHelper which manages vcard files.
+@protocol VcardTabHelperDelegate
+
+// Called to open a Vcard. |data| cannot be nil.
+- (void)openVcardFromData:(NSData*)vcardData;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DOWNLOAD_VCARD_TAB_HELPER_DELEGATE_H_
diff --git a/ios/chrome/browser/download/vcard_tab_helper_unittest.mm b/ios/chrome/browser/download/vcard_tab_helper_unittest.mm
new file mode 100644
index 0000000..daf14113
--- /dev/null
+++ b/ios/chrome/browser/download/vcard_tab_helper_unittest.mm
@@ -0,0 +1,69 @@
+// 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 "ios/chrome/browser/download/vcard_tab_helper.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "ios/chrome/browser/download/download_test_util.h"
+#include "ios/chrome/browser/download/mime_type_util.h"
+#import "ios/chrome/browser/download/vcard_tab_helper.h"
+#import "ios/chrome/browser/download/vcard_tab_helper_delegate.h"
+#import "ios/chrome/browser/ui/download/features.h"
+#import "ios/web/public/test/fakes/fake_download_task.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
+#include "testing/platform_test.h"
+#include "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+char kUrl[] = "https://test.test/";
+
+}  // namespace
+
+// Test fixture for testing VcardTabHelperTest class.
+class VcardTabHelperTest : public PlatformTest {
+ protected:
+  VcardTabHelperTest() {
+    feature_list_.InitAndEnableFeature(kDownloadVcard);
+    VcardTabHelper::CreateForWebState(&web_state_);
+  }
+
+  VcardTabHelper* tab_helper() {
+    return VcardTabHelper::FromWebState(&web_state_);
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+  web::FakeWebState web_state_;
+};
+
+// Tests downloading a valid vcard file.
+TEST_F(VcardTabHelperTest, ValidVcardFile) {
+  auto task =
+      std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kVcardMimeType);
+  web::FakeDownloadTask* task_ptr = task.get();
+  tab_helper()->Download(std::move(task));
+
+  std::string pass_data = testing::GetTestFileContents(testing::kVcardFilePath);
+  NSData* data = [NSData dataWithBytes:pass_data.data()
+                                length:pass_data.size()];
+
+  // Verify that openVcardFromData was correctly dispatched.
+  id mockHandler = OCMProtocolMock(@protocol(VcardTabHelperDelegate));
+  tab_helper()->set_delegate(mockHandler);
+  OCMExpect([mockHandler openVcardFromData:data]);
+
+  task_ptr->SetResponseData(data);
+  task_ptr->SetDone(true);
+
+  EXPECT_OCMOCK_VERIFY(mockHandler);
+}
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
index 1e3145c..1f9e709 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
@@ -124,7 +124,7 @@
   options.set_same_site_cookie_context(
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
   cookie_manager->GetCookieList(
-      request_.url, options, net::CookiePartitionKeychain::Todo(),
+      request_.url, options, net::CookiePartitionKeyCollection::Todo(),
       base::BindOnce(
           &GaiaAuthFetcherIOSNSURLSessionBridge::FetchPendingRequestWithCookies,
           base::Unretained(this)));
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 2d1b30a1..7cfcf1f 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -30,6 +30,7 @@
 #import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.h"
 #import "ios/chrome/browser/download/ar_quick_look_tab_helper.h"
 #import "ios/chrome/browser/download/mobileconfig_tab_helper.h"
+#import "ios/chrome/browser/download/vcard_tab_helper.h"
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
 #import "ios/chrome/browser/find_in_page/find_tab_helper.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
@@ -64,6 +65,7 @@
 #import "ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h"
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/u2f/u2f_tab_helper.h"
+#import "ios/chrome/browser/ui/download/features.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
@@ -126,6 +128,8 @@
   InfobarOverlayTabHelper::CreateForWebState(web_state);
   TranslateOverlayTabHelper::CreateForWebState(web_state);
 
+  MobileConfigTabHelper::CreateForWebState(web_state);
+
   if (ios::provider::IsTextZoomEnabled()) {
     FontSizeTabHelper::CreateForWebState(web_state);
   }
@@ -134,7 +138,10 @@
     BreadcrumbManagerTabHelper::CreateForWebState(web_state);
   }
 
-  MobileConfigTabHelper::CreateForWebState(web_state);
+  if (base::FeatureList::IsEnabled(kDownloadVcard)) {
+    VcardTabHelper::CreateForWebState(web_state);
+  }
+
   SafeBrowsingQueryManager::CreateForWebState(web_state);
   SafeBrowsingTabHelper::CreateForWebState(web_state);
   SafeBrowsingUrlAllowList::CreateForWebState(web_state);
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 720247b..bda0bff 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -56,8 +56,10 @@
 #import "ios/chrome/browser/ui/default_promo/default_promo_non_modal_presentation_delegate.h"
 #import "ios/chrome/browser/ui/default_promo/tailored_promo_coordinator.h"
 #import "ios/chrome/browser/ui/download/ar_quick_look_coordinator.h"
+#import "ios/chrome/browser/ui/download/features.h"
 #import "ios/chrome/browser/ui/download/mobileconfig_coordinator.h"
 #import "ios/chrome/browser/ui/download/pass_kit_coordinator.h"
+#import "ios/chrome/browser/ui/download/vcard_coordinator.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
@@ -162,6 +164,9 @@
 // Presents a SFSafariViewController in order to download .mobileconfig file.
 @property(nonatomic, strong) MobileConfigCoordinator* mobileConfigCoordinator;
 
+// Opens downloaded Vcard.
+@property(nonatomic, strong) VcardCoordinator* vcardCoordinator;
+
 // Weak reference for the next coordinator to be displayed over the toolbar.
 @property(nonatomic, weak) ChromeCoordinator* nextToolbarCoordinator;
 
@@ -430,6 +435,13 @@
                          browser:self.browser];
   [self.mobileConfigCoordinator start];
 
+  if (base::FeatureList::IsEnabled(kDownloadVcard)) {
+    self.vcardCoordinator =
+        [[VcardCoordinator alloc] initWithBaseViewController:self.viewController
+                                                     browser:self.browser];
+    [self.vcardCoordinator start];
+  }
+
   self.passKitCoordinator =
       [[PassKitCoordinator alloc] initWithBaseViewController:self.viewController
                                                      browser:self.browser];
@@ -495,6 +507,9 @@
   [self.mobileConfigCoordinator stop];
   self.mobileConfigCoordinator = nil;
 
+  [self.vcardCoordinator stop];
+  self.vcardCoordinator = nil;
+
   [self.pageInfoCoordinator stop];
   self.pageInfoCoordinator = nil;
 
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index a452806..b1f5061 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -25,6 +25,8 @@
     "pass_kit_coordinator.mm",
     "radial_progress_view.h",
     "radial_progress_view.mm",
+    "vcard_coordinator.h",
+    "vcard_coordinator.mm",
   ]
   deps = [
     "resources:background_compact",
@@ -82,6 +84,7 @@
     "download_manager_view_controller_unittest.mm",
     "mobileconfig_coordinator_unittest.mm",
     "pass_kit_coordinator_unittest.mm",
+    "vcard_coordinator_unittest.mm",
   ]
   deps = [
     ":download",
diff --git a/ios/chrome/browser/ui/download/vcard_coordinator.h b/ios/chrome/browser/ui/download/vcard_coordinator.h
new file mode 100644
index 0000000..a00c18d0
--- /dev/null
+++ b/ios/chrome/browser/ui/download/vcard_coordinator.h
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_DOWNLOAD_VCARD_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_DOWNLOAD_VCARD_COORDINATOR_H_
+
+#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+
+// Opens downloaded Vcard.
+@interface VcardCoordinator : ChromeCoordinator
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_DOWNLOAD_VCARD_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/download/vcard_coordinator.mm b/ios/chrome/browser/ui/download/vcard_coordinator.mm
new file mode 100644
index 0000000..44a9786
--- /dev/null
+++ b/ios/chrome/browser/ui/download/vcard_coordinator.mm
@@ -0,0 +1,66 @@
+// 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 "ios/chrome/browser/ui/download/vcard_coordinator.h"
+
+#include "base/scoped_observation.h"
+#import "ios/chrome/browser/download/vcard_tab_helper.h"
+#import "ios/chrome/browser/download/vcard_tab_helper_delegate.h"
+#import "ios/chrome/browser/main/browser.h"
+#import "ios/chrome/browser/web_state_list/web_state_dependency_installer_bridge.h"
+#import "ios/web/public/web_state_observer_bridge.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface VcardCoordinator () <DependencyInstalling, VcardTabHelperDelegate> {
+  // Bridge which observes WebStateList and alerts this coordinator when this
+  // needs to register the Mediator with a new WebState.
+  std::unique_ptr<WebStateDependencyInstallerBridge> _dependencyInstallerBridge;
+}
+
+@end
+
+@implementation VcardCoordinator
+
+- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
+                                   browser:(Browser*)browser {
+  if (self = [super initWithBaseViewController:baseViewController
+                                       browser:browser]) {
+    _dependencyInstallerBridge =
+        std::make_unique<WebStateDependencyInstallerBridge>(
+            self, browser->GetWebStateList());
+  }
+  return self;
+}
+
+- (void)stop {
+  // Reset this observer manually. We want this to go out of scope now, to
+  // ensure it detaches before |browser| and its WebStateList get destroyed.
+  _dependencyInstallerBridge.reset();
+}
+
+#pragma mark - DependencyInstalling methods
+
+- (void)installDependencyForWebState:(web::WebState*)webState {
+  if (VcardTabHelper::FromWebState(webState)) {
+    VcardTabHelper::FromWebState(webState)->set_delegate(self);
+  }
+}
+
+- (void)uninstallDependencyForWebState:(web::WebState*)webState {
+  if (VcardTabHelper::FromWebState(webState)) {
+    VcardTabHelper::FromWebState(webState)->set_delegate(nil);
+  }
+}
+
+#pragma mark - VcardTabHelperDelegate
+
+- (void)openVcardFromData:(NSData*)vcardData {
+  DCHECK(vcardData);
+  // TODO(crbug.com/1244002): Open Vcard with CNContactVCardSerialization.
+}
+
+@end
diff --git a/ios/chrome/browser/ui/download/vcard_coordinator_unittest.mm b/ios/chrome/browser/ui/download/vcard_coordinator_unittest.mm
new file mode 100644
index 0000000..9defa26
--- /dev/null
+++ b/ios/chrome/browser/ui/download/vcard_coordinator_unittest.mm
@@ -0,0 +1,70 @@
+// 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 "ios/chrome/browser/ui/download/vcard_coordinator.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#import "ios/chrome/browser/download/vcard_tab_helper.h"
+#import "ios/chrome/browser/download/vcard_tab_helper_delegate.h"
+#import "ios/chrome/browser/main/test_browser.h"
+#import "ios/chrome/browser/ui/download/features.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.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/chrome/test/scoped_key_window.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for VcardCoordinatorTest class.
+class VcardCoordinatorTest : public PlatformTest {
+ protected:
+  VcardCoordinatorTest()
+      : browser_(std::make_unique<TestBrowser>()),
+        coordinator_([[VcardCoordinator alloc]
+            initWithBaseViewController:nil
+                               browser:browser_.get()]) {
+    [scoped_key_window_.Get() setRootViewController:nil];
+    feature_list_.InitAndEnableFeature(kDownloadVcard);
+
+    [coordinator_ start];
+  }
+
+  ~VcardCoordinatorTest() override { [coordinator_ stop]; }
+
+  // Needed for test browser state created by TestBrowser().
+  base::test::TaskEnvironment task_environment_;
+
+  base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<Browser> browser_;
+  VcardCoordinator* coordinator_;
+  ScopedKeyWindow scoped_key_window_;
+};
+
+// Tests that the coordinator installs itself as a VcardTabHelper delegate when
+// VcardTabHelper instances become available.
+TEST_F(VcardCoordinatorTest, InstallDelegates) {
+  // Coordinator should install itself as delegate for a new web state.
+  auto web_state2 = std::make_unique<web::FakeWebState>();
+  auto* web_state_ptr2 = web_state2.get();
+  VcardTabHelper::CreateForWebState(web_state_ptr2);
+  EXPECT_FALSE(VcardTabHelper::FromWebState(web_state_ptr2)->delegate());
+  browser_->GetWebStateList()->InsertWebState(0, std::move(web_state2),
+                                              WebStateList::INSERT_NO_FLAGS,
+                                              WebStateOpener());
+  EXPECT_TRUE(VcardTabHelper::FromWebState(web_state_ptr2)->delegate());
+
+  // Coordinator should install itself as delegate for a web state replacing an
+  // existing one.
+  auto web_state3 = std::make_unique<web::FakeWebState>();
+  auto* web_state_ptr3 = web_state3.get();
+  VcardTabHelper::CreateForWebState(web_state_ptr3);
+  EXPECT_FALSE(VcardTabHelper::FromWebState(web_state_ptr3)->delegate());
+  browser_->GetWebStateList()->ReplaceWebStateAt(0, std::move(web_state3));
+  EXPECT_TRUE(VcardTabHelper::FromWebState(web_state_ptr3)->delegate());
+}
diff --git a/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm b/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
index 3d34061..d1ed8bf 100644
--- a/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
+++ b/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
@@ -257,9 +257,8 @@
     return NO;
   }
 
-  if (self.sceneState.presentingModalOverlay) {
-    // Return NO when the scene cannot present views because it is blocked by
-    // the modal overlay.
+  if (self.sceneState.appState.currentUIBlocker) {
+    // Return NO when the scene cannot present views because it is blocked.
     return NO;
   }
 
diff --git a/ios/chrome/browser/ui/passwords/password_breach_consumer.h b/ios/chrome/browser/ui/passwords/password_breach_consumer.h
index b83b6f9..2cf081e 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_consumer.h
+++ b/ios/chrome/browser/ui/passwords/password_breach_consumer.h
@@ -13,8 +13,9 @@
 
 // Sets the respective state in the consumer.
 - (void)setTitleString:(NSString*)titleString
-         subtitleString:(NSString*)subtitleString
-    primaryActionString:(NSString*)primaryActionString;
+           subtitleString:(NSString*)subtitleString
+      primaryActionString:(NSString*)primaryActionString
+    secondaryActionString:(NSString*)secondaryActionString;
 
 @end
 
diff --git a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
index 203af909..aeebcefb 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
@@ -8,11 +8,14 @@
 #include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/passwords/password_breach_consumer.h"
 #import "ios/chrome/browser/ui/passwords/password_breach_presenter.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -36,6 +39,9 @@
 // Leak type of the dialog.
 @property(nonatomic, assign) LeakDialogType leakType;
 
+// Credential leak type of the dialog.
+@property(nonatomic, assign) CredentialLeakType credentialLeakType;
+
 // Dismiss reason, used for metrics.
 @property(nonatomic, assign) LeakDialogDismissalReason dismissReason;
 
@@ -52,17 +58,39 @@
   self = [super init];
   if (self) {
     _presenter = presenter;
+    _credentialLeakType = leakType;
     _leakType = GetLeakDialogType(leakType);
     _dismissReason = LeakDialogDismissalReason::kNoDirectInteraction;
 
-    NSString* subtitle = SysUTF16ToNSString(GetDescription(leakType));
-    NSString* primaryActionString =
-        ShouldCheckPasswords(leakType)
-            ? SysUTF16ToNSString(GetAcceptButtonLabel(leakType))
-            : nil;
-    [consumer setTitleString:SysUTF16ToNSString(GetTitle(leakType))
-              subtitleString:subtitle
-         primaryActionString:primaryActionString];
+    if (base::FeatureList::IsEnabled(
+            password_manager::features::
+                kIOSEnablePasswordManagerBrandingUpdate)) {
+      NSString* subtitle = SysUTF16ToNSString(GetDescription(leakType));
+      NSString* primaryActionString =
+          ShouldCheckPasswords(leakType)
+              ? SysUTF16ToNSString(GetAcceptButtonLabel(leakType))
+              : l10n_util::GetNSString(
+                    IDS_IOS_PASSWORD_LEAK_CHANGE_CREDENTIALS);
+
+      NSString* secondaryActionString =
+          ShouldCheckPasswords(leakType) ? l10n_util::GetNSString(IDS_NOT_NOW)
+                                         : nil;
+
+      [consumer setTitleString:SysUTF16ToNSString(GetTitle(leakType))
+                 subtitleString:subtitle
+            primaryActionString:primaryActionString
+          secondaryActionString:secondaryActionString];
+    } else {
+      NSString* subtitle = SysUTF16ToNSString(GetDescription(leakType));
+      NSString* primaryActionString =
+          ShouldCheckPasswords(leakType)
+              ? SysUTF16ToNSString(GetAcceptButtonLabel(leakType))
+              : nil;
+      [consumer setTitleString:SysUTF16ToNSString(GetTitle(leakType))
+                 subtitleString:subtitle
+            primaryActionString:primaryActionString
+          secondaryActionString:nil];
+    }
   }
   return self;
 }
@@ -79,10 +107,14 @@
 }
 
 - (void)confirmationAlertPrimaryAction {
-  self.dismissReason = LeakDialogDismissalReason::kClickedCheckPasswords;
-  // Opening Password page will stop the presentation in the presenter.
-  // No need to send |stop|.
-  [self.presenter startPasswordCheck];
+  if (ShouldCheckPasswords(self.credentialLeakType)) {
+    self.dismissReason = LeakDialogDismissalReason::kClickedCheckPasswords;
+    // Opening Password page will stop the presentation in the presenter.
+    // No need to send |stop|.
+    [self.presenter startPasswordCheck];
+  } else {
+    [self confirmationAlertDismissAction];
+  }
 }
 
 - (void)confirmationAlertSecondaryAction {
diff --git a/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm b/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
index 56dd314..e98e016 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/passwords/password_breach_view_controller.h"
 
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/passwords/password_constants.h"
 #import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -35,9 +34,7 @@
           password_manager::features::
               kIOSEnablePasswordManagerBrandingUpdate)) {
     self.image = [UIImage imageNamed:@"password_breach_illustration"];
-    self.secondaryActionString = l10n_util::GetNSString(IDS_NOT_NOW);
     self.showDismissBarButton = NO;
-    self.pinSpecificContentAboveButton = YES;
 
     UIImageView* imageView = [[UIImageView alloc]
         initWithImage:[UIImage imageNamed:@"passwords_logo_colored"]];
@@ -47,8 +44,7 @@
 
     [NSLayoutConstraint activateConstraints:@[
       [imageView.topAnchor
-          constraintGreaterThanOrEqualToAnchor:self.specificContentView
-                                                   .topAnchor],
+          constraintEqualToAnchor:self.specificContentView.topAnchor],
       [imageView.centerXAnchor
           constraintEqualToAnchor:self.specificContentView.centerXAnchor],
       [imageView.widthAnchor constraintLessThanOrEqualToConstant:kLogoWidth],
@@ -71,11 +67,13 @@
 #pragma mark - PasswordBreachConsumer
 
 - (void)setTitleString:(NSString*)titleString
-         subtitleString:(NSString*)subtitleString
-    primaryActionString:(NSString*)primaryActionString {
+           subtitleString:(NSString*)subtitleString
+      primaryActionString:(NSString*)primaryActionString
+    secondaryActionString:(NSString*)secondaryActionString {
   self.titleString = titleString;
   self.subtitleString = subtitleString;
   self.primaryActionString = primaryActionString;
+  self.secondaryActionString = secondaryActionString;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
index e9ad4244..118eea2 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
@@ -69,3 +69,54 @@
     "//testing/gtest:gtest",
   ]
 }
+
+source_set("eg_app_support+eg2") {
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+  sources = [
+    "passwords_in_other_apps_app_interface.h",
+    "passwords_in_other_apps_app_interface.mm",
+  ]
+  deps = [
+    "//base/test:test_support",
+    "//ios/chrome/test/fakes",
+    "//ios/testing/earl_grey:eg_app_support+eg2",
+  ]
+}
+
+source_set("eg_test_support+eg2") {
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+  sources = [
+    "passwords_in_other_apps_app_interface.h",
+    "passwords_in_other_apps_app_interface_stub.mm",
+  ]
+  deps = [ "//ios/third_party/earl_grey2:test_lib" ]
+}
+
+source_set("eg2_tests") {
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+  sources = [ "passwords_in_other_apps_egtest.mm" ]
+  deps = [
+    ":constants",
+    ":eg_test_support+eg2",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui:feature_flags",
+    "//ios/chrome/browser/ui/settings/password:password_constants",
+    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/testing/earl_grey:eg_test_support+eg2",
+    "//ios/third_party/earl_grey2:test_lib",
+    "//ui/base",
+  ]
+  frameworks = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.h b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.h
index 97deecf60..19dd98a 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.h
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.h
@@ -16,6 +16,9 @@
 // A11y Identifier for subtitle label.
 extern NSString* const kPasswordsInOtherAppsSubtitleAccessibilityIdentifier;
 
+// A11y Identifier for banner image.
+extern NSString* const kPasswordsInOtherAppsImageAccessibilityIdentifier;
+
 // A11y Identifier for the action button.
 extern NSString* const kPasswordsInOtherAppsActionAccessibilityIdentifier;
 
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.mm
index 70e8c6d..059792e 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.mm
@@ -15,6 +15,8 @@
     @"kPasswordsInOtherAppsTitleAccessibilityIdentifier";
 NSString* const kPasswordsInOtherAppsSubtitleAccessibilityIdentifier =
     @"kPasswordsInOtherAppsSubtitleAccessibilityIdentifier";
+NSString* const kPasswordsInOtherAppsImageAccessibilityIdentifier =
+    @"kPasswordsInOtherAppsImageAccessibilityIdentifier";
 NSString* const kPasswordsInOtherAppsActionAccessibilityIdentifier =
     @"kPasswordsInOtherAppsActionAccessibilityIdentifier";
 NSString* const kPasswordsInOtherAppsScrollViewAccessibilityIdentifier =
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h
new file mode 100644
index 0000000..b69cc99
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h
@@ -0,0 +1,37 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORDS_IN_OTHER_APPS_PASSWORDS_IN_OTHER_APPS_APP_INTERFACE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORDS_IN_OTHER_APPS_PASSWORDS_IN_OTHER_APPS_APP_INTERFACE_H_
+
+#import <Foundation/Foundation.h>
+
+// Bridges passwords_in_other_apps_egtest.mm to
+// FakePasswordAutoFillStatusManager.
+@interface PasswordsInOtherAppsAppInterface : NSObject
+
+#pragma mark - Swizzling
+
+// Returns the block to use for swizzling the PasswordAutoFillStatusManager.
+// This block is only used for swizzling, which is why its type is opaque. It
+// should not be called directly.
++ (id)swizzlePasswordAutoFillStatusManagerWithFake;
+
+#pragma mark - Mocking and Expectations
+
+// Mocks the scenario that the app has retrieved the current state of device
+// auto-fill status.
+// |isEnabled|: whether auto-fill with Chrome is enabled or not.
++ (void)startFakeManagerWithAutoFillStatus:(BOOL)autoFillEnabled;
+
+// Explicitly sets auto-fill status.
+// |autoFillEnabled|: whether auto-fill with Chrome should be.
++ (void)setAutoFillStatus:(BOOL)autoFillEnabled;
+
+// Resets the manager.
++ (void)resetManager;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORDS_IN_OTHER_APPS_PASSWORDS_IN_OTHER_APPS_APP_INTERFACE_H_
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.mm
new file mode 100644
index 0000000..c35a9d1
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.mm
@@ -0,0 +1,43 @@
+// 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 "ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h"
+
+#import "ios/chrome/test/fakes/fake_password_auto_fill_status_manager.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation PasswordsInOtherAppsAppInterface
+
++ (FakePasswordAutoFillStatusManager*)manager {
+  return [FakePasswordAutoFillStatusManager sharedFakeManager];
+}
+
+#pragma mark - Swizzling
+
++ (id)swizzlePasswordAutoFillStatusManagerWithFake {
+  FakePasswordAutoFillStatusManager* (^swizzlePasswordAutoFillManagerBlock)(
+      void) = ^{
+    return [self manager];
+  };
+  return swizzlePasswordAutoFillManagerBlock;
+}
+
+#pragma mark - Mocking and Expectations
+
++ (void)startFakeManagerWithAutoFillStatus:(BOOL)autoFillEnabled {
+  [[self manager] startFakeManagerWithAutoFillStatus:autoFillEnabled];
+}
+
++ (void)setAutoFillStatus:(BOOL)autoFillEnabled {
+  [[self manager] setAutoFillStatus:autoFillEnabled];
+}
+
++ (void)resetManager {
+  [[self manager] reset];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface_stub.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface_stub.mm
new file mode 100644
index 0000000..3d6a167
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface_stub.mm
@@ -0,0 +1,13 @@
+// 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 "ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h"
+
+#import <TestLib/EarlGreyImpl/EarlGrey.h>
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(PasswordsInOtherAppsAppInterface)
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_egtest.mm
new file mode 100644
index 0000000..c0fa1d7e
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_egtest.mm
@@ -0,0 +1,302 @@
+// 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 <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/settings/password/passwords_in_other_apps/constants.h"
+#import "ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_app_interface.h"
+#import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
+#include "ios/chrome/grit/ios_google_chrome_strings.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/chrome/test/earl_grey/earl_grey_scoped_block_swizzler.h"
+#import "ios/testing/earl_grey/earl_grey_test.h"
+#import "ui/base/device_form_factor.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using chrome_test_util::SettingsDoneButton;
+using chrome_test_util::SettingsMenuBackButton;
+
+namespace {
+// Matcher for view
+id<GREYMatcher> PasswordsInOtherAppsViewMatcher() {
+  return grey_accessibilityID(kPasswordsInOtherAppsViewAccessibilityIdentifier);
+}
+
+// Matcher for title.
+id<GREYMatcher> PasswordsInOtherAppsTitleMatcher() {
+  return grey_accessibilityID(
+      kPasswordsInOtherAppsTitleAccessibilityIdentifier);
+}
+
+// Matcher for subtitle.
+id<GREYMatcher> PasswordsInOtherAppsSubtitleMatcher() {
+  return grey_accessibilityID(
+      kPasswordsInOtherAppsSubtitleAccessibilityIdentifier);
+}
+
+// Matcher for banner image.
+id<GREYMatcher> PasswordsInOtherAppsImageMatcher() {
+  return grey_accessibilityID(
+      kPasswordsInOtherAppsImageAccessibilityIdentifier);
+}
+
+// Matcher for the cell item in Password Settings page.
+id<GREYMatcher> PasswordsInOtherAppsListItemMatcher() {
+  return grey_accessibilityID(kSettingsPasswordsInOtherAppsCellId);
+}
+
+// Matcher for turn off instructions.
+id<GREYMatcher> PasswordsInOtherAppsTurnOffInstruction() {
+  NSString* turnOffInstructionText =
+      @"To turn off, open Settings and go to Passwords.";
+  return grey_text(turnOffInstructionText);
+}
+
+// Matcher for the Show password button in Password Details view.
+id<GREYMatcher> OpenSettingsButton() {
+  return grey_accessibilityID(
+      kPasswordsInOtherAppsActionAccessibilityIdentifier);
+}
+
+// Action to open the Passwords in Other Apps modal from Chrome root view.
+void OpensPasswordsInOtherApps() {
+  [ChromeEarlGreyUI openSettingsMenu];
+  [ChromeEarlGreyUI
+      tapSettingsMenuButton:chrome_test_util::SettingsMenuPasswordsButton()];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsListItemMatcher()]
+      performAction:grey_tap()];
+}
+}  // namespace
+
+// This test tests overall behaviors and interactions of Passwords In Other Apps
+// view controller.
+@interface PasswordsInOtherAppsTestCase : ChromeTestCase
+@end
+
+@implementation PasswordsInOtherAppsTestCase {
+  // A swizzler to observe fake auto-fill status instead of real one.
+  std::unique_ptr<EarlGreyScopedBlockSwizzler> _passwordAutoFillStatusSwizzler;
+}
+
+- (void)setUp {
+  [super setUp];
+  _passwordAutoFillStatusSwizzler =
+      std::make_unique<EarlGreyScopedBlockSwizzler>(
+          @"PasswordAutoFillStatusManager", @"sharedManager",
+          [PasswordsInOtherAppsAppInterface
+              swizzlePasswordAutoFillStatusManagerWithFake]);
+}
+
+- (void)tearDown {
+  [super tearDown];
+  [PasswordsInOtherAppsAppInterface resetManager];
+  _passwordAutoFillStatusSwizzler.reset();
+}
+
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config;
+  config.features_enabled.push_back(kCredentialProviderExtensionPromo);
+  return config;
+}
+
+#pragma mark - helper functions
+
+// Tests that the banner image, title and subtitle are visible.
+- (void)checkThatCommonElementsAreVisible {
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsTitleMatcher()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsSubtitleMatcher()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsImageMatcher()]
+      assertWithMatcher:grey_minimumVisiblePercent(0.2)];
+}
+
+// Tests that instructions to turn on Chrome auto-fill is visible.
+- (void)checkThatTurnOnInstructionsAreVisible {
+  NSArray<NSString*>* steps = @[
+    ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
+        ? l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPAD)
+        : l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPHONE),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_2),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_3),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_4)
+  ];
+  for (NSString* step in steps) {
+    [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(step)]
+        assertWithMatcher:grey_sufficientlyVisible()];
+  }
+  [[EarlGrey selectElementWithMatcher:OpenSettingsButton()]
+      assertWithMatcher:grey_notVisible()];
+}
+
+// Tests that instructions to turn on Chrome auto-fill is invisible.
+- (void)checkThatTurnOnInstructionsAreNotVisible {
+  NSArray<NSString*>* steps = @[
+    ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
+        ? l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPAD)
+        : l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPHONE),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_2),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_3),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_4)
+  ];
+  for (NSString* step in steps) {
+    [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(step)]
+        assertWithMatcher:grey_notVisible()];
+  }
+}
+
+// Tests that instructions to turn off Chrome auto-fill is visible.
+- (void)checkThatTurnOffInstructionsAreVisible {
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsTurnOffInstruction()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+// Tests that instructions to turn off Chrome auto-fill is invisible.
+- (void)checkThatTurnOffInstructionsAreNotVisible {
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsTurnOffInstruction()]
+      assertWithMatcher:grey_notVisible()];
+}
+
+#pragma mark - Test cases
+
+// Tests Passwords In Other Apps first shows instructions when auto-fill is off,
+// then shows the caption label after auto-fill is turned on.
+- (void)testTurnOnPasswordsInOtherApps {
+  [PasswordsInOtherAppsAppInterface startFakeManagerWithAutoFillStatus:NO];
+  OpensPasswordsInOtherApps();
+
+  [self checkThatCommonElementsAreVisible];
+  [self checkThatTurnOnInstructionsAreVisible];
+  [self checkThatTurnOffInstructionsAreNotVisible];
+
+  [PasswordsInOtherAppsAppInterface setAutoFillStatus:YES];
+
+  [self checkThatTurnOnInstructionsAreNotVisible];
+  [self checkThatTurnOffInstructionsAreVisible];
+}
+
+// Tests Passwords In Other Apps first shows instructions when auto-fill is on,
+// then shows the caption label after auto-fill is turned off.
+- (void)testTurnOffPasswordsInOtherApps {
+  [PasswordsInOtherAppsAppInterface startFakeManagerWithAutoFillStatus:YES];
+  OpensPasswordsInOtherApps();
+
+  [self checkThatCommonElementsAreVisible];
+  [self checkThatTurnOffInstructionsAreVisible];
+  [self checkThatTurnOnInstructionsAreNotVisible];
+
+  [PasswordsInOtherAppsAppInterface setAutoFillStatus:NO];
+
+  [self checkThatTurnOffInstructionsAreNotVisible];
+  [self checkThatTurnOnInstructionsAreVisible];
+}
+
+// Tests Passwords In Other Apps shows instructions when auto-fill is off with
+// short instruction.
+- (void)testShowPasswordsInOtherAppsWithShortInstruction {
+  // Rewrites passwordInAppsViewController.useShortInstruction property.
+  EarlGreyScopedBlockSwizzler shortInstruction(
+      @"PasswordsInOtherAppsViewController", @"useShortInstruction", ^{
+        return YES;
+      });
+
+  [PasswordsInOtherAppsAppInterface startFakeManagerWithAutoFillStatus:NO];
+  OpensPasswordsInOtherApps();
+  // Check both turn off instructions and default turn on instructions aren't
+  // visible.
+  [self checkThatCommonElementsAreVisible];
+  [self checkThatTurnOnInstructionsAreNotVisible];
+  [self checkThatTurnOffInstructionsAreNotVisible];
+
+  // Check backup instructions are visible.
+  NSArray<NSString*>* steps = @[
+    l10n_util::GetNSString(
+        IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_1),
+    l10n_util::GetNSString(
+        IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_2)
+  ];
+  for (NSString* step in steps) {
+    [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(step)]
+        assertWithMatcher:grey_sufficientlyVisible()];
+  }
+  [[EarlGrey selectElementWithMatcher:OpenSettingsButton()]
+      assertWithMatcher:grey_interactable()];
+}
+
+// Tests Passwords In Other Apps shows instructions when auto-fill state is
+// unknown.
+- (void)testOpenPasswordsInOtherAppsWithAutoFillUnknown {
+  OpensPasswordsInOtherApps();
+
+  [self checkThatCommonElementsAreVisible];
+  [self checkThatTurnOnInstructionsAreVisible];
+  [self checkThatTurnOffInstructionsAreNotVisible];
+  [[EarlGrey
+      selectElementWithMatcher:grey_kindOfClassName(@"UIActivityIndicatorView")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Simulate status retrieved.
+  [PasswordsInOtherAppsAppInterface startFakeManagerWithAutoFillStatus:NO];
+  [[EarlGrey
+      selectElementWithMatcher:grey_kindOfClassName(@"UIActivityIndicatorView")]
+      assertWithMatcher:grey_notVisible()];
+}
+
+// Tests Passwords In Other Apps dismisses itself when top right "done" button
+// is tapped.
+- (void)testTapPasswordsInOtherAppsDoneButtonToDismiss {
+  OpensPasswordsInOtherApps();
+  [self checkThatCommonElementsAreVisible];
+  // Taps done button and check settings dismissed.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsViewMatcher()]
+      assertWithMatcher:grey_notVisible()];
+}
+
+// Tests Passwords In Other Apps dismisses itself when the user swipes down.
+- (void)testSwipeDownPasswordsInOtherAppsToDismiss {
+  OpensPasswordsInOtherApps();
+  [self checkThatCommonElementsAreVisible];
+  // Swipes down and check settings dismissed.
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsViewMatcher()]
+      performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsViewMatcher()]
+      assertWithMatcher:grey_notVisible()];
+}
+
+// Tests Passwords In Other Apps doesn't show the image on iPhone landscape
+// mode, while showing it for iPad.
+- (void)testImageVisibilityForLandscapeMode {
+  OpensPasswordsInOtherApps();
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsImageMatcher()]
+      assertWithMatcher:grey_minimumVisiblePercent(0.2)];
+  [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft
+                                error:nil];
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE) {
+    [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsImageMatcher()]
+        assertWithMatcher:grey_notVisible()];
+  } else {
+    [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsImageMatcher()]
+        assertWithMatcher:grey_minimumVisiblePercent(0.2)];
+  }
+  [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait error:nil];
+  [[EarlGrey selectElementWithMatcher:PasswordsInOtherAppsImageMatcher()]
+      assertWithMatcher:grey_minimumVisiblePercent(0.2)];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
index a7ba9bb..ee726019 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
@@ -324,6 +324,8 @@
         [[UIImageView alloc] initWithImage:[self createOrUpdateImage:nil]];
     _imageView.clipsToBounds = YES;
     _imageView.translatesAutoresizingMaskIntoConstraints = NO;
+    _imageView.accessibilityIdentifier =
+        kPasswordsInOtherAppsImageAccessibilityIdentifier;
   }
   return _imageView;
 }
diff --git a/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h b/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h
index 34a4ab0..4b4f9d5 100644
--- a/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h
+++ b/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h
@@ -12,7 +12,7 @@
 // observers on change.
 @interface PasswordAutoFillStatusManager : NSObject
 
-// Designated initializer for PasswordAutofillStatusManager.
+// The shared instance PasswordAutofillStatusManager.
 + (PasswordAutoFillStatusManager*)sharedManager;
 
 // Adds observer that registers auto-fill status updates.
diff --git a/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.mm b/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.mm
index 229bb2b1..42fec4c 100644
--- a/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.mm
+++ b/ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.mm
@@ -45,9 +45,9 @@
 }
 
 - (void)addObserver:(id<PasswordAutoFillStatusObserver>)observer {
-  [_observers addObject:observer];
+  [self.observers addObject:observer];
   [self checkAndUpdatePasswordAutoFillStatus];
-  if (_observers.count == 1) {
+  if (self.observers.count == 1) {
     [[NSNotificationCenter defaultCenter]
         addObserver:self
            selector:@selector(applicationWillEnterForeground:)
@@ -57,9 +57,9 @@
 }
 
 - (void)removeObserver:(id<PasswordAutoFillStatusObserver>)observer {
-  [_observers removeObject:observer];
-  if (_observers.count == 0) {
-    _ready = NO;
+  [self.observers removeObject:observer];
+  if (self.observers.count == 0) {
+    self.ready = NO;
     [[NSNotificationCenter defaultCenter]
         removeObserver:self
                   name:UIApplicationWillEnterForegroundNotification
diff --git a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
index ff83e6f..9d83c8e 100644
--- a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
+++ b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h
@@ -90,11 +90,6 @@
 // should add their UI elements to it, before the VC is loaded.
 @property(nonatomic, strong, readonly) UIView* specificContentView;
 
-// If NO (default) the scroll view is centered. If YES, the scroll view is no
-// longer centered and UI element in |specificContentView| can be constrained to
-// be to just above the buttons. Must be set before the VC is loaded.
-@property(nonatomic) BOOL pinSpecificContentAboveButton;
-
 @end
 
 #endif  // IOS_CHROME_COMMON_UI_CONFIRMATION_ALERT_CONFIRMATION_ALERT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.mm b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.mm
index c04b52e..a8b6f277 100644
--- a/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.mm
+++ b/ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.mm
@@ -93,9 +93,15 @@
   UIStackView* stackView =
       [self createStackViewWithArrangedSubviews:stackSubviews];
 
+  // UIView that wraps the scrollable content. Needed in order to pin UI
+  // elements in view specific content above actions buttons.
+  UIView* scrollContentView = [[UIView alloc] init];
+  scrollContentView.translatesAutoresizingMaskIntoConstraints = NO;
+
   UIScrollView* scrollView = [self createScrollView];
-  [scrollView addSubview:stackView];
-  [scrollView addSubview:self.specificContentView];
+  [scrollContentView addSubview:stackView];
+  [scrollContentView addSubview:self.specificContentView];
+  [scrollView addSubview:scrollContentView];
   [self.view addSubview:scrollView];
 
   self.view.preservesSuperviewLayoutMargins = YES;
@@ -112,30 +118,6 @@
   // the content area. No need to contraint horizontally as we don't want
   // horizontal scroll.
   [NSLayoutConstraint activateConstraints:@[
-    [stackView.topAnchor constraintEqualToAnchor:scrollView.topAnchor],
-    [stackView.bottomAnchor
-        constraintEqualToAnchor:self.specificContentView.topAnchor
-                       constant:-kScrollViewBottomInsets],
-
-    [self.specificContentView.bottomAnchor
-        constraintEqualToAnchor:scrollView.bottomAnchor],
-    [self.specificContentView.centerXAnchor
-        constraintEqualToAnchor:self.view.centerXAnchor],
-    [self.specificContentView.widthAnchor
-        constraintLessThanOrEqualToAnchor:scrollView.widthAnchor],
-  ]];
-
-  // Scroll View constraints to the height of its content. This allows to center
-  // the scroll view.
-  NSLayoutConstraint* heightConstraint = [scrollView.heightAnchor
-      constraintEqualToAnchor:scrollView.contentLayoutGuide.heightAnchor];
-  // UILayoutPriorityDefaultHigh is the default priority for content
-  // compression. Setting this lower avoids compressing the content of the
-  // scroll view.
-  heightConstraint.priority = UILayoutPriorityDefaultHigh - 1;
-  heightConstraint.active = YES;
-
-  [NSLayoutConstraint activateConstraints:@[
     [stackView.widthAnchor
         constraintLessThanOrEqualToConstant:kContentMaxWidth],
     [stackView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
@@ -144,6 +126,27 @@
     [stackView.widthAnchor
         constraintLessThanOrEqualToAnchor:margins.widthAnchor],
 
+    [stackView.topAnchor
+        constraintGreaterThanOrEqualToAnchor:scrollContentView.topAnchor],
+    [stackView.bottomAnchor
+        constraintLessThanOrEqualToAnchor:self.specificContentView.topAnchor
+                                 constant:-kScrollViewBottomInsets],
+
+    [self.specificContentView.bottomAnchor
+        constraintEqualToAnchor:scrollContentView.bottomAnchor],
+    [self.specificContentView.centerXAnchor
+        constraintEqualToAnchor:self.view.centerXAnchor],
+    [self.specificContentView.widthAnchor
+        constraintLessThanOrEqualToAnchor:scrollView.widthAnchor],
+
+    // Constrain its height to at least the scroll view height, so that derived
+    // VCs can pin UI elements just above the buttons.
+    [scrollContentView.topAnchor constraintEqualToAnchor:scrollView.topAnchor],
+    [scrollContentView.bottomAnchor
+        constraintEqualToAnchor:scrollView.bottomAnchor],
+    [scrollContentView.heightAnchor
+        constraintGreaterThanOrEqualToAnchor:scrollView.heightAnchor],
+
   ]];
 
   // Width Scroll View constraint for regular mode.
@@ -185,19 +188,9 @@
     scrollViewBottomAnchor = actionStackView.topAnchor;
   }
 
-  if (self.pinSpecificContentAboveButton &&
-      ([self.specificContentView.subviews count] > 0)) {
-    [scrollView.bottomAnchor constraintEqualToAnchor:scrollViewBottomAnchor
-                                            constant:-kScrollViewBottomInsets]
-        .active = YES;
-  } else {
-    [scrollView.bottomAnchor
-        constraintLessThanOrEqualToAnchor:scrollViewBottomAnchor
-                                 constant:-kScrollViewBottomInsets]
-        .active = YES;
-  }
-
   [NSLayoutConstraint activateConstraints:@[
+    [scrollView.bottomAnchor constraintEqualToAnchor:scrollViewBottomAnchor
+                                            constant:-kScrollViewBottomInsets],
     [scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
     [scrollView.trailingAnchor
         constraintEqualToAnchor:self.view.trailingAnchor],
@@ -211,24 +204,18 @@
     scrollViewTopAnchor = self.view.safeAreaLayoutGuide.topAnchor;
     scrollViewTopConstant = self.customSpacingBeforeImageIfNoToolbar;
   }
+
+  [scrollView.topAnchor constraintEqualToAnchor:scrollViewTopAnchor
+                                       constant:scrollViewTopConstant]
+      .active = YES;
+
   if (self.topAlignedLayout) {
-    [scrollView.topAnchor constraintEqualToAnchor:scrollViewTopAnchor
-                                         constant:scrollViewTopConstant]
+    [stackView.topAnchor constraintEqualToAnchor:scrollContentView.topAnchor]
         .active = YES;
   } else {
-    [scrollView.topAnchor
-        constraintGreaterThanOrEqualToAnchor:scrollViewTopAnchor
-                                    constant:scrollViewTopConstant]
+    [stackView.centerYAnchor
+        constraintEqualToAnchor:scrollContentView.centerYAnchor]
         .active = YES;
-
-    // Scroll View constraint to the vertical center.
-    NSLayoutConstraint* centerYConstraint = [scrollView.centerYAnchor
-        constraintEqualToAnchor:margins.centerYAnchor];
-    // This needs to be lower than the height constraint, so it's deprioritized.
-    // If this breaks, the scroll view is still constrained to the top toolbar
-    // and the bottom safe area or button.
-    centerYConstraint.priority = heightConstraint.priority - 1;
-    centerYConstraint.active = YES;
   }
 
   if (!self.imageHasFixedSize) {
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index b001ccc..1b81cd1 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -144,6 +144,7 @@
     "//ios/chrome/browser/ui/settings/language:eg_app_support+eg2",
     "//ios/chrome/browser/ui/settings/password:eg_app_support+eg2",
     "//ios/chrome/browser/ui/settings/password:password_constants",
+    "//ios/chrome/browser/ui/settings/password/passwords_in_other_apps:eg_app_support+eg2",
     "//ios/chrome/browser/ui/settings/privacy:privacy_ui",
     "//ios/chrome/browser/ui/settings/sync",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid:features",
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index ca61777..806cb45 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -129,6 +129,7 @@
     "//ios/chrome/browser/ui/settings/google_services:eg2_tests",
     "//ios/chrome/browser/ui/settings/language:eg2_tests",
     "//ios/chrome/browser/ui/settings/password:eg2_tests",
+    "//ios/chrome/browser/ui/settings/password/passwords_in_other_apps:eg2_tests",
     "//ios/chrome/browser/ui/settings/sync:eg2_tests",
   ]
   data_deps = [ ":ios_chrome_eg2tests" ]
diff --git a/ios/chrome/test/fakes/BUILD.gn b/ios/chrome/test/fakes/BUILD.gn
index 1d95ef9f..d9e4615 100644
--- a/ios/chrome/test/fakes/BUILD.gn
+++ b/ios/chrome/test/fakes/BUILD.gn
@@ -21,6 +21,8 @@
     "fake_overscroll_actions_controller_delegate.mm",
     "fake_pass_kit_tab_helper_delegate.h",
     "fake_pass_kit_tab_helper_delegate.mm",
+    "fake_password_auto_fill_status_manager.h",
+    "fake_password_auto_fill_status_manager.mm",
     "fake_store_kit_launcher.h",
     "fake_store_kit_launcher.mm",
     "fake_ui_view_controller.h",
@@ -39,6 +41,7 @@
     "//ios/chrome/browser/ui/download",
     "//ios/chrome/browser/ui/overscroll_actions",
     "//ios/chrome/browser/ui/presenters",
+    "//ios/chrome/browser/ui/settings/utils",
     "//ios/chrome/browser/web:web_internal",
     "//ios/chrome/browser/web_state_list",
     "//ios/web/public",
diff --git a/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.h b/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.h
new file mode 100644
index 0000000..a3d56c9
--- /dev/null
+++ b/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_TEST_FAKES_FAKE_PASSWORD_AUTO_FILL_STATUS_MANAGER_H_
+#define IOS_CHROME_TEST_FAKES_FAKE_PASSWORD_AUTO_FILL_STATUS_MANAGER_H_
+
+#import "ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h"
+
+// Substitute of the real PasswordAutoFillStatusManager that could update the UI
+// of observers accordingly without interacting with iOS API.
+@interface FakePasswordAutoFillStatusManager : PasswordAutoFillStatusManager
+
+// The shared instance MockPasswordAutofillStatusManager.
++ (FakePasswordAutoFillStatusManager*)sharedFakeManager;
+
+// Mocks the scenario that the app has retrieved the current state of device
+// auto-fill status.
+// |autoFillEnabled|: whether auto-fill with Chrome is enabled or not.
+- (void)startFakeManagerWithAutoFillStatus:(BOOL)autoFillEnabled;
+
+// Explicitly sets auto-fill status.
+// |autoFillEnabled|: whether auto-fill with Chrome should be.
+- (void)setAutoFillStatus:(BOOL)autoFillEnabled;
+
+// Resets the manager.
+- (void)reset;
+
+@end
+
+#endif  // IOS_CHROME_TEST_FAKES_FAKE_PASSWORD_AUTO_FILL_STATUS_MANAGER_H_
diff --git a/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.mm b/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.mm
new file mode 100644
index 0000000..add3a3d
--- /dev/null
+++ b/ios/chrome/test/fakes/fake_password_auto_fill_status_manager.mm
@@ -0,0 +1,71 @@
+// 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 "ios/chrome/test/fakes/fake_password_auto_fill_status_manager.h"
+#import "ios/chrome/browser/ui/settings/utils/password_auto_fill_status_observer.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// This interface declaration provides access to the super class's private
+// property self.observers.
+@interface PasswordAutoFillStatusManager ()
+@property(nonatomic, strong)
+    NSHashTable<id<PasswordAutoFillStatusObserver>>* observers;
+
+// Overwrite readonly properties in the header to be writable internally.
+@property(nonatomic, assign, readwrite) BOOL ready;
+@property(nonatomic, assign, readwrite) BOOL autoFillEnabled;
+@end
+
+@implementation FakePasswordAutoFillStatusManager
+
++ (FakePasswordAutoFillStatusManager*)sharedFakeManager {
+  static dispatch_once_t onceToken;
+  static FakePasswordAutoFillStatusManager* sharedManager = nil;
+  dispatch_once(&onceToken, ^{
+    sharedManager = [[FakePasswordAutoFillStatusManager alloc] init];
+  });
+  return sharedManager;
+}
+
+- (void)addObserver:(id<PasswordAutoFillStatusObserver>)observer {
+  [self.observers addObject:observer];
+}
+
+- (void)removeObserver:(id<PasswordAutoFillStatusObserver>)observer {
+  [self.observers removeObject:observer];
+}
+
+- (void)startFakeManagerWithAutoFillStatus:(BOOL)autoFillEnabled {
+  self.ready = YES;
+  self.autoFillEnabled = autoFillEnabled;
+  for (id<PasswordAutoFillStatusObserver> observer in self.observers) {
+    [observer passwordAutoFillStatusDidChange];
+  }
+}
+
+- (void)toggleAutoFillStatus {
+  self.autoFillEnabled = !self.autoFillEnabled;
+  for (id<PasswordAutoFillStatusObserver> observer in self.observers) {
+    [observer passwordAutoFillStatusDidChange];
+  }
+}
+
+- (void)setAutoFillStatus:(BOOL)autoFillEnabled {
+  if (self.autoFillEnabled != autoFillEnabled) {
+    self.autoFillEnabled = autoFillEnabled;
+    for (id<PasswordAutoFillStatusObserver> observer in self.observers) {
+      [observer passwordAutoFillStatusDidChange];
+    }
+  }
+}
+
+- (void)reset {
+  [self.observers removeAllObjects];
+  self.ready = NO;
+}
+
+@end
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 20d57a0..0698e94 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -91,7 +91,7 @@
   void GetCookieListWithOptionsAsync(
       const GURL& url,
       const net::CookieOptions& options,
-      const net::CookiePartitionKeychain& cookie_partition_keychain,
+      const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetAllCookiesCallback callback) override;
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index c1a1b118..c7e14519 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -282,7 +282,7 @@
 void CookieStoreIOS::GetCookieListWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
-    const net::CookiePartitionKeychain& cookie_partition_keychain,
+    const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
     GetCookieListCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -671,7 +671,7 @@
         &CookieStoreIOS::GotCookieListFor, weak_factory_.GetWeakPtr(), key);
     cookie_monster_->GetCookieListWithOptionsAsync(
         key.first, net::CookieOptions::MakeAllInclusive(),
-        net::CookiePartitionKeychain::Todo(), std::move(callback));
+        net::CookiePartitionKeyCollection::Todo(), std::move(callback));
   }
 }
 
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index 098b60b0..2db0bf8 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -154,7 +154,7 @@
     net::CookieOptions options;
     options.set_include_httponly();
     store_->GetCookieListWithOptionsAsync(kTestCookieURLFooBar, options,
-                                          net::CookiePartitionKeychain(),
+                                          net::CookiePartitionKeyCollection(),
                                           std::move(callback));
   }
 
@@ -349,7 +349,7 @@
   GetAllCookiesHelperCallback callback;
   cookie_store->GetCookieListWithOptionsAsync(
       kTestCookieURLFooBar, net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(),
+      net::CookiePartitionKeyCollection(),
       base::BindOnce(&GetAllCookiesHelperCallback::Run,
                      base::Unretained(&callback)));
   base::RunLoop().RunUntilIdle();
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index 1b4fa297..37354aa 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -149,6 +149,7 @@
     "data/http_server_files/two_pages.pdf",
     "data/http_server_files/user_agent_test_page.html",
     "data/http_server_files/username_password_field_form.html",
+    "data/http_server_files/vcard.vcf",
     "data/http_server_files/video_sample.mov",
     "data/http_server_files/window_close.html",
     "data/http_server_files/window_location.html",
diff --git a/ios/testing/data/http_server_files/vcard.vcf b/ios/testing/data/http_server_files/vcard.vcf
new file mode 100644
index 0000000..713cc60
--- /dev/null
+++ b/ios/testing/data/http_server_files/vcard.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD

+VERSION:3.0

+N:Chang;Mark

+FN:Mark Chang

+TEL;type=CELL:+1 (206) 7788078

+ORG:Google

+END:VCARD

diff --git a/ios/web/public/test/fakes/fake_cookie_store.cc b/ios/web/public/test/fakes/fake_cookie_store.cc
index 22d9ef64..32dae89 100644
--- a/ios/web/public/test/fakes/fake_cookie_store.cc
+++ b/ios/web/public/test/fakes/fake_cookie_store.cc
@@ -35,7 +35,7 @@
 void FakeCookieStore::GetCookieListWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
-    const net::CookiePartitionKeychain& cookie_partition_keychain,
+    const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
     GetCookieListCallback callback) {
   NOTIMPLEMENTED() << "Implement this if necessary.";
 }
diff --git a/ios/web/public/test/fakes/fake_cookie_store.h b/ios/web/public/test/fakes/fake_cookie_store.h
index 34ab871..50c72e7 100644
--- a/ios/web/public/test/fakes/fake_cookie_store.h
+++ b/ios/web/public/test/fakes/fake_cookie_store.h
@@ -30,7 +30,7 @@
   void GetCookieListWithOptionsAsync(
       const GURL& url,
       const net::CookieOptions& options,
-      const net::CookiePartitionKeychain& cookie_partition_keychain,
+      const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) override;
   void DeleteCanonicalCookieAsync(const net::CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
index c29fd670..f20e8d2 100644
--- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -1200,6 +1200,23 @@
       VLOG(1) << "JPEG Quality: max:" << queryctrl.maximum
               << ", min:" << queryctrl.minimum << ", value:" << quality;
       IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &ctrls);
+
+      queryctrl.id = V4L2_CID_JPEG_ACTIVE_MARKER;
+      queryctrl.type = V4L2_CTRL_TYPE_BITMASK;
+      // Driver may not have implemented V4L2_CID_JPEG_ACTIVE_MARKER.
+      // Ignore any error and assume the driver implements the JPEG stream
+      // the way we want it.
+      IOCTL_OR_ERROR_RETURN_VALUE(VIDIOC_QUERY_EXT_CTRL, &queryctrl, true,
+                                  "VIDIOC_QUERY_EXT_CTRL");
+
+      // Ask for JPEG markers we want. Since not all may be implemented,
+      // ask for the common subset of what we want and what is supported.
+      ctrl.id = V4L2_CID_JPEG_ACTIVE_MARKER;
+      ctrl.value = queryctrl.maximum &
+                   (V4L2_JPEG_ACTIVE_MARKER_APP0 | V4L2_JPEG_ACTIVE_MARKER_DQT |
+                    V4L2_JPEG_ACTIVE_MARKER_DHT);
+      IOCTL_OR_ERROR_RETURN_VALUE(VIDIOC_S_EXT_CTRLS, &ctrls, true,
+                                  "VIDIOC_S_EXT_CTRLS");
       break;
 
     default:
diff --git a/net/BUILD.gn b/net/BUILD.gn
index ac7e806..c50c247 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -417,8 +417,8 @@
     "cookies/cookie_options.h",
     "cookies/cookie_partition_key.cc",
     "cookies/cookie_partition_key.h",
-    "cookies/cookie_partition_keychain.cc",
-    "cookies/cookie_partition_keychain.h",
+    "cookies/cookie_partition_key_collection.cc",
+    "cookies/cookie_partition_key_collection.h",
     "cookies/cookie_store.cc",
     "cookies/cookie_store.h",
     "cookies/cookie_util.cc",
@@ -4196,8 +4196,8 @@
     "cookies/cookie_inclusion_status_unittest.cc",
     "cookies/cookie_monster_unittest.cc",
     "cookies/cookie_options_unittest.cc",
+    "cookies/cookie_partition_key_collection_unittest.cc",
     "cookies/cookie_partition_key_unittest.cc",
-    "cookies/cookie_partition_keychain_unittest.cc",
     "cookies/cookie_util_unittest.cc",
     "cookies/parsed_cookie_unittest.cc",
     "cookies/site_for_cookies_unittest.cc",
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 074f14a..c39c0da5 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -145,7 +145,8 @@
 //
 // This returns true if the |list| of key should include unpartitioned cookie in
 // GetCookie...().
-bool IncludeUnpartitionedCookies(const net::CookiePartitionKeychain& list) {
+bool IncludeUnpartitionedCookies(
+    const net::CookiePartitionKeyCollection& list) {
   if (list.IsEmpty() || list.ContainsAllKeys())
     return true;
 
@@ -429,7 +430,7 @@
 void CookieMonster::GetCookieListWithOptionsAsync(
     const GURL& url,
     const CookieOptions& options,
-    const CookiePartitionKeychain& cookie_partition_keychain,
+    const CookiePartitionKeyCollection& cookie_partition_key_collection,
     GetCookieListCallback callback) {
   DoCookieCallbackForURL(
       base::BindOnce(
@@ -437,7 +438,7 @@
           // the callback on |*this|, so the callback will not outlive
           // the object.
           &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
-          options, cookie_partition_keychain, std::move(callback)),
+          options, cookie_partition_key_collection, std::move(callback)),
       url);
 }
 
@@ -624,7 +625,7 @@
 void CookieMonster::GetCookieListWithOptions(
     const GURL& url,
     const CookieOptions& options,
-    const CookiePartitionKeychain& cookie_partition_keychain,
+    const CookiePartitionKeyCollection& cookie_partition_key_collection,
     GetCookieListCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -632,14 +633,14 @@
   CookieAccessResultList excluded_cookies;
   if (HasCookieableScheme(url)) {
     std::vector<CanonicalCookie*> cookie_ptrs;
-    if (IncludeUnpartitionedCookies(cookie_partition_keychain)) {
+    if (IncludeUnpartitionedCookies(cookie_partition_key_collection)) {
       cookie_ptrs = FindCookiesForRegistryControlledHost(url);
     } else {
-      DCHECK(!cookie_partition_keychain.IsEmpty());
+      DCHECK(!cookie_partition_key_collection.IsEmpty());
     }
 
-    if (!cookie_partition_keychain.IsEmpty()) {
-      if (cookie_partition_keychain.ContainsAllKeys()) {
+    if (!cookie_partition_key_collection.IsEmpty()) {
+      if (cookie_partition_key_collection.ContainsAllKeys()) {
         for (const auto& it : partitioned_cookies_) {
           std::vector<CanonicalCookie*> partitioned_cookie_ptrs =
               FindPartitionedCookiesForRegistryControlledHost(it.first, url);
@@ -648,7 +649,7 @@
         }
       } else {
         for (const CookiePartitionKey& key :
-             cookie_partition_keychain.PartitionKeys()) {
+             cookie_partition_key_collection.PartitionKeys()) {
           std::vector<CanonicalCookie*> partitioned_cookie_ptrs =
               FindPartitionedCookiesForRegistryControlledHost(key, url);
           cookie_ptrs.insert(cookie_ptrs.end(), partitioned_cookie_ptrs.begin(),
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 324c1d4..98ff48a 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -181,7 +181,7 @@
                                SetCookiesCallback callback) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const CookieOptions& options,
-                                     const CookiePartitionKeychain& s,
+                                     const CookiePartitionKeyCollection& s,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetAllCookiesCallback callback) override;
   void GetAllCookiesWithAccessSemanticsAsync(
@@ -380,7 +380,7 @@
   void GetCookieListWithOptions(
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain,
+      const CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback);
 
   void DeleteAllCreatedInTimeRange(
diff --git a/net/cookies/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc
index 4acddef..d6851a13 100644
--- a/net/cookies/cookie_monster_perftest.cc
+++ b/net/cookies/cookie_monster_perftest.cc
@@ -117,7 +117,7 @@
  public:
   const CookieList& GetCookieList(CookieMonster* cm, const GURL& gurl) {
     cm->GetCookieListWithOptionsAsync(
-        gurl, options_, CookiePartitionKeychain(),
+        gurl, options_, CookiePartitionKeyCollection(),
         base::BindOnce(&GetCookieListCallback::Run, base::Unretained(this)));
     WaitForCallback();
     return cookie_list_;
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index ce361f90..73295df2 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -139,12 +139,12 @@
       CookieMonster* cm,
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
     DCHECK(cm);
     GetCookieListCallback callback;
-    cm->GetCookieListWithOptionsAsync(url, options, cookie_partition_keychain,
-                                      callback.MakeCallback());
+    cm->GetCookieListWithOptionsAsync(
+        url, options, cookie_partition_key_collection, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -153,12 +153,12 @@
       CookieMonster* cm,
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
     DCHECK(cm);
     GetCookieListCallback callback;
-    cm->GetCookieListWithOptionsAsync(url, options, cookie_partition_keychain,
-                                      callback.MakeCallback());
+    cm->GetCookieListWithOptionsAsync(
+        url, options, cookie_partition_key_collection, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.excluded_cookies();
   }
@@ -918,7 +918,7 @@
                             cookie_partition_key));
       std::string cookies =
           this->GetCookies(cm.get(), https_www_foo_.url(),
-                           CookiePartitionKeychain(cookie_partition_key));
+                           CookiePartitionKeyCollection(cookie_partition_key));
       EXPECT_NE(cookies.find(cookie), std::string::npos);
       EXPECT_LE(CountInString(cookies, '='), max_cookies);
     }
@@ -1059,7 +1059,7 @@
   GetCookieListCallback call1;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call1.MakeCallback());
+      CookiePartitionKeyCollection(), call1.MakeCallback());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(call1.was_run());
 
@@ -1072,7 +1072,7 @@
   GetCookieListCallback call2;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call2.MakeCallback());
+      CookiePartitionKeyCollection(), call2.MakeCallback());
   // Already ready, no need for second load.
   EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
   EXPECT_EQ("", TakeCommandSummary());
@@ -1171,7 +1171,7 @@
   GetCookieListCallback call1;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call1.MakeCallback());
+      CookiePartitionKeyCollection(), call1.MakeCallback());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(call1.was_run());
 
@@ -1183,7 +1183,7 @@
   GetCookieListCallback call2;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call2.MakeCallback());
+      CookiePartitionKeyCollection(), call2.MakeCallback());
   EXPECT_TRUE(call2.was_run());
   EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
   EXPECT_EQ("", TakeCommandSummary());
@@ -1197,7 +1197,7 @@
   GetCookieListCallback call1;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call1.MakeCallback());
+      CookiePartitionKeyCollection(), call1.MakeCallback());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(call1.was_run());
 
@@ -1209,7 +1209,7 @@
   GetCookieListCallback call2;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), call2.MakeCallback());
+      CookiePartitionKeyCollection(), call2.MakeCallback());
   EXPECT_TRUE(call2.was_run());
   EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
   EXPECT_EQ("", TakeCommandSummary());
@@ -1363,7 +1363,7 @@
   base::RunLoop run_loop;
   cookie_monster_->GetCookieListWithOptionsAsync(
       http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(),
+      CookiePartitionKeyCollection(),
       base::BindLambdaForTesting(
           [&](const CookieAccessResultList& cookies,
               const CookieAccessResultList& excluded_list) {
@@ -1380,7 +1380,7 @@
             // before it.
             cookie_monster_->GetCookieListWithOptionsAsync(
                 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
-                CookiePartitionKeychain(),
+                CookiePartitionKeyCollection(),
                 get_cookie_list_callback_deferred.MakeCallback());
 
             run_loop.Quit();
@@ -1449,9 +1449,9 @@
       "__Host-" + std::string(kValidCookieLine) + "; partitioned; secure",
       cookie_partition_key));
   EXPECT_EQ(1u, DeleteAll(cm.get()));
-  EXPECT_EQ(
-      "", GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options,
-                                CookiePartitionKeychain(cookie_partition_key)));
+  EXPECT_EQ("", GetCookiesWithOptions(
+                    cm.get(), http_www_foo_.url(), options,
+                    CookiePartitionKeyCollection(cookie_partition_key)));
   EXPECT_EQ(2u, store->commands().size());
 }
 
@@ -1901,19 +1901,19 @@
   // Test reading partitioned cookies for a single partition.
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                          CookiePartitionKeychain(cookie_partition_key1)),
+                          CookiePartitionKeyCollection(cookie_partition_key1)),
       ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
                   MatchesCookieNameDomain("__Host-K", https_www_bar_.host())));
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                          CookiePartitionKeychain(cookie_partition_key2)),
+                          CookiePartitionKeyCollection(cookie_partition_key2)),
       ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
                   MatchesCookieNameDomain("__Host-M", https_www_bar_.host())));
 
   // Test reading partitioned cookies from multiple partitions.
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                          CookiePartitionKeychain(
+                          CookiePartitionKeyCollection(
                               {cookie_partition_key1, cookie_partition_key2})),
       ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
                   MatchesCookieNameDomain("__Host-K", https_www_bar_.host()),
@@ -1922,7 +1922,7 @@
   // Test reading partitioned cookies from every partition.
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                          CookiePartitionKeychain::ContainsAll()),
+                          CookiePartitionKeyCollection::ContainsAll()),
       ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
                   MatchesCookieNameDomain("__Host-K", https_www_bar_.host()),
                   MatchesCookieNameDomain("__Host-M", https_www_bar_.host()),
@@ -1931,7 +1931,7 @@
   // Test excluding partitioned cookies.
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                          CookiePartitionKeychain()),
+                          CookiePartitionKeyCollection()),
       ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D"))));
 
   EXPECT_THAT(
@@ -1976,7 +1976,7 @@
   // Checking that excluded cookies get sent with their statuses with http
   // request.
   excluded_cookies = GetExcludedCookiesForURL(cm.get(), http_www_foo_.url(),
-                                              CookiePartitionKeychain());
+                                              CookiePartitionKeyCollection());
   iter = excluded_cookies.begin();
 
   ASSERT_TRUE(iter != excluded_cookies.end());
@@ -2015,7 +2015,7 @@
 
   // Check that no excluded cookies are sent with secure request
   excluded_cookies = GetExcludedCookiesForURL(cm.get(), https_www_foo_.url(),
-                                              CookiePartitionKeychain());
+                                              CookiePartitionKeyCollection());
   iter = excluded_cookies.begin();
 
   EXPECT_TRUE(excluded_cookies.empty());
@@ -2073,7 +2073,7 @@
       CreateAndSetCookie(cm.get(), http_www_foo_.url(), "E=F;", options));
 
   CookieAccessResultList excluded_cookies = GetExcludedCookiesForURL(
-      cm.get(), www_foo_foo_.url(), CookiePartitionKeychain());
+      cm.get(), www_foo_foo_.url(), CookiePartitionKeyCollection());
   auto it = excluded_cookies.begin();
 
   ASSERT_TRUE(it != excluded_cookies.end());
@@ -2085,7 +2085,7 @@
   ASSERT_TRUE(++it == excluded_cookies.end());
 
   excluded_cookies = GetExcludedCookiesForURL(cm.get(), www_foo_bar_.url(),
-                                              CookiePartitionKeychain());
+                                              CookiePartitionKeyCollection());
   it = excluded_cookies.begin();
 
   ASSERT_TRUE(it != excluded_cookies.end());
@@ -2183,8 +2183,9 @@
                         "__Host-C=D; secure; path=/; partitioned",
                         cookie_partition_key));
 
-  cookies = GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                                CookiePartitionKeychain(cookie_partition_key));
+  cookies =
+      GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
+                          CookiePartitionKeyCollection(cookie_partition_key));
   EXPECT_EQ(2u, cookies.size());
 
   EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
@@ -2192,8 +2193,9 @@
                         "01-Jan-1970 00:00:00 GMT",
                         cookie_partition_key));
 
-  cookies = GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
-                                CookiePartitionKeychain(cookie_partition_key));
+  cookies =
+      GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
+                          CookiePartitionKeyCollection(cookie_partition_key));
   EXPECT_EQ(1u, cookies.size());
 }
 
@@ -2306,7 +2308,7 @@
 
   EXPECT_EQ("__Host-Z=a",
             GetCookies(cm.get(), GURL("https://www.bar.com/"),
-                       CookiePartitionKeychain(cookie_partition_key)));
+                       CookiePartitionKeyCollection(cookie_partition_key)));
 
   // Verify that the PersistentCookieStore was told to kill the 2
   // duplicates.
@@ -2442,11 +2444,11 @@
   EXPECT_EQ("dom_path_2=B; host_path_2=B; dom_2=B; host_2=B; sec_host=B",
             GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
                                       std::string("/dir1/dir2/xxx"))));
-  EXPECT_EQ(
-      "dom_2=B; host_2=B; sec_host=B; __Host-pc_2=B",
-      GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure),
-                 CookiePartitionKeychain(CookiePartitionKey::FromURLForTesting(
-                     GURL(kTopLevelDomainPlus1)))));
+  EXPECT_EQ("dom_2=B; host_2=B; sec_host=B; __Host-pc_2=B",
+            GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure),
+                       CookiePartitionKeyCollection(
+                           CookiePartitionKey::FromURLForTesting(
+                               GURL(kTopLevelDomainPlus1)))));
 }
 
 // Mainly a test of GetEffectiveDomain, or more specifically, of the
@@ -2781,7 +2783,7 @@
 
   GetCookieListCallback get_cookie_list_callback;
   cm->GetCookieListWithOptionsAsync(kUrl, CookieOptions::MakeAllInclusive(),
-                                    CookiePartitionKeychain(),
+                                    CookiePartitionKeyCollection(),
                                     get_cookie_list_callback.MakeCallback());
 
   // Only the main load should have been queued.
@@ -3238,9 +3240,9 @@
   std::unique_ptr<CookieMonster> cm(
       new CookieMonster(store.get(), net::NetLog::Get()));
 
-  EXPECT_EQ(
-      "foo=bar; hello=world",
-      GetCookies(cm.get(), url, CookiePartitionKeychain(cookie_partition_key)));
+  EXPECT_EQ("foo=bar; hello=world",
+            GetCookies(cm.get(), url,
+                       CookiePartitionKeyCollection(cookie_partition_key)));
 }
 
 // Test that cookie source schemes are histogrammed correctly.
@@ -3451,7 +3453,7 @@
     GetCookieListCallback callback;
     cm->GetCookieListWithOptionsAsync(
         insecure_localhost, CookieOptions::MakeAllInclusive(),
-        CookiePartitionKeychain(), callback.MakeCallback());
+        CookiePartitionKeyCollection(), callback.MakeCallback());
     callback.WaitUntilDone();
     EXPECT_EQ(2u, callback.cookies_with_access_results().size());
     for (const auto& cookie_item : callback.cookies_with_access_results()) {
@@ -3469,7 +3471,7 @@
     GetCookieListCallback callback;
     cm->GetCookieListWithOptionsAsync(
         secure_localhost, CookieOptions::MakeAllInclusive(),
-        CookiePartitionKeychain(), callback.MakeCallback());
+        CookiePartitionKeyCollection(), callback.MakeCallback());
     callback.WaitUntilDone();
     EXPECT_EQ(2u, callback.cookies_with_access_results().size());
     for (const auto& cookie_item : callback.cookies_with_access_results()) {
@@ -3622,9 +3624,9 @@
   EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
       {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
   EXPECT_THAT(
-      GetCookiesWithOptions(cm.get(), https_www_foo_.url(),
-                            CookieOptions::MakeAllInclusive(),
-                            CookiePartitionKeychain(cookie_partition_key1)),
+      GetCookiesWithOptions(
+          cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive(),
+          CookiePartitionKeyCollection(cookie_partition_key1)),
       ::testing::HasSubstr("A=B"));
 }
 
@@ -4362,7 +4364,7 @@
   GetCookieListCallback callback_get;
   cm.GetCookieListWithOptionsAsync(
       GURL("http://b.com/"), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(), callback_get.MakeCallback());
+      CookiePartitionKeyCollection(), callback_get.MakeCallback());
 
   // Now go through the store commands, and execute individual loads.
   const auto& commands = persistent_store->commands();
@@ -5304,7 +5306,7 @@
   // Check cookies from inside the anonymous iframe:
   EXPECT_THAT(
       GetAllCookiesForURL(cm.get(), https_www_foo_.url(),
-                          CookiePartitionKeychain(anonymous_iframe_key)),
+                          CookiePartitionKeyCollection(anonymous_iframe_key)),
       ElementsAre(MatchesCookieNameValue("__Host-B", "1"),
                   MatchesCookieNameValue("__Host-C", "0")));
 }
diff --git a/net/cookies/cookie_partition_key_collection.cc b/net/cookies/cookie_partition_key_collection.cc
new file mode 100644
index 0000000..9882324
--- /dev/null
+++ b/net/cookies/cookie_partition_key_collection.cc
@@ -0,0 +1,57 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cookies/cookie_partition_key_collection.h"
+
+namespace net {
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection() = default;
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection(
+    const CookiePartitionKeyCollection& other) = default;
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection(
+    CookiePartitionKeyCollection&& other) = default;
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection(
+    const CookiePartitionKey& key) {
+  keys_.push_back(key);
+}
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection(
+    const std::vector<CookiePartitionKey>& keys)
+    : keys_(keys) {}
+
+CookiePartitionKeyCollection::CookiePartitionKeyCollection(
+    bool contains_all_keys_)
+    : contains_all_keys_(contains_all_keys_) {}
+
+CookiePartitionKeyCollection& CookiePartitionKeyCollection::operator=(
+    const CookiePartitionKeyCollection& other) = default;
+
+CookiePartitionKeyCollection& CookiePartitionKeyCollection::operator=(
+    CookiePartitionKeyCollection&& other) = default;
+
+CookiePartitionKeyCollection::~CookiePartitionKeyCollection() = default;
+
+CookiePartitionKeyCollection CookiePartitionKeyCollection::FirstPartySetify(
+    const CookieAccessDelegate* cookie_access_delegate) const {
+  if (!cookie_access_delegate || IsEmpty() || ContainsAllKeys())
+    return *this;
+  std::vector<CookiePartitionKey> keys;
+  keys.reserve(PartitionKeys().size());
+  for (const auto& key : PartitionKeys()) {
+    absl::optional<SchemefulSite> fps_owner =
+        cookie_access_delegate->FindFirstPartySetOwner(key.site());
+    if (fps_owner) {
+      keys.push_back(
+          CookiePartitionKey::FromWire(fps_owner.value(), key.nonce()));
+    } else {
+      keys.push_back(key);
+    }
+  }
+  return CookiePartitionKeyCollection(keys);
+}
+
+}  // namespace net
diff --git a/net/cookies/cookie_partition_key_collection.h b/net/cookies/cookie_partition_key_collection.h
new file mode 100644
index 0000000..58f8b9e
--- /dev/null
+++ b/net/cookies/cookie_partition_key_collection.h
@@ -0,0 +1,95 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_COOKIES_COOKIE_PARTITION_KEY_COLLECTION_H_
+#define NET_COOKIES_COOKIE_PARTITION_KEY_COLLECTION_H_
+
+#include <vector>
+
+#include "net/base/net_export.h"
+#include "net/cookies/cookie_access_delegate.h"
+#include "net/cookies/cookie_partition_key.h"
+
+namespace net {
+
+// A data structure used to represent a collection of cookie partition keys.
+//
+// It can represent all possible cookie partition keys when
+// `contains_all_keys_` is true.
+//
+// It can also represent a finite number of cookie partition keys, including
+// zero.
+class NET_EXPORT CookiePartitionKeyCollection {
+ public:
+  // Creates an empty key collection.
+  explicit CookiePartitionKeyCollection();
+  CookiePartitionKeyCollection(const CookiePartitionKeyCollection& other);
+  CookiePartitionKeyCollection(CookiePartitionKeyCollection&& other);
+  // Creates a key collection with a single element.
+  explicit CookiePartitionKeyCollection(const CookiePartitionKey& key);
+  // Creates a set that contains each partition key in the vector.
+  explicit CookiePartitionKeyCollection(
+      const std::vector<CookiePartitionKey>& keys);
+
+  CookiePartitionKeyCollection& operator=(
+      const CookiePartitionKeyCollection& other);
+  CookiePartitionKeyCollection& operator=(CookiePartitionKeyCollection&& other);
+  ~CookiePartitionKeyCollection();
+
+  static CookiePartitionKeyCollection ContainsAll() {
+    return CookiePartitionKeyCollection(true);
+  }
+
+  static CookiePartitionKeyCollection FromOptional(
+      const absl::optional<CookiePartitionKey>& opt_key) {
+    return opt_key ? CookiePartitionKeyCollection(opt_key.value())
+                   : CookiePartitionKeyCollection();
+  }
+
+  // Takes a CookiePartitionKeyCollection which was created in a context that
+  // does not have access to sites' First-Party Set owners and converts it to
+  // the correct First-Party-Sets-aware CookiePartitionKeyCollection, replacing
+  // any CookiePartitionKeys whose sites which are members of a set with a new
+  // partition key containing the set's owner site.
+  CookiePartitionKeyCollection FirstPartySetify(
+      const CookieAccessDelegate* cookie_access_delegate) const;
+
+  // Temporary method used to record where we need to decide how to build the
+  // CookiePartitionKeyCollection.
+  //
+  // Returns an empty key collection, so no partitioned cookies will be returned
+  // at callsites this is used.
+  //
+  // TODO(crbug.com/1225444): Remove this method and update callsites to use
+  // appropriate constructor.
+  static CookiePartitionKeyCollection Todo() {
+    return CookiePartitionKeyCollection();
+  }
+
+  // CookieMonster can check if the key collection is empty to avoid searching
+  // the PartitionedCookieMap at all.
+  bool IsEmpty() const { return !contains_all_keys_ && keys_.empty(); }
+
+  // Returns if the key collection contains every partition key.
+  bool ContainsAllKeys() const { return contains_all_keys_; }
+
+  // Iterate over all keys in the key collection, do not call this method if
+  // `contains_all_keys` is true.
+  const std::vector<CookiePartitionKey>& PartitionKeys() const {
+    DCHECK(!contains_all_keys_);
+    return keys_;
+  }
+
+ private:
+  explicit CookiePartitionKeyCollection(bool contains_all_keys_);
+
+  bool contains_all_keys_ = false;
+  // If `contains_all_keys_` is true, `keys_` must be empty.
+  // If `keys_` is not empty, then `contains_all_keys_` must be false.
+  std::vector<CookiePartitionKey> keys_;
+};
+
+}  // namespace net
+
+#endif  // NET_COOKIES_COOKIE_PARTITION_KEY_COLLECTION_H_
diff --git a/net/cookies/cookie_partition_key_collection_unittest.cc b/net/cookies/cookie_partition_key_collection_unittest.cc
new file mode 100644
index 0000000..20fbc12f
--- /dev/null
+++ b/net/cookies/cookie_partition_key_collection_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cookies/cookie_partition_key_collection.h"
+#include "net/cookies/test_cookie_access_delegate.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(CookiePartitionKeyCollectionTest, EmptySet) {
+  CookiePartitionKeyCollection key_collection;
+
+  EXPECT_TRUE(key_collection.IsEmpty());
+  EXPECT_FALSE(key_collection.ContainsAllKeys());
+  EXPECT_EQ(0u, key_collection.PartitionKeys().size());
+}
+
+TEST(CookiePartitionKeyCollectionTest, SingletonSet) {
+  CookiePartitionKeyCollection key_collection(
+      CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
+
+  EXPECT_FALSE(key_collection.IsEmpty());
+  EXPECT_FALSE(key_collection.ContainsAllKeys());
+  EXPECT_THAT(
+      key_collection.PartitionKeys(),
+      testing::UnorderedElementsAre(
+          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
+}
+
+TEST(CookiePartitionKeyCollectionTest, MultipleElements) {
+  CookiePartitionKeyCollection key_collection({
+      CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")),
+      CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com")),
+  });
+
+  EXPECT_FALSE(key_collection.IsEmpty());
+  EXPECT_FALSE(key_collection.ContainsAllKeys());
+  EXPECT_THAT(
+      key_collection.PartitionKeys(),
+      testing::UnorderedElementsAre(
+          CookiePartitionKey::FromURLForTesting(
+              GURL("https://subdomain.foo.com")),
+          CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"))));
+}
+
+TEST(CookiePartitionKeyCollectionTest, ContainsAll) {
+  CookiePartitionKeyCollection key_collection =
+      CookiePartitionKeyCollection::ContainsAll();
+  EXPECT_FALSE(key_collection.IsEmpty());
+  EXPECT_TRUE(key_collection.ContainsAllKeys());
+}
+
+TEST(CookiePartitionKeyCollectionTest, FromOptional) {
+  CookiePartitionKeyCollection key_collection =
+      CookiePartitionKeyCollection::FromOptional(absl::nullopt);
+  EXPECT_TRUE(key_collection.IsEmpty());
+  EXPECT_FALSE(key_collection.ContainsAllKeys());
+
+  key_collection = CookiePartitionKeyCollection::FromOptional(
+      absl::make_optional<CookiePartitionKey>(
+          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
+  EXPECT_FALSE(key_collection.IsEmpty());
+  EXPECT_FALSE(key_collection.ContainsAllKeys());
+  EXPECT_THAT(
+      key_collection.PartitionKeys(),
+      testing::UnorderedElementsAre(
+          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
+}
+
+TEST(CookiePartitionKeyCollectionTest, FirstPartySetify) {
+  const GURL kOwnerURL("https://owner.com");
+  const SchemefulSite kOwnerSite(kOwnerURL);
+  const CookiePartitionKey kOwnerPartitionKey =
+      CookiePartitionKey::FromURLForTesting(kOwnerURL);
+
+  const GURL kMemberURL("https://member.com");
+  const SchemefulSite kMemberSite(kMemberURL);
+  const CookiePartitionKey kMemberPartitionKey =
+      CookiePartitionKey::FromURLForTesting(kMemberURL);
+
+  const GURL kNonMemberURL("https://nonmember.com");
+  const CookiePartitionKey kNonMemberPartitionKey =
+      CookiePartitionKey::FromURLForTesting(kNonMemberURL);
+
+  TestCookieAccessDelegate delegate;
+  base::flat_map<SchemefulSite, std::set<SchemefulSite>> first_party_sets;
+  first_party_sets.insert(std::make_pair(
+      kOwnerSite, std::set<SchemefulSite>({kOwnerSite, kMemberSite})));
+  delegate.SetFirstPartySets(first_party_sets);
+
+  CookiePartitionKeyCollection empty_key_collection;
+  EXPECT_TRUE(empty_key_collection.FirstPartySetify(&delegate).IsEmpty());
+  EXPECT_TRUE(empty_key_collection.FirstPartySetify(nullptr).IsEmpty());
+
+  CookiePartitionKeyCollection contains_all_keys =
+      CookiePartitionKeyCollection::ContainsAll();
+  EXPECT_TRUE(contains_all_keys.FirstPartySetify(&delegate).ContainsAllKeys());
+  EXPECT_TRUE(contains_all_keys.FirstPartySetify(nullptr).ContainsAllKeys());
+
+  // An owner site of an FPS should not have its partition key changed.
+  CookiePartitionKeyCollection got =
+      CookiePartitionKeyCollection(kOwnerPartitionKey)
+          .FirstPartySetify(&delegate);
+  EXPECT_EQ(1u, got.PartitionKeys().size());
+  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
+
+  // A member site should have its partition key changed to the owner site.
+  got = CookiePartitionKeyCollection(kMemberPartitionKey)
+            .FirstPartySetify(&delegate);
+  EXPECT_EQ(1u, got.PartitionKeys().size());
+  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
+
+  // A member site's partition key should not change if the CookieAccessDelegate
+  // is null.
+  got = CookiePartitionKeyCollection(kMemberPartitionKey)
+            .FirstPartySetify(nullptr);
+  EXPECT_EQ(1u, got.PartitionKeys().size());
+  EXPECT_EQ(kMemberPartitionKey, got.PartitionKeys()[0]);
+
+  // A non-member site should not have its partition key changed.
+  got = CookiePartitionKeyCollection(kNonMemberPartitionKey)
+            .FirstPartySetify(&delegate);
+  EXPECT_EQ(1u, got.PartitionKeys().size());
+  EXPECT_EQ(kNonMemberPartitionKey, got.PartitionKeys()[0]);
+
+  // A key collection that contains a member site and non-member site should be
+  // changed to include the owner site and the unmodified non-member site.
+  got = CookiePartitionKeyCollection(
+            {kMemberPartitionKey, kNonMemberPartitionKey})
+            .FirstPartySetify(&delegate);
+  EXPECT_EQ(2u, got.PartitionKeys().size());
+  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
+  EXPECT_EQ(kNonMemberPartitionKey, got.PartitionKeys()[1]);
+}
+
+}  // namespace net
diff --git a/net/cookies/cookie_partition_key_unittest.cc b/net/cookies/cookie_partition_key_unittest.cc
index d855883..f3c41a8 100644
--- a/net/cookies/cookie_partition_key_unittest.cc
+++ b/net/cookies/cookie_partition_key_unittest.cc
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_COOKIES_COOKIE_PARTITION_KEY_UNITTEST_H_
-#define NET_COOKIES_COOKIE_PARTITION_KEY_UNITTEST_H_
-
 #include <string>
 
 #include "net/cookies/cookie_partition_key.h"
@@ -253,5 +250,3 @@
 }
 
 }  // namespace net
-
-#endif  // NET_COOKIES_COOKIE_PARTITION_KEY_UNITTEST_H_
diff --git a/net/cookies/cookie_partition_keychain.cc b/net/cookies/cookie_partition_keychain.cc
deleted file mode 100644
index 2ab53b6..0000000
--- a/net/cookies/cookie_partition_keychain.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cookies/cookie_partition_keychain.h"
-
-namespace net {
-
-CookiePartitionKeychain::CookiePartitionKeychain() = default;
-
-CookiePartitionKeychain::CookiePartitionKeychain(
-    const CookiePartitionKeychain& other) = default;
-
-CookiePartitionKeychain::CookiePartitionKeychain(
-    CookiePartitionKeychain&& other) = default;
-
-CookiePartitionKeychain::CookiePartitionKeychain(
-    const CookiePartitionKey& key) {
-  keys_.push_back(key);
-}
-
-CookiePartitionKeychain::CookiePartitionKeychain(
-    const std::vector<CookiePartitionKey>& keys)
-    : keys_(keys) {}
-
-CookiePartitionKeychain::CookiePartitionKeychain(bool contains_all_keys_)
-    : contains_all_keys_(contains_all_keys_) {}
-
-CookiePartitionKeychain& CookiePartitionKeychain::operator=(
-    const CookiePartitionKeychain& other) = default;
-
-CookiePartitionKeychain& CookiePartitionKeychain::operator=(
-    CookiePartitionKeychain&& other) = default;
-
-CookiePartitionKeychain::~CookiePartitionKeychain() = default;
-
-CookiePartitionKeychain CookiePartitionKeychain::FirstPartySetify(
-    const CookieAccessDelegate* cookie_access_delegate) const {
-  if (!cookie_access_delegate || IsEmpty() || ContainsAllKeys())
-    return *this;
-  std::vector<CookiePartitionKey> keys;
-  keys.reserve(PartitionKeys().size());
-  for (const auto& key : PartitionKeys()) {
-    absl::optional<SchemefulSite> fps_owner =
-        cookie_access_delegate->FindFirstPartySetOwner(key.site());
-    if (fps_owner) {
-      keys.push_back(
-          CookiePartitionKey::FromWire(fps_owner.value(), key.nonce()));
-    } else {
-      keys.push_back(key);
-    }
-  }
-  return CookiePartitionKeychain(keys);
-}
-
-}  // namespace net
diff --git a/net/cookies/cookie_partition_keychain.h b/net/cookies/cookie_partition_keychain.h
deleted file mode 100644
index 910ed58c..0000000
--- a/net/cookies/cookie_partition_keychain.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_H_
-#define NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_H_
-
-#include <vector>
-
-#include "net/base/net_export.h"
-#include "net/cookies/cookie_access_delegate.h"
-#include "net/cookies/cookie_partition_key.h"
-
-namespace net {
-
-// A data structure used to represent a collection of cookie partition keys.
-//
-// It can represent all possible cookie partition keys when
-// `contains_all_keys_` is true.
-//
-// It can also represent a finite number of cookie partition keys, including
-// zero.
-// TODO(crbug.com/1268880): Consider changing the name of this class since the
-// term "keychain" has a certain meaning for iOS and macOS.
-class NET_EXPORT CookiePartitionKeychain {
- public:
-  // Creates an empty keychain.
-  explicit CookiePartitionKeychain();
-  CookiePartitionKeychain(const CookiePartitionKeychain& other);
-  CookiePartitionKeychain(CookiePartitionKeychain&& other);
-  // Creates a keychain with a single element.
-  explicit CookiePartitionKeychain(const CookiePartitionKey& key);
-  // Creates a set that contains each partition key in the vector.
-  explicit CookiePartitionKeychain(const std::vector<CookiePartitionKey>& keys);
-
-  CookiePartitionKeychain& operator=(const CookiePartitionKeychain& other);
-  CookiePartitionKeychain& operator=(CookiePartitionKeychain&& other);
-  ~CookiePartitionKeychain();
-
-  static CookiePartitionKeychain ContainsAll() {
-    return CookiePartitionKeychain(true);
-  }
-
-  static CookiePartitionKeychain FromOptional(
-      const absl::optional<CookiePartitionKey>& opt_key) {
-    return opt_key ? CookiePartitionKeychain(opt_key.value())
-                   : CookiePartitionKeychain();
-  }
-
-  // Takes a CookiePartitionKeychain which was created in a context that does
-  // not have access to sites' First-Party Set owners and converts it to the
-  // correct First-Party-Sets-aware CookiePartitionKeychain, replacing any
-  // CookiePartitionKeys whose sites which are members of a set with a new
-  // partition key containing the set's owner site.
-  CookiePartitionKeychain FirstPartySetify(
-      const CookieAccessDelegate* cookie_access_delegate) const;
-
-  // Temporary method used to record where we need to decide how to build the
-  // CookiePartitionKeychain.
-  //
-  // Returns an empty keychain, so no partitioned cookies will be returned at
-  // callsites this is used.
-  //
-  // TODO(crbug.com/1225444): Remove this method and update callsites to use
-  // appropriate constructor.
-  static CookiePartitionKeychain Todo() { return CookiePartitionKeychain(); }
-
-  // CookieMonster can check if the keychain is empty to avoid searching the
-  // PartitionedCookieMap at all.
-  bool IsEmpty() const { return !contains_all_keys_ && keys_.empty(); }
-
-  // Returns if the keychain contains every partition key.
-  bool ContainsAllKeys() const { return contains_all_keys_; }
-
-  // Iterate over all keys in the keychain, do not call this method if
-  // `contains_all_keys` is true.
-  const std::vector<CookiePartitionKey>& PartitionKeys() const {
-    DCHECK(!contains_all_keys_);
-    return keys_;
-  }
-
- private:
-  explicit CookiePartitionKeychain(bool contains_all_keys_);
-
-  bool contains_all_keys_ = false;
-  // If `contains_all_keys_` is true, `keys_` must be empty.
-  // If `keys_` is not empty, then `contains_all_keys_` must be false.
-  std::vector<CookiePartitionKey> keys_;
-};
-
-}  // namespace net
-
-#endif  // NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_H_
diff --git a/net/cookies/cookie_partition_keychain_unittest.cc b/net/cookies/cookie_partition_keychain_unittest.cc
deleted file mode 100644
index c4d8955..0000000
--- a/net/cookies/cookie_partition_keychain_unittest.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_UNITTEST_H_
-#define NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_UNITTEST_H_
-
-#include "net/cookies/cookie_partition_keychain.h"
-#include "net/cookies/test_cookie_access_delegate.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-TEST(CookiePartitionKeychainTest, EmptySet) {
-  CookiePartitionKeychain keychain;
-
-  EXPECT_TRUE(keychain.IsEmpty());
-  EXPECT_FALSE(keychain.ContainsAllKeys());
-  EXPECT_EQ(0u, keychain.PartitionKeys().size());
-}
-
-TEST(CookiePartitionKeychainTest, SingletonSet) {
-  CookiePartitionKeychain keychain(
-      CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")));
-
-  EXPECT_FALSE(keychain.IsEmpty());
-  EXPECT_FALSE(keychain.ContainsAllKeys());
-  EXPECT_THAT(
-      keychain.PartitionKeys(),
-      testing::UnorderedElementsAre(
-          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
-}
-
-TEST(CookiePartitionKeychainTest, MultipleElements) {
-  CookiePartitionKeychain keychain({
-      CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com")),
-      CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com")),
-  });
-
-  EXPECT_FALSE(keychain.IsEmpty());
-  EXPECT_FALSE(keychain.ContainsAllKeys());
-  EXPECT_THAT(
-      keychain.PartitionKeys(),
-      testing::UnorderedElementsAre(
-          CookiePartitionKey::FromURLForTesting(
-              GURL("https://subdomain.foo.com")),
-          CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"))));
-}
-
-TEST(CookiePartitionKeychainTest, ContainsAll) {
-  CookiePartitionKeychain keychain = CookiePartitionKeychain::ContainsAll();
-  EXPECT_FALSE(keychain.IsEmpty());
-  EXPECT_TRUE(keychain.ContainsAllKeys());
-}
-
-TEST(CookiePartitionKeychainTest, FromOptional) {
-  CookiePartitionKeychain keychain =
-      CookiePartitionKeychain::FromOptional(absl::nullopt);
-  EXPECT_TRUE(keychain.IsEmpty());
-  EXPECT_FALSE(keychain.ContainsAllKeys());
-
-  keychain = CookiePartitionKeychain::FromOptional(
-      absl::make_optional<CookiePartitionKey>(
-          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
-  EXPECT_FALSE(keychain.IsEmpty());
-  EXPECT_FALSE(keychain.ContainsAllKeys());
-  EXPECT_THAT(
-      keychain.PartitionKeys(),
-      testing::UnorderedElementsAre(
-          CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"))));
-}
-
-TEST(CookiePartitionKeychainTest, FirstPartySetify) {
-  const GURL kOwnerURL("https://owner.com");
-  const SchemefulSite kOwnerSite(kOwnerURL);
-  const CookiePartitionKey kOwnerPartitionKey =
-      CookiePartitionKey::FromURLForTesting(kOwnerURL);
-
-  const GURL kMemberURL("https://member.com");
-  const SchemefulSite kMemberSite(kMemberURL);
-  const CookiePartitionKey kMemberPartitionKey =
-      CookiePartitionKey::FromURLForTesting(kMemberURL);
-
-  const GURL kNonMemberURL("https://nonmember.com");
-  const CookiePartitionKey kNonMemberPartitionKey =
-      CookiePartitionKey::FromURLForTesting(kNonMemberURL);
-
-  TestCookieAccessDelegate delegate;
-  base::flat_map<SchemefulSite, std::set<SchemefulSite>> first_party_sets;
-  first_party_sets.insert(std::make_pair(
-      kOwnerSite, std::set<SchemefulSite>({kOwnerSite, kMemberSite})));
-  delegate.SetFirstPartySets(first_party_sets);
-
-  CookiePartitionKeychain empty_keychain;
-  EXPECT_TRUE(empty_keychain.FirstPartySetify(&delegate).IsEmpty());
-  EXPECT_TRUE(empty_keychain.FirstPartySetify(nullptr).IsEmpty());
-
-  CookiePartitionKeychain contains_all_keys =
-      CookiePartitionKeychain::ContainsAll();
-  EXPECT_TRUE(contains_all_keys.FirstPartySetify(&delegate).ContainsAllKeys());
-  EXPECT_TRUE(contains_all_keys.FirstPartySetify(nullptr).ContainsAllKeys());
-
-  // An owner site of an FPS should not have its partition key changed.
-  CookiePartitionKeychain got =
-      CookiePartitionKeychain(kOwnerPartitionKey).FirstPartySetify(&delegate);
-  EXPECT_EQ(1u, got.PartitionKeys().size());
-  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
-
-  // A member site should have its partition key changed to the owner site.
-  got =
-      CookiePartitionKeychain(kMemberPartitionKey).FirstPartySetify(&delegate);
-  EXPECT_EQ(1u, got.PartitionKeys().size());
-  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
-
-  // A member site's partition key should not change if the CookieAccessDelegate
-  // is null.
-  got = CookiePartitionKeychain(kMemberPartitionKey).FirstPartySetify(nullptr);
-  EXPECT_EQ(1u, got.PartitionKeys().size());
-  EXPECT_EQ(kMemberPartitionKey, got.PartitionKeys()[0]);
-
-  // A non-member site should not have its partition key changed.
-  got = CookiePartitionKeychain(kNonMemberPartitionKey)
-            .FirstPartySetify(&delegate);
-  EXPECT_EQ(1u, got.PartitionKeys().size());
-  EXPECT_EQ(kNonMemberPartitionKey, got.PartitionKeys()[0]);
-
-  // A keychain that contains a member site and non-member site should be
-  // changed to include the owner site and the unmodified non-member site.
-  got = CookiePartitionKeychain({kMemberPartitionKey, kNonMemberPartitionKey})
-            .FirstPartySetify(&delegate);
-  EXPECT_EQ(2u, got.PartitionKeys().size());
-  EXPECT_EQ(kOwnerPartitionKey, got.PartitionKeys()[0]);
-  EXPECT_EQ(kNonMemberPartitionKey, got.PartitionKeys()[1]);
-}
-
-}  // namespace net
-
-#endif  // NET_COOKIES_COOKIE_PARTITION_KEYCHAIN_UNITTEST_H_
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 3a6c7c10..8631b10 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -20,7 +20,7 @@
 #include "net/cookies/cookie_access_result.h"
 #include "net/cookies/cookie_deletion_info.h"
 #include "net/cookies/cookie_options.h"
-#include "net/cookies/cookie_partition_keychain.h"
+#include "net/cookies/cookie_partition_key_collection.h"
 
 class GURL;
 
@@ -74,13 +74,14 @@
   // creation date.
   // To get all the cookies for a URL, use this method with an all-inclusive
   // |options|.
-  // If |cookie_partition_keychain| is not empty, then this function will return
-  // the partitioned cookies for that URL whose partition keys are in the
-  // keychain *in addition to* the unpartitioned cookies for that URL.
+  // If |cookie_partition_key_collection| is not empty, then this function will
+  // return the partitioned cookies for that URL whose partition keys are in the
+  // cookie_partition_key_collection *in addition to* the unpartitioned cookies
+  // for that URL.
   virtual void GetCookieListWithOptionsAsync(
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain,
+      const CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) = 0;
 
   // Returns all the cookies, for use in management UI, etc. This does not mark
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index fb963c9..6daa675 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -112,11 +112,11 @@
 void DelayedCookieMonster::GetCookieListWithOptionsAsync(
     const GURL& url,
     const CookieOptions& options,
-    const CookiePartitionKeychain& cookie_partition_keychain,
+    const CookiePartitionKeyCollection& cookie_partition_key_collection,
     CookieMonster::GetCookieListCallback callback) {
   did_run_ = false;
   cookie_monster_->GetCookieListWithOptionsAsync(
-      url, options, cookie_partition_keychain,
+      url, options, cookie_partition_key_collection,
       base::BindOnce(
           &DelayedCookieMonster::GetCookieListWithOptionsInternalCallback,
           base::Unretained(this)));
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index df553e3..6395146 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -67,7 +67,7 @@
   void GetCookieListWithOptionsAsync(
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain,
+      const CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) override;
 
   void GetAllCookiesAsync(GetAllCookiesCallback callback) override;
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 80c5c973..a649ca8 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -145,37 +145,38 @@
   std::string GetCookies(
       CookieStore* cs,
       const GURL& url,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
     DCHECK(cs);
     CookieOptions options;
     if (!CookieStoreTestTraits::supports_http_only)
       options.set_include_httponly();
     options.set_same_site_cookie_context(
         net::CookieOptions::SameSiteCookieContext::MakeInclusive());
-    return GetCookiesWithOptions(cs, url, options, cookie_partition_keychain);
+    return GetCookiesWithOptions(cs, url, options,
+                                 cookie_partition_key_collection);
   }
 
   std::string GetCookiesWithOptions(
       CookieStore* cs,
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
-    return CanonicalCookie::BuildCookieLine(
-        GetCookieListWithOptions(cs, url, options, cookie_partition_keychain));
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
+    return CanonicalCookie::BuildCookieLine(GetCookieListWithOptions(
+        cs, url, options, cookie_partition_key_collection));
   }
 
   CookieList GetCookieListWithOptions(
       CookieStore* cs,
       const GURL& url,
       const CookieOptions& options,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
     DCHECK(cs);
     GetCookieListCallback callback;
-    cs->GetCookieListWithOptionsAsync(url, options, cookie_partition_keychain,
-                                      callback.MakeCallback());
+    cs->GetCookieListWithOptionsAsync(
+        url, options, cookie_partition_key_collection, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -184,23 +185,23 @@
   CookieList GetAllCookiesForURL(
       CookieStore* cs,
       const GURL& url,
-      const CookiePartitionKeychain& cookie_partition_keychain =
-          CookiePartitionKeychain()) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection =
+          CookiePartitionKeyCollection()) {
     return GetCookieListWithOptions(cs, url, CookieOptions::MakeAllInclusive(),
-                                    cookie_partition_keychain);
+                                    cookie_partition_key_collection);
   }
 
   // This does not update the access time on the cookies.
   CookieAccessResultList GetExcludedCookiesForURL(
       CookieStore* cs,
       const GURL& url,
-      const CookiePartitionKeychain& cookie_partition_keychain) {
+      const CookiePartitionKeyCollection& cookie_partition_key_collection) {
     DCHECK(cs);
     GetCookieListCallback callback;
     CookieOptions options = CookieOptions::MakeAllInclusive();
     options.set_return_excluded_cookies();
-    cs->GetCookieListWithOptionsAsync(url, options, cookie_partition_keychain,
-                                      callback.MakeCallback());
+    cs->GetCookieListWithOptionsAsync(
+        url, options, cookie_partition_key_collection, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.excluded_cookies();
   }
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 2a94c6ce..ed4e31b 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -2410,7 +2410,7 @@
   request_context_->cookie_store()->GetCookieListWithOptionsAsync(
       GURL(GetURLFromTemplateWithoutParameters(
           config_.dns_over_https_servers[0].server_template)),
-      CookieOptions::MakeAllInclusive(), CookiePartitionKeychain(),
+      CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
       base::BindOnce(&CookieCallback::GetCookieListCallback,
                      base::Unretained(&callback)));
   callback.WaitUntilDone();
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index 990161a..cc0780dd 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -1440,7 +1440,7 @@
   GetCookieListCallback get_callback;
   cookie_monster->GetCookieListWithOptionsAsync(
       GURL("ftp://subdomain.ftperiffic.com/page"),
-      CookieOptions::MakeAllInclusive(), CookiePartitionKeychain(),
+      CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
       base::BindOnce(&GetCookieListCallback::Run,
                      base::Unretained(&get_callback)));
   get_callback.WaitUntilDone();
diff --git a/net/reporting/reporting_uploader_unittest.cc b/net/reporting/reporting_uploader_unittest.cc
index 53bd470f..945cdf4 100644
--- a/net/reporting/reporting_uploader_unittest.cc
+++ b/net/reporting/reporting_uploader_unittest.cc
@@ -504,7 +504,7 @@
   GetCookieListCallback cookie_callback;
   context_.cookie_store()->GetCookieListWithOptionsAsync(
       server_.GetURL("/"), CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(),
+      CookiePartitionKeyCollection(),
       base::BindOnce(&GetCookieListCallback::Run,
                      base::Unretained(&cookie_callback)));
   cookie_callback.WaitUntilDone();
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 5289d0e..dc5c2d9 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -598,7 +598,7 @@
 
     cookie_store->GetCookieListWithOptionsAsync(
         request_->url(), options,
-        CookiePartitionKeychain::FromOptional(cookie_partition_key_),
+        CookiePartitionKeyCollection::FromOptional(cookie_partition_key_),
         base::BindOnce(&URLRequestHttpJob::SetCookieHeaderAndStart,
                        weak_factory_.GetWeakPtr(), options));
   } else {
diff --git a/net/websockets/websocket_stream_cookie_test.cc b/net/websockets/websocket_stream_cookie_test.cc
index 98ba3fb..f229003 100644
--- a/net/websockets/websocket_stream_cookie_test.cc
+++ b/net/websockets/websocket_stream_cookie_test.cc
@@ -211,7 +211,7 @@
   base::RunLoop run_loop;
   store->GetCookieListWithOptionsAsync(
       cookie_url, net::CookieOptions::MakeAllInclusive(),
-      CookiePartitionKeychain(),
+      CookiePartitionKeyCollection(),
       base::BindOnce(&GetCookieListHelperFunction, run_loop.QuitClosure(),
                      weak_is_called.GetWeakPtr(),
                      weak_get_cookie_list_result.GetWeakPtr()));
diff --git a/pdf/pdfium/fuzzers/BUILD.gn b/pdf/pdfium/fuzzers/BUILD.gn
index 6185e374..b57f6b6a 100644
--- a/pdf/pdfium/fuzzers/BUILD.gn
+++ b/pdf/pdfium/fuzzers/BUILD.gn
@@ -88,7 +88,10 @@
       ":pdf_nametree_fuzzer",
     ]
     if (pdf_enable_xfa) {
-      deps += [ ":pdf_xfa_fdp_fuzzer" ]
+      deps += [
+        ":pdf_xfa_fdp_fuzzer",
+        ":pdf_xfa_raw_fuzzer",
+      ]
     }
   }
 }
@@ -280,6 +283,9 @@
   if (pdf_enable_xfa) {
     pdfium_fuzzer_test("pdf_xfa_fdp_fuzzer") {
     }
+    pdfium_fuzzer_test("pdf_xfa_raw_fuzzer") {
+      dict = "dicts/pdf_xfa_raw_fuzzer.dict"
+    }
   }
 }
 
diff --git a/pdf/pdfium/fuzzers/dicts/pdf_xfa_raw_fuzzer.dict b/pdf/pdfium/fuzzers/dicts/pdf_xfa_raw_fuzzer.dict
new file mode 100644
index 0000000..14c045c
--- /dev/null
+++ b/pdf/pdfium/fuzzers/dicts/pdf_xfa_raw_fuzzer.dict
@@ -0,0 +1,363 @@
+# Tags
+"accessibleContent"
+"acrobat"
+"acrobat"
+"acrobat7"
+"ADBE_JSConsole"
+"ADBE_JSDebugger"
+"addSilentPrint"
+"addViewerPreferences"
+"adjustData"
+"adobeExtensionLevel"
+"agent"
+"alwaysEmbed"
+"amd"
+"appearanceFilter"
+"arc"
+"area"
+"assist"
+"attributes"
+"autoSave"
+"barcode"
+"base"
+"batchOutput"
+"behaviorOverride"
+"bind"
+"bindItems"
+"bookend"
+"boolean"
+"border"
+"break"
+"breakAfter"
+"breakBefore"
+"button"
+"cache"
+"calculate"
+"calendarSymbols"
+"caption"
+"certificate"
+"certificates"
+"change"
+"checkButton"
+"choiceList"
+"color"
+"comb"
+"command"
+"common"
+"compress"
+"compression"
+"compressLogicalStructure"
+"compressObjectStream"
+"config"
+"config"
+"conformance"
+"connect"
+"connectionSet"
+"connectString"
+"contentArea"
+"contentCopy"
+"copies"
+"corner"
+"creator"
+"currencySymbol"
+"currencySymbols"
+"currentPage"
+"data"
+"dataGroup"
+"dataModel"
+"dataValue"
+"dataWindow"
+"date"
+"datePattern"
+"datePatterns"
+"dateTime"
+"dateTimeEdit"
+"dateTimeSymbols"
+"day"
+"dayNames"
+"debug"
+"decimal"
+"defaultTypeface"
+"defaultUi"
+"delete"
+"delta"
+"deltas"
+"desc"
+"destination"
+"digestMethod"
+"digestMethods"
+"documentAssembly"
+"draw"
+"driver"
+"dSigData"
+"duplexOption"
+"dynamicRender"
+"edge"
+"effectiveInputPolicy"
+"effectiveOutputPolicy"
+"embed"
+"encoding"
+"encodings"
+"encrypt"
+"encryption"
+"encryptionLevel"
+"encryptionMethod"
+"encryptionMethods"
+"enforce"
+"equate"
+"equateRange"
+"era"
+"eraNames"
+"event"
+"eventPseudoModel"
+"exclGroup"
+"exclude"
+"excludeNS"
+"exData"
+"execute"
+"exObject"
+"extras"
+"field"
+"fill"
+"filter"
+"flipLabel"
+"float"
+"font"
+"fontInfo"
+"form"
+"format"
+"formFieldFilling"
+"groupParent"
+"handler"
+"hostPseudoModel"
+"hyphenation"
+"ifEmpty"
+"image"
+"imageEdit"
+"includeXDPContent"
+"incrementalLoad"
+"incrementalMerge"
+"insert"
+"instanceManager"
+"integer"
+"interactive"
+"issuers"
+"items"
+"jog"
+"keep"
+"keyUsage"
+"labelPrinter"
+"layout"
+"layoutPseudoModel"
+"level"
+"line"
+"linear"
+"linearized"
+"list"
+"locale"
+"localeSet"
+"lockDocument"
+"log"
+"logPseudoModel"
+"manifest"
+"map"
+"margin"
+"mdp"
+"medium"
+"mediumInfo"
+"meridiem"
+"meridiemNames"
+"message"
+"messaging"
+"mode"
+"modifyAnnots"
+"month"
+"monthNames"
+"msgId"
+"nameAttr"
+"neverEmbed"
+"numberOfCopies"
+"numberPattern"
+"numberPatterns"
+"numberSymbol"
+"numberSymbols"
+"numericEdit"
+"object"
+"occur"
+"oid"
+"oids"
+"openAction"
+"operation"
+"output"
+"outputBin"
+"outputXSL"
+"overflow"
+"overprint"
+"packet"
+"packets"
+"pageArea"
+"pageOffset"
+"pageRange"
+"pageSet"
+"pagination"
+"paginationOverride"
+"para"
+"part"
+"password"
+"passwordEdit"
+"pattern"
+"pcl"
+"pdf"
+"pdfa"
+"permissions"
+"pickTrayByPDFSize"
+"picture"
+"plaintextMetadata"
+"presence"
+"present"
+"present"
+"print"
+"printerName"
+"printHighQuality"
+"printScaling"
+"producer"
+"proto"
+"ps"
+"psMap"
+"query"
+"radial"
+"range"
+"reason"
+"reasons"
+"record"
+"recordSet"
+"rectangle"
+"ref"
+"relevant"
+"rename"
+"renderPolicy"
+"rootElement"
+"runScripts"
+"script"
+"scriptModel"
+"select"
+"setProperty"
+"severity"
+"signature"
+"signatureProperties"
+"signaturePseudoModel"
+"signData"
+"signing"
+"silentPrint"
+"soapAction"
+"soapAddress"
+"solid"
+"source"
+"sourceSet"
+"speak"
+"staple"
+"startNode"
+"startPage"
+"stipple"
+"subform"
+"subform"
+"subformSet"
+"subjectDN"
+"subjectDNs"
+"submit"
+"submitFormat"
+"submitUrl"
+"subsetBelow"
+"suppressBanner"
+"tagged"
+"template"
+"template"
+"templateCache"
+"#text"
+"text"
+"textedit"
+"textEdit"
+"threshold"
+"time"
+"timePattern"
+"timePatterns"
+"timeStamp"
+"to"
+"toolTip"
+"trace"
+"transform"
+"traversal"
+"traverse"
+"treeList"
+"type"
+"typeface"
+"typefaces"
+"ui"
+"update"
+"uri"
+"user"
+"validate"
+"validate"
+"validateApprovalSignatures"
+"validationMessaging"
+"value"
+"variables"
+"version"
+"versionControl"
+"viewerPreferences"
+"webClient"
+"whitespace"
+"window"
+"wsdlAddress"
+"wsdlConnection"
+"xdc"
+"xdp"
+"xfa"
+"#xHTML"
+"#xml"
+"xmlConnection"
+"xsdConnection"
+"xsl"
+"zpl"
+
+# Attributes
+"activity"
+"activity"
+"baselineShift"
+"contentType"
+"h"
+"id"
+"layout"
+"layout"
+"leftInset"
+"locale"
+"long"
+"marginLeft"
+"marginRight"
+"marginRight"
+"mergeMode"
+"name"
+"ref"
+"scriptTest"
+"short"
+"size"
+"spaceAbove"
+"spaceBelow"
+"startNew"
+"stock"
+"tetIndent"
+"timeStamp"
+"typeface"
+"uuid"
+"vAlign"
+"value"
+"w"
+"weight"
+"x"
+"y"
+
+# Useful chars
+"<"
+">"
+"</"
+"="
diff --git a/sandbox/win/sandbox_standalone.sln b/sandbox/win/sandbox_standalone.sln
deleted file mode 100644
index 529d20e..0000000
--- a/sandbox/win/sandbox_standalone.sln
+++ /dev/null
@@ -1,127 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox", "src\sandbox.vcproj", "{881F6A97-D539-4C48-B401-DF04385B2343}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_unittests", "tests\unit_tests\sbox_unittests.vcproj", "{883553BE-2A9D-418C-A121-61FE1DFBC562}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
-	EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_validation_tests", "tests\validation_tests\sbox_validation_tests.vcproj", "{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
-	EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{BCE54389-D18D-48B9-977E-9D1998200F63}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debug_message", "..\base\debug_message.vcproj", "{F0F92189-193A-6607-C2BB-0F98BBD19ADF}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{7F36EE20-5016-4051-B0D7-42824CDA0291}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "proof_of_concept", "proof_of_concept", "{B607BE7B-3555-422C-A40B-28E73C0B5E24}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_poc", "sandbox_poc\sandbox_poc.vcproj", "{CF757839-F2A1-417C-8F25-DCAE480020F1}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {AE5BFB87-850E-4454-B01D-58E7D8BAC224}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocdll", "sandbox_poc\pocdll\pocdll.vcproj", "{AE5BFB87-850E-4454-B01D-58E7D8BAC224}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "finder", "tools\finder\finder.vcproj", "{ACDC2E06-0366-41A4-A646-C37E130A605D}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "tools\launcher\launcher.vcproj", "{386FA217-FBC2-4461-882D-CDAD221ED800}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_integration_tests", "tests\integration_tests\sbox_integration_tests.vcproj", "{542D4B3B-98D4-4233-B68D-0103891508C6}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
-		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "..\base\base.vcproj", "{1832A374-8A74-4F9E-B536-69A699B3E165}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\testing\gtest.vcproj", "{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Win32 = Debug|Win32
-		Release|Win32 = Release|Win32
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.ActiveCfg = Debug|Win32
-		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.Build.0 = Debug|Win32
-		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.ActiveCfg = Release|Win32
-		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.Build.0 = Release|Win32
-		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.ActiveCfg = Debug|Win32
-		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.Build.0 = Debug|Win32
-		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.ActiveCfg = Release|Win32
-		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.Build.0 = Release|Win32
-		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.ActiveCfg = Debug|Win32
-		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.Build.0 = Debug|Win32
-		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.ActiveCfg = Release|Win32
-		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.Build.0 = Release|Win32
-		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.ActiveCfg = Debug|Win32
-		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.Build.0 = Debug|Win32
-		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.ActiveCfg = Release|Win32
-		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.Build.0 = Release|Win32
-		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.ActiveCfg = Debug|Win32
-		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.Build.0 = Debug|Win32
-		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.ActiveCfg = Release|Win32
-		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.Build.0 = Release|Win32
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.ActiveCfg = Debug|Win32
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.Build.0 = Debug|Win32
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.ActiveCfg = Release|Win32
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.Build.0 = Release|Win32
-		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.ActiveCfg = Debug|Win32
-		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.Build.0 = Debug|Win32
-		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.ActiveCfg = Release|Win32
-		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.Build.0 = Release|Win32
-		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.ActiveCfg = Debug|Win32
-		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.Build.0 = Debug|Win32
-		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.ActiveCfg = Release|Win32
-		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.Build.0 = Release|Win32
-		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.ActiveCfg = Debug|Win32
-		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.Build.0 = Debug|Win32
-		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.ActiveCfg = Release|Win32
-		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.Build.0 = Release|Win32
-		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.ActiveCfg = Debug|Win32
-		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.Build.0 = Debug|Win32
-		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.ActiveCfg = Release|Win32
-		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.Build.0 = Release|Win32
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.ActiveCfg = Debug|Win32
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.Build.0 = Debug|Win32
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.ActiveCfg = Release|Win32
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.Build.0 = Release|Win32
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(NestedProjects) = preSolution
-		{883553BE-2A9D-418C-A121-61FE1DFBC562} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
-		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
-		{542D4B3B-98D4-4233-B68D-0103891508C6} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
-		{F0F92189-193A-6607-C2BB-0F98BBD19ADF} = {BCE54389-D18D-48B9-977E-9D1998200F63}
-		{1832A374-8A74-4F9E-B536-69A699B3E165} = {BCE54389-D18D-48B9-977E-9D1998200F63}
-		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BCE54389-D18D-48B9-977E-9D1998200F63}
-		{ACDC2E06-0366-41A4-A646-C37E130A605D} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
-		{386FA217-FBC2-4461-882D-CDAD221ED800} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
-		{CF757839-F2A1-417C-8F25-DCAE480020F1} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
-		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
-	EndGlobalSection
-EndGlobal
diff --git a/sandbox/win/src/sandbox.vcproj b/sandbox/win/src/sandbox.vcproj
deleted file mode 100644
index 229441c..0000000
--- a/sandbox/win/src/sandbox.vcproj
+++ /dev/null
@@ -1,648 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="8.00"
-	Name="sandbox"
-	ProjectGUID="{881F6A97-D539-4C48-B401-DF04385B2343}"
-	RootNamespace="sandbox"
-	Keyword="Win32Proj"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			ConfigurationType="4"
-			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				UsePrecompiledHeader="2"
-				ForcedIncludeFiles="stdafx.h"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			ConfigurationType="4"
-			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				UsePrecompiledHeader="0"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="security"
-			>
-			<File
-				RelativePath=".\acl.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\acl.h"
-				>
-			</File>
-			<File
-				RelativePath=".\dep.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\dep.h"
-				>
-			</File>
-			<File
-				RelativePath=".\job.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\job.h"
-				>
-			</File>
-			<File
-				RelativePath=".\restricted_token.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\restricted_token.h"
-				>
-			</File>
-			<File
-				RelativePath=".\restricted_token_utils.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\restricted_token_utils.h"
-				>
-			</File>
-			<File
-				RelativePath=".\security_level.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sid.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sid.h"
-				>
-			</File>
-			<File
-				RelativePath=".\window.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\window.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Interception"
-			>
-			<File
-				RelativePath=".\eat_resolver.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\eat_resolver.h"
-				>
-			</File>
-			<File
-				RelativePath=".\interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\interception_agent.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\interception_agent.h"
-				>
-			</File>
-			<File
-				RelativePath=".\interception_internal.h"
-				>
-			</File>
-			<File
-				RelativePath=".\pe_image.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\pe_image.h"
-				>
-			</File>
-			<File
-				RelativePath=".\resolver.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\resolver.h"
-				>
-			</File>
-			<File
-				RelativePath=".\service_resolver.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\service_resolver.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sidestep_resolver.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sidestep_resolver.h"
-				>
-			</File>
-			<File
-				RelativePath=".\target_interceptions.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\target_interceptions.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Wow64.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\Wow64.h"
-				>
-			</File>
-			<Filter
-				Name="sidestep"
-				>
-				<File
-					RelativePath=".\sidestep\ia32_modrm_map.cpp"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\ia32_opcode_map.cpp"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\mini_disassembler.cpp"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\mini_disassembler.h"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\mini_disassembler_types.h"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\preamble_patcher.h"
-					>
-				</File>
-				<File
-					RelativePath=".\sidestep\preamble_patcher_with_stub.cpp"
-					>
-				</File>
-			</Filter>
-		</Filter>
-		<Filter
-			Name="nt_level"
-			>
-			<File
-				RelativePath=".\nt_internals.h"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_target.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_target.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sandbox_nt_types.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sandbox_nt_util.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sandbox_nt_util.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Policy_handlers"
-			>
-			<File
-				RelativePath=".\filesystem_dispatcher.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\filesystem_dispatcher.h"
-				>
-			</File>
-			<File
-				RelativePath=".\filesystem_interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\filesystem_interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\filesystem_policy.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\filesystem_policy.h"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_dispatcher.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_dispatcher.h"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_policy.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\named_pipe_policy.h"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_params.h"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_dispatcher.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_dispatcher.h"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_policy.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\process_thread_policy.h"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_dispatcher.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_dispatcher.h"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_policy.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\registry_policy.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_dispatcher.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_dispatcher.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_interception.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_interception.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_policy.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sync_policy.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="IPC"
-			>
-			<File
-				RelativePath=".\crosscall_client.h"
-				>
-			</File>
-			<File
-				RelativePath=".\crosscall_params.h"
-				>
-			</File>
-			<File
-				RelativePath=".\crosscall_server.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\crosscall_server.h"
-				>
-			</File>
-			<File
-				RelativePath=".\ipc_tags.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sharedmem_ipc_client.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sharedmem_ipc_client.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sharedmem_ipc_server.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sharedmem_ipc_server.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Policy_base"
-			>
-			<File
-				RelativePath=".\policy_engine_opcodes.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_engine_opcodes.h"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_engine_params.h"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_engine_processor.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_engine_processor.h"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_low_level.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\policy_low_level.h"
-				>
-			</File>
-			<File
-				RelativePath=".\sandbox_policy_base.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\sandbox_policy_base.h"
-				>
-			</File>
-		</Filter>
-		<File
-			RelativePath=".\broker_services.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\broker_services.h"
-			>
-		</File>
-		<File
-			RelativePath=".\internal_types.h"
-			>
-		</File>
-		<File
-			RelativePath=".\policy_broker.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\policy_broker.h"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox.h"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox_factory.h"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox_policy.h"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox_types.h"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox_utils.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\sandbox_utils.h"
-			>
-		</File>
-		<File
-			RelativePath=".\shared_handles.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\shared_handles.h"
-			>
-		</File>
-		<File
-			RelativePath=".\stdafx.cc"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCLCompilerTool"
-					UsePrecompiledHeader="1"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCLCompilerTool"
-					UsePrecompiledHeader="0"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath=".\stdafx.h"
-			>
-		</File>
-		<File
-			RelativePath=".\target_process.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\target_process.h"
-			>
-		</File>
-		<File
-			RelativePath=".\target_services.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\target_services.h"
-			>
-		</File>
-		<File
-			RelativePath=".\win2k_threadpool.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\win2k_threadpool.h"
-			>
-		</File>
-		<File
-			RelativePath=".\win_utils.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\win_utils.h"
-			>
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj b/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
deleted file mode 100644
index 53816e7..0000000
--- a/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
+++ /dev/null
@@ -1,242 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="8.00"
-	Name="sbox_integration_tests"
-	ProjectGUID="{542D4B3B-98D4-4233-B68D-0103891508C6}"
-	RootNamespace="unit_tests"
-	Keyword="Win32Proj"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="2"
-				ForcedIncludeFiles="stdafx.h"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="0"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Common"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{49F2D231-E141-4455-B241-7D37C09B6EEB}"
-			>
-			<File
-				RelativePath="..\common\controller.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\common\controller.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\integration_tests.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\stdafx.cc"
-				>
-				<FileConfiguration
-					Name="Debug|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						UsePrecompiledHeader="1"
-					/>
-				</FileConfiguration>
-				<FileConfiguration
-					Name="Release|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						UsePrecompiledHeader="0"
-					/>
-				</FileConfiguration>
-			</File>
-			<File
-				RelativePath=".\stdafx.h"
-				>
-			</File>
-		</Filter>
-		<File
-			RelativePath="..\..\src\dep_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\file_policy_test.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\integration_tests_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\integrity_level_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\ipc_ping_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\named_pipe_policy_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\policy_target_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\process_policy_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\registry_policy_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\sync_policy_test.cc"
-			>
-		</File>
-		<File
-			RelativePath="..\..\src\unload_dll_test.cc"
-			>
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/sandbox/win/tests/unit_tests/sbox_unittests.vcproj b/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
deleted file mode 100644
index a2df792..0000000
--- a/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
+++ /dev/null
@@ -1,258 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="8.00"
-	Name="sbox_unittests"
-	ProjectGUID="{883553BE-2A9D-418C-A121-61FE1DFBC562}"
-	RootNamespace="unit_tests"
-	Keyword="Win32Proj"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="2"
-				WarningLevel="3"
-				ForcedIncludeFiles="stdafx.h"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Common"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\stdafx.cc"
-				>
-				<FileConfiguration
-					Name="Debug|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						UsePrecompiledHeader="1"
-					/>
-				</FileConfiguration>
-				<FileConfiguration
-					Name="Release|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						UsePrecompiledHeader="0"
-					/>
-				</FileConfiguration>
-			</File>
-			<File
-				RelativePath=".\stdafx.h"
-				>
-			</File>
-			<File
-				RelativePath=".\unit_tests.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="TestInterception"
-			>
-			<File
-				RelativePath="..\..\src\interception_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\..\src\pe_image_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\..\src\service_resolver_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="TestRestrictedToken"
-			>
-			<File
-				RelativePath="..\..\src\restricted_token_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="TestJob"
-			>
-			<File
-				RelativePath="..\..\src\job_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Sid"
-			>
-			<File
-				RelativePath="..\..\src\sid_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Policy"
-			>
-			<File
-				RelativePath="..\..\src\policy_engine_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\..\src\policy_low_level_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\..\src\policy_opcodes_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="IPC"
-			>
-			<File
-				RelativePath="..\..\src\ipc_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\..\src\threadpool_unittest.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj b/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
deleted file mode 100644
index 9b7b599..0000000
--- a/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
+++ /dev/null
@@ -1,216 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="8.00"
-	Name="sbox_validation_tests"
-	ProjectGUID="{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
-	RootNamespace="unit_tests"
-	Keyword="Win32Proj"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="2"
-				WarningLevel="3"
-				ForcedIncludeFiles="stdafx.h"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="shlwapi.lib"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="_CONSOLE"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="shlwapi.lib"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Common"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{2E6C7E35-7538-4883-B80C-C89961A80D66}"
-			>
-			<File
-				RelativePath="..\common\controller.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\common\controller.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\stdafx.cc"
-				>
-				<FileConfiguration
-					Name="Debug|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						UsePrecompiledHeader="1"
-					/>
-				</FileConfiguration>
-				<FileConfiguration
-					Name="Release|Win32"
-					ExcludedFromBuild="true"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-					/>
-				</FileConfiguration>
-			</File>
-			<File
-				RelativePath=".\stdafx.h"
-				>
-			</File>
-			<File
-				RelativePath=".\unit_tests.cc"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Suite"
-			>
-			<File
-				RelativePath=".\commands.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\commands.h"
-				>
-			</File>
-			<File
-				RelativePath=".\suite.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/services/audio/audio_processor.cc b/services/audio/audio_processor.cc
index dbe75ed1..5a9c742 100644
--- a/services/audio/audio_processor.cc
+++ b/services/audio/audio_processor.cc
@@ -36,8 +36,10 @@
   base::TimeTicks start_;
 };
 
-AudioProcessor::AudioProcessor(DeviceOutputListener* device_output_listener)
-    : device_output_listener_(device_output_listener) {
+AudioProcessor::AudioProcessor(DeviceOutputListener* device_output_listener,
+                               LogCallback log_callback)
+    : device_output_listener_(device_output_listener),
+      log_callback_(std::move(log_callback)) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   DCHECK(device_output_listener_);
 }
@@ -74,6 +76,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   DCHECK(active_);
   device_output_listener_->StopListening(this);
+  log_callback_.Run("AudioProcessor: stop listening");
   active_ = false;
   uma_logger_.reset();
 }
@@ -89,6 +92,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   DCHECK(active_);
   uma_logger_ = std::make_unique<UmaLogger>(output_device_id_);
+  log_callback_.Run(base::StrCat(
+      {"AudioProcessor: listening to output device: ", output_device_id_}));
   device_output_listener_->StartListening(this, output_device_id_);
 }
 
diff --git a/services/audio/audio_processor.h b/services/audio/audio_processor.h
index 2823948e..aec014a 100644
--- a/services/audio/audio_processor.h
+++ b/services/audio/audio_processor.h
@@ -7,8 +7,10 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/strings/string_piece.h"
 #include "services/audio/reference_output.h"
 
 namespace media {
@@ -20,7 +22,10 @@
 
 class AudioProcessor final : public ReferenceOutput::Listener {
  public:
-  explicit AudioProcessor(DeviceOutputListener* device_output_listener);
+  using LogCallback = base::RepeatingCallback<void(base::StringPiece)>;
+
+  AudioProcessor(DeviceOutputListener* device_output_listener,
+                 LogCallback log_callback);
   AudioProcessor(const AudioProcessor&) = delete;
   AudioProcessor& operator=(const AudioProcessor&) = delete;
   ~AudioProcessor() final;
@@ -42,6 +47,7 @@
   bool active_ = false;
   std::string output_device_id_;
   raw_ptr<DeviceOutputListener> const device_output_listener_;
+  const LogCallback log_callback_;
   std::unique_ptr<UmaLogger> uma_logger_;
 };
 
diff --git a/services/audio/input_controller.cc b/services/audio/input_controller.cc
index bdb84f2..f13afc7 100644
--- a/services/audio/input_controller.cc
+++ b/services/audio/input_controller.cc
@@ -224,8 +224,12 @@
   DCHECK(activity_monitor_);
 
 #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION)
-  if (device_output_listener)
-    audio_processor_ = std::make_unique<AudioProcessor>(device_output_listener);
+  if (device_output_listener) {
+    // Unretained() is safe, because |handler_| outlives |audio_processor_|.
+    audio_processor_ = std::make_unique<AudioProcessor>(
+        device_output_listener,
+        base::BindRepeating(&EventHandler::OnLog, base::Unretained(handler_)));
+  }
 #endif
 
   if (!user_input_monitor_) {
diff --git a/services/audio/public/cpp/BUILD.gn b/services/audio/public/cpp/BUILD.gn
index 3dbf5a8..f1faf29 100644
--- a/services/audio/public/cpp/BUILD.gn
+++ b/services/audio/public/cpp/BUILD.gn
@@ -20,8 +20,6 @@
     "sounds/audio_stream_handler.h",
     "sounds/sounds_manager.cc",
     "sounds/sounds_manager.h",
-    "sounds/test_data.cc",
-    "sounds/test_data.h",
   ]
 
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
@@ -42,11 +40,14 @@
     "fake_stream_factory.h",
     "fake_system_info.cc",
     "fake_system_info.h",
+    "sounds/test_data.cc",
+    "sounds/test_data.h",
   ]
 
   deps = [ "//testing/gmock" ]
 
   public_deps = [
+    ":cpp",
     "//base",
     "//media",
     "//services/audio",
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index 99fa5c19..abce7ae 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -92,7 +92,7 @@
 void CookieManager::GetCookieList(
     const GURL& url,
     const net::CookieOptions& cookie_options,
-    const net::CookiePartitionKeychain& cookie_partition_keychain,
+    const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
     GetCookieListCallback callback) {
 #if !defined(OS_IOS)
   if (g_crash_on_get_cookie_list)
@@ -101,7 +101,7 @@
 
   cookie_store_->GetCookieListWithOptionsAsync(
       url, cookie_options,
-      cookie_partition_keychain.FirstPartySetify(
+      cookie_partition_key_collection.FirstPartySetify(
           cookie_store_->cookie_access_delegate()),
       std::move(callback));
 }
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h
index 66b928c..bb988d9 100644
--- a/services/network/cookie_manager.h
+++ b/services/network/cookie_manager.h
@@ -65,7 +65,7 @@
   void GetCookieList(
       const GURL& url,
       const net::CookieOptions& cookie_options,
-      const net::CookiePartitionKeychain& cookie_partition_keychain,
+      const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) override;
   void SetCanonicalCookie(const net::CanonicalCookie& cookie,
                           const GURL& source_url,
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index 54912a1e..fea2731 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -122,11 +122,12 @@
   std::vector<net::CanonicalCookie> GetCookieList(
       const GURL& url,
       net::CookieOptions options,
-      const net::CookiePartitionKeychain& cookie_partition_keychain) {
+      const net::CookiePartitionKeyCollection&
+          cookie_partition_key_collection) {
     base::RunLoop run_loop;
     std::vector<net::CanonicalCookie> cookies_out;
     cookie_service_->GetCookieList(
-        url, options, cookie_partition_keychain,
+        url, options, cookie_partition_key_collection,
         base::BindLambdaForTesting(
             [&run_loop, &cookies_out](
                 const net::CookieAccessResultList& cookies,
@@ -139,14 +140,15 @@
   }
 
   // TODO(crbug.com/1225444): CookieManager should be able to see which cookies
-  // are excluded because their partition key is not contained in the keychain.
+  // are excluded because their partition key is not contained in the
+  // key collection.
   net::CookieAccessResultList GetExcludedCookieList(
       const GURL& url,
       net::CookieOptions options) {
     base::RunLoop run_loop;
     net::CookieAccessResultList cookies_out;
     cookie_service_->GetCookieList(
-        url, options, net::CookiePartitionKeychain::Todo(),
+        url, options, net::CookiePartitionKeyCollection::Todo(),
         base::BindLambdaForTesting(
             [&run_loop, &cookies_out](
                 const net::CookieAccessResultList& cookies,
@@ -679,9 +681,9 @@
   net::CookieOptions options;
   options.set_same_site_cookie_context(
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
-  std::vector<net::CanonicalCookie> cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
 
   ASSERT_EQ(2u, cookies.size());
   std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
@@ -733,9 +735,9 @@
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
 
   EXPECT_TRUE(options.exclude_httponly());
-  std::vector<net::CanonicalCookie> cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("C", cookies[0].Name());
 
@@ -749,9 +751,9 @@
 
   // Retrieve with httponly cookies.
   options.set_include_httponly();
-  cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(2u, cookies.size());
   std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
 
@@ -794,9 +796,9 @@
       net::CookieOptions::SameSiteCookieContext(
           net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
       options.same_site_cookie_context());
-  std::vector<net::CanonicalCookie> cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("A", cookies[0].Name());
 
@@ -812,9 +814,9 @@
       net::CookieOptions::SameSiteCookieContext(
           net::CookieOptions::SameSiteCookieContext::ContextType::
               SAME_SITE_LAX));
-  cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(2u, cookies.size());
   std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
   EXPECT_EQ("A", cookies[0].Name());
@@ -827,9 +829,9 @@
   // Retrieve everything.
   options.set_same_site_cookie_context(
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
-  cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(3u, cookies.size());
   std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
   EXPECT_EQ("A", cookies[0].Name());
@@ -910,7 +912,7 @@
     // non-SameSite=None cookies are excluded.
     EXPECT_THAT(
         service_wrapper()->GetCookieList(cookie_url, options,
-                                         net::CookiePartitionKeychain()),
+                                         net::CookiePartitionKeyCollection()),
         UnorderedElementsAre(net::MatchesCookieWithName("nonSameParty-None")));
 
     EXPECT_THAT(
@@ -928,7 +930,7 @@
     options.set_same_party_context(
         net::SamePartyContext(net::SamePartyContext::Type::kSameParty));
     EXPECT_THAT(service_wrapper()->GetCookieList(
-                    cookie_url, options, net::CookiePartitionKeychain()),
+                    cookie_url, options, net::CookiePartitionKeyCollection()),
                 UnorderedElementsAre(
                     net::MatchesCookieWithName("SameParty-Unspecified"),
                     net::MatchesCookieWithName("SameParty-None"),
@@ -944,7 +946,7 @@
     options.set_same_site_cookie_context(
         net::CookieOptions::SameSiteCookieContext::MakeInclusive());
     EXPECT_THAT(service_wrapper()->GetCookieList(
-                    cookie_url, options, net::CookiePartitionKeychain()),
+                    cookie_url, options, net::CookiePartitionKeyCollection()),
                 UnorderedElementsAre(
                     net::MatchesCookieWithName("SameParty-Unspecified"),
                     net::MatchesCookieWithName("SameParty-None"),
@@ -973,7 +975,7 @@
     // Cross-party, cross-site.
     EXPECT_THAT(
         service_wrapper()->GetCookieList(cookie_url, options,
-                                         net::CookiePartitionKeychain()),
+                                         net::CookiePartitionKeyCollection()),
         UnorderedElementsAre(net::MatchesCookieWithName("SameParty-None"),
                              net::MatchesCookieWithName("nonSameParty-None")));
 
@@ -990,7 +992,7 @@
         net::SamePartyContext(net::SamePartyContext::Type::kSameParty));
     EXPECT_THAT(
         service_wrapper()->GetCookieList(cookie_url, options,
-                                         net::CookiePartitionKeychain()),
+                                         net::CookiePartitionKeyCollection()),
         UnorderedElementsAre(net::MatchesCookieWithName("SameParty-None"),
                              net::MatchesCookieWithName("nonSameParty-None")));
     EXPECT_THAT(
@@ -1005,7 +1007,7 @@
     options.set_same_site_cookie_context(
         net::CookieOptions::SameSiteCookieContext::MakeInclusive());
     EXPECT_THAT(service_wrapper()->GetCookieList(
-                    cookie_url, options, net::CookiePartitionKeychain()),
+                    cookie_url, options, net::CookiePartitionKeyCollection()),
                 UnorderedElementsAre(
                     net::MatchesCookieWithName("SameParty-Unspecified"),
                     net::MatchesCookieWithName("SameParty-None"),
@@ -1018,7 +1020,7 @@
   }
 }
 
-TEST_F(CookieManagerTest, GetCookieListCookiePartitionKeychain) {
+TEST_F(CookieManagerTest, GetCookieListCookiePartitionKeyCollection) {
   // Add unpartitioned cookie.
   ASSERT_TRUE(SetCanonicalCookie(
       *net::CanonicalCookie::CreateUnsafeCookieForTesting(
@@ -1060,28 +1062,30 @@
                   GURL("https://www.c.com")))),
       "https", true));
 
-  // Test empty keychain.
-  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
-      GURL("https://foo_host.com/with/path"),
-      net::CookieOptions::MakeAllInclusive(), net::CookiePartitionKeychain());
+  // Test empty key_collection.
+  std::vector<net::CanonicalCookie> cookies =
+      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
+                                       net::CookieOptions::MakeAllInclusive(),
+                                       net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("__Host-A", cookies[0].Name());
 
-  // Test keychain with single partition key.
+  // Test key_collection with single partition key.
   cookies = service_wrapper()->GetCookieList(
       GURL("https://foo_host.com/with/path"),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(net::CookiePartitionKey::FromURLForTesting(
-          GURL("https://subdomain.a.com"))));
+      net::CookiePartitionKeyCollection(
+          net::CookiePartitionKey::FromURLForTesting(
+              GURL("https://subdomain.a.com"))));
   ASSERT_EQ(2u, cookies.size());
   EXPECT_EQ("__Host-A", cookies[0].Name());
   EXPECT_EQ("__Host-B", cookies[1].Name());
 
-  // Test keychain with multiple partition keys.
+  // Test key_collection with multiple partition keys.
   cookies = service_wrapper()->GetCookieList(
       GURL("https://foo_host.com/with/path"),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain({
+      net::CookiePartitionKeyCollection({
           net::CookiePartitionKey::FromURLForTesting(
               GURL("https://subdomain.a.com")),
           net::CookiePartitionKey::FromURLForTesting(
@@ -1092,11 +1096,11 @@
   EXPECT_EQ("__Host-B", cookies[1].Name());
   EXPECT_EQ("__Host-C", cookies[2].Name());
 
-  // Test keychain with all partition keys.
+  // Test key_collection with all partition keys.
   cookies = service_wrapper()->GetCookieList(
       GURL("https://foo_host.com/with/path"),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain::ContainsAll());
+      net::CookiePartitionKeyCollection::ContainsAll());
   ASSERT_EQ(4u, cookies.size());
   EXPECT_EQ("__Host-A", cookies[0].Name());
   EXPECT_EQ("__Host-B", cookies[1].Name());
@@ -1121,9 +1125,9 @@
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
 
   options.set_do_not_update_access_time();
-  std::vector<net::CanonicalCookie> cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("A", cookies[0].Name());
   EXPECT_TRUE(cookies[0].LastAccessDate().is_null());
@@ -1132,9 +1136,9 @@
   // that it's a valid value.
   base::Time start(base::Time::Now());
   options.set_update_access_time();
-  cookies =
-      service_wrapper()->GetCookieList(GURL("https://foo_host.com/with/path"),
-                                       options, net::CookiePartitionKeychain());
+  cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host.com/with/path"), options,
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("A", cookies[0].Name());
   EXPECT_FALSE(cookies[0].LastAccessDate().is_null());
@@ -1252,7 +1256,7 @@
   std::vector<net::CanonicalCookie> http_localhost_cookies =
       service_wrapper()->GetCookieList(http_localhost_url,
                                        net::CookieOptions::MakeAllInclusive(),
-                                       net::CookiePartitionKeychain());
+                                       net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, http_localhost_cookies.size());
   EXPECT_EQ("http_localhost", http_localhost_cookies[0].Name());
   EXPECT_EQ(net::CookieSourceScheme::kNonSecure,
@@ -1296,7 +1300,7 @@
   std::vector<net::CanonicalCookie> http_other_cookies =
       service_wrapper()->GetCookieList(http_other_url,
                                        net::CookieOptions::MakeAllInclusive(),
-                                       net::CookiePartitionKeychain());
+                                       net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, http_other_cookies.size());
   EXPECT_EQ("http_other", http_other_cookies[0].Name());
   EXPECT_EQ(net::CookieSourceScheme::kNonSecure,
@@ -2612,7 +2616,7 @@
 
   std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
       GURL("http://www.other.host/"), net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain());
+      net::CookiePartitionKeyCollection());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ("X", cookies[0].Name());
   EXPECT_EQ("Y", cookies[0].Value());
@@ -2990,7 +2994,7 @@
   auto cookies = service_wrapper()->GetCookieList(
       GURL("https://foo_host.com/with/path"),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(member_partition_key_));
+      net::CookiePartitionKeyCollection(member_partition_key_));
   EXPECT_EQ(2u, cookies.size());
   EXPECT_EQ("__Host-unpartitioned", cookies[0].Name());
   EXPECT_EQ("__Host-intheset", cookies[1].Name());
@@ -3031,7 +3035,7 @@
   auto cookies = service_wrapper()->GetCookieList(
       GURL("https://foo_host.com/with/path"),
       net::CookieOptions::MakeAllInclusive(),
-      net::CookiePartitionKeychain(owner_partition_key_));
+      net::CookiePartitionKeyCollection(owner_partition_key_));
   EXPECT_EQ(2u, cookies.size());
   EXPECT_EQ("__Host-unpartitioned", cookies[0].Name());
   EXPECT_EQ("__Host-intheset", cookies[1].Name());
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 8ae22bd..adef22b 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2590,7 +2590,7 @@
       ->GetCookieListWithOptionsAsync(
           GURL("http://www.test.com/whatever"),
           net::CookieOptions::MakeAllInclusive(),
-          net::CookiePartitionKeychain(),
+          net::CookiePartitionKeyCollection(),
           base::BindOnce(&GetCookieListCallback, &run_loop2, &cookies));
   run_loop2.Run();
   ASSERT_EQ(1u, cookies.size());
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
index b670d7dc..d54625c 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -482,30 +482,31 @@
   return true;
 }
 
-const std::vector<net::CookiePartitionKey> StructTraits<
-    network::mojom::CookiePartitionKeychainDataView,
-    net::CookiePartitionKeychain>::keys(const net::CookiePartitionKeychain&
-                                            keychain) {
+const std::vector<net::CookiePartitionKey>
+StructTraits<network::mojom::CookiePartitionKeyCollectionDataView,
+             net::CookiePartitionKeyCollection>::
+    keys(const net::CookiePartitionKeyCollection& key_collection) {
   std::vector<net::CookiePartitionKey> result;
-  if (keychain.ContainsAllKeys() || keychain.IsEmpty())
+  if (key_collection.ContainsAllKeys() || key_collection.IsEmpty())
     return result;
-  result.insert(result.begin(), keychain.PartitionKeys().begin(),
-                keychain.PartitionKeys().end());
+  result.insert(result.begin(), key_collection.PartitionKeys().begin(),
+                key_collection.PartitionKeys().end());
   return result;
 }
 
-bool StructTraits<network::mojom::CookiePartitionKeychainDataView,
-                  net::CookiePartitionKeychain>::
-    Read(network::mojom::CookiePartitionKeychainDataView keychain,
-         net::CookiePartitionKeychain* out) {
-  if (keychain.contains_all_partitions()) {
-    *out = net::CookiePartitionKeychain::ContainsAll();
+bool StructTraits<network::mojom::CookiePartitionKeyCollectionDataView,
+                  net::CookiePartitionKeyCollection>::
+    Read(network::mojom::CookiePartitionKeyCollectionDataView
+             key_collection_data_view,
+         net::CookiePartitionKeyCollection* out) {
+  if (key_collection_data_view.contains_all_partitions()) {
+    *out = net::CookiePartitionKeyCollection::ContainsAll();
     return true;
   }
   std::vector<net::CookiePartitionKey> keys;
-  if (!keychain.ReadKeys(&keys))
+  if (!key_collection_data_view.ReadKeys(&keys))
     return false;
-  *out = net::CookiePartitionKeychain(keys);
+  *out = net::CookiePartitionKeyCollection(keys);
   return true;
 }
 
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
index 7ec1fee..c2dc387 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -15,7 +15,7 @@
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_inclusion_status.h"
 #include "net/cookies/cookie_options.h"
-#include "net/cookies/cookie_partition_keychain.h"
+#include "net/cookies/cookie_partition_key_collection.h"
 #include "net/cookies/same_party_context.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -199,17 +199,18 @@
 };
 
 template <>
-struct StructTraits<network::mojom::CookiePartitionKeychainDataView,
-                    net::CookiePartitionKeychain> {
+struct StructTraits<network::mojom::CookiePartitionKeyCollectionDataView,
+                    net::CookiePartitionKeyCollection> {
   static bool contains_all_partitions(
-      const net::CookiePartitionKeychain& keychain) {
-    return keychain.ContainsAllKeys();
+      const net::CookiePartitionKeyCollection& key_collection) {
+    return key_collection.ContainsAllKeys();
   }
   static const std::vector<net::CookiePartitionKey> keys(
-      const net::CookiePartitionKeychain& keychain);
+      const net::CookiePartitionKeyCollection& key_collection);
 
-  static bool Read(network::mojom::CookiePartitionKeychainDataView keychain,
-                   net::CookiePartitionKeychain* out);
+  static bool Read(network::mojom::CookiePartitionKeyCollectionDataView
+                       key_collection_data_view,
+                   net::CookiePartitionKeyCollection* out);
 };
 
 template <>
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
index c15fa4a..650ff5c 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
@@ -397,27 +397,25 @@
   EXPECT_TRUE(copied.PartitionKey()->from_script());
 }
 
-TEST(CookieManagerTraitsTest, Roundtrips_CookiePartitionKeychain) {
+TEST(CookieManagerTraitsTest, Roundtrips_CookiePartitionKeyCollection) {
   {
-    net::CookiePartitionKeychain original;
-    net::CookiePartitionKeychain copied;
+    net::CookiePartitionKeyCollection original;
+    net::CookiePartitionKeyCollection copied;
 
-    EXPECT_TRUE(
-        mojo::test::SerializeAndDeserialize<mojom::CookiePartitionKeychain>(
-            original, copied));
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+                mojom::CookiePartitionKeyCollection>(original, copied));
     EXPECT_FALSE(copied.ContainsAllKeys());
     EXPECT_EQ(0u, copied.PartitionKeys().size());
   }
 
   {
-    net::CookiePartitionKeychain original(
+    net::CookiePartitionKeyCollection original(
         net::CookiePartitionKey::FromURLForTesting(
             GURL("https://www.example.com")));
-    net::CookiePartitionKeychain copied;
+    net::CookiePartitionKeyCollection copied;
 
-    EXPECT_TRUE(
-        mojo::test::SerializeAndDeserialize<mojom::CookiePartitionKeychain>(
-            original, copied));
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+                mojom::CookiePartitionKeyCollection>(original, copied));
     EXPECT_FALSE(copied.ContainsAllKeys());
     EXPECT_THAT(copied.PartitionKeys(),
                 testing::UnorderedElementsAre(
@@ -426,15 +424,14 @@
   }
 
   {
-    net::CookiePartitionKeychain original({
+    net::CookiePartitionKeyCollection original({
         net::CookiePartitionKey::FromURLForTesting(GURL("https://a.foo.com")),
         net::CookiePartitionKey::FromURLForTesting(GURL("https://b.bar.com")),
     });
-    net::CookiePartitionKeychain copied;
+    net::CookiePartitionKeyCollection copied;
 
-    EXPECT_TRUE(
-        mojo::test::SerializeAndDeserialize<mojom::CookiePartitionKeychain>(
-            original, copied));
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+                mojom::CookiePartitionKeyCollection>(original, copied));
     EXPECT_FALSE(copied.ContainsAllKeys());
     EXPECT_THAT(copied.PartitionKeys(),
                 testing::UnorderedElementsAre(
@@ -445,13 +442,12 @@
   }
 
   {
-    net::CookiePartitionKeychain original =
-        net::CookiePartitionKeychain::ContainsAll();
-    net::CookiePartitionKeychain copied;
+    net::CookiePartitionKeyCollection original =
+        net::CookiePartitionKeyCollection::ContainsAll();
+    net::CookiePartitionKeyCollection copied;
 
-    EXPECT_TRUE(
-        mojo::test::SerializeAndDeserialize<mojom::CookiePartitionKeychain>(
-            original, copied));
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+                mojom::CookiePartitionKeyCollection>(original, copied));
     EXPECT_TRUE(copied.ContainsAllKeys());
   }
 }
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 1fa2508..0e735dd 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -809,8 +809,8 @@
           cpp = "::net::CookieOptions"
         },
         {
-          mojom = "network.mojom.CookiePartitionKeychain"
-          cpp = "::net::CookiePartitionKeychain"
+          mojom = "network.mojom.CookiePartitionKeyCollection"
+          cpp = "::net::CookiePartitionKeyCollection"
         },
         {
           mojom = "network.mojom.CanonicalCookie"
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
index 44476e20..e08f8ce 100644
--- a/services/network/public/mojom/cookie_manager.mojom
+++ b/services/network/public/mojom/cookie_manager.mojom
@@ -161,7 +161,7 @@
   mojo_base.mojom.UnguessableToken? nonce;
 };
 
-struct CookiePartitionKeychain {
+struct CookiePartitionKeyCollection {
   bool contains_all_partitions = false;
   array<CookiePartitionKey> keys;
 };
@@ -359,7 +359,7 @@
 
   // Get all cookies for the specified URL and cookie options.
   // Will also return any partitioned cookies whose partition key are in
-  // |cookie_partition_keychain|.
+  // |cookie_partition_key_collection|.
   // Returned cookie list is sorted first by path length (longest first)
   // and second by creation time. If the |return_excluded_cookies| option is set
   // in the options, |excluded_cookies| with be a list of cookies that were
@@ -367,7 +367,7 @@
   // default, that option is not set and |excluded_cookies| is an empty list.
   GetCookieList(url.mojom.Url url,
                 CookieOptions cookie_options,
-                CookiePartitionKeychain cookie_partition_keychain)
+                CookiePartitionKeyCollection cookie_partition_key_collection)
       => (array<CookieWithAccessResult> cookies,
           array<CookieWithAccessResult> excluded_cookies);
 
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index ddd5c03..c17b4d0 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -352,8 +352,8 @@
   cookie_partition_key_ = net::CookieAccessDelegate::CreateCookiePartitionKey(
       cookie_store_->cookie_access_delegate(),
       isolation_info_.network_isolation_key());
-  cookie_partition_keychain_ =
-      net::CookiePartitionKeychain::FromOptional(cookie_partition_key_);
+  cookie_partition_key_collection_ =
+      net::CookiePartitionKeyCollection::FromOptional(cookie_partition_key_);
 }
 
 void RestrictedCookieManager::GetAllForUrl(
@@ -379,7 +379,7 @@
   net_options.set_return_excluded_cookies();
 
   cookie_store_->GetCookieListWithOptionsAsync(
-      url, net_options, cookie_partition_keychain_,
+      url, net_options, cookie_partition_key_collection_,
       base::BindOnce(&RestrictedCookieManager::CookieListToGetAllForUrlCallback,
                      weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies,
                      top_frame_origin, net_options, std::move(options),
diff --git a/services/network/restricted_cookie_manager.h b/services/network/restricted_cookie_manager.h
index ea892b3..1333fcb 100644
--- a/services/network/restricted_cookie_manager.h
+++ b/services/network/restricted_cookie_manager.h
@@ -209,10 +209,10 @@
   // Cookie partition key that the instance of RestrictedCookieManager will have
   // access to.
   absl::optional<net::CookiePartitionKey> cookie_partition_key_;
-  // CookiePartitionKeychain that is either empty if `cookie_partition_key_` is
-  // nullopt. If `cookie_partition_key_` is not null, the keychain contains its
-  // value.
-  net::CookiePartitionKeychain cookie_partition_keychain_;
+  // CookiePartitionKeyCollection that is either empty if
+  // `cookie_partition_key_` is nullopt. If `cookie_partition_key_` is not null,
+  // the key collection contains its value.
+  net::CookiePartitionKeyCollection cookie_partition_key_collection_;
 
   // Contains a mapping of url/site -> recent cookie updates for duplicate
   // update filtering.
diff --git a/services/network/test/test_cookie_manager.h b/services/network/test/test_cookie_manager.h
index 0a485c73..40a34ac3 100644
--- a/services/network/test/test_cookie_manager.h
+++ b/services/network/test/test_cookie_manager.h
@@ -31,7 +31,7 @@
   void GetCookieList(
       const GURL& url,
       const net::CookieOptions& cookie_options,
-      const net::CookiePartitionKeychain& cookie_partition_keychain,
+      const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
       GetCookieListCallback callback) override {}
   void DeleteCanonicalCookie(const net::CanonicalCookie& cookie,
                              DeleteCanonicalCookieCallback callback) override {}
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ac0e81c0..ca4973f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8735,7 +8735,7 @@
                         "mode": "0",
                         "reference_window_delay": "5",
                         "reference_window_length": "5",
-                        "use_predicted_step": "false",
+                        "use_predicted_step": "true",
                         "window_length": "5"
                     },
                     "enable_features": [
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 391f6b2a..df46093 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3399,6 +3399,7 @@
   kCrossOriginOpenerPolicySameOriginReportOnly = 4090,
   kImageLoadAtDismissalEvent = 4091,
   kPrivateNetworkAccessIgnoredPreflightError = 4092,
+  kAbortPaymentRespondWithTrue = 4093,
 
 
   // Add new features immediately above this line. Don't change assigned
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index ec30aa6..c26a418 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -50,6 +50,8 @@
 
 class WebServiceWorkerContextProxy;
 class WebString;
+class WebURLResponse;
+struct WebServiceWorkerError;
 
 // WebServiceWorkerContextClient is a "client" of a service worker execution
 // context. This interface is implemented by the embedder and allows the
@@ -168,6 +170,27 @@
   // worker. This is called on the initiator thread.
   virtual scoped_refptr<blink::WebServiceWorkerFetchContext>
   CreateWorkerFetchContextOnInitiatorThread() = 0;
+
+  // Called to resolve the FetchEvent.preloadResponse promise.
+  virtual void OnNavigationPreloadResponse(
+      int fetch_event_id,
+      std::unique_ptr<WebURLResponse> response,
+      mojo::ScopedDataPipeConsumerHandle data_pipe) = 0;
+
+  // Called when the navigation preload request completed. Either
+  // OnNavigationPreloadComplete() or OnNavigationPreloadError() must be
+  // called to release the preload related resources.
+  virtual void OnNavigationPreloadComplete(int fetch_event_id,
+                                           base::TimeTicks completion_time,
+                                           int64_t encoded_data_length,
+                                           int64_t encoded_body_length,
+                                           int64_t decoded_body_length) = 0;
+
+  // Called when an error occurred while receiving the response of the
+  // navigation preload request.
+  virtual void OnNavigationPreloadError(
+      int fetch_event_id,
+      std::unique_ptr<WebServiceWorkerError> error) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index 55895d1..231977e 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -202,6 +202,7 @@
 StringKeyframeEffectModel* CreateKeyframeEffectModel(
     StyleResolver* resolver,
     Element& element,
+    const Element& animating_element,
     const ComputedStyle* style,
     const ComputedStyle* parent_style,
     const AtomicString& name,
@@ -227,7 +228,7 @@
   //    existing animation matching name is canceled.
 
   const StyleRuleKeyframes* keyframes_rule =
-      resolver->FindKeyframesRule(&element, name);
+      resolver->FindKeyframesRule(&element, &animating_element, name);
   DCHECK(keyframes_rule);
 
   // 3. Let keyframes be an empty sequence of keyframe objects.
@@ -651,7 +652,7 @@
       timing.timing_function = Timing().timing_function;
 
       StyleRuleKeyframes* keyframes_rule =
-          resolver->FindKeyframesRule(&element, name);
+          resolver->FindKeyframesRule(&element, &animating_element, name);
       if (!keyframes_rule)
         continue;  // Cancel the animation if there's no style rule for it.
 
@@ -758,9 +759,9 @@
           update.UpdateAnimation(
               existing_animation_index, animation,
               *MakeGarbageCollected<InertEffect>(
-                  CreateKeyframeEffectModel(resolver, element, &style,
-                                            parent_style, name,
-                                            keyframe_timing_function.get(), i),
+                  CreateKeyframeEffectModel(
+                      resolver, element, animating_element, &style,
+                      parent_style, name, keyframe_timing_function.get(), i),
                   timing, is_paused, inherited_time, inherited_phase,
                   timeline_duration, animation->playbackRate()),
               specified_timing, keyframes_rule, timeline,
@@ -783,15 +784,16 @@
             inherited_time = timeline->CurrentTime();
           }
         }
-        update.StartAnimation(name, name_index, i,
-                              *MakeGarbageCollected<InertEffect>(
-                                  CreateKeyframeEffectModel(
-                                      resolver, element, &style, parent_style,
-                                      name, keyframe_timing_function.get(), i),
-                                  timing, is_paused, inherited_time,
-                                  inherited_phase, timeline_duration, 1.0),
-                              specified_timing, keyframes_rule, timeline,
-                              animation_data->PlayStateList());
+        update.StartAnimation(
+            name, name_index, i,
+            *MakeGarbageCollected<InertEffect>(
+                CreateKeyframeEffectModel(resolver, element, animating_element,
+                                          &style, parent_style, name,
+                                          keyframe_timing_function.get(), i),
+                timing, is_paused, inherited_time, inherited_phase,
+                timeline_duration, 1.0),
+            specified_timing, keyframes_rule, timeline,
+            animation_data->PlayStateList());
       }
     }
   }
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index c1b7aaa79..147e212 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -646,47 +646,58 @@
 
 }  // namespace
 
-void StyleResolver::MatchUARules(const Element& element,
-                                 ElementRuleCollector& collector) {
-  collector.SetMatchingUARules(true);
-
+template <typename Functor>
+void StyleResolver::ForEachUARulesForElement(const Element& element,
+                                             ElementRuleCollector* collector,
+                                             Functor& func) const {
   CSSDefaultStyleSheets& default_style_sheets =
       CSSDefaultStyleSheets::Instance();
   if (!print_media_type_) {
     if (LIKELY(element.IsHTMLElement() || element.IsVTTElement())) {
-      MatchRuleSet(collector, default_style_sheets.DefaultHtmlStyle());
+      func(default_style_sheets.DefaultHtmlStyle());
       if (UNLIKELY(IsInMediaUAShadow(element))) {
-        MatchRuleSet(collector,
-                     default_style_sheets.DefaultMediaControlsStyle());
+        func(default_style_sheets.DefaultMediaControlsStyle());
       }
     } else if (element.IsSVGElement()) {
-      MatchRuleSet(collector, default_style_sheets.DefaultSVGStyle());
+      func(default_style_sheets.DefaultSVGStyle());
     } else if (element.namespaceURI() == mathml_names::kNamespaceURI) {
-      MatchRuleSet(collector, default_style_sheets.DefaultMathMLStyle());
+      func(default_style_sheets.DefaultMathMLStyle());
     }
   } else {
-    MatchRuleSet(collector, default_style_sheets.DefaultPrintStyle());
+    func(default_style_sheets.DefaultPrintStyle());
   }
 
   // In quirks mode, we match rules from the quirks user agent sheet.
   if (GetDocument().InQuirksMode())
-    MatchRuleSet(collector, default_style_sheets.DefaultHtmlQuirksStyle());
+    func(default_style_sheets.DefaultHtmlQuirksStyle());
 
-  // If document uses view source styles (in view source mode or in xml viewer
-  // mode), then we match rules from the view source style sheet.
+  // If document uses view source styles (in view source mode or in xml
+  // viewer mode), then we match rules from the view source style sheet.
   if (GetDocument().IsViewSource())
-    MatchRuleSet(collector, default_style_sheets.DefaultViewSourceStyle());
+    func(default_style_sheets.DefaultViewSourceStyle());
 
   // If the system is in forced colors mode, match rules from the forced colors
   // style sheet.
   if (IsForcedColorsModeEnabled())
-    MatchRuleSet(collector, default_style_sheets.DefaultForcedColorStyle());
+    func(default_style_sheets.DefaultForcedColorStyle());
 
-  if (collector.IsCollectingForPseudoElement()) {
+  if (element.IsPseudoElement() ||
+      (collector && collector->IsCollectingForPseudoElement())) {
     if (RuleSet* default_pseudo_style =
-            default_style_sheets.DefaultPseudoElementStyleOrNull())
-      MatchRuleSet(collector, default_pseudo_style);
+            default_style_sheets.DefaultPseudoElementStyleOrNull()) {
+      func(default_style_sheets.DefaultPseudoElementStyleOrNull());
+    }
   }
+}
+
+void StyleResolver::MatchUARules(const Element& element,
+                                 ElementRuleCollector& collector) {
+  collector.SetMatchingUARules(true);
+
+  auto func = [this, &collector](RuleSet* rules) {
+    MatchRuleSet(collector, rules);
+  };
+  ForEachUARulesForElement(element, &collector, func);
 
   collector.FinishAddingUARules();
   collector.SetMatchingUARules(false);
@@ -1408,6 +1419,7 @@
 
 StyleRuleKeyframes* StyleResolver::FindKeyframesRule(
     const Element* element,
+    const Element* animating_element,
     const AtomicString& animation_name) {
   HeapVector<Member<ScopedStyleResolver>, 8> resolvers;
   CollectScopedResolversForHostedShadowTrees(*element, resolvers);
@@ -1426,6 +1438,19 @@
               animation_name))
     return keyframes_rule;
 
+  // Match UA keyframe rules after user and author rules.
+  StyleRuleKeyframes* matched_keyframes_rule = nullptr;
+  auto func = [&matched_keyframes_rule, &animation_name](RuleSet* rules) {
+    auto keyframes_rules = rules->KeyframesRules();
+    for (auto& keyframes_rule : keyframes_rules) {
+      if (keyframes_rule->GetName() == animation_name)
+        matched_keyframes_rule = keyframes_rule;
+    }
+  };
+  ForEachUARulesForElement(*animating_element, nullptr, func);
+  if (matched_keyframes_rule)
+    return matched_keyframes_rule;
+
   for (auto& resolver : resolvers)
     resolver->SetHasUnresolvedKeyframesRule();
   return nullptr;
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 66f6a02..daf5b33 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -115,6 +115,7 @@
   SelectorFilter& GetSelectorFilter() { return selector_filter_; }
 
   StyleRuleKeyframes* FindKeyframesRule(const Element*,
+                                        const Element* animating_element,
                                         const AtomicString& animation_name);
 
   // These methods will give back the set of rules that matched for a given
@@ -285,6 +286,11 @@
 
   bool IsForcedColorsModeEnabled() const;
 
+  template <typename Functor>
+  void ForEachUARulesForElement(const Element& element,
+                                ElementRuleCollector* collector,
+                                Functor& func) const;
+
   MatchedPropertiesCache matched_properties_cache_;
   Member<Document> document_;
   scoped_refptr<const ComputedStyle> initial_style_;
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index f7d9b78..dd3e3042a 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -423,7 +423,7 @@
 
   // There's no @keyframes rule named dummy-animation
   ASSERT_FALSE(GetStyleEngine().GetStyleResolver().FindKeyframesRule(
-      t5, AtomicString("dummy-animation")));
+      t5, t5, AtomicString("dummy-animation")));
 
   auto* keyframes_parsed_sheet = MakeGarbageCollected<StyleSheetContents>(
       MakeGarbageCollected<CSSParserContext>(GetDocument()));
@@ -437,7 +437,7 @@
   // is found with one keyframe.
   StyleRuleKeyframes* keyframes =
       GetStyleEngine().GetStyleResolver().FindKeyframesRule(
-          t5, AtomicString("dummy-animation"));
+          t5, t5, AtomicString("dummy-animation"));
   ASSERT_TRUE(keyframes);
   EXPECT_EQ(1u, keyframes->Keyframes().size());
 
@@ -450,7 +450,7 @@
   // Author @keyframes rules take precedence; now there are two keyframes (from
   // and to).
   keyframes = GetStyleEngine().GetStyleResolver().FindKeyframesRule(
-      t5, AtomicString("dummy-animation"));
+      t5, t5, AtomicString("dummy-animation"));
   ASSERT_TRUE(keyframes);
   EXPECT_EQ(2u, keyframes->Keyframes().size());
 
@@ -458,7 +458,7 @@
   UpdateAllLifecyclePhases();
 
   keyframes = GetStyleEngine().GetStyleResolver().FindKeyframesRule(
-      t5, AtomicString("dummy-animation"));
+      t5, t5, AtomicString("dummy-animation"));
   ASSERT_TRUE(keyframes);
   EXPECT_EQ(1u, keyframes->Keyframes().size());
 
@@ -467,7 +467,7 @@
 
   // Injected @keyframes rules are no longer available once removed.
   ASSERT_FALSE(GetStyleEngine().GetStyleResolver().FindKeyframesRule(
-      t5, AtomicString("dummy-animation")));
+      t5, t5, AtomicString("dummy-animation")));
 
   // Custom properties
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index d7cf3ab..36b871e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -874,6 +874,7 @@
   if (!response.IsSuccess())
     return response;
 
+  Element* animating_element = element;
   PseudoId element_pseudo_id = element->GetPseudoId();
   if (element_pseudo_id) {
     element = element->ParentOrShadowHostElement();
@@ -943,7 +944,7 @@
     inherited_entries->fromJust()->emplace_back(std::move(entry));
   }
 
-  *css_keyframes_rules = AnimationsForNode(element);
+  *css_keyframes_rules = AnimationsForNode(element, animating_element);
   return Response::Success();
 }
 
@@ -966,7 +967,8 @@
 }
 
 std::unique_ptr<protocol::Array<protocol::CSS::CSSKeyframesRule>>
-InspectorCSSAgent::AnimationsForNode(Element* element) {
+InspectorCSSAgent::AnimationsForNode(Element* element,
+                                     Element* animating_element) {
   auto css_keyframes_rules =
       std::make_unique<protocol::Array<protocol::CSS::CSSKeyframesRule>>();
   Document& document = element->GetDocument();
@@ -982,8 +984,8 @@
     AtomicString animation_name(animation_data->NameList()[i]);
     if (animation_name == CSSAnimationData::InitialName())
       continue;
-    StyleRuleKeyframes* keyframes_rule =
-        style_resolver.FindKeyframesRule(element, animation_name);
+    StyleRuleKeyframes* keyframes_rule = style_resolver.FindKeyframesRule(
+        element, animating_element, animation_name);
     if (!keyframes_rule)
       continue;
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.h b/third_party/blink/renderer/core/inspector/inspector_css_agent.h
index 20f45af4..f871eb2a 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.h
@@ -297,8 +297,10 @@
       std::unique_ptr<protocol::Array<protocol::CSS::StyleDeclarationEdit>>,
       HeapVector<Member<StyleSheetAction>>* actions);
 
+  // If the |animating_element| is a pseudo element, then |element| is a
+  // reference to its originating DOM element.
   std::unique_ptr<protocol::Array<protocol::CSS::CSSKeyframesRule>>
-  AnimationsForNode(Element*);
+  AnimationsForNode(Element* element, Element* animating_element);
 
   void CollectPlatformFontsForLayoutObject(
       LayoutObject*,
diff --git a/third_party/blink/renderer/modules/hid/hid.cc b/third_party/blink/renderer/modules/hid/hid.cc
index 31e3e5b5..f3d1c1cf 100644
--- a/third_party/blink/renderer/modules/hid/hid.cc
+++ b/third_party/blink/renderer/modules/hid/hid.cc
@@ -31,6 +31,24 @@
 const char kFeaturePolicyBlocked[] =
     "Access to the feature \"hid\" is disallowed by permissions policy.";
 
+// Carries out basic checks for the web-exposed APIs, to make sure the minimum
+// requirements for them to be served are met. Returns true if any conditions
+// fail to be met, generating an appropriate exception as well. Otherwise,
+// returns false to indicate the call should be allowed.
+bool ShouldBlockHidServiceCall(LocalDOMWindow* window,
+                               ExceptionState& exception_state) {
+  if (!window) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+                                      kContextGone);
+  } else if (!window->IsFeatureEnabled(
+                 mojom::blink::PermissionsPolicyFeature::kHid,
+                 ReportOptions::kReportOnFailure)) {
+    exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
+  }
+
+  return exception_state.HadException();
+}
+
 void RejectWithTypeError(const String& message,
                          ScriptPromiseResolver* resolver) {
   ScriptState::Scope scope(resolver->GetScriptState());
@@ -178,16 +196,8 @@
 
 ScriptPromise HID::getDevices(ScriptState* script_state,
                               ExceptionState& exception_state) {
-  auto* context = GetExecutionContext();
-  if (!context) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
-                                      kContextGone);
-    return ScriptPromise();
-  }
-
-  if (!context->IsFeatureEnabled(mojom::blink::PermissionsPolicyFeature::kHid,
-                                 ReportOptions::kReportOnFailure)) {
-    exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
+  if (ShouldBlockHidServiceCall(GetSupplementable()->DomWindow(),
+                                exception_state)) {
     return ScriptPromise();
   }
 
@@ -203,16 +213,8 @@
 ScriptPromise HID::requestDevice(ScriptState* script_state,
                                  const HIDDeviceRequestOptions* options,
                                  ExceptionState& exception_state) {
-  if (!GetExecutionContext()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
-                                      kContextGone);
-    return ScriptPromise();
-  }
-
-  if (!GetExecutionContext()->IsFeatureEnabled(
-          mojom::blink::PermissionsPolicyFeature::kHid,
-          ReportOptions::kReportOnFailure)) {
-    exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
+  if (ShouldBlockHidServiceCall(GetSupplementable()->DomWindow(),
+                                exception_state)) {
     return ScriptPromise();
   }
 
diff --git a/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc b/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
index e83cb12..71fae68f 100644
--- a/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -44,6 +45,11 @@
     return;
   }
 
+  if (response) {
+    UseCounter::Count(ExecutionContext::From(script_state),
+                      WebFeature::kAbortPaymentRespondWithTrue);
+  }
+
   To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToAbortPaymentEvent(event_id_, response);
 }
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index 3b6e1c0..56f9d0b5 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom-blink.h"
 #include "third_party/blink/public/mojom/timing/worker_timing_container.mojom-blink.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
@@ -236,6 +237,21 @@
     return base::MakeRefCounted<FakeWebServiceWorkerFetchContext>();
   }
 
+  void OnNavigationPreloadResponse(
+      int fetch_event_id,
+      std::unique_ptr<WebURLResponse> response,
+      mojo::ScopedDataPipeConsumerHandle data_pipe) override {}
+
+  void OnNavigationPreloadComplete(int fetch_event_id,
+                                   base::TimeTicks completion_time,
+                                   int64_t encoded_data_length,
+                                   int64_t encoded_body_length,
+                                   int64_t decoded_body_length) override {}
+
+  void OnNavigationPreloadError(
+      int fetch_event_id,
+      std::unique_ptr<WebServiceWorkerError> error) override {}
+
   void WorkerContextDestroyed() override { termination_event_.Signal(); }
 
   // These methods must be called on the main thread.
diff --git a/third_party/blink/renderer/platform/wtf/allocator/allocator.h b/third_party/blink/renderer/platform/wtf/allocator/allocator.h
index c4d94a60..b9eec06 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/allocator.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/allocator.h
@@ -123,39 +123,6 @@
 #define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
   USING_FAST_MALLOC_INTERNAL(type, #type)
 
-// FastMalloc doesn't provide isolation, only a (hopefully fast) malloc(). When
-// PartitionAlloc is already the malloc() implementation, there is nothing to
-// do.
-//
-// Note that we could keep the two heaps separate, but each PartitionAlloc's
-// root has a cost, both in used memory and in virtual address space. Don't pay
-// it when we don't have to.
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-
-// Still using operator overaloading to be closer to the other case, and not
-// require code changes to DISALLOW_NEW() objects.
-#define USING_FAST_MALLOC_INTERNAL(type, typeName)           \
- public:                                                     \
-  void* operator new(size_t, void* p) { return p; }          \
-  void* operator new[](size_t, void* p) { return p; }        \
-                                                             \
-  void* operator new(size_t size) { return malloc(size); }   \
-                                                             \
-  void operator delete(void* p) { free(p); }                 \
-                                                             \
-  void* operator new[](size_t size) { return malloc(size); } \
-                                                             \
-  void operator delete[](void* p) { free(p); }               \
-  void* operator new(size_t, NotNullTag, void* location) {   \
-    DCHECK(location);                                        \
-    return location;                                         \
-  }                                                          \
-                                                             \
- private:                                                    \
-  friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-
-#else
-
 #define USING_FAST_MALLOC_INTERNAL(type, typeName)                    \
  public:                                                              \
   void* operator new(size_t, void* p) { return p; }                   \
@@ -180,8 +147,6 @@
  private:                                                             \
   friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
 
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-
 // TOOD(omerkatz): replace these casts with std::atomic_ref (C++20) once it
 // becomes available
 template <typename T>
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index 1389e76..c67be453 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -56,17 +56,15 @@
 
 #if defined(PA_ALLOW_PCSCAN)
 // Runs PCScan on WTF partitions.
-const base::Feature kPCScanBlinkPartitions{"PCScanBlinkPartitions",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPCScanBlinkPartitions{
+    "PartitionAllocPCScanBlinkPartitions", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
 bool Partitions::initialized_ = false;
 
 // These statics are inlined, so cannot be LazyInstances. We create the values,
 // and then set the pointers correctly in Initialize().
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 base::ThreadSafePartitionRoot* Partitions::fast_malloc_root_ = nullptr;
-#endif
 base::ThreadSafePartitionRoot* Partitions::array_buffer_root_ = nullptr;
 base::ThreadSafePartitionRoot* Partitions::buffer_root_ = nullptr;
 
@@ -82,8 +80,10 @@
 #if BUILDFLAG(USE_BACKUP_REF_PTR)
       base::FeatureList::IsEnabled(
           base::features::kPartitionAllocBackupRefPtr) &&
-      base::features::kBackupRefPtrEnabledProcessesParam.Get() ==
-          base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer &&
+      (base::features::kBackupRefPtrEnabledProcessesParam.Get() ==
+           base::features::BackupRefPtrEnabledProcesses::kAllProcesses ||
+       base::features::kBackupRefPtrEnabledProcessesParam.Get() ==
+           base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer) &&
       base::features::kBackupRefPtrModeParam.Get() ==
           base::features::BackupRefPtrMode::kEnabled;
 #else
@@ -94,19 +94,44 @@
           ? base::PartitionOptions::LazyCommit::kEnabled
           : base::PartitionOptions::LazyCommit::kDisabled;
 
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  static base::NoDestructor<base::PartitionAllocator> fast_malloc_allocator{};
-  fast_malloc_allocator->init(
-      {base::PartitionOptions::AlignedAlloc::kDisallowed,
-       base::PartitionOptions::ThreadCache::kEnabled,
-       base::PartitionOptions::Quarantine::kAllowed,
-       base::PartitionOptions::Cookie::kAllowed,
-       (enable_brp ? base::PartitionOptions::BackupRefPtr::kEnabled
-                   : base::PartitionOptions::BackupRefPtr::kDisabled),
-       base::PartitionOptions::UseConfigurablePool::kNo, lazy_commit});
+  const bool enable_scan_on_blink_partitions =
+      !enable_brp &&
+#if defined(PA_ALLOW_PCSCAN)
+      (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan) ||
+       base::FeatureList::IsEnabled(kPCScanBlinkPartitions));
+#else
+      false;
+#endif
 
-  fast_malloc_root_ = fast_malloc_allocator->root();
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+  // FastMalloc doesn't provide isolation, only a (hopefully fast) malloc().
+  // When PartitionAlloc is already the malloc() implementation, there is
+  // nothing to do.
+  //
+  // Note that we could keep the two heaps separate, but each PartitionAlloc's
+  // root has a cost, both in used memory and in virtual address space. Don't
+  // pay it when we don't have to.
+  //
+  // In addition, enable the FastMalloc partition if
+  // --enable-features=PartitionAllocPCScanBlinkPartitions is specified.
+  if (enable_scan_on_blink_partitions ||
+      !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)) {
+    static base::NoDestructor<base::PartitionAllocator> fast_malloc_allocator{};
+    fast_malloc_allocator->init({
+      base::PartitionOptions::AlignedAlloc::kDisallowed,
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+          base::PartitionOptions::ThreadCache::kDisabled,
+#else
+          base::PartitionOptions::ThreadCache::kEnabled,
+#endif
+          base::PartitionOptions::Quarantine::kAllowed,
+          base::PartitionOptions::Cookie::kAllowed,
+          (enable_brp ? base::PartitionOptions::BackupRefPtr::kEnabled
+                      : base::PartitionOptions::BackupRefPtr::kDisabled),
+          base::PartitionOptions::UseConfigurablePool::kNo, lazy_commit
+    });
+
+    fast_malloc_root_ = fast_malloc_allocator->root();
+  }
 
   static base::NoDestructor<base::PartitionAllocator> buffer_allocator{};
 
@@ -124,12 +149,15 @@
   buffer_root_ = buffer_allocator->root();
 
 #if defined(PA_ALLOW_PCSCAN)
-  if (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan) ||
-      base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) {
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+  if (enable_scan_on_blink_partitions) {
+    if (!base::internal::PCScan::IsInitialized()) {
+      base::internal::PCScan::Initialize(
+          {base::internal::PCScan::InitConfig::WantedWriteProtectionMode::
+               kDisabled,
+           base::internal::PCScan::InitConfig::SafepointMode::kDisabled});
+    }
     base::internal::PCScan::RegisterScannableRoot(fast_malloc_root_);
-#endif
-    base::internal::PCScan::RegisterScannableRoot(buffer_root_);
+    // Ignore other partitions for now.
   }
 #endif  // defined(PA_ALLOW_PCSCAN)
 
@@ -191,10 +219,10 @@
   // accessed only on the main thread.
   DCHECK(IsMainThread());
 
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  FastMallocPartition()->DumpStats("fast_malloc", is_light_dump,
-                                   partition_stats_dumper);
-#endif
+  if (auto* fast_malloc_partition = FastMallocPartition()) {
+    fast_malloc_partition->DumpStats("fast_malloc", is_light_dump,
+                                     partition_stats_dumper);
+  }
   if (ArrayBufferPartitionInitialized()) {
     ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump,
                                       partition_stats_dumper);
@@ -231,10 +259,10 @@
   DCHECK(initialized_);
   size_t total_size = 0;
   // Racy reads below: this is fine to collect statistics.
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  total_size +=
-      TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages);
-#endif
+  if (auto* fast_malloc_partition = FastMallocPartition()) {
+    total_size +=
+        TS_UNCHECKED_READ(fast_malloc_partition->total_size_of_committed_pages);
+  }
   if (ArrayBufferPartitionInitialized()) {
     total_size += TS_UNCHECKED_READ(
         ArrayBufferPartition()->total_size_of_committed_pages);
@@ -340,30 +368,31 @@
 // no-op.
 // static
 void* Partitions::FastMalloc(size_t n, const char* type_name) {
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  return FastMallocPartition()->Alloc(n, type_name);
-#else
-  return malloc(n);
-#endif
+  auto* fast_malloc_partition = FastMallocPartition();
+  if (UNLIKELY(fast_malloc_partition))
+    return fast_malloc_partition->Alloc(n, type_name);
+  else
+    return malloc(n);
 }
 
 // static
 void* Partitions::FastZeroedMalloc(size_t n, const char* type_name) {
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  return FastMallocPartition()->AllocFlags(base::PartitionAllocZeroFill, n,
-                                           type_name);
-#else
-  return calloc(n, 1);
-#endif
+  auto* fast_malloc_partition = FastMallocPartition();
+  if (UNLIKELY(fast_malloc_partition)) {
+    return fast_malloc_partition->AllocFlags(base::PartitionAllocZeroFill, n,
+                                             type_name);
+  } else {
+    return calloc(n, 1);
+  }
 }
 
 // static
 void Partitions::FastFree(void* p) {
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  FastMallocPartition()->Free(p);
-#else
-  free(p);
-#endif
+  auto* fast_malloc_partition = FastMallocPartition();
+  if (UNLIKELY(fast_malloc_partition))
+    fast_malloc_partition->Free(p);
+  else
+    free(p);
 }
 
 // static
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.h b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
index 0520cc0..4b8754b 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
@@ -98,20 +98,16 @@
   static void HandleOutOfMemory(size_t size);
 
  private:
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
   ALWAYS_INLINE static base::ThreadSafePartitionRoot* FastMallocPartition() {
     DCHECK(initialized_);
     return fast_malloc_root_;
   }
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
   static bool InitializeOnce();
 
   static bool initialized_;
   // See Allocator.md for a description of these partitions.
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
   static base::ThreadSafePartitionRoot* fast_malloc_root_;
-#endif
   static base::ThreadSafePartitionRoot* array_buffer_root_;
   static base::ThreadSafePartitionRoot* buffer_root_;
 };
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index fa5f323..e1e63498 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -175,6 +175,3 @@
 crbug.com/1215390 [ Linux ] external/wpt/pointerevents/pointerevent_pointerId_scope.html [ Pass Failure Timeout ]
 crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Pass Timeout ]
 crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html [ Pass Timeout ]
-
-# Sheriff 2021-07-15
-crbug.com/1229588 [ Linux ] external/wpt/secure-payment-confirmation/secure-payment-confirmation.tentative.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index f34cca2..1a68ff32 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -731,7 +731,6 @@
 crbug.com/1046784 http/tests/devtools/sources/source-frame-toolbar-items.js [ Slow ]
 crbug.com/1046784 http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.js [ Slow ]
 crbug.com/1108423 external/wpt/referrer-policy/gen/worker-classic.http-rp/unset/worker-classic.http.html [ Slow ]
-crbug.com/1115091 [ Linux ] external/wpt/secure-payment-confirmation/secure-payment-confirmation.tentative.https.html [ Slow ]
 crbug.com/1135978 [ Linux Release ] fast/dom/css-delete-doc.html [ Slow ]
 crbug.com/1145424 [ Linux ] http/tests/devtools/sources/debugger-ui/reveal-execution-line.js [ Slow ]
 crbug.com/1145424 [ Win ] http/tests/devtools/sources/debugger-ui/reveal-execution-line.js [ Slow ]
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html
new file mode 100644
index 0000000..e54ed26
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Test of Web Bluetooth API</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+
+<script>
+promise_test(async t => {
+  const hid_get_device_key = KEYS['hid.getDevice'];
+
+  attachFencedFrame('resources/hid-inner.html');
+  const result = await nextValueFromServer(hid_get_device_key);
+
+  assert_equals(
+      result, 'HID getDevice failed',
+      'HID getDevice must fail in a fenced frame.');
+}, 'HID getDevice must fail in a fenced frame');
+</script>
+
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html
new file mode 100644
index 0000000..a7063c7
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="utils.js"></script>
+<title>Fenced frame content to test HID services</title>
+
+<body>
+<button id="button">Button</button>
+<script>
+window.addEventListener("load", (async () => {
+  // Wait requestAnimationFrame to ensure that the page is updated, and
+  // test_driver.click() works.
+  await new Promise(resolve => { requestAnimationFrame(resolve); });
+
+  const button = document.getElementById("button");
+  button.addEventListener('click', async () => {
+    const hid_get_device_key = KEYS['hid.getDevice'];
+    try {
+      await navigator.hid.getDevices();
+      writeValueToServer(hid_get_device_key,
+                        'HID getDevice succeeded');
+    } catch(e) {
+      if (e.name == 'SecurityError' &&
+          e.message.includes(
+            'Access to the feature "hid" is disallowed by permissions policy.')) {
+        writeValueToServer(hid_get_device_key,
+                          'HID getDevice failed');
+      } else {
+        writeValueToServer(hid_get_device_key,
+                          `HID getDevice failed with unknown error - ${e.name}: ${e.message}`);
+      }
+    }
+  });
+  test_driver.click(button);
+}))
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html.headers b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html.headers
new file mode 100644
index 0000000..1b63235
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/hid-inner.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
index 541a1ab..1813efc 100644
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
@@ -95,6 +95,8 @@
 
   "embed_coep_require_corp"                     : "00000000-0000-0000-0000-000000000031",
   "embed_no_coep"                               : "00000000-0000-0000-0000-000000000032",
+
+  "hid.getDevice"                               : "00000000-0000-0000-0000-000000000033",
   // Add keys above this list, incrementing the key UUID in hexadecimal
 }
 
diff --git a/third_party/devtools-frontend/OWNERS b/third_party/devtools-frontend/OWNERS
new file mode 100644
index 0000000..7e26c945
--- /dev/null
+++ b/third_party/devtools-frontend/OWNERS
@@ -0,0 +1,4 @@
+# Copied from src/config/owner/ENG_REVIEW_OWNERS. That file can't be referenced
+# from here because it is in another repo.
+danno@chromium.org
+yangguo@chromium.org
diff --git a/third_party/devtools-frontend/README.chromium b/third_party/devtools-frontend/README.chromium
new file mode 100644
index 0000000..1fbedb8e
--- /dev/null
+++ b/third_party/devtools-frontend/README.chromium
@@ -0,0 +1,10 @@
+Name: Devtools-Frontend
+URL: https://chromium.googlesource.com/devtools/devtools-frontend
+Version: 0
+License: BSD
+License File: src/LICENSE
+Security Critical: yes
+
+Description:
+
+Chrome DevTools frontend
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium
index 3a6a4cc..e453d8b 100644
--- a/third_party/metrics_proto/README.chromium
+++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@
 Name: Metrics Protos
 Short Name: metrics_proto
 URL: This is the canonical public repository
-Version: 412995826
-Date: 2021/11/29 UTC
+Version: 415121218
+Date: 2021/12/09 UTC
 License: BSD
 Security Critical: Yes
 
diff --git a/third_party/metrics_proto/system_profile.proto b/third_party/metrics_proto/system_profile.proto
index 1a0dff1..d23d53e 100644
--- a/third_party/metrics_proto/system_profile.proto
+++ b/third_party/metrics_proto/system_profile.proto
@@ -614,11 +614,6 @@
     // GMS Core updates.
     optional int32 crash_count_due_to_gms_core_update = 30;
 
-    // The number of times the program began, but did not complete, the shutdown
-    // process.  (For example, this may occur when Windows is shutting down, and
-    // it only gives the process a few seconds to clean up.)
-    optional int32 incomplete_shutdown_count = 17;
-
     // Whether the metrics being reported are from a previous run picked up via
     // the left-over memory mapped files.
     optional bool from_previous_run = 29;
diff --git a/tools/licenses.py b/tools/licenses.py
index 080b98c6..3ccf0845 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -172,13 +172,6 @@
         # Absolute path here is resolved as relative to the source root.
         "License File": "/LICENSE.chromium_os",
     },
-    os.path.join('third_party', 'devtools-frontend'): {
-        # TODO(crbug.com/1151057): Remove this special case when issue is fixed.
-        "Name": "Devtools-Frontend",
-        "URL": "https://chromium.googlesource.com/devtools/devtools-frontend",
-        "License": "BSD",
-        "License File": "src/LICENSE",
-    },
     os.path.join('third_party', 'lss'): {
         "Name": "linux-syscall-support",
         "URL": "http://code.google.com/p/linux-syscall-support/",
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 0ed13e3..09577ee9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -288,7 +288,6 @@
       'Libfuzzer Upload Windows ASan': 'libfuzzer_windows_asan_release_bot',
       'Linux Builder (j-500) (reclient)': 'gpu_tests_release_bot_reclient',
       'Linux CFI (reclient shadow)': 'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_reclient',
-      'Linux Builder (j-500) (reclient)': 'gpu_tests_release_bot_reclient',
       'Linux Viz': 'release_trybot_minimal_symbols',
       'lacros-amd64-generic-rel-fyi': 'chromeos_amd64-generic_lacros_rel',
       'linux-ash-chromium-builder-fyi-rel': 'chromeos_with_codecs_release_bot',
@@ -449,7 +448,7 @@
       # These all use the 'trybot' mixins to ensure that dcheck is on.
       'GPU Mac Builder': 'gpu_tests_release_trybot_minimal_symbols',
       'GPU Mac Builder (dbg)': 'gpu_tests_debug_bot',
-      'GPU Linux Builder': 'gpu_tests_release_trybot_minimal_symbols',
+      'GPU Linux Builder': 'gpu_tests_release_trybot_minimal_symbols_reclient',
       'GPU Linux Builder (dbg)': 'gpu_tests_debug_bot',
       'GPU Win x64 Builder': 'gpu_tests_release_bot_dcheck_always_on_resource_allowlisting',
       'GPU Win x64 Builder Code Coverage': 'gpu_tests_release_trybot_resource_allowlisting_code_coverage',
@@ -515,7 +514,7 @@
       'Leak Detection Linux': 'release_bot',
       'Linux Builder (dbg)': 'gpu_tests_debug_bot_reclient',
       'Linux Builder (dbg)(32)': 'gpu_tests_debug_bot_x86_reclient',
-      'Linux Builder': 'gpu_tests_release_bot',
+      'Linux Builder': 'gpu_tests_release_bot_reclient',
       'Linux Builder (Wayland)': 'gpu_tests_wayland_release_bot_reclient',
       'Network Service Linux': 'release_bot',
       'fuchsia-arm64-cast': 'release_bot_fuchsia_arm64_cast',
@@ -2428,6 +2427,10 @@
       'gpu_tests', 'release_trybot_minimal_symbols',
     ],
 
+    'gpu_tests_release_trybot_minimal_symbols_reclient': [
+      'gpu_tests', 'release_trybot_minimal_symbols_reclient',
+    ],
+
     'gpu_tests_release_trybot_minimal_symbol_x86_resource_allowlisting': [
       'gpu_tests', 'release_trybot_minimal_symbols', 'x86', 'resource_allowlisting',
     ],
diff --git a/tools/mb/mb_config_expectations/chromium.gpu.json b/tools/mb/mb_config_expectations/chromium.gpu.json
index 287c4853..f19f469 100644
--- a/tools/mb/mb_config_expectations/chromium.gpu.json
+++ b/tools/mb/mb_config_expectations/chromium.gpu.json
@@ -26,7 +26,8 @@
       "is_debug": false,
       "proprietary_codecs": true,
       "symbol_level": 1,
-      "use_goma": true
+      "use_rbe": true,
+      "use_remoteexec": true
     }
   },
   "GPU Linux Builder (dbg)": {
diff --git a/tools/mb/mb_config_expectations/chromium.linux.json b/tools/mb/mb_config_expectations/chromium.linux.json
index e522f4d..bdd37ed 100644
--- a/tools/mb/mb_config_expectations/chromium.linux.json
+++ b/tools/mb/mb_config_expectations/chromium.linux.json
@@ -106,7 +106,8 @@
       "is_component_build": false,
       "is_debug": false,
       "proprietary_codecs": true,
-      "use_goma": true
+      "use_rbe": true,
+      "use_remoteexec": true
     }
   },
   "Linux Builder (Wayland)": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6bce7a2..6d3c289 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -35817,6 +35817,7 @@
   <int value="4090" label="CrossOriginOpenerPolicySameOriginReportOnly"/>
   <int value="4091" label="ImageLoadAtDismissalEvent"/>
   <int value="4092" label="PrivateNetworkAccessIgnoredPreflightError"/>
+  <int value="4093" label="AbortPaymentRespondWithTrue"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -64965,6 +64966,7 @@
   <int value="19" label="BLOOM_FILTER_VALIDATION"/>
   <int value="20" label="ABOUT_THIS_SITE"/>
   <int value="21" label="MERCHANT_TRUST_SIGNALS_V2"/>
+  <int value="22" label="PAGE_ENTITIES"/>
 </enum>
 
 <enum name="OptOutBlacklistReason">
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index 7946932..e14f05a6 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -96,6 +96,8 @@
       Removed in M89.
     </obsolete>
   </variant>
+  <variant name="PageEntities"
+      summary="Provides the entities that are present on the page"/>
   <variant name="PerformanceHints"
       summary="Provides aggregated performance information about the page"/>
   <variant name="PriceTracking"
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index f03f6499..39adc79 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -18223,7 +18223,7 @@
 </histogram>
 
 <histogram name="WebUITabStrip.TabCreation" units="ms"
-    expires_after="2021-12-26">
+    expires_after="2022-04-10">
   <owner>robliao@chromium.org</owner>
   <owner>johntlee@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 9e3459e..e585544 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -626,6 +626,18 @@
   </token>
 </histogram>
 
+<histogram name="PasswordManager.AddCredentialFromSettings.AccountStoreUsed"
+    enum="Boolean" expires_after="M104">
+  <owner>lizapopova@google.com</owner>
+  <owner>mamir@google.com</owner>
+  <summary>
+    Tracks which store is used when the user adds a new credential from
+    Settings. True means account store, false means device store. Recorded only
+    for users who opted in for account storage and thus are given a choice. Only
+    applicable to Desktop platform.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.AddCredentialFromSettings.UserAction"
     enum="AddCredentialFromSettingsUserInteractions" expires_after="M104">
   <owner>vidhanj@google.com</owner>
@@ -2395,117 +2407,36 @@
 </histogram>
 
 <histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.Diff.Abs"
+    name="PasswordManager.PasswordStoreProxyBackend.{Function}.{Metric}.{Measurement}"
     units="count" expires_after="2022-06-30">
   <owner>fhorschig@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
-    Records the number of logins in either the main or the shadow backend but
-    not in both of them. In other words, it records |(M \ S) ∪ (S \ M)|, where M
-    and S are the sets of logins from the main and shadow backends,
-    respectively. Recorded when the asynchronous job has returned.
+    Records the number of logins {Metric}{Measurement} Recorded when the
+    asynchronous job for {Function} has returned.
   </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.Diff.Rel"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins in either the main or the shadow backend but
-    not in both of them, divided by the total number of logins, as a percentage
-    rounded up to the next integer. In other words, it records ⌈|(M \ S) ∪ (S \
-    M)| / |M ∪ S| %⌉, where M and S are the sets of logins from the main and
-    shadow backends, respectively. If the denominator is zero, no value is
-    emitted. Recorded when the asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.InconsistentPasswords.Abs"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins that occur in both the main and the shadow
-    backend but differ in their stored passwords. In other words, it records
-    |{(m,s) ∈ M × S | m.password ≠ s.password}|, where M and S are the sets of
-    logins from the main and shadow backends, respectively. Recorded when the
-    asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.InconsistentPasswords.Rel"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins that occur in both the main and the shadow
-    backend but differ in their stored passwords, divided by the number of
-    logins in both the main and the shadow backend, as a percentage rounded up
-    to the next integer. In other words, it records ⌈|{(m,s) ∈ M × S |
-    m.password ≠ s.password}| / |M ∩ S| %⌉, where M and S are the sets of logins
-    from the main and shadow backends, respectively. If the denominator is zero,
-    no value is emitted. Recorded when the asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.MainMinusShadow.Abs"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins in the main backend that are not the shadow
-    backend. In other words, it records |M \ S|, where M and S are the sets of
-    logins from the main and shadow backends, respectively. Recorded when the
-    asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.MainMinusShadow.Rel"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins in the main backend that are not the shadow
-    backend, divided by the total number of logins, as a percentage rounded up
-    to the next integer. In other words, it records ⌈|M \ S| / |M ∪ S| %⌉, where
-    M and S are the sets of logins from the main and shadow backends,
-    respectively. If the denominator is zero, no value is emitted. Recorded when
-    the asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.ShadowMinusMain.Abs"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins in the shadow backend that are not the main
-    backend. In other words, it records |S \ M|, where M and S are the sets of
-    logins from the main and shadow backends, respectively. Recorded when the
-    asynchronous job has returned.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.ShadowMinusMain.Rel"
-    units="count" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    Records the number of logins in the shadow backend that are not the main
-    backend, divided by the total number of logins, as a percentage rounded up
-    to the next integer. In other words, it records ⌈|S \ M| / |M ∪ S| %⌉, where
-    M and S are the sets of logins from the main and shadow backends,
-    respectively. If the denominator is zero, no value is emitted. Recorded when
-    the asynchronous job has returned.
-  </summary>
+  <token key="Function">
+    <variant name="GetAllLoginsAsync" summary="GetAllLoginsAsync()"/>
+  </token>
+  <token key="Metric">
+    <variant name="Diff"
+        summary="in either the main or the shadow backend but not in both of
+                 them"/>
+    <variant name="InconsistentPasswords"
+        summary="that occur in both the main and the shadow backend but
+                 differ in their stored passwords"/>
+    <variant name="MainMinusShadow"
+        summary="in the main backend that are not in the shadow backend"/>
+    <variant name="ShadowMinusMain"
+        summary="in the shadow backend that are not the main backend"/>
+  </token>
+  <token key="Measurement">
+    <variant name="Abs" summary="."/>
+    <variant name="Rel"
+        summary=", divided by the total number of logins, as a percentage
+                 rounded up to the next integer. If the denominator is zero,
+                 no value is emitted."/>
+  </token>
 </histogram>
 
 <histogram name="PasswordManager.PasswordSyncState" enum="PasswordSyncState"
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index c0d0f5f..984e1098 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,20 +5,20 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "7477f909e8a85d62457cb1dff13416d5b81f66b7",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/496f94a1281c8430d4657b6df90b72fcbcc0b3c6/trace_processor_shell.exe"
+            "hash": "7a8c90dab92d6462751328cc39ae388f639dbde8",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/514135fb1a37ba15cf7daad4918e17cfc1724de4/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "c4c63a91933a03bf9568723b48174c59dafd9216",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/496f94a1281c8430d4657b6df90b72fcbcc0b3c6/trace_processor_shell"
+            "hash": "b496947696214825013daad71d4d7eaf3adf45a2",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/593db496f656e1b936a82ca9e45fb092696091f3/trace_processor_shell"
         },
         "linux_arm64": {
             "hash": "5074025a2898ec41a872e70a5719e417acb0a380",
             "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "linux": {
-            "hash": "4909ab93d3cf54c899956cfd5bd615d1cbef6a2a",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/496f94a1281c8430d4657b6df90b72fcbcc0b3c6/trace_processor_shell"
+            "hash": "6ce5f6c1bfebb849aef30298931e9be8428b6673",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/593db496f656e1b936a82ca9e45fb092696091f3/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/results_processor/formatters/json3_output.py b/tools/perf/core/results_processor/formatters/json3_output.py
index a17e86e..6c96d0f6 100644
--- a/tools/perf/core/results_processor/formatters/json3_output.py
+++ b/tools/perf/core/results_processor/formatters/json3_output.py
@@ -103,11 +103,16 @@
   # (i.e. story) may be run multiple times, we squash as sequence of PASS
   # results to a single one. Note this does not affect the total number of
   # passes in num_failures_by_type.
+  # See also crbug.com/1254733 for why we want to report a FAIL in the case
+  # of flaky failures. A failed test run means less perf data so in general we
+  # want to investigate and fix those failures, not dismiss them as flakes.
   deduped = set(values)
   if deduped == {'PASS'}:
     return 'PASS'
   elif deduped == {'SKIP'}:
     return 'SKIP'
+  elif 'FAIL' in deduped:
+    return 'FAIL'
   else:
     return ' '.join(values)
 
diff --git a/tools/perf/core/results_processor/formatters/json3_output_unittest.py b/tools/perf/core/results_processor/formatters/json3_output_unittest.py
index c8938418..0b2eeea 100644
--- a/tools/perf/core/results_processor/formatters/json3_output_unittest.py
+++ b/tools/perf/core/results_processor/formatters/json3_output_unittest.py
@@ -104,7 +104,7 @@
 
     self.assertEqual(results['num_failures_by_type'], {'PASS': 2, 'SKIP': 2})
 
-  def testFaliedAndSippedTestCases(self):
+  def testFailedAndSkippedTestCases(self):
     results = self.Convert([
         testing.TestResult('benchmark/story1', status='PASS'),
         testing.TestResult('benchmark/story2', status='PASS'),
@@ -114,7 +114,7 @@
     ])
 
     test_result = self.FindTestResult(results, 'benchmark', 'story1')
-    self.assertEqual(test_result['actual'], 'PASS FAIL')
+    self.assertEqual(test_result['actual'], 'FAIL')
     self.assertEqual(test_result['expected'], 'PASS')
     self.assertTrue(test_result['is_unexpected'])
 
@@ -147,7 +147,7 @@
     self.assertFalse(test_result['is_unexpected'])
 
     test_result = self.FindTestResult(results, 'benchmark', 'story3')
-    self.assertEqual(test_result['actual'], 'FAIL FAIL')
+    self.assertEqual(test_result['actual'], 'FAIL')
     self.assertEqual(test_result['expected'], 'PASS')
     self.assertTrue(test_result['is_unexpected'])
 
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index 24125ba..ae66c0f3 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -305,12 +305,6 @@
   // and line layout. We don't expose those to platform APIs, though, so
   // suppress CHILDREN_CHANGED events on static text nodes.
   if (new_node_data.child_ids != old_node_data.child_ids && !node->IsText()) {
-    if (node->IsIgnored()) {
-      AXNode* unignored_parent = node->GetUnignoredParent();
-      if (unignored_parent)
-        AddEvent(unignored_parent, Event::CHILDREN_CHANGED);
-      return;
-    }
     AddEvent(node, Event::CHILDREN_CHANGED);
   }
 }
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index bf9038fb..38df4e1 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -3364,48 +3364,4 @@
   // HasEventAtNode(AXEventGenerator::Event::PARENT_CHANGED, 101),
 }
 
-TEST(AXEventGeneratorTest, InsertUnderIgnoredTest) {
-  AXTreeUpdate initial_state;
-  initial_state.root_id = 1;
-  {
-    AXNodeData data;
-    data.id = 1;
-    data.role = ax::mojom::Role::kRootWebArea;
-    data.child_ids = {3};
-    initial_state.nodes.push_back(data);
-  }
-  {
-    AXNodeData data;
-    data.id = 3;
-    data.role = ax::mojom::Role::kGenericContainer;
-    data.AddState(ax::mojom::State::kIgnored);
-    initial_state.nodes.push_back(data);
-  }
-  AXTree tree(initial_state);
-
-  AXEventGenerator event_generator(&tree);
-  AXTreeUpdate update;
-  update.node_id_to_clear = 3;
-  {
-    AXNodeData data;
-    data.id = 3;
-    data.role = ax::mojom::Role::kGenericContainer;
-    data.child_ids = {5};
-    data.AddState(ax::mojom::State::kIgnored);
-    update.nodes.push_back(data);
-  }
-  {
-    AXNodeData data;
-    data.id = 5;
-    data.role = ax::mojom::Role::kGenericContainer;
-    update.nodes.push_back(data);
-  }
-
-  EXPECT_TRUE(tree.Unserialize(update));
-  EXPECT_THAT(event_generator,
-              UnorderedElementsAre(
-                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
-                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 5)));
-}
-
 }  // namespace ui
diff --git a/ui/android/java/res/OWNERS b/ui/android/java/res/OWNERS
index 0ceaa75..4e8518d 100644
--- a/ui/android/java/res/OWNERS
+++ b/ui/android/java/res/OWNERS
@@ -6,3 +6,4 @@
 
 per-file ...color*.xml=lazzzis@google.com
 per-file ...style*.xml=lazzzis@google.com
+per-file ...SemanticColorUtils.java=lazzzis@google.com
\ No newline at end of file
diff --git a/ui/chromeos/translations/ui_chromeos_strings_mn.xtb b/ui/chromeos/translations/ui_chromeos_strings_mn.xtb
index 181240f..0a43b290 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_mn.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_mn.xtb
@@ -311,6 +311,7 @@
 <translation id="3691184985318546178">Синхала</translation>
 <translation id="3726463242007121105">Файлын систем нь дэмжигдээгүй учир энэ төхөөрөмжийг нээх боломжгүй.</translation>
 <translation id="3727148787322499904">Энэ тохиргоог өөрчилснөөр хуваалцсан бүх сүлжээнд нөлөөлнө</translation>
+<translation id="3737576078404241332">Хажуугийн цэсээс хасах</translation>
 <translation id="3741243925913727067">Өөрийн төхөөрөмж дээрх зураг болон видеог Google Drive дээр хадгалах.</translation>
 <translation id="3749289110408117711">Файлын нэр</translation>
 <translation id="3780536599611287598">Танд '<ph name="FOLDER_NAME" />'-д файл зөөх зөвшөөрөл алга.</translation>
@@ -371,6 +372,7 @@
 <translation id="4326142238881453352">Ургамал судлаач</translation>
 <translation id="4326192123064055915">Кофе</translation>
 <translation id="4336032328163998280">Хуулах үйл ажиллагаа амжилтгүй боллоо. <ph name="ERROR_MESSAGE" /></translation>
+<translation id="4340491671558548972">Хажуугийн цэсэд нэмэх</translation>
 <translation id="4348495354623233847">Араб суурьтай гартай сорани курд</translation>
 <translation id="4363958938297989186">Авиа зүйн гартай орос</translation>
 <translation id="4364327530094270451">Амтат гуа</translation>
diff --git a/ui/strings/translations/ui_strings_mn.xtb b/ui/strings/translations/ui_strings_mn.xtb
index 5c02f8d..b401b54 100644
--- a/ui/strings/translations/ui_strings_mn.xtb
+++ b/ui/strings/translations/ui_strings_mn.xtb
@@ -105,6 +105,7 @@
 <translation id="4565377596337484307">Нууц үгийг нуух</translation>
 <translation id="4588090240171750605">Баруун тийш гүйлгэх</translation>
 <translation id="4724120544754982507">Мэдэгдлийн төв, <ph name="UNREAD_NOTIFICATION_COUNT" /> уншаагүй мэдэгдэл</translation>
+<translation id="4746179598275229723">Өргөтгөлийг бэхэлснийг болиулсан</translation>
 <translation id="4788285488841504513">{MONTHS,plural, =1{1 сар үлдсэн}other{# сар үлдсэн}}</translation>
 <translation id="4888938634149558681">Дуудлага хийх</translation>
 <translation id="4968171027979920686">{SECONDS,plural, =1{1 секунд}other{# секунд}}</translation>
@@ -130,6 +131,7 @@
 <translation id="5906667377645263094">{SECONDS,plural, =1{1 секунд үлдсэн}other{# секунд үлдсэн}}</translation>
 <translation id="5941711191222866238">Багасгах</translation>
 <translation id="5943826764092288734">{HOURS,plural, =1{1 цаг}other{# цаг}}</translation>
+<translation id="6007284015834422026">Өргөтгөлийг бэхэлсэн</translation>
 <translation id="6040143037577758943">Хаах</translation>
 <translation id="6117103120090651229">Голын товчлуур</translation>
 <translation id="6129953537138746214">Space</translation>
diff --git a/weblayer/browser/cookie_manager_impl.cc b/weblayer/browser/cookie_manager_impl.cc
index 7e9e5f92..b972434 100644
--- a/weblayer/browser/cookie_manager_impl.cc
+++ b/weblayer/browser/cookie_manager_impl.cc
@@ -76,7 +76,7 @@
   browser_context_->GetDefaultStoragePartition()
       ->GetCookieManagerForBrowserProcess()
       ->GetCookieList(url, net::CookieOptions::MakeAllInclusive(),
-                      net::CookiePartitionKeychain::Todo(),
+                      net::CookiePartitionKeyCollection::Todo(),
                       base::BindOnce(&GetCookieComplete, std::move(callback)));
 }