diff --git a/AUTHORS b/AUTHORS
index 903f358..84f7329 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1358,6 +1358,7 @@
 Xu Samuel <samuel.xu@intel.com>
 Xu Xing <xing.xu@intel.com>
 Xuefei Ren <xrenishere@gmail.com>
+Xuefu Zhang <xuefu.sh@gmail.com>
 Xuehui Xie <xuehui.xxh@alibaba-inc.com>
 Xueqing Huang <huangxueqing@xiaomi.com>
 Xun Sun <xun.sun@intel.com>
diff --git a/BUILD.gn b/BUILD.gn
index d3b8e88..f4ec1f03 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1631,6 +1631,7 @@
       "//third_party/depot_tools/pylint_main.py",
       "//third_party/depot_tools/pylintrc",
       "//third_party/ply/",
+      "//third_party/pyjson5/",
       "//third_party/wpt_tools/",
       "//tools/idl_parser/",
     ]
diff --git a/DEPS b/DEPS
index 6681b95..0464c62 100644
--- a/DEPS
+++ b/DEPS
@@ -300,15 +300,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'cf0dd295c1bb396063efc8fed2accbca938ea38e',
+  'skia_revision': '4becb53e3c21d2905e99c8933b65e7d1460cc0bd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '7c8dc6d97acbc320d7c994abb0f067f02982badc',
+  'v8_revision': 'c664f127542b473984485efd4e9c3157c61e8ea2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b526112dafd79c1eebc72c392d1b180282206370',
+  'angle_revision': '57e4bb883c212b4ed51bfe57881ea30e417c6d8e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -316,7 +316,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'e60fa0d7d7733b23c444daa048dd509972d68cfe',
+  'pdfium_revision': '7884587b96051cbe6a5792c2d069acbc73c8d972',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -351,7 +351,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '3af4772d68f261ae34677db4a0434ababe5676bd',
+  'freetype_revision': 'e1a4e081aa57b3e044c7f30c3118cb6015e397d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -371,7 +371,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '829e9b448a2fd480fe2c2287b5c738ec5c56f7cb',
+  'catapult_revision': '730ebc3ef2f306b4c6b5aa08771aee7da9d29f93',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -387,7 +387,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': '781856f3da6cbec8356f8b49b6b08d141d9fbb99',
+  'devtools_frontend_revision': '8805a1584e20c110de0f506633569888868996cf',
   # 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.
@@ -427,7 +427,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '9ae8ed2f62491423d28302927f35d5add9caf2ab',
+  'dawn_revision': 'ac4b5f2bd2df26a2c17b59f9b3279b6aa03ffef8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -463,7 +463,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '9cd2e615d994d9b32c294c72de6cb987316005cd',
+  'cros_components_revision': 'dd6570edf24fa96e945fdb93f17f5fe0c32f49e4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -471,11 +471,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    'd5e79e117ce9adfdcfdc5dde56ee8cddd7742854',
+  'libcxxabi_revision':    'f2cb09f94e39caed554c0ea453741edbc24a38a4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    '229ff3e23223299d50a33caa1b90e89b78fdd84b',
+  'libunwind_revision':    '129773dde556dfd5dfc7df0eb3c0b970c56029f6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -616,6 +616,17 @@
     'condition': '(host_os == "linux")',
   },
 
+  'src/third_party/apache-windows-arm64': {
+    'packages': [
+        {
+            'package': 'infra/3pp/tools/httpd-php/windows-arm64',
+            'version': 'version:2@httpd2.4.55-php8.2.5.chromium.6.chromium.5',
+        }
+    ],
+    'dep_type': 'cipd',
+    'condition': '(host_os == "win")'
+  },
+
   'src/third_party/aosp_dalvik': {
       'packages': [
           {
@@ -761,7 +772,7 @@
   },
 
   'src/chrome/test/data/autofill/captured_sites/artifacts': {
-    'url': Var('chrome_git') + '/chrome/test/captured_sites/autofill.git' + '@' + 'e55de04e333a03583fb35df94bba331603bf1274',
+    'url': Var('chrome_git') + '/chrome/test/captured_sites/autofill.git' + '@' + '47f4547ce696dcafa837541132149341ebba15b9',
     'condition': 'checkout_chromium_autofill_test_dependencies',
   },
 
@@ -792,7 +803,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'cdebce11d28b49f1806558dfe4ff16942f056434',
+    '1d9e39eebe3eca3e0886f4222b234518edb7c0c6',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -821,7 +832,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'f949cc1df66544fc723a396caaacf9f18733e3d3',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3f5a80e035fb9186dada8882915cb22a71faac16',
       'condition': 'checkout_ios',
   },
 
@@ -981,7 +992,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'r34hN5quqAdkelP-WPYWmrBejJtMGWDVjQYQaWY98wsC',
+          'version': 'WSxa-08AqOZaGLllD6rcid2GJdSU7ZlzpyvpeiwJgr8C',
       },
     ],
     'condition': 'checkout_android',
@@ -1184,7 +1195,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' + '@' + '802eaf809650efa726068b2680ae3a19abc8c840',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f990189313f6c748658a87ddeb016351ebb15763',
       'condition': 'checkout_chromeos',
   },
 
@@ -1222,7 +1233,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '41701d83415488258b46d595e54114137f9c5038',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '23644124c254131380b0175796d15fb24cf1c174',
     'condition': 'checkout_src_internal',
   },
 
@@ -1689,7 +1700,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a6abd9944464ff392ea57c6e3e82784e603987ec',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8962065c2d161b04046d8bb1af2f68b2cb155487',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1834,7 +1845,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@0d737f7018653a0ecee629fa61e91150782cf3ef',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3a356ab9798772ac682757e9a0415585705917bc',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1871,7 +1882,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '13476ef7408a828a641dce55c363a085eff8e228',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'db412d7f763a7598a79f6044518b23506827f58e',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + 'a79bc6ee47446865a229e69d835ddcd0b9d39c8e',
@@ -1964,7 +1975,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': Var('chrome_git') + '/chrome/src-internal.git@2b923545e8362ee0c006529ebc4c8763165fd7dc',
+    'url': Var('chrome_git') + '/chrome/src-internal.git@f00b1dc3d6110a3b8bff7a51834a5f5426216555',
     'condition': 'checkout_src_internal',
   },
 
@@ -1994,7 +2005,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'dtc0BdxGMO8vXYbFFOsQLIHNtbaPy43QO7SfKi5U1FMC',
+        'version': 'VjrS96hE95CfVTQlXK21BZwwtk6SBz7yPYqCWwpEAmkC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2005,7 +2016,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'ZqoJl676iJHbSO1RK4MmZKjHy0b8ttQIE7p-4VDh3EcC',
+        'version': 'JWnJece1g2Y9kaCFW3udsuS3QNa18vcoRZqpc0Y_ueUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2027,7 +2038,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'LvGNi7OlFJpdRxEE1Pb0_-GMD6FHwH2_MaS-N_hVaIIC',
+        'version': '6AEuGAh0iuQcHzLgxiBVWMbVtWDyNunGMxlr_7RicXQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4163,7 +4174,7 @@
 
   'src/ios_internal':  {
       'url': '{chrome_git}/chrome/ios_internal.git' + '@' +
-        '6e7940481da07fbbb0147d58ddfff81ce33ff680',
+        '2e3f1b52155d0d2041583593d52072332a2c2c56',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc
index d9881a0..6d83c46 100644
--- a/ash/app_list/app_list_controller_impl_unittest.cc
+++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -24,8 +24,10 @@
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/assistant/model/assistant_ui_model.h"
 #include "ash/constants/ash_pref_names.h"
+#include "ash/drag_drop/drag_drop_controller.h"
 #include "ash/keyboard/keyboard_controller_impl.h"
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
 #include "ash/public/cpp/session/session_types.h"
 #include "ash/public/cpp/shelf_config.h"
@@ -50,6 +52,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -133,7 +136,8 @@
 
 }  // namespace
 
-class AppListControllerImplTest : public AshTestBase {
+class AppListControllerImplTest : public AshTestBase,
+                                  public testing::WithParamInterface<bool> {
  public:
   AppListControllerImplTest() = default;
 
@@ -144,9 +148,16 @@
   ~AppListControllerImplTest() override = default;
 
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatureState(
+        app_list_features::kDragAndDropRefactor, GetParam());
     AshTestBase::SetUp();
     shelf_item_factory_ = std::make_unique<ShelfItemFactoryFake>();
     ShelfModel::Get()->SetShelfItemFactory(shelf_item_factory_.get());
+    // Disable nested loops to avoid blocking during drag and drop sequences.
+    if (GetParam()) {
+      ShellTestApi().drag_drop_controller()->SetDisableNestedLoopForTesting(
+          true);
+    }
   }
 
   void TearDown() override {
@@ -180,12 +191,20 @@
   int populated_item_count_ = 0;
 
   std::unique_ptr<ShelfItemFactoryFake> shelf_item_factory_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
+// Instantiate the values in the parameterized tests. The boolean
+// determines whether to run the test with or without drag and
+// drop refactor feature enabled.
+INSTANTIATE_TEST_SUITE_P(All, AppListControllerImplTest, testing::Bool());
+
 // Tests that the AppList hides when shelf alignment changes. This necessary
 // because the AppList is shown with certain assumptions based on shelf
 // orientation.
-TEST_F(AppListControllerImplTest, AppListHiddenWhenShelfAlignmentChanges) {
+TEST_P(AppListControllerImplTest, AppListHiddenWhenShelfAlignmentChanges) {
   Shelf* const shelf = AshTestBase::GetPrimaryShelf();
   shelf->SetAlignment(ShelfAlignment::kBottom);
 
@@ -204,7 +223,7 @@
 
 // Verifies that the dragged item has the correct focusable siblings after drag
 // (https://crbug.com/990071).
-TEST_F(AppListControllerImplTest, CheckTabOrderAfterDragIconToShelf) {
+TEST_P(AppListControllerImplTest, CheckTabOrderAfterDragIconToShelf) {
   // Adds three items to AppsGridView.
   PopulateItem(3);
 
@@ -234,7 +253,9 @@
   item2->FireMouseDragTimerForTest();
   GetEventGenerator()->MoveMouseTo(
       shelf_view->GetBoundsInScreen().CenterPoint());
-  ASSERT_TRUE(GetAppsGridView()->FireDragToShelfTimerForTest());
+  if (!app_list_features::IsDragAndDropRefactorEnabled()) {
+    ASSERT_TRUE(GetAppsGridView()->FireDragToShelfTimerForTest());
+  }
   GetEventGenerator()->ReleaseLeftButton();
   ASSERT_EQ(1u, shelf_view->view_model()->view_size());
 
@@ -244,7 +265,7 @@
   EXPECT_EQ(item3, item2->GetNextFocusableView());
 }
 
-TEST_F(AppListControllerImplTest, PageResetByTimerInTabletMode) {
+TEST_P(AppListControllerImplTest, PageResetByTimerInTabletMode) {
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   PopulateItem(30);
 
@@ -275,7 +296,7 @@
   EXPECT_EQ(0, apps_grid_view->pagination_model()->selected_page());
 }
 
-TEST_F(AppListControllerImplTest, PagePersistanceTabletModeTest) {
+TEST_P(AppListControllerImplTest, PagePersistanceTabletModeTest) {
   PopulateItem(30);
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
@@ -297,7 +318,7 @@
 // Verifies that the the virtual keyboard does not get shown if the search box
 // is activated by user typing when the app list in the fullscreen state in
 // tablet mode.
-TEST_F(AppListControllerImplTest, VirtualKeyboardNotShownWhenUserStartsTyping) {
+TEST_P(AppListControllerImplTest, VirtualKeyboardNotShownWhenUserStartsTyping) {
   Shell::Get()->keyboard_controller()->SetEnableFlag(
       keyboard::KeyboardEnableFlag::kShelfEnabled);
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
@@ -334,7 +355,7 @@
 // Verifies that closing notification by gesture should not dismiss the AppList.
 // (see https://crbug.com/948344)
 // TODO(crbug.com/1120501): Test is flaky on ASAN builds.
-TEST_F(AppListControllerImplTest, MAYBE_CloseNotificationWithAppListShown) {
+TEST_P(AppListControllerImplTest, MAYBE_CloseNotificationWithAppListShown) {
   ShowAppListNow(AppListViewState::kFullscreenAllApps);
 
   // Add one notification.
@@ -375,7 +396,7 @@
 // Verifiy that when showing the launcher, the virtual keyboard dismissed before
 // will not show automatically due to the feature called "transient blur" (see
 // https://crbug.com/1057320).
-TEST_F(AppListControllerImplTest,
+TEST_P(AppListControllerImplTest,
        TransientBlurIsNotTriggeredWhenShowingLauncher) {
   // Enable animation.
   ui::ScopedAnimationDurationScaleMode non_zero_duration(
@@ -438,7 +459,7 @@
 // Regression test for https://crbug.com/1073548
 // Verifies that app list shown from overview after toggling tablet mode can be
 // closed.
-TEST_F(AppListControllerImplTest,
+TEST_P(AppListControllerImplTest,
        CloseAppListShownFromOverviewAfterTabletExit) {
   auto* shell = Shell::Get();
   auto* tablet_mode_controller = shell->tablet_mode_controller();
@@ -468,7 +489,7 @@
 // Tests that swapping out an AppListModel (simulating a profile swap with
 // multiprofile enabled) drops all references to previous folders (see
 // https://crbug.com/1130901).
-TEST_F(AppListControllerImplTest, SimulateProfileSwapNoCrashOnDestruct) {
+TEST_P(AppListControllerImplTest, SimulateProfileSwapNoCrashOnDestruct) {
   // Add a folder, whose AppListItemList the AppListModel will observe.
   AppListModel* model = GetAppListModel();
   const std::string folder_id("folder_1");
@@ -514,9 +535,13 @@
   }
 };
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         AppListControllerImplTestWithNotificationBadging,
+                         testing::Bool());
+
 // Tests that when an app has an update to its notification badge, the change
 // gets propagated to the corresponding AppListItemView.
-TEST_F(AppListControllerImplTestWithNotificationBadging,
+TEST_P(AppListControllerImplTestWithNotificationBadging,
        NotificationBadgeUpdateTest) {
   PopulateItem(1);
   ShowAppListNow(AppListViewState::kFullscreenAllApps);
@@ -537,7 +562,7 @@
   EXPECT_FALSE(item_view->IsNotificationIndicatorShownForTest());
 }
 
-TEST_F(AppListControllerImplTestWithNotificationBadging,
+TEST_P(AppListControllerImplTestWithNotificationBadging,
        NotificationBadgeUpdateForFolderTest) {
   std::string folder_id = "folder_1";
   AppListModel* model = GetAppListModel();
@@ -567,7 +592,7 @@
   EXPECT_FALSE(folder_view->IsNotificationIndicatorShownForTest());
 }
 
-TEST_F(AppListControllerImplTestWithNotificationBadging,
+TEST_P(AppListControllerImplTestWithNotificationBadging,
        NotificationBadgeUpdateAfterAddingRemovingAppTest) {
   std::string folder_id = "folder_1";
   AppListModel* model = GetAppListModel();
@@ -600,7 +625,7 @@
 
 // Verifies that the pinned app should still show after canceling the drag from
 // AppsGridView to Shelf (https://crbug.com/1021768).
-TEST_F(AppListControllerImplTest, DragItemFromAppsGridView) {
+TEST_P(AppListControllerImplTest, DragItemFromAppsGridView) {
   // Turn on the tablet mode.
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(IsTabletMode());
@@ -647,7 +672,7 @@
   EXPECT_EQ(1.0f, shelf_icon_view->layer()->opacity());
 }
 
-TEST_F(AppListControllerImplTest, OnlyMinimizeCycleListWindows) {
+TEST_P(AppListControllerImplTest, OnlyMinimizeCycleListWindows) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 400, 400)));
   std::unique_ptr<aura::Window> w2(CreateTestWindow(
       gfx::Rect(0, 0, 400, 400), aura::client::WINDOW_TYPE_POPUP));
@@ -662,7 +687,7 @@
 
 // Tests that the home screen is visible after rotating the screen in overview
 // mode.
-TEST_F(AppListControllerImplTest,
+TEST_P(AppListControllerImplTest,
        HomeScreenVisibleAfterDisplayUpdateInOverview) {
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EnterOverview();
@@ -679,7 +704,7 @@
       Shell::Get()->app_list_controller()->GetHomeScreenWindow()->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, CreatePage) {
+TEST_P(AppListControllerImplTest, CreatePage) {
   ShowAppListNow(AppListViewState::kFullscreenAllApps);
   PagedAppsGridView* apps_grid_view = GetAppsGridView();
   test::AppsGridViewTestApi test_api(apps_grid_view);
@@ -691,7 +716,7 @@
   EXPECT_EQ(2, apps_grid_view->pagination_model()->total_pages());
 }
 
-TEST_F(AppListControllerImplTest, ShowAppListOpensBubble) {
+TEST_P(AppListControllerImplTest, ShowAppListOpensBubble) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
 
@@ -699,7 +724,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, ToggleAppListOpensBubble) {
+TEST_P(AppListControllerImplTest, ToggleAppListOpensBubble) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ToggleAppList(GetPrimaryDisplay().id(),
                             AppListShowSource::kShelfButton,
@@ -709,7 +734,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, DismissAppListClosesBubble) {
+TEST_P(AppListControllerImplTest, DismissAppListClosesBubble) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
 
@@ -719,7 +744,7 @@
   EXPECT_FALSE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, ShowAppListDoesNotOpenBubbleInTabletMode) {
+TEST_P(AppListControllerImplTest, ShowAppListDoesNotOpenBubbleInTabletMode) {
   EnableTabletMode();
 
   auto* controller = Shell::Get()->app_list_controller();
@@ -729,7 +754,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, ToggleAppListDoesNotOpenBubbleInTabletMode) {
+TEST_P(AppListControllerImplTest, ToggleAppListDoesNotOpenBubbleInTabletMode) {
   EnableTabletMode();
 
   auto* controller = Shell::Get()->app_list_controller();
@@ -741,7 +766,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplTest, EnteringTabletModeClosesBubble) {
+TEST_P(AppListControllerImplTest, EnteringTabletModeClosesBubble) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
 
@@ -750,7 +775,7 @@
   EXPECT_FALSE(controller->bubble_presenter_for_test()->IsShowing());
 }
 
-TEST_F(AppListControllerImplTest, WallpaperColorChangeDoesNotCrash) {
+TEST_P(AppListControllerImplTest, WallpaperColorChangeDoesNotCrash) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
   // Simulate synced wallpaper update while bubble is open.
@@ -758,7 +783,7 @@
   // No crash.
 }
 
-TEST_F(AppListControllerImplTest, HideContinueSectionUpdatesPref) {
+TEST_P(AppListControllerImplTest, HideContinueSectionUpdatesPref) {
   auto* controller = Shell::Get()->app_list_controller();
   PrefService* prefs =
       Shell::Get()->session_controller()->GetLastActiveUserPrefService();
@@ -795,8 +820,11 @@
     Shell::Get()->session_controller()->SetSessionInfo(info);
   }
 };
+INSTANTIATE_TEST_SUITE_P(All,
+                         AppListControllerImplNotLoggedInTest,
+                         testing::Bool());
 
-TEST_F(AppListControllerImplNotLoggedInTest, ToggleAppListOnLoginScreen) {
+TEST_P(AppListControllerImplNotLoggedInTest, ToggleAppListOnLoginScreen) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ToggleAppList(GetPrimaryDisplay().id(),
                             AppListShowSource::kSearchKey,
@@ -827,7 +855,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ShowAppListOnLoginScreen) {
+TEST_P(AppListControllerImplNotLoggedInTest, ShowAppListOnLoginScreen) {
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
 
@@ -852,7 +880,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ToggleAppListInOobe) {
+TEST_P(AppListControllerImplNotLoggedInTest, ToggleAppListInOobe) {
   SetSessionState(session_manager::SessionState::OOBE);
   auto* controller = Shell::Get()->app_list_controller();
   controller->ToggleAppList(GetPrimaryDisplay().id(),
@@ -883,7 +911,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ShowAppListInOobe) {
+TEST_P(AppListControllerImplNotLoggedInTest, ShowAppListInOobe) {
   SetSessionState(session_manager::SessionState::OOBE);
   auto* controller = Shell::Get()->app_list_controller();
   controller->ShowAppList(AppListShowSource::kSearchKey);
@@ -909,7 +937,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ToggleAppListOnLockScreen) {
+TEST_P(AppListControllerImplNotLoggedInTest, ToggleAppListOnLockScreen) {
   SetSessionState(session_manager::SessionState::ACTIVE);
 
   auto* controller = Shell::Get()->app_list_controller();
@@ -944,7 +972,7 @@
   EXPECT_FALSE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ShowAppListOnLockScreen) {
+TEST_P(AppListControllerImplNotLoggedInTest, ShowAppListOnLockScreen) {
   SetSessionState(session_manager::SessionState::ACTIVE);
 
   auto* controller = Shell::Get()->app_list_controller();
@@ -981,7 +1009,7 @@
   EXPECT_FALSE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest, ShowAppListWhenInTabletMode) {
+TEST_P(AppListControllerImplNotLoggedInTest, ShowAppListWhenInTabletMode) {
   // Enable tablet mode while on login screen.
   EnableTabletMode();
 
@@ -1004,7 +1032,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest,
+TEST_P(AppListControllerImplNotLoggedInTest,
        FullscreenLauncherInTabletModeWhenLocked) {
   auto* controller = Shell::Get()->app_list_controller();
   EXPECT_FALSE(controller->bubble_presenter_for_test()->IsShowing());
@@ -1027,7 +1055,7 @@
   EXPECT_TRUE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplNotLoggedInTest,
+TEST_P(AppListControllerImplNotLoggedInTest,
        FullscreenLauncherShownWhenEnteringTabletModeOnLockScreen) {
   auto* controller = Shell::Get()->app_list_controller();
   EXPECT_FALSE(controller->bubble_presenter_for_test()->IsShowing());
@@ -1065,15 +1093,16 @@
     Shell::Get()->session_controller()->SetSessionInfo(info);
   }
 };
+INSTANTIATE_TEST_SUITE_P(All, AppListControllerImplKioskTest, testing::Bool());
 
-TEST_F(AppListControllerImplKioskTest, ShouldNotShowLauncherInTabletMode) {
+TEST_P(AppListControllerImplKioskTest, ShouldNotShowLauncherInTabletMode) {
   EnableTabletMode();
   auto* controller = Shell::Get()->app_list_controller();
 
   EXPECT_FALSE(controller->ShouldHomeLauncherBeVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotShowAnyAppListInClamshellModeWhenShowAppListCalled) {
   auto* controller = Shell::Get()->app_list_controller();
 
@@ -1083,7 +1112,7 @@
   EXPECT_FALSE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotShowAnyAppListInTabletModeWhenShowAppListCalled) {
   EnableTabletMode();
   auto* controller = Shell::Get()->app_list_controller();
@@ -1094,7 +1123,7 @@
   EXPECT_FALSE(controller->IsVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotShowHomeLauncherInTabletModeWhenOnSessionStateChangedCalled) {
   EnableTabletMode();
   auto* controller = Shell::Get()->app_list_controller();
@@ -1104,7 +1133,7 @@
   EXPECT_FALSE(controller->ShouldHomeLauncherBeVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotMinimizeAppWindowInTabletModeWhenGoHomeCalled) {
   // Emulation of a Kiosk app window.
   std::unique_ptr<aura::Window> w(CreateTestWindow(gfx::Rect(0, 0, 400, 400)));
@@ -1116,7 +1145,7 @@
   EXPECT_TRUE(w->IsVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotShowAppListInTabletModeWhenPressHomeButton) {
   // Emulation of a Kiosk app window.
   std::unique_ptr<aura::Window> w(CreateTestWindow(gfx::Rect(0, 0, 400, 400)));
@@ -1129,7 +1158,7 @@
   EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible());
 }
 
-TEST_F(AppListControllerImplKioskTest,
+TEST_P(AppListControllerImplKioskTest,
        DoNotOpenAnyAppListAfterSwitchingFromTabletMode) {
   auto* controller = Shell::Get()->app_list_controller();
   EnableTabletMode();
@@ -1179,10 +1208,13 @@
 
   std::unique_ptr<AssistantTestApi> assistant_test_api_;
 };
+INSTANTIATE_TEST_SUITE_P(All,
+                         AppListControllerWithAssistantTest,
+                         testing::Bool());
 
 // Verifies the scenario that the Assistant shortcut is triggered when the app
 // list close animation is running.
-TEST_F(AppListControllerWithAssistantTest,
+TEST_P(AppListControllerWithAssistantTest,
        TriggerAssistantKeyWhenAppListClosing) {
   // Show the Assistant and verify the app list state.
   ToggleAssistantUiWithAccelerator();
@@ -1231,7 +1263,7 @@
 
 // Verifies the scenario that the search key is triggered when the app list
 // close animation is running.
-TEST_F(AppListControllerWithAssistantTest, TriggerSearchKeyWhenAppListClosing) {
+TEST_P(AppListControllerWithAssistantTest, TriggerSearchKeyWhenAppListClosing) {
   ToggleAssistantUiWithAccelerator();
   auto* app_list_controller = Shell::Get()->app_list_controller();
   EXPECT_TRUE(app_list_controller->IsVisible());
@@ -1254,7 +1286,7 @@
   EXPECT_EQ(AssistantVisibility::kClosed, GetAssistantVisibility());
 }
 
-TEST_F(AppListControllerWithAssistantTest,
+TEST_P(AppListControllerWithAssistantTest,
        AppListWindowIsNotShowingOnTopOfOtherApps) {
   CreateAppWindow();
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
diff --git a/ash/app_list/views/app_list_main_view_unittest.cc b/ash/app_list/views/app_list_main_view_unittest.cc
index cc56d28c..8d7ee55 100644
--- a/ash/app_list/views/app_list_main_view_unittest.cc
+++ b/ash/app_list/views/app_list_main_view_unittest.cc
@@ -4,8 +4,10 @@
 
 #include "ash/app_list/views/app_list_main_view.h"
 
+#include <list>
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "ash/app_list/app_list_model_provider.h"
 #include "ash/app_list/model/app_list_test_model.h"
@@ -20,11 +22,16 @@
 #include "ash/app_list/views/page_switcher.h"
 #include "ash/app_list/views/paged_apps_grid_view.h"
 #include "ash/app_list/views/search_box_view.h"
+#include "ash/drag_drop/drag_drop_controller.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
+#include "ash/public/cpp/test/shell_test_api.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/memory/raw_ptr.h"
 #include "base/ranges/algorithm.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "ui/compositor/layer.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
@@ -36,15 +43,20 @@
 
 namespace ash {
 
-class AppListMainViewTest : public AshTestBase {
+// Parameterized by drag and drop refactor enabled/disabled.
+class AppListMainViewTest : public AshTestBase,
+                            public testing::WithParamInterface<bool> {
  public:
-  AppListMainViewTest() = default;
+  AppListMainViewTest() : is_drag_drop_refactor_enabled_(GetParam()) {}
   AppListMainViewTest(const AppListMainViewTest& other) = delete;
   AppListMainViewTest& operator=(const AppListMainViewTest& other) = delete;
   ~AppListMainViewTest() override = default;
 
   // testing::Test overrides:
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatureState(
+        app_list_features::kDragAndDropRefactor,
+        is_drag_drop_refactor_enabled_);
     AshTestBase::SetUp();
 
     // Create and show the app list in fullscreen apps grid state.
@@ -71,36 +83,14 @@
   }
 
   // |point| is in |grid_view|'s coordinates.
-  AppListItemView* SimulateInitiateDrag(AppsGridView* grid_view,
-                                        const gfx::Point& point) {
-    AppListItemView* view = GetItemViewAtPointInGrid(grid_view, point);
-    DCHECK(view);
-
+  void SimulateUpdateDragInGridView(AppsGridView* grid_view,
+                                    AppListItemView* drag_view,
+                                    const gfx::Point& point) {
     // NOTE: Assumes that the app list view window bounds match the root window
     // bounds.
     gfx::Point root_window_point = point;
-    views::View::ConvertPointToWidget(grid_view, &root_window_point);
-
-    view->InitiateDrag(point, root_window_point);
-    return view;
-  }
-
-  // |point| is in |grid_view|'s coordinates.
-  void SimulateUpdateDrag(AppsGridView* grid_view,
-                          AppsGridView::Pointer pointer,
-                          AppListItemView* drag_view,
-                          const gfx::Point& point) {
-    DCHECK(drag_view);
-
-    // NOTE: Assumes that the app list view window bounds match the root window
-    // bounds.
-    gfx::Point root_window_point = point;
-    views::View::ConvertPointToWidget(grid_view, &root_window_point);
-
-    ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, point, root_window_point,
-                              ui::EventTimeForNow(), 0, 0);
-
-    grid_view->UpdateDragFromItem(pointer, drag_event);
+    views::View::ConvertPointToScreen(grid_view, &root_window_point);
+    GetEventGenerator()->MoveMouseTo(root_window_point);
   }
 
   AppListMainView* main_view() { return app_list_view_->app_list_main_view(); }
@@ -156,35 +146,81 @@
     return folder_item_view;
   }
 
-  AppListItemView* StartDragForReparent(int index_in_folder) {
-    // Start to drag the item in folder.
+  AppListItemView* StartDragOnItemInFolderAt(int index_in_folder) {
+    DCHECK(GetAppListTestHelper()->IsInFolderView());
     views::View* item_view = GetFolderViewModel()->view_at(index_in_folder);
-    AppListItemView* dragged = SimulateInitiateDrag(
-        GetFolderGridView(), item_view->bounds().CenterPoint());
-    EXPECT_EQ(item_view, dragged);
-    EXPECT_TRUE(GetRootGridView()->GetVisible());
-    EXPECT_TRUE(GetFolderView()->GetVisible());
 
+    AppListItemView* view = GetItemViewAtPointInGrid(
+        GetFolderGridView(), item_view->bounds().CenterPoint());
+    DCHECK(view);
+    EXPECT_EQ(view, item_view);
+
+    GetEventGenerator()->MoveMouseTo(
+        view->GetIconBoundsInScreen().CenterPoint());
+    GetEventGenerator()->PressLeftButton();
+    EXPECT_TRUE(view->FireMouseDragTimerForTest());
+    return view;
+  }
+
+  AppListItemView* DragItemOutsideFolder(AppListItemView* item_view) {
+    DCHECK(GetAppListTestHelper()->IsInFolderView());
     // Drag the item completely outside the folder bounds.
-    gfx::Point drag_target = gfx::Point(-(item_view->width() + 1) / 2,
-                                        -(item_view->height() + 1) / 2);
-    // Two update drags needed to actually drag the view. The first changes
-    // state and the 2nd one actually moves the view. The 2nd call can be
-    // removed when UpdateDrag is fixed.
-    SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged,
-                       drag_target);
-    SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged,
-                       drag_target);
+    GetEventGenerator()->MoveMouseTo(
+        GetFolderGridView()->GetBoundsInScreen().bottom_right());
+    GetEventGenerator()->MoveMouseBy(10, 10);
 
     // Fire reparent timer, which should start when the item exits the folder
     // bounds. The timer closes the folder view.
     EXPECT_TRUE(GetFolderGridView()->FireFolderItemReparentTimerForTest());
 
-    // Note: the folder item is expected to remain visible so it keeps getting
-    // drag events, but it should become completely transparent.
+    // Generate OnDragExit/OnDragEnter
+    GetEventGenerator()->MoveMouseTo(
+        GetRootGridView()->GetBoundsInScreen().CenterPoint());
+
+    // Note: with the old behaviour, the folder item is expected to remain
+    // visible so it keeps getting drag events, but it should become
+    // completely transparent.
+    // The drag and drop refactor, expects the folder grid view to end drag once
+    // the dragged view exits the host.
+    EXPECT_EQ(!is_drag_drop_refactor_enabled_, GetFolderView()->GetVisible());
+    if (!is_drag_drop_refactor_enabled_) {
+      EXPECT_EQ(0.0f, GetFolderGridView()->layer()->opacity());
+    }
+    EXPECT_TRUE(GetRootGridView()->has_dragged_item());
+    EXPECT_EQ(!is_drag_drop_refactor_enabled_,
+              GetFolderGridView()->has_dragged_item());
+    return item_view;
+  }
+
+  void MaybeRunDragAndDropSequence(std::list<base::OnceClosure>* tasks) {
+    if (!is_drag_drop_refactor_enabled_) {
+      while (!tasks->empty()) {
+        std::move(tasks->front()).Run();
+        tasks->pop_front();
+      }
+      return;
+    }
+
+    ShellTestApi().drag_drop_controller()->SetLoopClosureForTesting(
+        base::BindLambdaForTesting([&]() {
+          auto task = std::move(tasks->front());
+          tasks->pop_front();
+          std::move(task).Run();
+        }),
+        base::DoNothing());
+    tasks->push_front(base::BindLambdaForTesting([&]() {
+      // Generate OnDragEnter() event for the host view.
+      GetEventGenerator()->MoveMouseBy(10, 10);
+    }));
+    // Start Drag and Drop Sequence by moving the mouse.
+    GetEventGenerator()->MoveMouseBy(10, 10);
+  }
+
+  void RunInitialReparentChecks() {
+    EXPECT_TRUE(GetRootGridView()->GetVisible());
     EXPECT_TRUE(GetFolderView()->GetVisible());
-    EXPECT_EQ(0.0f, GetFolderGridView()->layer()->opacity());
-    return dragged;
+    EXPECT_FALSE(GetRootGridView()->has_dragged_item());
+    EXPECT_TRUE(GetFolderGridView()->has_dragged_item());
   }
 
   void ClickButton(views::Button* button) {
@@ -193,34 +229,43 @@
         ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
   }
 
+  bool is_drag_drop_refactor_enabled() {
+    return is_drag_drop_refactor_enabled_;
+  }
+
  protected:
   raw_ptr<AppListView, ExperimentalAsh> app_list_view_ =
       nullptr;  // Owned by native widget.
+ private:
+  const bool is_drag_drop_refactor_enabled_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
+INSTANTIATE_TEST_SUITE_P(All, AppListMainViewTest, testing::Bool());
+
 // Tests that the close button becomes invisible after close button is clicked.
-TEST_F(AppListMainViewTest, CloseButtonInvisibleAfterCloseButtonClicked) {
+TEST_P(AppListMainViewTest, CloseButtonInvisibleAfterCloseButtonClicked) {
   PressAndReleaseKey(ui::VKEY_A);
   ClickButton(search_box_view()->close_button());
   EXPECT_FALSE(search_box_view()->close_button()->GetVisible());
 }
 
 // Tests that the search box becomes empty after close button is clicked.
-TEST_F(AppListMainViewTest, SearchBoxEmptyAfterCloseButtonClicked) {
+TEST_P(AppListMainViewTest, SearchBoxEmptyAfterCloseButtonClicked) {
   PressAndReleaseKey(ui::VKEY_A);
   ClickButton(search_box_view()->close_button());
   EXPECT_TRUE(search_box_view()->search_box()->GetText().empty());
 }
 
 // Tests that the search box is no longer active after close button is clicked.
-TEST_F(AppListMainViewTest, SearchBoxActiveAfterCloseButtonClicked) {
+TEST_P(AppListMainViewTest, SearchBoxActiveAfterCloseButtonClicked) {
   PressAndReleaseKey(ui::VKEY_A);
   ClickButton(search_box_view()->close_button());
   EXPECT_FALSE(search_box_view()->is_search_box_active());
 }
 
 // Tests changing the AppListModel when switching profiles.
-TEST_F(AppListMainViewTest, ModelChanged) {
+TEST_P(AppListMainViewTest, ModelChanged) {
   const size_t kInitialItems = 2;
   GetTestModel()->PopulateApps(kInitialItems);
   EXPECT_EQ(kInitialItems, GetRootViewModel()->view_size());
@@ -248,7 +293,7 @@
 
 // Tests dragging an item out of a single item folder and dropping it onto the
 // page switcher. Regression test for http://crbug.com/415530/.
-TEST_F(AppListMainViewTest, DragReparentItemOntoPageSwitcher) {
+TEST_P(AppListMainViewTest, DragReparentItemOntoPageSwitcher) {
   AppListItemView* folder_item_view = CreateAndOpenSingleItemFolder();
   ASSERT_TRUE(folder_item_view);
 
@@ -261,16 +306,24 @@
   EXPECT_EQ(1u, GetFolderViewModel()->view_size());
   EXPECT_EQ(kNumApps + 1, GetRootViewModel()->view_size());
 
-  AppListItemView* dragged = StartDragForReparent(0);
+  AppListItemView* dragged = StartDragOnItemInFolderAt(0);
 
-  // Drag the reparent item to the page switcher.
-  gfx::Point point = GetPageSwitcherView()->GetLocalBounds().CenterPoint();
-  views::View::ConvertPointToTarget(GetPageSwitcherView(), GetFolderGridView(),
-                                    &point);
-  SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged, point);
-
-  // Drop it.
-  GetFolderGridView()->EndDrag(false);
+  auto* generator = GetEventGenerator();
+  std::list<base::OnceClosure> tasks;
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { RunInitialReparentChecks(); }));
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { DragItemOutsideFolder(dragged); }));
+  tasks.push_back(base::BindLambdaForTesting([&]() {
+    // Drag the reparent item to the page switcher.
+    gfx::Point point = GetPageSwitcherView()->GetLocalBounds().CenterPoint();
+    views::View::ConvertPointToTarget(GetPageSwitcherView(),
+                                      GetFolderGridView(), &point);
+    SimulateUpdateDragInGridView(GetFolderGridView(), dragged, point);
+  }));
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { generator->ReleaseLeftButton(); }));
+  MaybeRunDragAndDropSequence(&tasks);
 
   // The folder should not be destroyed.
   EXPECT_EQ(kNumApps + 1, GetRootViewModel()->view_size());
@@ -282,23 +335,35 @@
 
 // Test that an interrupted drag while reparenting an item from a folder, when
 // canceled via the root grid, correctly forwards the cancelation to the drag
-// ocurring from the folder.
-TEST_F(AppListMainViewTest, MouseDragItemOutOfFolderWithCancel) {
+// occurring from the folder.
+TEST_P(AppListMainViewTest, MouseDragItemOutOfFolderWithCancel) {
   CreateAndOpenSingleItemFolder();
-  AppListItemView* dragged = StartDragForReparent(0);
+  AppListItemView* dragged = StartDragOnItemInFolderAt(0);
 
-  // Now add an item to the model, not in any folder, e.g., as if by Sync.
-  EXPECT_TRUE(GetRootGridView()->has_dragged_item());
-  EXPECT_TRUE(GetFolderGridView()->has_dragged_item());
-  GetTestModel()->CreateAndAddItem("Extra");
-
-  // The drag operation should get canceled.
-  EXPECT_FALSE(GetRootGridView()->has_dragged_item());
-  EXPECT_FALSE(GetFolderGridView()->has_dragged_item());
+  std::list<base::OnceClosure> tasks;
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { RunInitialReparentChecks(); }));
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { DragItemOutsideFolder(dragged); }));
+  tasks.push_back(base::BindLambdaForTesting([&]() {
+    // Now add an item to the model, not in any folder, e.g., as if by Sync.
+    GetTestModel()->CreateAndAddItem("Extra");
+    // The drag operation is canceled.
+    EXPECT_FALSE(GetRootGridView()->has_dragged_item());
+    EXPECT_FALSE(GetFolderGridView()->has_dragged_item());
+  }));
+  if (is_drag_drop_refactor_enabled()) {
+    tasks.push_back(base::BindLambdaForTesting([&]() {
+      // Required by the drag and drop controller to end the loop, since the
+      // action does not cancel the drag sequence.
+      GetEventGenerator()->ReleaseLeftButton();
+    }));
+  }
+  MaybeRunDragAndDropSequence(&tasks);
 
   // Additional mouse move operations should be ignored.
   gfx::Point point(1, 1);
-  SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged, point);
+  SimulateUpdateDragInGridView(GetFolderGridView(), dragged, point);
   EXPECT_FALSE(GetRootGridView()->has_dragged_item());
   EXPECT_FALSE(GetFolderGridView()->has_dragged_item());
 }
@@ -306,7 +371,7 @@
 // Test that dragging an app out of a single item folder and reparenting it
 // back into its original folder results in a cancelled reparent. This is a
 // regression test for http://crbug.com/429083.
-TEST_F(AppListMainViewTest, ReparentSingleItemOntoSelf) {
+TEST_P(AppListMainViewTest, ReparentSingleItemOntoSelf) {
   // Add a folder with 1 item.
   AppListItemView* folder_item_view = CreateAndOpenSingleItemFolder();
   std::string folder_id = folder_item_view->item()->id();
@@ -318,12 +383,21 @@
   views::View::ConvertPointToTarget(GetRootGridView(), GetFolderGridView(),
                                     &drag_point);
 
-  AppListItemView* dragged = StartDragForReparent(0);
+  AppListItemView* dragged = StartDragOnItemInFolderAt(0);
 
-  // Drag the reparent item back into its folder.
-  SimulateUpdateDrag(GetFolderGridView(), AppsGridView::MOUSE, dragged,
-                     drag_point);
-  GetFolderGridView()->EndDrag(false);
+  auto* generator = GetEventGenerator();
+  std::list<base::OnceClosure> tasks;
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { RunInitialReparentChecks(); }));
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { DragItemOutsideFolder(dragged); }));
+  tasks.push_back(base::BindLambdaForTesting([&]() {
+    // Drag the reparent item back into its folder.
+    SimulateUpdateDragInGridView(GetFolderGridView(), dragged, drag_point);
+  }));
+  tasks.push_back(
+      base::BindLambdaForTesting([&]() { generator->ReleaseLeftButton(); }));
+  MaybeRunDragAndDropSequence(&tasks);
 
   // The app list model should remain unchanged.
   EXPECT_EQ(2u, GetRootViewModel()->view_size());
diff --git a/ash/app_list/views/app_list_search_view_unittest.cc b/ash/app_list/views/app_list_search_view_unittest.cc
index fe00fe3..8bd2e45 100644
--- a/ash/app_list/views/app_list_search_view_unittest.cc
+++ b/ash/app_list/views/app_list_search_view_unittest.cc
@@ -35,6 +35,7 @@
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/layout/table_layout_view.h"
 #include "ui/views/test/ax_event_counter.h"
 #include "ui/views/view_utils.h"
 
@@ -306,6 +307,45 @@
   client->set_search_callback(TestAppListClient::SearchCallback());
 }
 
+TEST_P(SearchResultImageViewTest, OneResultShowsImageInfo) {
+  GetAppListTestHelper()->ShowAppList();
+
+  TestAppListClient* const client = GetAppListTestHelper()->app_list_client();
+  client->set_search_callback(
+      base::BindLambdaForTesting([&](const std::u16string& query) {
+        if (query.empty()) {
+          AppListModelProvider::Get()->search_model()->DeleteAllResults();
+          return;
+        }
+        EXPECT_EQ(u"a", query);
+
+        auto* test_helper = GetAppListTestHelper();
+        SearchModel::SearchResults* results = test_helper->GetSearchResults();
+        // Only shows 1 result.
+        SetUpImageSearchResults(results, 1, 1);
+      }));
+
+  // Press a key to start a search.
+  PressAndReleaseKey(ui::VKEY_A);
+
+  // Check result container visibility.
+  std::vector<SearchResultContainerView*> result_containers =
+      GetSearchView()->result_container_views_for_test();
+  for (auto* container : result_containers) {
+    EXPECT_TRUE(container->RunScheduledUpdateForTest());
+  }
+
+  // SearchResultImageListView container should be visible.
+  EXPECT_TRUE(result_containers[2]->GetVisible());
+
+  SearchResultImageListView* image_list_view =
+      static_cast<SearchResultImageListView*>(result_containers[2]);
+
+  // Verify that the info container of the search result is visible
+  EXPECT_TRUE(image_list_view->image_info_container_for_test()->GetVisible());
+  client->set_search_callback(TestAppListClient::SearchCallback());
+}
+
 TEST_P(SearchResultImageViewTest, ShowContextMenu) {
   auto* test_helper = GetAppListTestHelper();
   test_helper->ShowAppList();
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 8550957b..ef955ff0 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -297,6 +297,8 @@
     auto disabled_features = std::vector<base::test::FeatureRef>();
     if (use_drag_drop_refactor_) {
       enabled_features.push_back(app_list_features::kDragAndDropRefactor);
+    } else {
+      disabled_features.push_back(app_list_features::kDragAndDropRefactor);
     }
 
     if (folder_icon_refresh_) {
@@ -307,6 +309,8 @@
 
     if (enable_shelf_party_) {
       enabled_features.push_back(features::kShelfParty);
+    } else {
+      disabled_features.push_back(features::kShelfParty);
     }
 
     scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
diff --git a/ash/app_list/views/search_result_image_list_view.cc b/ash/app_list/views/search_result_image_list_view.cc
index 7e17a49..a4615e6e 100644
--- a/ash/app_list/views/search_result_image_list_view.cc
+++ b/ash/app_list/views/search_result_image_list_view.cc
@@ -5,6 +5,7 @@
 #include "ash/app_list/views/search_result_image_list_view.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -22,6 +23,7 @@
 #include "ui/views/layout/box_layout_view.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/table_layout_view.h"
 
 namespace ash {
 
@@ -34,6 +36,9 @@
 
 }  // namespace
 
+using views::LayoutAlignment;
+using views::TableLayout;
+
 SearchResultImageListView::SearchResultImageListView(
     AppListViewDelegate* view_delegate)
     : SearchResultContainerView(view_delegate) {
@@ -67,6 +72,40 @@
     image_views_.back()->SetVisible(true);
     image_view_container_->AddChildView(image_views_.back());
   }
+
+  // TODO(crbug.com/1352636): replace mock results with real results.
+  std::vector<std::u16string> info_strings = {
+      u"3.46MB", u"Today 13:28", u"image/png", u"My files/Downloads/abc.png"};
+  std::vector<int> title_string_ids = {
+      IDS_ASH_SEARCH_RESULT_IMAGE_FILE_SIZE,
+      IDS_ASH_SEARCH_RESULT_IMAGE_DATE_MODIFIED,
+      IDS_ASH_SEARCH_RESULT_IMAGE_FILE_TYPE,
+      IDS_ASH_SEARCH_RESULT_IMAGE_FILE_LOCATION};
+  const views::Label::CustomFont title_font = {
+      views::Label::GetDefaultFontList().DeriveWithWeight(
+          gfx::Font::Weight::MEDIUM)};
+
+  auto append_image_info = [&](int idx) {
+    image_info_container_->AddChildView(std::make_unique<views::Label>(
+        l10n_util::GetStringUTF16(title_string_ids[idx]), title_font));
+    image_info_container_->AddChildView(
+        std::make_unique<views::Label>(info_strings[idx]));
+  };
+
+  image_info_container_ = image_view_container_->AddChildView(
+      std::make_unique<views::TableLayoutView>());
+  image_info_container_->SetVisible(false);
+  image_info_container_->AddColumn(
+      LayoutAlignment::kStart, LayoutAlignment::kStretch,
+      TableLayout::kFixedSize, TableLayout::ColumnSize::kUsePreferred, 0, 0);
+  image_info_container_->AddPaddingColumn(TableLayout::kFixedSize, 5);
+  image_info_container_->AddColumn(
+      LayoutAlignment::kStart, LayoutAlignment::kStretch, 1.0f,
+      TableLayout::ColumnSize::kUsePreferred, 0, 0);
+  image_info_container_->AddRows(title_string_ids.size(), 1.0f);
+  for (size_t i = 0; i < title_string_ids.size(); ++i) {
+    append_image_info(i);
+  }
 }
 
 SearchResultImageListView::~SearchResultImageListView() = default;
@@ -149,6 +188,7 @@
       result_view->SetResult(nullptr);
     }
   }
+  image_info_container_->SetVisible(num_results == 1);
   SetVisible(num_results > 0);
   return num_results;
 }
diff --git a/ash/app_list/views/search_result_image_list_view.h b/ash/app_list/views/search_result_image_list_view.h
index dfc4507..3e42ca2 100644
--- a/ash/app_list/views/search_result_image_list_view.h
+++ b/ash/app_list/views/search_result_image_list_view.h
@@ -15,6 +15,7 @@
 
 namespace views {
 class BoxLayoutView;
+class TableLayoutView;
 class Label;
 }  // namespace views
 
@@ -47,6 +48,10 @@
   // Returns all search result image views children of this view.
   std::vector<SearchResultImageView*> GetSearchResultImageViews();
 
+  const views::TableLayoutView* image_info_container_for_test() const {
+    return image_info_container_.get();
+  }
+
  private:
   // Overridden from views::View:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
@@ -63,6 +68,7 @@
   // Owned by views hierarchy.
   raw_ptr<views::Label> title_label_ = nullptr;
   raw_ptr<views::BoxLayoutView> image_view_container_ = nullptr;
+  raw_ptr<views::TableLayoutView> image_info_container_ = nullptr;
   std::vector<SearchResultImageView*> image_views_;
 };
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 81d456a8..f294b8cc 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2064,6 +2064,18 @@
       <message name="IDS_ASH_SEARCH_RESULT_CATEGORY_LABEL_IMAGES" desc="Category title for the list of image results shown in launcher search relevant to the query in the search box.">
         Images
       </message>
+      <message name="IDS_ASH_SEARCH_RESULT_IMAGE_FILE_SIZE" desc="The title for the file size of the image file search result, where the information is listed beside the launcher image result.">
+        Size
+      </message>
+      <message name="IDS_ASH_SEARCH_RESULT_IMAGE_DATE_MODIFIED" desc="The title for the last modified date of the image file search result, where the information is listed beside the launcher image result.">
+        Date modified
+      </message>
+      <message name="IDS_ASH_SEARCH_RESULT_IMAGE_FILE_TYPE" desc="The title for the file type of the image file search result, where the information is listed beside the launcher image result.">
+        Type
+      </message>
+      <message name="IDS_ASH_SEARCH_RESULT_IMAGE_FILE_LOCATION" desc="The title for the file location of the image file search result, where the information is listed beside the launcher image result.">
+        Location
+      </message>
       <message name="IDS_ASH_SEARCH_RESULT_SEPARATOR" desc="Separator between the title and details text in ash search result view.">
         ''' - '''
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_DATE_MODIFIED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_DATE_MODIFIED.png.sha1
new file mode 100644
index 0000000..001fc58b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_DATE_MODIFIED.png.sha1
@@ -0,0 +1 @@
+ce08897322366dfc848bb808315e6bbf40ad446d
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_LOCATION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_LOCATION.png.sha1
new file mode 100644
index 0000000..001fc58b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_LOCATION.png.sha1
@@ -0,0 +1 @@
+ce08897322366dfc848bb808315e6bbf40ad446d
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_SIZE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_SIZE.png.sha1
new file mode 100644
index 0000000..001fc58b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_SIZE.png.sha1
@@ -0,0 +1 @@
+ce08897322366dfc848bb808315e6bbf40ad446d
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_TYPE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_TYPE.png.sha1
new file mode 100644
index 0000000..001fc58b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SEARCH_RESULT_IMAGE_FILE_TYPE.png.sha1
@@ -0,0 +1 @@
+ce08897322366dfc848bb808315e6bbf40ad446d
\ No newline at end of file
diff --git a/ash/booting/OWNERS b/ash/booting/OWNERS
new file mode 100644
index 0000000..64c5b7c
--- /dev/null
+++ b/ash/booting/OWNERS
@@ -0,0 +1 @@
+file://ash/login/OOBE_WEBUI_OWNERS
diff --git a/ash/booting/booting_animation_controller.h b/ash/booting/booting_animation_controller.h
index 206d8a8..b387ded40 100644
--- a/ash/booting/booting_animation_controller.h
+++ b/ash/booting/booting_animation_controller.h
@@ -12,7 +12,7 @@
 #include "base/scoped_observation.h"
 #include "ui/display/manager/display_configurator.h"
 #include "ui/lottie/animation_observer.h"
-#include "ui/views/widget/unique_widget_ptr.h"
+#include "ui/views/widget/widget.h"
 
 namespace ash {
 
@@ -51,7 +51,7 @@
   void StartAnimation();
 
   std::string animation_data_;
-  views::UniqueWidgetPtr widget_;
+  std::unique_ptr<views::Widget> widget_;
   bool start_once_ready_ = false;
   bool was_shown_ = false;
   bool is_gpu_ready_ = false;
diff --git a/ash/capture_mode/capture_mode_bar_view.cc b/ash/capture_mode/capture_mode_bar_view.cc
index facad852..ac36baf 100644
--- a/ash/capture_mode/capture_mode_bar_view.cc
+++ b/ash/capture_mode/capture_mode_bar_view.cc
@@ -41,11 +41,11 @@
 
 CaptureModeBarView::~CaptureModeBarView() = default;
 
-CaptureModeTypeView* CaptureModeBarView::capture_type_view() const {
+CaptureModeTypeView* CaptureModeBarView::GetCaptureTypeView() const {
   return nullptr;
 }
 
-CaptureModeSourceView* CaptureModeBarView::capture_source_view() const {
+CaptureModeSourceView* CaptureModeBarView::GetCaptureSourceView() const {
   return nullptr;
 }
 
diff --git a/ash/capture_mode/capture_mode_bar_view.h b/ash/capture_mode/capture_mode_bar_view.h
index 22f2bb4d..5d5bdec 100644
--- a/ash/capture_mode/capture_mode_bar_view.h
+++ b/ash/capture_mode/capture_mode_bar_view.h
@@ -31,12 +31,10 @@
   IconButton* settings_button() const { return settings_button_; }
   IconButton* close_button() const { return close_button_; }
 
-  // TODO(minch): Renames these two functions to GetCaptureTypeView and
-  // GetCaptureSourceView and updates all the clients.
   // These functions may return `nullptr` depending on the actual type of the
   // bar.
-  virtual CaptureModeTypeView* capture_type_view() const;
-  virtual CaptureModeSourceView* capture_source_view() const;
+  virtual CaptureModeTypeView* GetCaptureTypeView() const;
+  virtual CaptureModeSourceView* GetCaptureSourceView() const;
   virtual PillButton* GetStartRecordingButton() const;
 
   // Called when either the capture mode source or type changes.
diff --git a/ash/capture_mode/capture_mode_session_focus_cycler.cc b/ash/capture_mode/capture_mode_session_focus_cycler.cc
index e357451..0c6f9b9da 100644
--- a/ash/capture_mode/capture_mode_session_focus_cycler.cc
+++ b/ash/capture_mode/capture_mode_session_focus_cycler.cc
@@ -585,7 +585,7 @@
   // create a default region in this case.
   CaptureModeBarView* bar_view = session_->capture_mode_bar_view_;
   if (const CaptureModeSourceView* capture_source_view =
-          bar_view->capture_source_view();
+          bar_view->GetCaptureSourceView();
       capture_source_view &&
       view->GetView() == capture_source_view->region_toggle_button() &&
       CaptureModeController::Get()->source() == CaptureModeSource::kRegion) {
@@ -804,8 +804,8 @@
       break;
     case FocusGroup::kTypeSource: {
       CaptureModeBarView* bar_view = session_->capture_mode_bar_view_;
-      CaptureModeTypeView* type_view = bar_view->capture_type_view();
-      CaptureModeSourceView* source_view = bar_view->capture_source_view();
+      CaptureModeTypeView* type_view = bar_view->GetCaptureTypeView();
+      CaptureModeSourceView* source_view = bar_view->GetCaptureSourceView();
       if (!type_view || !source_view) {
         break;
       }
diff --git a/ash/capture_mode/capture_mode_test_util.cc b/ash/capture_mode/capture_mode_test_util.cc
index 8be22a3..66f3648 100644
--- a/ash/capture_mode/capture_mode_test_util.cc
+++ b/ash/capture_mode/capture_mode_test_util.cc
@@ -284,21 +284,21 @@
 IconButton* GetImageToggleButton() {
   auto* controller = CaptureModeController::Get();
   DCHECK(controller->IsActive());
-  auto* capture_type_view = GetCaptureModeBarView()->capture_type_view();
+  auto* capture_type_view = GetCaptureModeBarView()->GetCaptureTypeView();
   return capture_type_view ? capture_type_view->image_toggle_button() : nullptr;
 }
 
 IconButton* GetVideoToggleButton() {
   auto* controller = CaptureModeController::Get();
   DCHECK(controller->IsActive());
-  auto* capture_type_view = GetCaptureModeBarView()->capture_type_view();
+  auto* capture_type_view = GetCaptureModeBarView()->GetCaptureTypeView();
   return capture_type_view ? capture_type_view->video_toggle_button() : nullptr;
 }
 
 IconButton* GetFullscreenToggleButton() {
   auto* controller = CaptureModeController::Get();
   DCHECK(controller->IsActive());
-  auto* capture_source_view = GetCaptureModeBarView()->capture_source_view();
+  auto* capture_source_view = GetCaptureModeBarView()->GetCaptureSourceView();
   return capture_source_view ? capture_source_view->fullscreen_toggle_button()
                              : nullptr;
 }
@@ -306,7 +306,7 @@
 IconButton* GetRegionToggleButton() {
   auto* controller = CaptureModeController::Get();
   DCHECK(controller->IsActive());
-  auto* capture_source_view = GetCaptureModeBarView()->capture_source_view();
+  auto* capture_source_view = GetCaptureModeBarView()->GetCaptureSourceView();
   return capture_source_view ? capture_source_view->region_toggle_button()
                              : nullptr;
 }
@@ -314,7 +314,7 @@
 IconButton* GetWindowToggleButton() {
   auto* controller = CaptureModeController::Get();
   DCHECK(controller->IsActive());
-  auto* capture_source_view = GetCaptureModeBarView()->capture_source_view();
+  auto* capture_source_view = GetCaptureModeBarView()->GetCaptureSourceView();
   return capture_source_view ? capture_source_view->window_toggle_button()
                              : nullptr;
 }
diff --git a/ash/capture_mode/normal_capture_bar_view.cc b/ash/capture_mode/normal_capture_bar_view.cc
index 8c0ce46f..5be43d1 100644
--- a/ash/capture_mode/normal_capture_bar_view.cc
+++ b/ash/capture_mode/normal_capture_bar_view.cc
@@ -41,11 +41,11 @@
 
 NormalCaptureBarView::~NormalCaptureBarView() = default;
 
-CaptureModeTypeView* NormalCaptureBarView::capture_type_view() const {
+CaptureModeTypeView* NormalCaptureBarView::GetCaptureTypeView() const {
   return capture_type_view_;
 }
 
-CaptureModeSourceView* NormalCaptureBarView::capture_source_view() const {
+CaptureModeSourceView* NormalCaptureBarView::GetCaptureSourceView() const {
   return capture_source_view_;
 }
 
diff --git a/ash/capture_mode/normal_capture_bar_view.h b/ash/capture_mode/normal_capture_bar_view.h
index 3ced7e4..0b2458b 100644
--- a/ash/capture_mode/normal_capture_bar_view.h
+++ b/ash/capture_mode/normal_capture_bar_view.h
@@ -50,8 +50,8 @@
   ~NormalCaptureBarView() override;
 
   // CaptureModeBarView:
-  CaptureModeTypeView* capture_type_view() const override;
-  CaptureModeSourceView* capture_source_view() const override;
+  CaptureModeTypeView* GetCaptureTypeView() const override;
+  CaptureModeSourceView* GetCaptureSourceView() const override;
   void OnCaptureSourceChanged(CaptureModeSource new_source) override;
   void OnCaptureTypeChanged(CaptureModeType new_type) override;
 
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc
index 03e3648..77155d4 100644
--- a/ash/clipboard/clipboard_history_controller_impl.cc
+++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -54,6 +54,7 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/clipboard/clipboard_data.h"
 #include "ui/base/clipboard/clipboard_non_backed.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/ime/input_method.h"
@@ -91,7 +92,7 @@
     std::map<base::UnguessableToken, std::vector<uint8_t>>* const encoded_pngs,
     base::UnguessableToken id,
     SkBitmap bitmap) {
-  auto png = ui::ClipboardData::EncodeBitmapData(bitmap);
+  auto png = ui::clipboard_util::EncodeBitmapToPng(bitmap);
 
   // Don't acquire the lock until after the image encoding has finished.
   static base::NoDestructor<base::Lock> map_lock;
diff --git a/ash/clipboard/clipboard_history_unittest.cc b/ash/clipboard/clipboard_history_unittest.cc
index 9111587e..fab98ae 100644
--- a/ash/clipboard/clipboard_history_unittest.cc
+++ b/ash/clipboard/clipboard_history_unittest.cc
@@ -25,6 +25,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/clipboard/custom_data_helper.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/events/event_constants.h"
@@ -465,7 +466,7 @@
       data_to_duplicate.sequence_number_token();
   const auto original_timestamp = items.back().time_copied();
   EXPECT_FALSE(data_to_duplicate.maybe_png());
-  auto png = ui::ClipboardData::EncodeBitmapData(test_bitmap_1);
+  auto png = ui::clipboard_util::EncodeBitmapToPng(test_bitmap_1);
   data_to_duplicate.SetPngDataAfterEncoding(png);
   EXPECT_TRUE(data_to_duplicate.maybe_png());
 
diff --git a/ash/components/arc/mojom/app.mojom b/ash/components/arc/mojom/app.mojom
index 7aaf6dd..09d9591 100644
--- a/ash/components/arc/mojom/app.mojom
+++ b/ash/components/arc/mojom/app.mojom
@@ -415,19 +415,9 @@
   // Establishes full-duplex communication with the host.
   [MinVersion=26] Init@21(pending_remote<AppHost> host_remote) => ();
 
-  [MinVersion=1] CanHandleResolutionDeprecated@4(
-      string package_name, string activity, Rect dimension) =>
-          (bool can_handle);
-
   // Closes the the given task.
   [MinVersion=4] CloseTask@8(int32 task_id);
 
-  // Requests information about task. Deprecated: b/265158447
-  // Use the kArcPackageNameKey window property to get the package name, and
-  // OnTaskCreated to get the activity.
-  [MinVersion=3] GetTaskInfoDeprecated@6(int32 task_id) =>
-      (string package_name, string activity);
-
   // Sends a request to ARC to install package.
   [MinVersion=8] InstallPackage@11(ArcPackageInfo arcPackageInfo);
 
diff --git a/ash/components/arc/session/arc_vm_client_adapter.cc b/ash/components/arc/session/arc_vm_client_adapter.cc
index 7bbcdf7..ea57812 100644
--- a/ash/components/arc/session/arc_vm_client_adapter.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter.cc
@@ -382,6 +382,10 @@
   else
     request.set_vm_memory_psi_period(-1);
 
+  request.set_enable_vmm_swap(
+      base::FeatureList::IsEnabled(kVmmSwapPolicy) ||
+      base::FeatureList::IsEnabled(kVmmSwapKeyboardShortcut));
+
   auto orientation = display::PanelOrientation::kNormal;
   if (auto* screen = display::Screen::GetScreen()) {
     const auto display_id = screen->GetPrimaryDisplay().id();
diff --git a/ash/components/arc/test/fake_app_instance.cc b/ash/components/arc/test/fake_app_instance.cc
index 3ed5e916..a863e27c 100644
--- a/ash/components/arc/test/fake_app_instance.cc
+++ b/ash/components/arc/test/fake_app_instance.cc
@@ -298,23 +298,10 @@
       mojom::InstallationResultPtr(result.Clone()));
 }
 
-void FakeAppInstance::CanHandleResolutionDeprecated(
-    const std::string& package_name,
-    const std::string& activity,
-    const gfx::Rect& dimension,
-    CanHandleResolutionDeprecatedCallback callback) {
-  std::move(callback).Run(true);
-}
-
 void FakeAppInstance::UninstallPackage(const std::string& package_name) {
   app_host_->OnPackageRemoved(package_name);
 }
 
-void FakeAppInstance::GetTaskInfoDeprecated(
-    int32_t task_id, GetTaskInfoDeprecatedCallback callback) {
-  LOG(FATAL) << "GetTaskInfo is deprecated: b/265158447";
-}
-
 void FakeAppInstance::SetTaskActive(int32_t task_id) {}
 
 void FakeAppInstance::CloseTask(int32_t task_id) {}
diff --git a/ash/components/arc/test/fake_app_instance.h b/ash/components/arc/test/fake_app_instance.h
index a29a6ba..26a48e0 100644
--- a/ash/components/arc/test/fake_app_instance.h
+++ b/ash/components/arc/test/fake_app_instance.h
@@ -134,14 +134,7 @@
                       bool normalize,
                       GetPackageIconCallback callback) override;
   void RemoveCachedIcon(const std::string& icon_resource_id) override;
-  void CanHandleResolutionDeprecated(
-      const std::string& package_name,
-      const std::string& activity,
-      const gfx::Rect& dimension,
-      CanHandleResolutionDeprecatedCallback callback) override;
   void UninstallPackage(const std::string& package_name) override;
-  void GetTaskInfoDeprecated(int32_t task_id,
-                              GetTaskInfoDeprecatedCallback callback) override;
   void SetTaskActive(int32_t task_id) override;
   void CloseTask(int32_t task_id) override;
   void ShowPackageInfoDeprecated(const std::string& package_name,
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 7b02b81..4df2c5a59 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -822,7 +822,7 @@
 // or not (=decides using heuristics based on key code etc.).
 BASE_FEATURE(kExoConsumedByImeByFlag,
              "ExoConsumedByImeByFlag",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Allows RGB Keyboard to test new animations/patterns.
 BASE_FEATURE(kExperimentalRgbKeyboardPatterns,
@@ -1620,7 +1620,7 @@
 BASE_FEATURE(kFeatureManagementOobeSimon,
              "FeatureManagementOobeSimon",
              base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kOobeSimon, "OobeSimon", base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kOobeSimon, "OobeSimon", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Enables Skipping the assistant setup screen in OOBE.
 BASE_FEATURE(kOobeSkipAssistant,
@@ -2418,7 +2418,7 @@
 // Enables settings to be split per device.
 BASE_FEATURE(kInputDeviceSettingsSplit,
              "InputDeviceSettingsSplit",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Enables or disables whether to store UMA logs per-user and whether metrics
 // consent is per-user.
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc
index e9d078fa..704195c 100644
--- a/ash/constants/ash_switches.cc
+++ b/ash/constants/ash_switches.cc
@@ -39,12 +39,6 @@
 // allows the user to install from USB to disk.
 const char kAllowOsInstall[] = "allow-os-install";
 
-// Allows remote attestation (RA) in dev mode for testing purpose. Usually RA
-// is disabled in dev mode because it will always fail. However, there are cases
-// in testing where we do want to go through the permission flow even in dev
-// mode. This can be enabled by this flag.
-const char kAllowRAInDevMode[] = "allow-ra-in-dev-mode";
-
 // Override for the URL used for the ChromeOS Almanac API. Used for local
 // testing with a non-production server (e.g.
 // "--almanac-api-url=http://localhost:8000").
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h
index 3d8340a..0f75799 100644
--- a/ash/constants/ash_switches.h
+++ b/ash/constants/ash_switches.h
@@ -26,7 +26,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const char kAllowFailedPolicyFetchForTest[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAllowOsInstall[];
-COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAllowRAInDevMode[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAlmanacApiUrl[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAlwaysEnableHdcp[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAppAutoLaunched[];
diff --git a/ash/strings/ash_strings_af.xtb b/ash/strings/ash_strings_af.xtb
index 9711324..ba72e5da 100644
--- a/ash/strings/ash_strings_af.xtb
+++ b/ash/strings/ash_strings_af.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">Kalender, <ph name="CURRENT_MONTH_YEAR" />, <ph name="DATE" /> is tans gekies.</translation>
 <translation id="1787955149152357925">Af</translation>
 <translation id="181103072419391116">Seinsterkte <ph name="SIGNAL_STRENGTH" />, deur jou administrateur bestuur</translation>
+<translation id="1815245884418711390">Wissel warmkol. Warmkol is af.</translation>
 <translation id="1816896987747843206">Dit gee kameratoegang vir alle apps en webwerwe met die kameratoestemming</translation>
 <translation id="1823280932251546115">Statuslaai, tyd <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">Jy kan pakketvasvang enige tyd stop</translation>
 <translation id="2034971124472263449">Stoor in elk geval</translation>
 <translation id="2049240716062114887">Lessenaarnaam is verander na <ph name="DESK_NAME" /></translation>
+<translation id="206377500836174974">Vol</translation>
 <translation id="2064048859448024834">Kameravoorskou is aan</translation>
 <translation id="2067602449040652523">Sleutelbordhelderheid</translation>
 <translation id="2075520525463668108">Wissel <ph name="CAPTURE_MEDIUM" />. <ph name="CAPTURE_MEDIUM" /> is <ph name="CAPTURE_STATE" /></translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">Tik op die stilusknoppie op die rak om 'n nota te maak, 'n skermkiekie te neem, of om die laseraanwyser of vergrootglas te gebruik.</translation>
 <translation id="2341729377289034582">Gesluit op vertikaal</translation>
 <translation id="2345226652884463045">Druk Enter of Search+spasiebalk om die teks te kies wat jy wil wysig.</translation>
+<translation id="2349785431103945039">Wys warmkolbesonderhede. Koppel aan mobiele data om warmkol te gebruik.</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" />-spraak word nou plaaslik verwerk en werk vanlyn. Jy kan jou dikteertaal in Instellings &gt; Toeganklikheid verander.</translation>
 <translation id="2352467521400612932">Stilusinstellings</translation>
 <translation id="2354174487190027830">Aktiveer tans <ph name="NAME" /></translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">toestel stadig</translation>
 <translation id="2542089167727451762">Tik op jou profielprent</translation>
 <translation id="254900897760075745">Kopieer geselekteerde inhoud na knipbord</translation>
+<translation id="2549711466868162843">Verbeter beligting</translation>
 <translation id="255671100581129685">Die Google Assistent is nie in 'n publieke sessie beskikbaar nie.</translation>
 <translation id="256712445991462162">die gedokte vergrootglas</translation>
 <translation id="2573588302192866788">Kon nie <ph name="NAME" /> koppel nie</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">Uitvoer</translation>
 <translation id="3009958530611748826">Kies 'n vouer om in te stoor</translation>
 <translation id="301282384882049174">Gedeel deur jou administrateur</translation>
+<translation id="301584155502740476">Wys warmkolbesonderhede. Warmkol is af.</translation>
 <translation id="3018135054368884502">Spoel media vinnig vorentoe</translation>
 <translation id="3033545621352269033">Aan</translation>
 <translation id="3033912566804961911">Kombineer met <ph name="DESK_NAME" /></translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">Skuif na begin van vorige woord</translation>
 <translation id="3294437725009624529">Gas</translation>
 <translation id="3298690094479023523">Jou PIN of wagwoord kon steeds nie geverifieer word nie. Probeer weer.</translation>
+<translation id="3300193645498960160">Jy sal in kennis gestel word as jy praat terwyl gedemp aan is. Oudio verlaat nooit jou toestel nie.</translation>
 <translation id="3307642347673023554">Het na skootrekenaarmodus oorgeskakel</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> kan steeds later aanmeld.</translation>
 <translation id="3321628682574733415">Verkeerde ouerkode</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">Invoer</translation>
 <translation id="3621712662352432595">Oudio-instellings</translation>
 <translation id="3626281679859535460">Helderheid</translation>
+<translation id="3629640897379005903">Wys warmkolbesonderhede. Warmkol tans gedeaktiveer.</translation>
 <translation id="3630697955794050612">af</translation>
 <translation id="3631369015426612114">Laat kennisgewings van die volgende af toe</translation>
 <translation id="3633097874324966332">Maak Bluetooth-instellings oop om jou toestel saam te bind</translation>
@@ -702,6 +709,7 @@
 <translation id="423685346499232137">Kan nie op die oomblik inhoud kopieer of plak nie</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">Oorsigmodus</translation>
+<translation id="4240756737570479726">Deaktiveer tans …</translation>
 <translation id="4242533952199664413">Maak instellings oop</translation>
 <translation id="4247123849143712100">Dateer op en skakel af</translation>
 <translation id="4250229828105606438">Skermkiekie</translation>
@@ -840,6 +848,7 @@
 <translation id="4864369630010738180">Meld tans aan …</translation>
 <translation id="4864648187878336334">Lessenaar 15</translation>
 <translation id="4868492592575313542">geaktiveer</translation>
+<translation id="4871905435473761992">Wys warmkolbesonderhede. Jou mobiele netwerk gebruik nie warmkol nie.</translation>
 <translation id="4872237917498892622">Alt+Search of Shift</translation>
 <translation id="4872852897273142380">Fokus op of kleurmerk die boekmerkbalk (as dit gewys word)</translation>
 <translation id="4881695831933465202">Maak oop</translation>
@@ -899,6 +908,7 @@
 <translation id="5104236669533825617">Kan nie skermopname skep nie</translation>
 <translation id="5107522548814527560">Web</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">Agtergrondwasigheid</translation>
 <translation id="5117590920725113268">Wys volgende maand</translation>
 <translation id="5121628974188116412">Gaan na onderkant van bladsy</translation>
 <translation id="5136175204352732067">Ander sleutelbord is gekoppel</translation>
@@ -910,6 +920,7 @@
 <translation id="5168181903108465623">Uitsaaitoestelle is beskikbaar</translation>
 <translation id="5170568018924773124">Wys in vouer</translation>
 <translation id="5176318573511391780">Neem gedeeltelike skerm op</translation>
+<translation id="5187627942836026988">Wys warmkolbesonderhede. Jou administrateur blokkeer warmkol.</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> geleenthede</translation>
 <translation id="5198715732953550718"><ph name="MOVED_APP_NAME" /> is met <ph name="IN_PLACE_APP" /> gekombineer om 'n nuwe vouer te skep.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1081,6 +1092,7 @@
 <translation id="595202126637698455">Prestasie-nasporing geaktiveer</translation>
 <translation id="5955304353782037793">program</translation>
 <translation id="5958529069007801266">Gebruiker onder toesig</translation>
+<translation id="5961960957587052807">Lig</translation>
 <translation id="5965524703725988602">Wissel Donkertema. <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">Druk Enter om venster op te neem</translation>
 <translation id="5978382165065462689">Deel tans beheer oor jou skerm deur afstandbystand.</translation>
@@ -1253,6 +1265,7 @@
 <translation id="6752912906630585008">Lessenaar <ph name="REMOVED_DESK" /> is verwyder en met lessenaar <ph name="RECEIVE_DESK" /> saamgevoeg</translation>
 <translation id="6753390234084146956">oortjies</translation>
 <translation id="6757237461819837179">Geen media speel tans nie</translation>
+<translation id="6759628406555734414">Wys warmkolbesonderhede. Aktiveer tans warmkol.</translation>
 <translation id="6768043681523654438">berging</translation>
 <translation id="6777216307882431711">Gee tans krag aan gekoppelde USB-C-toestelle</translation>
 <translation id="6781002679438061620">Lessenaar 9</translation>
@@ -1277,6 +1290,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> sek.</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{Een syfer bly oor}other{# syfers bly oor}}</translation>
 <translation id="6867938213751067702">Aflaai is onderbreek <ph name="FILENAME" /></translation>
+<translation id="6874854809828346832">Wys warmkolbesonderhede. Warmkol is aan.</translation>
 <translation id="6878400149835617132">Kortpad is afgeskakel</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 app}other{# apps}}</translation>
 <translation id="6884665277231944629">Gaan terug na vandag</translation>
@@ -1286,6 +1300,7 @@
 <translation id="6896758677409633944">Kopieer</translation>
 <translation id="6901883536534621389">Probeer gebare om te navigeer</translation>
 <translation id="6919251195245069855">Kon nie jou slimkaart herken nie. Probeer weer.</translation>
+<translation id="6920245099716267363">Wissel warmkol. Warmkol is aan; 1 toestel is gekoppel</translation>
 <translation id="6931576957638141829">Stoor in</translation>
 <translation id="6941333068993625698">Dien terugvoer in</translation>
 <translation id="6942518653766415536">Opnameformaatkieslys</translation>
@@ -1375,6 +1390,7 @@
 <translation id="7378203170292176219">Sleep om 'n area te kies om op te neem</translation>
 <translation id="7378594059915113390">Media-kontroles</translation>
 <translation id="7378889811480108604">Batterybespaardermodus is af</translation>
+<translation id="7382640522316003298">Wissel warmkol. Warmkol is aan; <ph name="DEVICECOUNT" /> toestelle is gekoppel.</translation>
 <translation id="7382680553121047388">Aan</translation>
 <translation id="7384028040782072252">Regsklik op enige plek om jou programme te herrangskik</translation>
 <translation id="7386767620098596324">Wissel netwerkverbinding. <ph name="STATE_TEXT" />.</translation>
@@ -1425,6 +1441,7 @@
 <translation id="7579778809502851308">Skermskoot</translation>
 <translation id="7593891976182323525">Search of Shift</translation>
 <translation id="7600875258240007829">Sien alle kennisgewings</translation>
+<translation id="7601417191446344542">Sakel die demp-aanporder aan?</translation>
 <translation id="7607002721634913082">Laat wag</translation>
 <translation id="7609951632080598826">Kalenderaansig, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">Kamera is herkoppel.</translation>
@@ -1547,6 +1564,7 @@
 <translation id="8131740175452115882">Bevestig</translation>
 <translation id="8131994907636310308">Maak "sorteer opspringers" toe</translation>
 <translation id="8132793192354020517">Gekoppel aan <ph name="NAME" /></translation>
+<translation id="8135163608236671037">Wissel warmkol. Warmkol is aan; geen toestel is gekoppel nie</translation>
 <translation id="8138705869659070104">Aktiveer ná toestelopstelling</translation>
 <translation id="813913629614996137">Inisialiseer tans …</translation>
 <translation id="8142441511840089262">Dubbelklik</translation>
@@ -1727,6 +1745,7 @@
 <translation id="8990809378771970590">Gebruik tans <ph name="IME_NAME" /></translation>
 <translation id="8991617137207906966">Kleuromkeringmodus is geaktiveer. Druk weer Ctrl+Search+H om dit af te skakel.</translation>
 <translation id="899350903320462459">Ontsluit toestel as <ph name="LOGIN_ID" /> om die kennisgewinghandeling uit te voer</translation>
+<translation id="8993733019280019776">Praat jy tans? Jou mikrofoon is af. Kies die mikrofoon om dit aan te skakel.</translation>
 <translation id="9000771174482730261">BESTUUR BERGING</translation>
 <translation id="9005984960510803406">Maak Crosh-venster oop</translation>
 <translation id="9017320285115481645">Voer die Family Link-ouertoegangskode in.</translation>
diff --git a/ash/strings/ash_strings_am.xtb b/ash/strings/ash_strings_am.xtb
index 0f09cd3..0d7feffd 100644
--- a/ash/strings/ash_strings_am.xtb
+++ b/ash/strings/ash_strings_am.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">ቀን መቁጠሪያ፣ <ph name="CURRENT_MONTH_YEAR" />፣ በአሁኑ ጊዜ <ph name="DATE" /> ተመርጧል።</translation>
 <translation id="1787955149152357925">አጥፋ</translation>
 <translation id="181103072419391116">የሲግናል ጥንካሬ <ph name="SIGNAL_STRENGTH" />፣ በየእርስዎ አስተዳዳሪ የሚተዳደር</translation>
+<translation id="1815245884418711390">መገናኛ ነጥብ ቀያይር። መገናኛ ነጥብ ጠፍቷል።</translation>
 <translation id="1816896987747843206">ይህ የካሜራ ፈቃድ ላላቸው ሁሉም መተግበሪያዎች እና ድር ጣቢያዎች የካሜራ መዳረሻ ይፈቅዳል</translation>
 <translation id="1823280932251546115">የሁኔታ ትሪ፣ ሰዓት <ph name="TIME" />፣
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">በማንኛውም ጊዜ የፓኬት ቀረጻን ማቆም ይችላሉ</translation>
 <translation id="2034971124472263449">ቢሆንም አስቀምጥ</translation>
 <translation id="2049240716062114887">የዴስክ ስም ወደ <ph name="DESK_NAME" /> ተለውጧል</translation>
+<translation id="206377500836174974">ሙሉ</translation>
 <translation id="2064048859448024834">የካሜራ ቅድመ-እይታ በርቷል</translation>
 <translation id="2067602449040652523">የቁልፍ ሰሌዳ ብሩህነት</translation>
 <translation id="2075520525463668108"><ph name="CAPTURE_MEDIUM" /> ቀያይር። <ph name="CAPTURE_MEDIUM" /> <ph name="CAPTURE_STATE" /> ነው</translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">ማስታወሻ ለመያዝ፣ ቅጽበታዊ ገፅ እይታን ለማንሳት፣ ሌዘር ጠቋሚውን ወይም ማጉያ መነጽሩን ለመጠቀም በመደርደሪያው ላይ ያለውን የስታይለስ አዝራሩን መታ ያድርጉ።</translation>
 <translation id="2341729377289034582">ወደ አቀባዊ ተቆልፏል</translation>
 <translation id="2345226652884463045">ጽሁፉን ለአርትዖት ለመምረጥ አስገባን ወይም ፈልግ + ክፍት ቦታን ይጫኑ።</translation>
+<translation id="2349785431103945039">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብን ለመጠቀም ከተንቀሳቃሽ ስልክ አውታረ መረብ ጋር ይገናኙ።</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" /> ንግግር በአካባቢው የሚሰናዳ እና ከመስመር ውጭ የሚሰራ ነው። በቅንብሮች&gt; ተደራሽነት ውስጥ የበቃል ማስጻፍ ቋንቋዎን መለወጥ ይችላሉ።</translation>
 <translation id="2352467521400612932">የስቲለስ ቅንብሮች</translation>
 <translation id="2354174487190027830"><ph name="NAME" />ን በማግበር ላይ</translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">መሣሪያ ቀርፋፋ ነው</translation>
 <translation id="2542089167727451762">የመገለጫ ምስልዎን መታ ያድርጉ</translation>
 <translation id="254900897760075745">የተመረጠውን ይዘት ወደ ቅንጥብ ሰሌዳው ይቅዱት</translation>
+<translation id="2549711466868162843">ብርሃን አሻሽል</translation>
 <translation id="255671100581129685">የGoogle ረዳቱ በይፋዊ ክፍለ-ጊዜ ውስጥ አይገኝም።</translation>
 <translation id="256712445991462162">የተተከለው ማጉያ</translation>
 <translation id="2573588302192866788">ወደ <ph name="NAME" /> መናኘት አልተቻለም</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">ውጽዓት</translation>
 <translation id="3009958530611748826">የሚያስቀምጡበትን አቃፊ ይምረጡ</translation>
 <translation id="301282384882049174">በእርስዎ አስተዳዳሪ የተጋራ</translation>
+<translation id="301584155502740476">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብ ጠፍቷል።</translation>
 <translation id="3018135054368884502">ሚዲያን ወደፊት አሳልፍ</translation>
 <translation id="3033545621352269033">አብራ</translation>
 <translation id="3033912566804961911">ከ<ph name="DESK_NAME" /> ጋር ማጣመር</translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">ወደ ቀዳሚው ቃል መጀመሪያ ይንቀሳቀሱ</translation>
 <translation id="3294437725009624529">እንግዳ</translation>
 <translation id="3298690094479023523">የእርስዎ ፒን ወይም ይለፍ ቃል አሁንም ሊረጋገጥ አልቻለም። እንደገና ይሞክሩ።</translation>
+<translation id="3300193645498960160">ድምጸ-ከል ሆነው ሳለ ካወሩ ማሳወቂያ ይደርስዎታል። ኦዲዮ ከመሣሪያዎ በጭራሽ አይወጣም።</translation>
 <translation id="3307642347673023554">ወደ የላፕቶፕ ሁነታ ተቀይሯል</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> አሁንም በኋላ በመለያ መግባት ይችላሉ።</translation>
 <translation id="3321628682574733415">ትክክል ያልሆነ የወላጅ ኮድ</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">ግብዓት</translation>
 <translation id="3621712662352432595">የድምጽ ቅንብሮች</translation>
 <translation id="3626281679859535460">ብሩህነት</translation>
+<translation id="3629640897379005903">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብ እየተሰናከለ ነው።</translation>
 <translation id="3630697955794050612">ጠፍቷል</translation>
 <translation id="3631369015426612114">ማሳወቂያዎች ከሚከተሉት እንዲመጡ ፍቀድ፦</translation>
 <translation id="3633097874324966332">መሣሪያዎን ለማጣመር የብሉቱዝ ቅንብሮችን ይክፈቱ</translation>
@@ -701,6 +708,7 @@
 <translation id="423685346499232137">በዚህ ጊዜ ላይ ይዘትን መቅዳት ወይም መለጠፍ አልተቻለም</translation>
 <translation id="4239069858505860023">ጂፒአርኤስ</translation>
 <translation id="4240486403425279990">የአጠቃላይ እይታ ሁነታ</translation>
+<translation id="4240756737570479726">በማሰናከል ላይ...</translation>
 <translation id="4242533952199664413">ቅንብሮችን ክፈት</translation>
 <translation id="4247123849143712100">አዘምን እና ዝጋ</translation>
 <translation id="4250229828105606438">ቅጽበታዊ ገፅ እይታ</translation>
@@ -839,6 +847,7 @@
 <translation id="4864369630010738180">በመግባት ላይ...</translation>
 <translation id="4864648187878336334">ዴስክ 15</translation>
 <translation id="4868492592575313542">ገብሯል</translation>
+<translation id="4871905435473761992">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። የእርስዎ የተንቀሳቃሽ ስልክ አውታረ መረብ መገናኛ ነጥብን አይደግፍም።</translation>
 <translation id="4872237917498892622">Alt+Search ወይም Shift</translation>
 <translation id="4872852897273142380">(የሚታይ ከሆነ) በዕልባቶች አሞሌው ላይ ያተኩሩ ወይም ያድምቁት</translation>
 <translation id="4881695831933465202">ክፍት የሚሆንባቸው</translation>
@@ -898,6 +907,7 @@
 <translation id="5104236669533825617">ማያገጽ መቅርጽን መፍጠር አልተቻለም</translation>
 <translation id="5107522548814527560">ድር</translation>
 <translation id="5111318697104479778"><ph name="DESC" />፣ <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">የዳራ ብዥታ</translation>
 <translation id="5117590920725113268">ቀጣዩን ወር አሳይ</translation>
 <translation id="5121628974188116412">ወደ ገጹ ግርጌ ይሂዱ</translation>
 <translation id="5136175204352732067">የተለየ የቁልፍ ሰሌዳ ተገናኝቷል</translation>
@@ -909,6 +919,7 @@
 <translation id="5168181903108465623">የCast መሣሪያዎች ይገኛሉ</translation>
 <translation id="5170568018924773124">በአቃፊ አሳይ</translation>
 <translation id="5176318573511391780">ከፊል የማያ ገጽን ቅረጽ</translation>
+<translation id="5187627942836026988">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብ በአስተዳዳሪዎ ታግዷል።</translation>
 <translation id="5198413532174090167"><ph name="DATE" />፣ <ph name="NUMBER" /> ክስተቶች</translation>
 <translation id="5198715732953550718"><ph name="MOVED_APP_NAME" /> ከ<ph name="IN_PLACE_APP" /> ጋር አዲስ አቃፊ ለመፍጠር ተጣምሯል።</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />፣ <ph name="NOTIFICATION_TITLE" />፦ <ph name="MESSAGE" />፣ <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1091,7 @@
 <translation id="595202126637698455">አፈጻጸም መከታተያ ነቅቷል</translation>
 <translation id="5955304353782037793">app</translation>
 <translation id="5958529069007801266">ክትትል የሚደረግበት ተጠቃሚ</translation>
+<translation id="5961960957587052807">ብርሃን</translation>
 <translation id="5965524703725988602">ጠቆር ያለ ገጽታን ቀያይር። <ph name="STATE_TEXT" />።</translation>
 <translation id="5976112937189445008">መስኮት ለመቅዳት አስገባን ይጫኑ</translation>
 <translation id="5978382165065462689">የማያ ገጽዎን ቁጥጥር በርቀት እርዳታ በኩል በማጋራት ላይ።</translation>
@@ -1252,6 +1264,7 @@
 <translation id="6752912906630585008">ዴስክ <ph name="REMOVED_DESK" /> ተወግዶ ከዴስክ <ph name="RECEIVE_DESK" /> ጋር ተዋህዷል</translation>
 <translation id="6753390234084146956">ትሮች</translation>
 <translation id="6757237461819837179">ምንም ሚዲያ እየተጫወተ አይደለም</translation>
+<translation id="6759628406555734414">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብ እየነቃ ነው።</translation>
 <translation id="6768043681523654438">ማከማቻ</translation>
 <translation id="6777216307882431711">የተገናኙ የUSB-C መሣሪያዎችን ኃይል በመሙላት ላይ</translation>
 <translation id="6781002679438061620">ዴስክ 9</translation>
@@ -1276,6 +1289,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> ሰከንድ</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{አንድ አሃዝ ይቀራል}one{# አሃዞች ይቀራሉ}other{# አሃዞች ይቀራሉ}}</translation>
 <translation id="6867938213751067702">ማውረድ ባለበት ቆሟል <ph name="FILENAME" /></translation>
+<translation id="6874854809828346832">የመገናኛ ነጥብ ዝርዝሮችን አሳይ። መገናኛ ነጥብ በርቷል።</translation>
 <translation id="6878400149835617132">አቋራጭ ጠፍቷል</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 መተግበሪያ}one{# መተግበሪያ}other{# መተግበሪያዎች}}</translation>
 <translation id="6884665277231944629">ወደ ዛሬ ተመለስ</translation>
@@ -1285,6 +1299,7 @@
 <translation id="6896758677409633944">ቅዳ</translation>
 <translation id="6901883536534621389">ለማሰስ የእጅ ምልክቶችን ይሞክሩ</translation>
 <translation id="6919251195245069855">የእርስዎን ዘመናዊ ካርድ ለይቶ ማወቅ አልተቻለም። እንደገና ይሞክሩ።</translation>
+<translation id="6920245099716267363">መገናኛ ነጥብ ቀያይር። መገናኛ ነጥብ በርቷል፣ 1 መሣሪያ ተገናኝቷል።</translation>
 <translation id="6931576957638141829">አስቀምጥ ወደ</translation>
 <translation id="6941333068993625698">ግብረመልስ ያስገቡ</translation>
 <translation id="6942518653766415536">የመቅዳት ቅርጸት ምናሌ</translation>
@@ -1374,6 +1389,7 @@
 <translation id="7378203170292176219">ለመቅዳት አካባቢ ለመምረጥ ይጎትቱ</translation>
 <translation id="7378594059915113390">የሚዲያ መቆጣጠሪያዎች</translation>
 <translation id="7378889811480108604">የባትሪ ኃይል ቆጣቢ ሁነታ ጠፍቷል</translation>
+<translation id="7382640522316003298">መገናኛ ነጥብ ቀያይር። መገናኛ ነጥብ በርቷል፣ <ph name="DEVICECOUNT" /> መሣሪያዎች ተገናኝተዋል።</translation>
 <translation id="7382680553121047388">በርቷል</translation>
 <translation id="7384028040782072252">መተግበሪያዎችዎን እንደገና ለመደርደር በማንኛውም ቦታ ላይ በቀኝ ጠቅ ያድርጉ</translation>
 <translation id="7386767620098596324">የአውታረ መረብ ግንኙነትን ቀያይር። <ph name="STATE_TEXT" />።</translation>
@@ -1424,6 +1440,7 @@
 <translation id="7579778809502851308">የማያ ገፅ ቀረጻ</translation>
 <translation id="7593891976182323525">Search ወይም Shift</translation>
 <translation id="7600875258240007829">ሁሉንም ማሳወቂያዎች ይመልከቱ</translation>
+<translation id="7601417191446344542">ድምጸ-ከልን ገፋ ማድረግ ይብራ?</translation>
 <translation id="7607002721634913082">ለአፍታ ቆሟል</translation>
 <translation id="7609951632080598826">የቀን መቁጠሪያ እይታ፣ <ph name="DATE" />፣ <ph name="TIME" /></translation>
 <translation id="7611213136657090146">ካሜራ እንደገና ተገናኝቷል።</translation>
@@ -1546,6 +1563,7 @@
 <translation id="8131740175452115882">አረጋግጥ</translation>
 <translation id="8131994907636310308">የድርድር ቶስትን ዝጋ</translation>
 <translation id="8132793192354020517">ከ<ph name="NAME" /> ጋር ተገናኝቷል</translation>
+<translation id="8135163608236671037">መገናኛ ነጥብ ቀያይር። መገናኛ ነጥብ በርቷል፣ ምንም መሣሪያ አልተገናኘም።</translation>
 <translation id="8138705869659070104">ከመሣሪያ ውቅረት በኋላ ያግብሩ</translation>
 <translation id="813913629614996137">በማስጀመር ላይ…</translation>
 <translation id="8142441511840089262">ድርብ ጠቅታ</translation>
@@ -1726,6 +1744,7 @@
 <translation id="8990809378771970590"><ph name="IME_NAME" />ን በመጠቀም ላይ</translation>
 <translation id="8991617137207906966">የተቃራኒ ቀለም ሁነታ ነቅቷል። መቀያየሪያውን ለማጥፋት Ctrl+Search+Hን እንደገና ይጫኑ።</translation>
 <translation id="899350903320462459">የማሳወቅ እርምጃውን ለማከናወን መሣሪያን እንደ <ph name="LOGIN_ID" /> ይክፈቱ</translation>
+<translation id="8993733019280019776">እያወሩ ነው? የእርስዎ ማይክሮፎን ጠፍቷል። እሱን ለማብራት ማይክሮፎኑን ይምረጡት።</translation>
 <translation id="9000771174482730261">ማከማቻን ያቀናብሩ</translation>
 <translation id="9005984960510803406">የCrosh መስኮትን አሳይ</translation>
 <translation id="9017320285115481645">የ Family Link ወላጅ መዳረሻ ኮድ ያስገቡ።</translation>
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index d87e591..c870462 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -1063,6 +1063,7 @@
 <translation id="5881540930187678962">إعداد "مركز التحكم بالهاتف" لاحقًا</translation>
 <translation id="5881663018261910378">غير مفعّلة</translation>
 <translation id="5887954372087850114">تم تخصيص النافذة <ph name="WINDOW_TITLE" /> لسطح المكتب <ph name="DESK_TITLE" /> وإلغاء تخصيصها من جميع أسطح المكتب الأخرى.</translation>
+<translation id="588817334757907802">‏فتح الملف في متصفِّح Chrome</translation>
 <translation id="5895138241574237353">إعادة التشغيل</translation>
 <translation id="589817443623831496">مسح النقاط</translation>
 <translation id="5901316534475909376">Shift+Esc</translation>
diff --git a/ash/strings/ash_strings_da.xtb b/ash/strings/ash_strings_da.xtb
index e89bdc56..bf9bb8a 100644
--- a/ash/strings/ash_strings_da.xtb
+++ b/ash/strings/ash_strings_da.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">Kalender for <ph name="CURRENT_MONTH_YEAR" /> – <ph name="DATE" /> er valgt.</translation>
 <translation id="1787955149152357925">Fra</translation>
 <translation id="181103072419391116">Signalstyrke <ph name="SIGNAL_STRENGTH" />, administreret af din administrator</translation>
+<translation id="1815245884418711390">Slå hotspot til/fra. Hotspot er deaktiveret.</translation>
 <translation id="1816896987747843206">Dette giver alle apps og websites med kameratilladelse adgang til kameraet</translation>
 <translation id="1823280932251546115">Statusbakke, klokkeslæt <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">Du kan til enhver tid afbryde registrering af pakker</translation>
 <translation id="2034971124472263449">Gem alligevel</translation>
 <translation id="2049240716062114887">Navnet på skrivebordet blev ændret til <ph name="DESK_NAME" /></translation>
+<translation id="206377500836174974">Fuld</translation>
 <translation id="2064048859448024834">Forhåndsvisning af kamera er slået til</translation>
 <translation id="2067602449040652523">Lysstyrke for tastatur</translation>
 <translation id="2075520525463668108">Slå <ph name="CAPTURE_MEDIUM" /> til/fra. <ph name="CAPTURE_MEDIUM" /> er <ph name="CAPTURE_STATE" /></translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">Tryk på knappen for styluspen på hylden for at skrive en note, tage et screenshot eller bruge lasermarkøren og luppen.</translation>
 <translation id="2341729377289034582">Altid lodret</translation>
 <translation id="2345226652884463045">Tryk på Enter eller søgetasten + mellemrumstasten for at vælge den tekst, der skal redigeres.</translation>
+<translation id="2349785431103945039">Vis oplysninger om hotspot. Opret forbindelse via mobildata for at bruge hotspot.</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" /> behandles nu lokalt og kan bruges offline. Du kan skifte dikteringssprog i Indstillinger &gt; Hjælpefunktioner.</translation>
 <translation id="2352467521400612932">Indstillinger for styluspen</translation>
 <translation id="2354174487190027830">Aktiverer <ph name="NAME" /></translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">langsom enhed</translation>
 <translation id="2542089167727451762">Tryk på dit profilbillede</translation>
 <translation id="254900897760075745">Kopiér valgt indhold til udklipsholderen</translation>
+<translation id="2549711466868162843">Fremhæv lys</translation>
 <translation id="255671100581129685">Google Assistent er ikke tilgængelig i en offentlig session.</translation>
 <translation id="256712445991462162">den fastgjorte lup</translation>
 <translation id="2573588302192866788">Forbindelsen til <ph name="NAME" /> kunne ikke oprettes</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">Output</translation>
 <translation id="3009958530611748826">Vælg en mappe, du vil gemme i</translation>
 <translation id="301282384882049174">Delt af din administrator</translation>
+<translation id="301584155502740476">Vis oplysninger om hotspot. Hotspot er deaktiveret.</translation>
 <translation id="3018135054368884502">Spol frem i mediet</translation>
 <translation id="3033545621352269033">Til</translation>
 <translation id="3033912566804961911">Kombiner med <ph name="DESK_NAME" /></translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">Flyt til starten af ​​foregående ord</translation>
 <translation id="3294437725009624529">Gæst</translation>
 <translation id="3298690094479023523">Din pin- eller adgangskode kan stadig ikke verificeres. Prøv igen.</translation>
+<translation id="3300193645498960160">Du får besked, hvis du taler, mens mikrofonen er slået fra. Lyden forlader aldrig din enhed.</translation>
 <translation id="3307642347673023554">Skiftede til computertilstand</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> kan stadig logge ind senere.</translation>
 <translation id="3321628682574733415">Forkert forældrekode</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">Input</translation>
 <translation id="3621712662352432595">Lydindstillinger</translation>
 <translation id="3626281679859535460">Lysstyrke</translation>
+<translation id="3629640897379005903">Vis oplysninger om hotspot. Hotspot deaktiveres.</translation>
 <translation id="3630697955794050612">fra</translation>
 <translation id="3631369015426612114">Tillad notifikationer fra følgende</translation>
 <translation id="3633097874324966332">Åbn Bluetooth-indstillingerne for at parre din enhed</translation>
@@ -701,6 +708,7 @@
 <translation id="423685346499232137">Det er ikke muligt at kopiere eller indsætte indhold på nuværende tidspunkt</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">Oversigtstilstand</translation>
+<translation id="4240756737570479726">Deaktiverer...</translation>
 <translation id="4242533952199664413">Åbn Indstillinger</translation>
 <translation id="4247123849143712100">Opdater, og sluk</translation>
 <translation id="4250229828105606438">Screenshot</translation>
@@ -839,6 +847,7 @@
 <translation id="4864369630010738180">Logger ind...</translation>
 <translation id="4864648187878336334">Skrivebord 15</translation>
 <translation id="4868492592575313542">aktiveret</translation>
+<translation id="4871905435473761992">Vis oplysninger om hotspot. Dit mobilnetværk understøtter ikke hotspot.</translation>
 <translation id="4872237917498892622">Alt+Søg eller Shift</translation>
 <translation id="4872852897273142380">Fokuser på eller fremhæv bogmærkelinjen (hvis den vises)</translation>
 <translation id="4881695831933465202">Åbn</translation>
@@ -898,6 +907,7 @@
 <translation id="5104236669533825617">Screencasten kan ikke oprettes</translation>
 <translation id="5107522548814527560">Internet</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">Baggrundssløring</translation>
 <translation id="5117590920725113268">Vis næste måned</translation>
 <translation id="5121628974188116412">Gå til bunden af siden</translation>
 <translation id="5136175204352732067">Du har tilsluttet et andet tastatur</translation>
@@ -909,6 +919,7 @@
 <translation id="5168181903108465623">Tilgængelige Cast-enheder</translation>
 <translation id="5170568018924773124">Vis i mappe</translation>
 <translation id="5176318573511391780">Optag dele af skærmen</translation>
+<translation id="5187627942836026988">Vis oplysninger om hotspot. Hotspot er blokeret af din administrator.</translation>
 <translation id="5198413532174090167"><ph name="DATE" /> – <ph name="NUMBER" /> begivenheder</translation>
 <translation id="5198715732953550718">En ny mappe blev oprettet ved at slå <ph name="MOVED_APP_NAME" /> og <ph name="IN_PLACE_APP" /> sammen.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1091,7 @@
 <translation id="595202126637698455">Sporing af ydelsen er aktiveret</translation>
 <translation id="5955304353782037793">app</translation>
 <translation id="5958529069007801266">Overvåget bruger</translation>
+<translation id="5961960957587052807">Let</translation>
 <translation id="5965524703725988602">Slå Mørkt tema til/fra. <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">Tryk på Enter for at optage vinduet</translation>
 <translation id="5978382165065462689">Skærmdeling via Fjernsupport.</translation>
@@ -1252,6 +1264,7 @@
 <translation id="6752912906630585008">Skrivebord <ph name="REMOVED_DESK" /> blev fjernet og slået sammen med Skrivebord <ph name="RECEIVE_DESK" /></translation>
 <translation id="6753390234084146956">faner</translation>
 <translation id="6757237461819837179">Der afspilles ingen medier</translation>
+<translation id="6759628406555734414">Vis oplysninger om hotspot. Hotspot aktiveres.</translation>
 <translation id="6768043681523654438">lagerplads</translation>
 <translation id="6777216307882431711">Leverer strøm til tilsluttede USB-C-enheder</translation>
 <translation id="6781002679438061620">Skrivebord 9</translation>
@@ -1276,6 +1289,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> sek.</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{Der skal angives ét ciffer mere}one{Der skal angives # ciffer mere}other{Der skal angives # cifre mere}}</translation>
 <translation id="6867938213751067702">Download af <ph name="FILENAME" /> er sat på pause</translation>
+<translation id="6874854809828346832">Vis oplysninger om hotspot. Hotspot er aktiveret.</translation>
 <translation id="6878400149835617132">Genvejen er deaktiveret</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 app}one{# app}other{# apps}}</translation>
 <translation id="6884665277231944629">Gå tilbage til i dag</translation>
@@ -1285,6 +1299,7 @@
 <translation id="6896758677409633944">Kopiér</translation>
 <translation id="6901883536534621389">Prøv at navigere ved hjælp af bevægelser</translation>
 <translation id="6919251195245069855">Dit chipkort blev ikke genkendt. Prøv igen.</translation>
+<translation id="6920245099716267363">Slå hotspot til/fra. Hotspot er aktiveret, og 1 enhed er tilsluttet.</translation>
 <translation id="6931576957638141829">Gem i</translation>
 <translation id="6941333068993625698">Send feedback</translation>
 <translation id="6942518653766415536">Menu for optagelsesformat</translation>
@@ -1374,6 +1389,7 @@
 <translation id="7378203170292176219">Træk for at vælge et område, der skal optages</translation>
 <translation id="7378594059915113390">Mediestyring</translation>
 <translation id="7378889811480108604">Tilstanden Batterisparefunktion er deaktiveret</translation>
+<translation id="7382640522316003298">Slå hotspot til/fra. Hotspot er aktiveret. <ph name="DEVICECOUNT" /> enheder er tilsluttet.</translation>
 <translation id="7382680553121047388">Til</translation>
 <translation id="7384028040782072252">Højreklik et vilkårligt sted for at omarrangere dine apps</translation>
 <translation id="7386767620098596324">Slå netværksforbindelse til/fra. <ph name="STATE_TEXT" />.</translation>
@@ -1424,6 +1440,7 @@
 <translation id="7579778809502851308">Screenshot</translation>
 <translation id="7593891976182323525">Søg eller Shift</translation>
 <translation id="7600875258240007829">Se alle notifikationer</translation>
+<translation id="7601417191446344542">Vil du aktivere påmindelse om at slå mikrofonen fra?</translation>
 <translation id="7607002721634913082">Sat på pause</translation>
 <translation id="7609951632080598826">Kalendervisning, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">Der blev oprettet forbindelse til kameraet igen.</translation>
@@ -1546,6 +1563,7 @@
 <translation id="8131740175452115882">Bekræft</translation>
 <translation id="8131994907636310308">Luk sorteringstoast</translation>
 <translation id="8132793192354020517">Forbundet til <ph name="NAME" /></translation>
+<translation id="8135163608236671037">Slå hotspot til/fra. Hotspot er aktiveret, og der er ingen tilsluttede enheder.</translation>
 <translation id="8138705869659070104">Aktivér efter enhedskonfiguration</translation>
 <translation id="813913629614996137">Initialiserer...</translation>
 <translation id="8142441511840089262">Dobbeltklik</translation>
@@ -1726,6 +1744,7 @@
 <translation id="8990809378771970590"><ph name="IME_NAME" /> anvendes</translation>
 <translation id="8991617137207906966">Tilstanden for ombytning af farver er aktiveret. Tryk på Ctrl+søgetasten+H igen for at deaktivere den.</translation>
 <translation id="899350903320462459">Lås enheden op som <ph name="LOGIN_ID" /> for at udføre notifikationshandlingen</translation>
+<translation id="8993733019280019776">Taler du nu? Din mikrofon er slukket. Vælg mikrofonen for at tænde den.</translation>
 <translation id="9000771174482730261">ADMINISTRER LAGERPLADS</translation>
 <translation id="9005984960510803406">Åbn Crosh Window</translation>
 <translation id="9017320285115481645">Angiv forældreadgangskoden til Family Link.</translation>
diff --git a/ash/strings/ash_strings_lo.xtb b/ash/strings/ash_strings_lo.xtb
index 4fdb943..c1b5fea4 100644
--- a/ash/strings/ash_strings_lo.xtb
+++ b/ash/strings/ash_strings_lo.xtb
@@ -94,6 +94,7 @@
 <translation id="1346748346194534595">ເບື້ອງຂວາ</translation>
 <translation id="1351937230027495976">ຫຍໍ້ເມນູ</translation>
 <translation id="1360220746312242196">ເມື່ອຊອກຫາໃນໜ້າ, ໃຫ້ເຂົ້າໄປລາຍການກ່ອນໜ້າທີ່ກົງກັນກັບການຊອກຫາ</translation>
+<translation id="1360788414852622716">ກຳລັງປິດການນຳໃຊ້ໂປຣໄຟລ໌. ຂັ້ນຕອນນີ້ອາດໃຊ້ເວລາສອງສາມນາທີ.</translation>
 <translation id="1364382257761975320">ເພື່ອປົດລັອກ Chromebook ຂອງທ່ານ, ໃຫ້ໃຊ້ລາຍນິ້ວມືຂອງທ່ານ</translation>
 <translation id="1365866993922957110">ຮັບການອັບເດດໂດຍອັດຕະໂນມັດ</translation>
 <translation id="1372545819342940910">ບັນທຶກໂຕະໄວ້ພາຍຫຼັງ</translation>
@@ -183,6 +184,7 @@
 <translation id="1774796056689732716">ປະຕິທິນ, <ph name="CURRENT_MONTH_YEAR" />, ຕອນນີ້ເລືອກ <ph name="DATE" /> ຢູ່.</translation>
 <translation id="1787955149152357925">ປິດ</translation>
 <translation id="181103072419391116">ຄວາມແຮງສັນຍານ <ph name="SIGNAL_STRENGTH" />, ຈັດການໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ</translation>
+<translation id="1815245884418711390">ເປີດ/ປິດຮັອດສະປອດ. ຮັອດສະປອດປິດຢູ່.</translation>
 <translation id="1816896987747843206">ການດຳເນີນການນີ້ອະນຸຍາດສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບໃຫ້ແກ່ແອັບ ແລະ ເວັບໄຊທັງໝົດທີ່ມີສິດການອະນຸຍາດກ້ອງຖ່າຍຮູບ</translation>
 <translation id="1823280932251546115">ຖາດສະຖານະ, ເວລາ <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +243,7 @@
 <translation id="2023558322300866873">ທ່ານສາມາດຢຸດການບັນທຶກແພັກເກັດຕອນໃດກໍໄດ້</translation>
 <translation id="2034971124472263449">ຢືນຢັນການບັນທຶກ</translation>
 <translation id="2049240716062114887">ຊື່ໂຕະໄດ້ຖືກປ່ຽນເປັນ <ph name="DESK_NAME" /> ແລ້ວ</translation>
+<translation id="206377500836174974">ເຕັມຮູບແບບ</translation>
 <translation id="2064048859448024834">ເປີດຕົວຢ່າງກ້ອງຖ່າຍຮູບແລ້ວ</translation>
 <translation id="2067602449040652523">ຄວາມແຈ້ງຂອງແປ້ນພິມ</translation>
 <translation id="2075520525463668108">ສະຫຼັບ <ph name="CAPTURE_MEDIUM" />. <ph name="CAPTURE_MEDIUM" /> ແມ່ນ <ph name="CAPTURE_STATE" /></translation>
@@ -293,6 +296,7 @@
 <translation id="2339073806695260576">ແຕະປຸ່ມປາກກາຢູ່ໃນຖ້ານເພື່ອຈົດບັນທຶກ, ຖ່າຍຮູບໜ້າຈໍ, ໃຊ້ຕົວຊີ້ເລເຊີ ຫຼື ແວ່ນຂະຫຍາຍ.</translation>
 <translation id="2341729377289034582">ລັອກເປັນລວງຕັ້ງ</translation>
 <translation id="2345226652884463045">ກົດ Enter ຫຼື ຊອກຫາ + ຍະຫວ່າງ ເພື່ອເລືອກຂໍ້ຄວາມເພື່ອແກ້ໄຂ.</translation>
+<translation id="2349785431103945039">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ເຊື່ອມຕໍ່ເຄືອຂ່າຍມືຖືເພື່ອໃຊ້ຮັອດສະປອດ.</translation>
 <translation id="2350794187831162545">ຕອນນີ້ປະມວນການເວົ້າພາສາ <ph name="LANGUAGE" /> ໃນເຄື່ອງແລ້ວ ແລະ ສາມາດເຮັດວຽກໄດ້ອອບລາຍ. ທ່ານສາມາດປ່ຽນການປ້ອນຂໍ້ມູນດ້ວຍສຽງຂອງທ່ານໄດ້ໃນການຕັ້ງຄ່າ &gt; ການຊ່ວຍເຂົ້າເຖິງ.</translation>
 <translation id="2352467521400612932">ການຕັ້ງຄ່າປາຍປາກກາ</translation>
 <translation id="2354174487190027830">ກຳລັງເປີດນຳໃຊ້ <ph name="NAME" /></translation>
@@ -335,6 +339,7 @@
 <translation id="2531025035050312891">ອຸປະກອນເຮັດວຽກຊ້າ</translation>
 <translation id="2542089167727451762">ແຕະຮູບໂປຣໄຟລ໌ຂອງທ່ານ</translation>
 <translation id="254900897760075745">ສຳເນົາເນື້ອຫາທີ່ເລືອກໃສ່ຄລິບບອດ</translation>
+<translation id="2549711466868162843">ປັບແສງ</translation>
 <translation id="255671100581129685">ຜູ້ຊ່ວຍ Google ບໍ່ສາມາດໃຊ້ໄດ້ໃນເຊດຊັນສາທາລະນະ.</translation>
 <translation id="256712445991462162">ແວ່ນຂະຫຍາຍໜ້າຈໍບາງສ່ວນ</translation>
 <translation id="2573588302192866788">ບໍ່ສາມາດເຊື່ອມຕໍ່ຫາ <ph name="NAME" /> ໄດ້</translation>
@@ -427,6 +432,7 @@
 <translation id="3009178788565917040">ຜົນອອກມາ</translation>
 <translation id="3009958530611748826">ເລືອກໂຟນເດີທີ່ຈະບັນທຶກໄວ້ໃນ</translation>
 <translation id="301282384882049174">ແບ່ງປັນໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ</translation>
+<translation id="301584155502740476">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ຮັອດສະປອດປິດຢູ່.</translation>
 <translation id="3018135054368884502">ເລື່ອນມີເດຍໄປໜ້າ</translation>
 <translation id="3033545621352269033">ເປີດ</translation>
 <translation id="3033912566804961911">ຮວມກັບ <ph name="DESK_NAME" /></translation>
@@ -487,6 +493,7 @@
 <translation id="3291862315280588024">ຍ້າຍໄປໃສ່ຈຸດເລີ່ມຕົ້ນຂອງຄຳກ່ອນໜ້າ</translation>
 <translation id="3294437725009624529">ແຂກ</translation>
 <translation id="3298690094479023523">ຍັງບໍ່ສາມາດຢັ້ງຢືນ PIN ຫຼື ລະຫັດຜ່ານຂອງທ່ານໄດ້. ກະລຸນາລອງໃໝ່.</translation>
+<translation id="3300193645498960160">ທ່ານຈະໄດ້ຮັບການແຈ້ງເຕືອນຫາກທ່ານເວົ້າໃນລະຫວ່າງທີ່ປິດສຽງຢູ່. ໂດຍຈະບໍ່ມີການສົ່ງສຽງຜ່ານອຸປະກອນຂອງທ່ານ.</translation>
 <translation id="3307642347673023554">ປ່ຽນເປັນໂໝດແລັບທັອບແລ້ວ</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> ສາມາດເຂົ້າສູ່ລະບົບໃນພາຍຫຼັງໄດ້ຄືເກົ່າ.</translation>
 <translation id="3321628682574733415">ລະຫັດພໍ່ແມ່ບໍ່ຖືກຕ້ອງ</translation>
@@ -537,6 +544,7 @@
 <translation id="3510164367642747937">ໝາຍເຄີເຊີເມົ້າ</translation>
 <translation id="3513798432020909783">ບັນຊີທີ່ຈັດການໂດຍ <ph name="MANAGER_EMAIL" /></translation>
 <translation id="352245152354538528">{0,plural, =1{ອັບເດດອຸປະກອນພາຍໃນ 1 ນາທີ}other{ອັບເດດອຸປະກອນພາຍໃນ # ນາທີ}}</translation>
+<translation id="3522979239100719575">ກຳລັງຊອກຫາໂປຣໄຟລ໌ທີ່ສາມາດໃຊ້ໄດ້. ຂັ້ນຕອນນີ້ອາດໃຊ້ເວລາສອງສາມນາທີ.</translation>
 <translation id="3526440770046466733">ເປີດລິ້ງໃນແຖບໃໝ່ ແລະ ຢູ່ໃນແຖບປັດຈຸບັນຕໍ່ໄປ</translation>
 <translation id="353086728817903341">ເຊື່ອມຕໍ່ຫາ <ph name="NUM_DEVICES" /> ອຸປະກອນແລ້ວ</translation>
 <translation id="3533126039236445965">ແອັບໃນຖ້ານ</translation>
@@ -570,6 +578,7 @@
 <translation id="3621202678540785336">ການປ້ອນເຂົ້າ</translation>
 <translation id="3621712662352432595">ການຕັ້ງ​ຄ່າສຽງ</translation>
 <translation id="3626281679859535460">ຄວາມແຈ້ງ</translation>
+<translation id="3629640897379005903">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ຮັອດສະປອດປິດການນຳໃຊ້ຢູ່.</translation>
 <translation id="3630697955794050612">ປິດ</translation>
 <translation id="3631369015426612114">ອະ​ນຸ​ຍາດ​ການແຈ້ງ​ເຕືອນຈາກ​ສິ່ງຕໍ່​ໄປ​ນີ້​</translation>
 <translation id="3633097874324966332">ເປີດການຕັ້ງຄ່າ Bluetooth ເພື່ອຈັບຄູ່ອຸປະກອນຂອງທ່ານ</translation>
@@ -701,6 +710,7 @@
 <translation id="423685346499232137">ບໍ່ສາມາດສຳເນົາ ຫຼື ວາງເນື້ອຫາໄດ້ໃນຕອນນີ້</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">ໂໝດພາບຮວມ</translation>
+<translation id="4240756737570479726">ກຳລັງປິດການນຳໃຊ້...</translation>
 <translation id="4242533952199664413">ເປີດ​ການ​ຕັ້ງ​ຄ່າ</translation>
 <translation id="4247123849143712100">ອັບເດດ ແລະ ປິດເຄື່ອງ</translation>
 <translation id="4250229828105606438">ຮູບຖ່າຍໜ້າຈໍ</translation>
@@ -839,6 +849,7 @@
 <translation id="4864369630010738180">ກຳລັງເຂົ້າສູ່ລະບົບ...</translation>
 <translation id="4864648187878336334">ໂຕະ 15</translation>
 <translation id="4868492592575313542">ເປີດນຳໃຊ້ແລ້ວ</translation>
+<translation id="4871905435473761992">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ເຄືອຂ່າຍມືຖືຂອງທ່ານບໍ່ຮອງຮັບຮັອດສະປອດ.</translation>
 <translation id="4872237917498892622">Alt+ຊອກຫາ ຫຼື Shift</translation>
 <translation id="4872852897273142380">ໂຟກັສ ຫຼື ໄຮໄລ້ແຖບບຸກມາກ (ຫາກສະແດງຢູ່)</translation>
 <translation id="4881695831933465202">ເປີດ</translation>
@@ -898,6 +909,7 @@
 <translation id="5104236669533825617">ບໍ່ສາມາດສ້າງ screencast ໄດ້</translation>
 <translation id="5107522548814527560">ເວັບ</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">ການມົວພື້ນຫຼັງ</translation>
 <translation id="5117590920725113268">ສະ​ແດງ​ເດືອນ​ຕໍ່​ໄປ</translation>
 <translation id="5121628974188116412">ໄປຫາສ່ວນລຸ່ມຂອງໜ້າ</translation>
 <translation id="5136175204352732067">ເຊື່ອມຕໍ່ແປ້ນພິມອື່ນແລ້ວ</translation>
@@ -909,6 +921,7 @@
 <translation id="5168181903108465623">ອຸປະກອນຄາສທ໌ທີ່ມີໃຫ້</translation>
 <translation id="5170568018924773124">ສະ​ແດງ​ຢູ່​ໃນ​ໂຟລ​ເດີ</translation>
 <translation id="5176318573511391780">ບັນທຶກໜ້າຈໍບາງສ່ວນ</translation>
+<translation id="5187627942836026988">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ຮັອດສະປອດຖືກບລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ.</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> ນັດໝາຍ</translation>
 <translation id="5198715732953550718"><ph name="MOVED_APP_NAME" /> ຮວມກັນກັບ <ph name="IN_PLACE_APP" /> ເພື່ອສ້າງໂຟນເດີໃໝ່.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1093,7 @@
 <translation id="595202126637698455">ການຕິດຕາມການປະຕິບັດເປີດໃຊ້ງານແລ້ວ</translation>
 <translation id="5955304353782037793">ແອັບ</translation>
 <translation id="5958529069007801266">ຜູ້ໃຊ້ທີ່ມີການຄວບຄຸມດູແລ</translation>
+<translation id="5961960957587052807">ໜ້ອຍ</translation>
 <translation id="5965524703725988602">ສະຫຼັບຮູບແບບສີສັນມືດ. <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">ກົດ enter ເພື່ອບັນທຶກໜ້າຈໍ</translation>
 <translation id="5978382165065462689">​ການແບ່ງປັນ​ການ​ຄວບ​ຄຸມ​ໜ້າ​ຈໍ​ຂອງ​ທ່ານຜ່ານ​ຕົວ​ຊ່ວຍ​ທາງ​ໄກ.</translation>
@@ -1252,6 +1266,7 @@
 <translation id="6752912906630585008">ລຶບເດັສ <ph name="REMOVED_DESK" /> ອອກ ແລະ ຮວມກັບເດັສ <ph name="RECEIVE_DESK" /> ແລ້ວ</translation>
 <translation id="6753390234084146956">ແຖບ</translation>
 <translation id="6757237461819837179">ບໍ່ມີການຫຼິ້ນມີເດຍ</translation>
+<translation id="6759628406555734414">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ຮັອດສະປອດເປີດການນຳໃຊ້ຢູ່.</translation>
 <translation id="6768043681523654438">ບ່ອນຈັດເກັບຂໍ້ມູນ</translation>
 <translation id="6777216307882431711">ກຳລັງສາກອຸປະກອນ USB-C ທີ່ເຊື່ອມຕໍ່ແລ້ວ</translation>
 <translation id="6781002679438061620">ໂຕະ 9</translation>
@@ -1276,6 +1291,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> ວິ</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{ຍັງເຫຼືອໜຶ່ງຕົວເລກ}other{ຍັງເຫຼືອ # ຕົວເລກ}}</translation>
 <translation id="6867938213751067702">ຢຸດດາວໂຫຼດ <ph name="FILENAME" /> ຊົ່ວຄາວແລ້ວ</translation>
+<translation id="6874854809828346832">ສະແດງລາຍລະອຽດຮັອດສະປອດ. ຮັອດສະປອດເປີດຢູ່.</translation>
 <translation id="6878400149835617132">ປິດທາງລັດແລ້ວ</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 ແອັບ}other{# ແອັບ}}</translation>
 <translation id="6884665277231944629">ກັບໄປຫາມື້ນີ້</translation>
@@ -1285,6 +1301,7 @@
 <translation id="6896758677409633944">ກັອບປີ້</translation>
 <translation id="6901883536534621389">ລອງໃຊ້ທ່າທາງເພື່ອນຳທາງ</translation>
 <translation id="6919251195245069855">ບໍ່ສາມາດຮັບຮູ້ບັດອັດສະລິຍະຂອງທ່ານໄດ້. ລອງໃໝ່.</translation>
+<translation id="6920245099716267363">ເປີດ/ປິດຮັອດສະປອດ. ຮັອດສະປອດເປີດຢູ່, ເຊື່ອມຕໍ່ຢູ່ 1 ອຸປະກອນ.</translation>
 <translation id="6931576957638141829">ບັນ​ທຶກ​ໄປ​ໃສ່</translation>
 <translation id="6941333068993625698">ສົ່ງຄຳຄິດເຫັນ</translation>
 <translation id="6942518653766415536">ເມນູຮູບແບບການບັນທຶກ</translation>
@@ -1374,6 +1391,7 @@
 <translation id="7378203170292176219">ລາກເພື່ອເລືອກພື້ນທີ່ເພື່ອບັນທຶກ</translation>
 <translation id="7378594059915113390">ການຄວບຄຸມສື່</translation>
 <translation id="7378889811480108604">ໂໝດຕົວປະຢັດແບັດເຕີຣີປິດຢູ່</translation>
+<translation id="7382640522316003298">ເປີດ/ປິດຮັອດສະປອດ. ຮັອດສະປອດເປີດຢູ່, ເຊື່ອມຕໍ່ຢູ່ <ph name="DEVICECOUNT" /> ອຸປະກອນ.</translation>
 <translation id="7382680553121047388">ເປີດ</translation>
 <translation id="7384028040782072252">ຄລິກຂວາໃສ່ບ່ອນໃດກໍໄດ້ເພື່ອຈັດຮຽງແອັບຂອງທ່ານຄືນໃໝ່</translation>
 <translation id="7386767620098596324">ສະຫຼັບການເຊື່ອມຕໍ່ເຄືອຂ່າຍ. <ph name="STATE_TEXT" />.</translation>
@@ -1424,6 +1442,7 @@
 <translation id="7579778809502851308">ການຖ່າຍຮູບໜ້າຈໍ</translation>
 <translation id="7593891976182323525">ຄົ້ນ​ຫາ ຫຼື Shift</translation>
 <translation id="7600875258240007829">ເບິ່ງການແຈ້ງເຕືອນທັງໝົດ</translation>
+<translation id="7601417191446344542">ເປີດການສະກິດເຕືອນການປິດສຽງບໍ?</translation>
 <translation id="7607002721634913082">ຢຸດແລ້ວ</translation>
 <translation id="7609951632080598826">ມຸມມອງປະຕິທິນ, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">ເຊື່ອມຕໍ່ກ້ອງຖ່າຍຮູບຄືນໃໝ່ແລ້ວ.</translation>
@@ -1535,6 +1554,7 @@
 <translation id="8083540854303889870">ບັນທຶກໄວ້ສໍາລັບພາຍຫຼັງ</translation>
 <translation id="8091153018031979607">ເລີ່ມຕົ້ນ <ph name="START_TIME" /> <ph name="DAYS_ELAPSED" /></translation>
 <translation id="8091387634532529612">ອັບເດດອັດຕະໂນມັດ</translation>
+<translation id="8092380135549145188">ການຄວບຄຸມການເລື່ອນ</translation>
 <translation id="8098591350844501178">ຢຸດການສົ່ງສັນຍານໜ້າຈໍຫາ <ph name="RECEIVER_NAME" /></translation>
 <translation id="810637681351706236">ຖອນໝຸດແອັບຈາກຖ້ານ</translation>
 <translation id="8113423164597455979">ເປີດ, ທຸກແອັບ</translation>
@@ -1546,6 +1566,7 @@
 <translation id="8131740175452115882">ຢືນ​ຢັນ</translation>
 <translation id="8131994907636310308">ປິດຂໍ້ຄວາມໂທສການຈັດຮຽງ</translation>
 <translation id="8132793192354020517">ເຊື່ອມຕໍ່ກັບ <ph name="NAME" /> ແລ້ວ</translation>
+<translation id="8135163608236671037">ເປີດ/ປິດຮັອດສະປອດ. ຮັອດສະປອດເປີດຢູ່, ບໍ່ມີອຸປະກອນເຊື່ອມຕໍ່.</translation>
 <translation id="8138705869659070104">ເປີດໃຊ້ຫຼັງຈາກຕິດຕັ້ງອຸປະກອນ</translation>
 <translation id="813913629614996137">ກຳລັງລິເລີ່ມ...</translation>
 <translation id="8142441511840089262">ຄລິກສອງຄັ້ງ</translation>
@@ -1726,6 +1747,7 @@
 <translation id="8990809378771970590">ກຳລັງໃຊ້ <ph name="IME_NAME" /></translation>
 <translation id="8991617137207906966">ໂໝດການປີ້ນສີເປີດການນຳໃຊ້ຢູ່. ກົດ Ctrl+Search+H ອີກຄັ້ງເພື່ອປິດມັນ.</translation>
 <translation id="899350903320462459">ປົດລັອກອຸປະກອນເປັນ <ph name="LOGIN_ID" /> ເພື່ອເຮັດການດຳເນີນການແຈ້ງເຕືອນ</translation>
+<translation id="8993733019280019776">ທ່ານກຳລັງເວົ້າບໍ? ໄມຂອງທ່ານປິດຢູ່. ກະລຸນາເລືອກໄມເພື່ອເປີດ.</translation>
 <translation id="9000771174482730261">ຈັດການບ່ອນເກັບຂໍ້ມູນ</translation>
 <translation id="9005984960510803406">ເປີດໜ້າຈໍ Crosh</translation>
 <translation id="9017320285115481645">ປ້ອນລະຫັດເຂົ້າເຖິງ Family Link ຂອງພໍ່ແມ່.</translation>
diff --git a/ash/strings/ash_strings_ne.xtb b/ash/strings/ash_strings_ne.xtb
index 60d04f9..8d458ec4 100644
--- a/ash/strings/ash_strings_ne.xtb
+++ b/ash/strings/ash_strings_ne.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">पात्रो, <ph name="CURRENT_MONTH_YEAR" />, हाल चयन गरिएको मिति: <ph name="DATE" />।</translation>
 <translation id="1787955149152357925">अफ छ</translation>
 <translation id="181103072419391116">सिग्नलको क्षमता <ph name="SIGNAL_STRENGTH" />, तपाईंका प्रशासकले व्यवस्थित गर्नुभएको छ</translation>
+<translation id="1815245884418711390">हटस्पट टगल गर्नुहोस्। हटस्पट अफ छ।</translation>
 <translation id="1816896987747843206">यसले क्यामेरा प्रयोग गर्ने अनुमति भएका सबै एप तथा वेबसाइटहरूलाई क्यामेरा प्रयोग गर्ने अनुमति दिन्छ</translation>
 <translation id="1823280932251546115">स्ट्याटस ट्रे, समय <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">तपाईं जुनसुकै बेला प्याकेट क्याप्चर गर्ने कार्य बन्द गर्न सक्नुहुन्छ</translation>
 <translation id="2034971124472263449">जे भए पनि सेभ गर्नुहोस्</translation>
 <translation id="2049240716062114887">डेस्कको नाम बदलेर <ph name="DESK_NAME" /> बनाइयो</translation>
+<translation id="206377500836174974">फुल</translation>
 <translation id="2064048859448024834">क्यामेरामा फोटोको प्रिभ्यू हेर्ने सुविधा अन छ</translation>
 <translation id="2067602449040652523">किबोर्डको चमक</translation>
 <translation id="2075520525463668108"><ph name="CAPTURE_MEDIUM" /> टगल गर्नुहोस्। <ph name="CAPTURE_MEDIUM" /> <ph name="CAPTURE_STATE" /></translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">टिपोट गर्न, स्क्रिनसट खिच्न, लेजर पोइन्टर वा म्याग्निफाइङ्ग ग्लासको प्रयोग गर्न सेल्फमा रहेको स्टाइलस बटनमा ट्याप गर्नुहोस्।</translation>
 <translation id="2341729377289034582">ठाडो अवस्थामा लक गरियो</translation>
 <translation id="2345226652884463045">सम्पादन गर्नु पर्ने टेक्स्ट चयन गर्न इन्टर की वा खोज बटन + स्पेस की थिच्नुहोस्</translation>
+<translation id="2349785431103945039">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। हटस्पट प्रयोग गर्न मोबाइल नेटवर्कमा कनेक्ट गर्नुहोस्।</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" /> भाषा डिभाइसभित्रै प्रोसेस गरिन्छ र उक्त भाषा अफलाइन प्रयोग गर्न मिल्छ। तपाईं "सेटिङ &gt; सर्वसुलभता" मा गई स्पिच-टु-टेक्स्ट सुविधाको भाषा बदल्न सक्नुहुन्छ।</translation>
 <translation id="2352467521400612932">स्टाइलस सम्बन्धी सेटिङहरू</translation>
 <translation id="2354174487190027830"><ph name="NAME" /> लाई सक्रिय बनाउँदै</translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">डिभाइस सुस्त चलिरहेको छ</translation>
 <translation id="2542089167727451762">आफ्नो प्रोफाइल छविमा ट्याप गर्नुहोस्</translation>
 <translation id="254900897760075745">चयन गरिएको सामग्री क्लिपबोर्डमा कपी गर्नुहोस्</translation>
+<translation id="2549711466868162843">प्रकाशको गुणस्तर सुधार गरियोस्</translation>
 <translation id="255671100581129685">Google सहायक सार्वजनिक सत्रमा उपलब्ध छैन।</translation>
 <translation id="256712445991462162">डक गरिएको म्याग्निफायर</translation>
 <translation id="2573588302192866788"><ph name="NAME" /> कनेक्ट गर्न सकिएन</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">निर्गत</translation>
 <translation id="3009958530611748826">सुरक्षित गर्न कुनै फोल्डर चयन गर्नुहोस्</translation>
 <translation id="301282384882049174">तपाईंका एड्मिनले सेयर गरेका टेम्पलेट</translation>
+<translation id="301584155502740476">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। हटस्पट अफ छ।</translation>
 <translation id="3018135054368884502">मिडिया फास्ट फर्वार्ड गर्नुहोस्</translation>
 <translation id="3033545621352269033">अन</translation>
 <translation id="3033912566804961911"><ph name="DESK_NAME" /> मा संयोजन गर्नुहोस्</translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">अघिल्लो शब्दको सुरुवातमा जानुहोस्</translation>
 <translation id="3294437725009624529">पाहुना</translation>
 <translation id="3298690094479023523">तपाईंको PIN वा पासवर्ड अझै पनि पुष्टि गर्न सकिएन। फेरि प्रयास गर्नुहोस्।</translation>
+<translation id="3300193645498960160">तपाईं म्युट गरिएका बेला बोल्नुभयो भने तपाईंलाई सूचित गरिने छ। अडियो तपाईंको डिभाइसमै रहन्छ।</translation>
 <translation id="3307642347673023554">ल्यापटप मोड प्रयोग गर्न थालियो</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> अझै पनि पछि साइन इन गर्न सक्नुहुन्छ।</translation>
 <translation id="3321628682574733415">अभिभावकको कोड गलत छ</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">आगत</translation>
 <translation id="3621712662352432595">अडियो सेटिङहरू</translation>
 <translation id="3626281679859535460">चम्किलोपना</translation>
+<translation id="3629640897379005903">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। हटस्पट अफ गरिँदै छ।</translation>
 <translation id="3630697955794050612">अफ छ</translation>
 <translation id="3631369015426612114">निम्न स्रोतहरूबाट सूचनाहरूलाई अनुमति दिनुहोस्</translation>
 <translation id="3633097874324966332">आफ्नो डिभाइस कनेक्ट गर्न ब्लुटुथका सेटिङ खोल्नुहोस्</translation>
@@ -701,6 +708,7 @@
 <translation id="423685346499232137">यस बखत सामग्री कपी वा पेस्ट गर्न सकिँदैन</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">परिदृश्य मोड</translation>
+<translation id="4240756737570479726">अफ गरिँदै छ…</translation>
 <translation id="4242533952199664413">सेटिङहरू खोल्नुहोस्</translation>
 <translation id="4247123849143712100">अपडेट गर्नुहोस् अनि सट डाउन गर्नुहोस्</translation>
 <translation id="4250229828105606438">स्क्रिसट</translation>
@@ -839,6 +847,7 @@
 <translation id="4864369630010738180">साइन इन गरिँदै...</translation>
 <translation id="4864648187878336334">डेस्क १५</translation>
 <translation id="4868492592575313542">सक्रिय गरियो</translation>
+<translation id="4871905435473761992">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। तपाईंको मोबाइल नेटवर्कमा हटस्पट प्रयोग गर्न मिल्दैन।</translation>
 <translation id="4872237917498892622">Alt+खोज्नुहोस् वा Shift</translation>
 <translation id="4872852897273142380">बुकमार्क बारमा फोकस गर्नुहोस् वा बुकमार्क बार हाइलाइट गर्नुहोस् (बुकमार्क बार देखाइएको छ भने)</translation>
 <translation id="4881695831933465202">खोल्नुहोस्</translation>
@@ -898,6 +907,7 @@
 <translation id="5104236669533825617">स्क्रिनकास्ट बनाउन सकिएन</translation>
 <translation id="5107522548814527560">वेब</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">ब्याकग्राउन्ड ब्लर</translation>
 <translation id="5117590920725113268">अर्को महिना देखाउनुहोस्</translation>
 <translation id="5121628974188116412">पृष्ठको फेदमा जानुहोस्‌</translation>
 <translation id="5136175204352732067">भिन्न किबोर्ड जडान गरियो</translation>
@@ -909,6 +919,7 @@
 <translation id="5168181903108465623">Cast यन्त्रहरू उपलब्ध</translation>
 <translation id="5170568018924773124">फोल्डरमा देखाउनुहोस्</translation>
 <translation id="5176318573511391780">स्क्रिनको केही भागको भिडियो रेकर्ड गर्नुहोस्</translation>
+<translation id="5187627942836026988">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। तपाईंको एड्मिनले हटस्पट ब्लक गर्नुभएको छ।</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> वटा कार्यक्रम</translation>
 <translation id="5198715732953550718">नयाँ फोल्डर सिर्जना गर्न <ph name="MOVED_APP_NAME" /> <ph name="IN_PLACE_APP" /> सँग समायोजन गरियो</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1091,7 @@
 <translation id="595202126637698455">प्रदर्शन ट्रेसिङ सक्षम गरियो</translation>
 <translation id="5955304353782037793">एप</translation>
 <translation id="5958529069007801266">सुपरिवेक्षित प्रयोगकर्ता</translation>
+<translation id="5961960957587052807">हलुका</translation>
 <translation id="5965524703725988602">अँध्यारो थिम टगल गर्नुहोस्। <ph name="STATE_TEXT" />।</translation>
 <translation id="5976112937189445008">विन्डो रेकर्ड गर्न इन्टर थिच्नुहोस्</translation>
 <translation id="5978382165065462689">रिमोट सहायता मार्फत तपाईँको स्क्रीन नियन्त्रण साझेदारी गर्दै।</translation>
@@ -1252,6 +1264,7 @@
 <translation id="6752912906630585008">डेस्क <ph name="REMOVED_DESK" /> हटाइयो र डेस्क <ph name="RECEIVE_DESK" /> मा गाभियो</translation>
 <translation id="6753390234084146956">ट्याब</translation>
 <translation id="6757237461819837179">कुनै मिडिया प्ले भइरहेको छैन</translation>
+<translation id="6759628406555734414">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। हटस्पट अन गरिँदै छ।</translation>
 <translation id="6768043681523654438">भण्डारण</translation>
 <translation id="6777216307882431711">जडान गरिएका USB-C यन्त्रहरू चार्ज गर्दै</translation>
 <translation id="6781002679438061620">डेस्क ९</translation>
@@ -1276,6 +1289,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> सेकेन्ड</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{एउटा अङ्क बाँकी छ}other{# वटा अङ्क बाँकी छन्}}</translation>
 <translation id="6867938213751067702"><ph name="FILENAME" /> डाउनलोड गर्ने कार्य केही समयका लागि रोकिएको छ</translation>
+<translation id="6874854809828346832">हटस्पटसम्बन्धी विवरणहरू देखाइऊन्। हटस्पट अन छ।</translation>
 <translation id="6878400149835617132">सर्टकट निष्क्रिय पारियो</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{एउटा एप}other{# वटा एप}}</translation>
 <translation id="6884665277231944629">आजको मितिमा फर्कनुहोस्</translation>
@@ -1285,6 +1299,7 @@
 <translation id="6896758677409633944">प्रतिलिपि गर्नुहोस्</translation>
 <translation id="6901883536534621389">नेभिगेट गर्न जेस्चर प्रयोग गरी हेर्नुहोस्</translation>
 <translation id="6919251195245069855">तपाईंको स्मार्ट कार्ड पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।</translation>
+<translation id="6920245099716267363">हटस्पट टगल गर्नुहोस्। हटस्पट अन छ, एउटा डिभाइस कनेक्ट गरिएको छ।</translation>
 <translation id="6931576957638141829">यसमा सेभ गरियोस्</translation>
 <translation id="6941333068993625698">प्रतिक्रिया पेस गर्नुहोस्</translation>
 <translation id="6942518653766415536">रेकर्डिङको फर्म्याटसम्बन्धी मेनु</translation>
@@ -1374,6 +1389,7 @@
 <translation id="7378203170292176219">रेकर्ड गर्ने कुनै क्षेत्र चयन गर्न ड्र्याग गर्नुहोस्</translation>
 <translation id="7378594059915113390">मिडियासम्बन्धी नियन्त्रणहरू</translation>
 <translation id="7378889811480108604">ब्याट्री सेभर मोड अफ छ</translation>
+<translation id="7382640522316003298">हटस्पट टगल गर्नुहोस्। हटस्पट अन छ, <ph name="DEVICECOUNT" /> वटा डिभाइस कनेक्ट गरिएका छन्।</translation>
 <translation id="7382680553121047388">अन गर्नुहोस्</translation>
 <translation id="7384028040782072252">तपाईं आफ्ना एपहरूको क्रम पुनः मिलाउन चाहनुहुन्छ भने कुनै पनि ठाउँमा दायाँ क्लिक गर्नुहोस्</translation>
 <translation id="7386767620098596324">नेटवर्क कनेक्सन टगल गर्नुहोस्। <ph name="STATE_TEXT" />।</translation>
@@ -1424,6 +1440,7 @@
 <translation id="7579778809502851308">स्क्रिन क्याप्चर</translation>
 <translation id="7593891976182323525">सिफ्टको लागि खोज्नुहोस्</translation>
 <translation id="7600875258240007829">सबै सूचनाहरू हेर्नुहोस्</translation>
+<translation id="7601417191446344542">म्युट नज अन गर्ने हो?</translation>
 <translation id="7607002721634913082">रोकिएको छ</translation>
 <translation id="7609951632080598826">पात्रोको भ्यू, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">क्यामेरा पुनः कनेक्ट गरियो।</translation>
@@ -1546,6 +1563,7 @@
 <translation id="8131740175452115882">निश्चित</translation>
 <translation id="8131994907636310308">एप क्रमबद्ध गर्ने टोस्ट बन्द गर्नुहोस्</translation>
 <translation id="8132793192354020517"><ph name="NAME" /> मा जडित</translation>
+<translation id="8135163608236671037">हटस्पट टगल गर्नुहोस्। हटस्पट अन छ, कुनै पनि डिभाइस कनेक्ट गरिएको छैन।</translation>
 <translation id="8138705869659070104">डिभाइस सेटअप गरेपछि एक्टिभेट गर्नुहोस्</translation>
 <translation id="813913629614996137">सुरुवात गर्दै...</translation>
 <translation id="8142441511840089262">दुई पटक क्लिक गर्नुहोस्</translation>
@@ -1726,6 +1744,7 @@
 <translation id="8990809378771970590"><ph name="IME_NAME" /> प्रयोग गरिँदै</translation>
 <translation id="8991617137207906966">कलर इन्भर्सन मोड अन गरियो। उक्त मोड अफ गर्न फेरि Ctrl+Search+H थिच्नुहोस्।</translation>
 <translation id="899350903320462459">सूचनासम्बन्धी कारबाही गर्न यन्त्रलाई <ph name="LOGIN_ID" /> का रूपमा अनलक गर्नुहोस्</translation>
+<translation id="8993733019280019776">तपाईं बोल्दै हुनुहुन्छ? तपाईंको माइक अफ छ। माइक चयन गरेर सो माइक अन गर्नुहोस्।</translation>
 <translation id="9000771174482730261">भण्डारण व्यवस्थापन गर्नुहोस्</translation>
 <translation id="9005984960510803406">Crosh विन्डो खोल्नुहोस्‌</translation>
 <translation id="9017320285115481645">Family Link को अभिभावकको पहुँचसम्बन्धी कोड प्रविष्टि गर्नुहोस्।</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index 3bdaba9..f5812f6 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">క్యాలెండర్, <ph name="CURRENT_MONTH_YEAR" />, ప్రస్తుతం <ph name="DATE" /> తేదీ ఎంపిక చేయబడింది.</translation>
 <translation id="1787955149152357925">ఆఫ్ చేయి</translation>
 <translation id="181103072419391116">సిగ్నల్ సామర్థ్యం <ph name="SIGNAL_STRENGTH" />, మీ అడ్మినిస్ట్రేటర్ ద్వారా నిర్వహించబడుతుంది</translation>
+<translation id="1815245884418711390">హాట్‌స్పాట్‌ను టోగుల్ చేయండి. హాట్‌స్పాట్ ఆఫ్‌లో ఉంది.</translation>
 <translation id="1816896987747843206">ఇది కెమెరా అనుమతితో అన్ని యాప్‌లు, వెబ్‌సైట్‌ల కోసం కెమెరా యాక్సెస్‌ను అనుమతిస్తుంది</translation>
 <translation id="1823280932251546115">స్టేటస్ ట్రే, సమయం <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">మీరు ఎప్పుడైనా ప్యాకెట్ క్యాప్చర్ ఆపరేషన్‌ను ఆపివేయవచ్చు</translation>
 <translation id="2034971124472263449">ఏదేమైనా సేవ్ చేయండి</translation>
 <translation id="2049240716062114887">డెస్క్ పేరు <ph name="DESK_NAME" />గా మార్చబడింది</translation>
+<translation id="206377500836174974">పూర్తి బ్లర్</translation>
 <translation id="2064048859448024834">కెమెరా ప్రివ్యూ ఆన్‌లో ఉంది</translation>
 <translation id="2067602449040652523">కీబోర్డ్ ప్రకాశం</translation>
 <translation id="2075520525463668108"><ph name="CAPTURE_MEDIUM" />ను టోగుల్ చేయండి. <ph name="CAPTURE_MEDIUM" /> <ph name="CAPTURE_STATE" />లో ఉంది</translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">గమనికను రాయడానికి, స్క్రీన్‌షాట్‌ను తీయడానికి, లేజర్ పాయింటర్ లేదా భూతద్దాన్ని ఉపయోగించడానికి అరలో స్టైలస్ బటన్‌ను నొక్కండి.</translation>
 <translation id="2341729377289034582">నిలువు ప్రదర్శనకు లాక్ చేయబడింది</translation>
 <translation id="2345226652884463045">ఎడిటింగ్ కోసం టెక్స్ట్‌ను ఎంచుకోవడానికి enterను లేదా search + spaceను నొక్కండి.</translation>
+<translation id="2349785431103945039">హాట్‌స్పాట్ వివరాలను చూడండి. మొబైల్ నెట్‌వర్క్‌కు కనెక్ట్ చేసి, హాట్‌స్పాట్‌ను ఉపయోగించండి.</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" /> స్పీచ్ ఇప్పుడు పరికరంలోనే ప్రాసెస్ చేయబడింది, ఆఫ్‌లైన్‌లో పని చేస్తుంది. సెట్టింగ్‌లు &gt; యాక్సెసిబిలిటీకి వెళ్లడం ద్వారా మీరు మీ డిక్టేషన్ భాషను మార్చవచ్చు.</translation>
 <translation id="2352467521400612932">స్టైలస్ సెట్టింగ్‌లు</translation>
 <translation id="2354174487190027830"><ph name="NAME" />ని సక్రియం చేస్తోంది</translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">పరికరం నెమ్మదిగా ఉంది</translation>
 <translation id="2542089167727451762">మీ ప్రొఫైల్ ఫోటోను నొక్కండి</translation>
 <translation id="254900897760075745">ఎంపిక చేసిన కంటెంట్‌ను క్లిప్‌బోర్డ్‌కు కాపీ చేయండి</translation>
+<translation id="2549711466868162843">కాంతిని మెరుగుపరచండి</translation>
 <translation id="255671100581129685">Google Assistant పబ్లిక్ సెషన్‌లో అందుబాటులో లేదు.</translation>
 <translation id="256712445991462162">డాక్ చేసిన మాగ్నిఫైయర్</translation>
 <translation id="2573588302192866788"><ph name="NAME" />‌ను కనెక్ట్ చేయడం సాధ్యపడలేదు</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">అవుట్‌పుట్</translation>
 <translation id="3009958530611748826">దీనిలో సేవ్ చేయడానికి ఫోల్డర్‌ను ఎంచుకోండి</translation>
 <translation id="301282384882049174">మీ అడ్మినిస్ట్రేటర్ ద్వారా షేర్ చేయబడింది</translation>
+<translation id="301584155502740476">హాట్‌స్పాట్ వివరాలను చూడండి. హాట్‌స్పాట్ ఆఫ్‌లో ఉంది.</translation>
 <translation id="3018135054368884502">ఫాస్ట్ ఫార్వర్డ్ మీడియా</translation>
 <translation id="3033545621352269033">ఆన్</translation>
 <translation id="3033912566804961911"><ph name="DESK_NAME" />‌తో కలపండి</translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">మునుపటి పదం ప్రారంభానికి తరలించు</translation>
 <translation id="3294437725009624529">అతిథి</translation>
 <translation id="3298690094479023523">మీ PIN లేదా పాస్‌వర్డ్‌ను వెరిఫై చేయడం ఇంకా సాధ్యం కాలేదు. మళ్లీ ట్రై చేయండి.</translation>
+<translation id="3300193645498960160">మ్యూట్‌లో ఉన్నప్పుడు మీరు మాట్లాడితే, మీకు నోటిఫికేషన్ అందుతుంది. ఆడియో మీ పరికరం నుండి ఎన్నడూ పోదు.</translation>
 <translation id="3307642347673023554">ల్యాప్‌టాప్ మోడ్‌కు స్విచ్ చేయబడింది</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> ఇప్పటికీ తర్వాత సైన్ ఇన్ చేయవచ్చు.</translation>
 <translation id="3321628682574733415">తల్లి/తండ్రి కోడ్ తప్పు</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">ఇన్‌పుట్</translation>
 <translation id="3621712662352432595">ఆడియో సెట్టింగ్‌‍లు</translation>
 <translation id="3626281679859535460">ప్రకాశం</translation>
+<translation id="3629640897379005903">హాట్‌స్పాట్ వివరాలను చూడండి. హాట్‌స్పాట్ డిజేబుల్ అవుతోంది.</translation>
 <translation id="3630697955794050612">ఆ‌ఫ్‌లో ఉంది</translation>
 <translation id="3631369015426612114">కింది వాటి నుండి నోటిఫికేషన్‌లను అనుమతించండి</translation>
 <translation id="3633097874324966332">మీ పరికరాన్ని పెయిర్ చేయడానికి బ్లూటూత్ సెట్టింగ్‌లను తెరవండి</translation>
@@ -702,6 +709,7 @@
 <translation id="423685346499232137">ఈ సమయంలో కంటెంట్‌ను కాపీ లేదా పేస్ట్ చేయడం సాధ్యం కాదు</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">స్థూలదృష్టి మోడ్</translation>
+<translation id="4240756737570479726">డిజేబుల్ అవుతోంది...</translation>
 <translation id="4242533952199664413">సెట్టింగ్‌లను తెరువు</translation>
 <translation id="4247123849143712100">అప్‌డేట్ చేసి, షట్ డౌన్ చేయండి</translation>
 <translation id="4250229828105606438">స్క్రీన్‌షాట్</translation>
@@ -840,6 +848,7 @@
 <translation id="4864369630010738180">సైన్ ఇన్ అవుతోంది...</translation>
 <translation id="4864648187878336334">డెస్క్ 15</translation>
 <translation id="4868492592575313542">యాక్టివేట్ చేయబడింది</translation>
+<translation id="4871905435473761992">హాట్‌స్పాట్ వివరాలను చూడండి. మీ మొబైల్ నెట్‌వర్క్ హాట్‌స్పాట్‌ను సపోర్ట్ చేయదు.</translation>
 <translation id="4872237917498892622">Alt+Search లేదా Shift</translation>
 <translation id="4872852897273142380">బుక్‌మార్క్‌ల బార్‌ను (చూపించినట్లయితే) ఫోకస్ చేయండి లేదా దానిని హైలైట్ చేయండి</translation>
 <translation id="4881695831933465202">తెరువు</translation>
@@ -899,6 +908,7 @@
 <translation id="5104236669533825617">స్క్రీన్‌కాస్ట్‌ను క్రియేట్ చేయడం సాధ్యపడలేదు</translation>
 <translation id="5107522548814527560">వెబ్</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">బ్యాక్‌గ్రౌండ్ బ్లర్</translation>
 <translation id="5117590920725113268">తర్వాత నెలను చూపుతుంది</translation>
 <translation id="5121628974188116412">పేజీ దిగువకు వెళ్లండి</translation>
 <translation id="5136175204352732067">వేరే కీబోర్డ్ కనెక్ట్ చేయబడింది</translation>
@@ -910,6 +920,7 @@
 <translation id="5168181903108465623">Cast పరికరాలు అందుబాటులో ఉన్నాయి</translation>
 <translation id="5170568018924773124">ఫోల్డర్‌లో చూపించు</translation>
 <translation id="5176318573511391780">పాక్షిక స్క్రీన్‌ను రికార్డ్ చేయండి</translation>
+<translation id="5187627942836026988">హాట్‌స్పాట్ వివరాలను చూడండి. హాట్‌స్పాట్‌ను మీ అడ్మినిస్ట్రేటర్ బ్లాక్ చేశారు.</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> ఈవెంట్‌లు</translation>
 <translation id="5198715732953550718">కొత్త ఫోల్డర్‌ను క్రియేట్ చేయడం కోసం <ph name="MOVED_APP_NAME" /> అనేది <ph name="IN_PLACE_APP" />తో కలపబడింది.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1081,6 +1092,7 @@
 <translation id="595202126637698455">పనితీరుని గుర్తించడం ప్రారంభించబడింది</translation>
 <translation id="5955304353782037793">app</translation>
 <translation id="5958529069007801266">పర్యవేక్షించబడే వినియోగదారు</translation>
+<translation id="5961960957587052807">పాక్షిక బ్లర్</translation>
 <translation id="5965524703725988602">ముదురు రంగు రూపాన్ని టోగుల్ చేయండి. <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">విండోను రికార్డ్ చేయడానికి enterను నొక్కండి</translation>
 <translation id="5978382165065462689">రిమోట్ సహాయం విధానంలో మీ స్క్రీన్ నియంత్రణను షేర్ చేస్తోంది.</translation>
@@ -1253,6 +1265,7 @@
 <translation id="6752912906630585008">"<ph name="REMOVED_DESK" />" డెస్క్ తీసివేసి, "<ph name="RECEIVE_DESK" />" డెస్క్‌తో విలీనం చేయబడింది</translation>
 <translation id="6753390234084146956">ట్యాబ్‌లు</translation>
 <translation id="6757237461819837179">మీడియా ఏదీ ప్లే కావడం లేదు</translation>
+<translation id="6759628406555734414">హాట్‌స్పాట్ వివరాలను చూడండి. హాట్‌స్పాట్ ఎనేబుల్ అవుతోంది.</translation>
 <translation id="6768043681523654438">స్టోరేజ్</translation>
 <translation id="6777216307882431711">కనెక్ట్ చేసిన USB-C పరికరాలకు పవర్ అందిస్తోంది</translation>
 <translation id="6781002679438061620">డెస్క్ 9</translation>
@@ -1277,6 +1290,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> సెక</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{ఒక అంకె మిగిలింది}other{# అంకెలు మిగిలాయి}}</translation>
 <translation id="6867938213751067702"><ph name="FILENAME" /> డౌన్‌లోడ్ పాజ్ చేయబడింది</translation>
+<translation id="6874854809828346832">హాట్‌స్పాట్ వివరాలను చూడండి. హాట్‌స్పాట్ ఆన్‌లో ఉంది.</translation>
 <translation id="6878400149835617132">షార్ట్‌కట్ ఆఫ్ చేయబడింది</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 యాప్}other{# యాప్‌లు}}</translation>
 <translation id="6884665277231944629">ఈరోజుకు తిరిగి వెళ్లండి</translation>
@@ -1286,6 +1300,7 @@
 <translation id="6896758677409633944">కాపీ చేయి</translation>
 <translation id="6901883536534621389">నావిగేట్ చేయడానికి సంజ్ఞలను ట్రై చేయండి</translation>
 <translation id="6919251195245069855">మీ స్మార్ట్ కార్డ్‌ను గుర్తించడం సాధ్యం కాలేదు. మళ్ళీ ప్రయత్నించండి.</translation>
+<translation id="6920245099716267363">హాట్‌స్పాట్‌ను టోగుల్ చేయండి. మీ హాట్‌స్పాట్ ఆన్‌లో ఉంది, 1 పరికరం కనెక్ట్ అయి ఉంది.</translation>
 <translation id="6931576957638141829">దీనిలో సేవ్ చేయండి</translation>
 <translation id="6941333068993625698">అభిప్రాయాన్ని సమర్పించండి</translation>
 <translation id="6942518653766415536">రికార్డింగ్ ఫార్మాట్ మెనూ</translation>
@@ -1375,6 +1390,7 @@
 <translation id="7378203170292176219">రికార్డ్ చేసేందుకు ప్రదేశాన్ని ఎంచుకోవడానికి లాగండి</translation>
 <translation id="7378594059915113390">మీడియా నియంత్రణలు</translation>
 <translation id="7378889811480108604">బ్యాటరీ సేవర్ మోడ్ ఆఫ్‌లో ఉంది</translation>
+<translation id="7382640522316003298">హాట్‌స్పాట్‌ను టోగుల్ చేయండి. హాట్‌స్పాట్ ఆన్‌లో ఉంది, <ph name="DEVICECOUNT" /> పరికరాలు కనెక్ట్ అయి ఉన్నాయి.</translation>
 <translation id="7382680553121047388">ఆన్ చేయండి</translation>
 <translation id="7384028040782072252">మీ యాప్‌ల క్రమాన్ని మార్చడానికి, ఎక్కడైనా కుడి క్లిక్ ఇవ్వండి</translation>
 <translation id="7386767620098596324">నెట్‌వర్క్ కనెక్షన్‌ను టోగుల్ చేయండి. <ph name="STATE_TEXT" />.</translation>
@@ -1425,6 +1441,7 @@
 <translation id="7579778809502851308">స్క్రీన్‌ను క్యాప్చర్ చేయి</translation>
 <translation id="7593891976182323525">Search లేదా Shift</translation>
 <translation id="7600875258240007829">అన్ని నోటిఫికేషన్‌లను చూడండి</translation>
+<translation id="7601417191446344542">మ్యూట్‌కు సంబంధించిన ఆటోమేటిక్ రిమైండర్‌ను ఆన్ చేయాలా?</translation>
 <translation id="7607002721634913082">పాజ్ చేయబడింది</translation>
 <translation id="7609951632080598826">క్యాలెండర్ వీక్షణ, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">కెమెరా తిరిగి కనెక్ట్ చేయబడింది.</translation>
@@ -1547,6 +1564,7 @@
 <translation id="8131740175452115882">నిర్ధారించు</translation>
 <translation id="8131994907636310308">క్రమపద్ధతిలో అమర్చే ఆప్షన్‌ను మూసివేయమని చూపే టోస్ట్</translation>
 <translation id="8132793192354020517"><ph name="NAME" />కు కనెక్ట్ చేయబడింది</translation>
+<translation id="8135163608236671037">హాట్‌స్పాట్‌ను టోగుల్ చేయండి. మీ హాట్‌స్పాట్ ఆన్‌లో ఉంది, పరికరం ఏదీ కనెక్ట్ అయి లేదు.</translation>
 <translation id="8138705869659070104">పరికరాన్ని సెటప్ చేసిన తర్వాత యాక్టివేట్ చేయండి</translation>
 <translation id="813913629614996137">ప్రారంభిస్తోంది...</translation>
 <translation id="8142441511840089262">రెండు సార్లు క్లిక్ చేయండి</translation>
@@ -1727,6 +1745,7 @@
 <translation id="8990809378771970590"><ph name="IME_NAME" /> ఉపయోగిస్తోంది</translation>
 <translation id="8991617137207906966">కలర్ మార్పిడి మోడ్ ఎనేబుల్ చేయబడింది. Ctrl+Search+Hను నొక్కి, దాన్ని టోగుల్ ఆఫ్ చేయండి.</translation>
 <translation id="899350903320462459">నోటిఫికేషన్ చర్యను మేనేజ్ చేయడానికి <ph name="LOGIN_ID" />గా పరికరాన్ని అన్‌లాక్ చేయండి</translation>
+<translation id="8993733019280019776">మీరు మాట్లాడుతున్నారా? మీ మైక్ ఆఫ్‌లో ఉంది. మైక్‌ను ఎంచుకొని దానిని ఆన్ చేయండి.</translation>
 <translation id="9000771174482730261">స్టోరేజ్‌ను మేనేజ్ చేయండి</translation>
 <translation id="9005984960510803406">Crosh విండోను తెరవండి</translation>
 <translation id="9017320285115481645">Family Link తల్లిదండ్రుల యాక్సెస్ కోడ్‌ను నమోదు చేయండి.</translation>
diff --git a/ash/strings/ash_strings_uz.xtb b/ash/strings/ash_strings_uz.xtb
index 9c3a547..9ba0c16 100644
--- a/ash/strings/ash_strings_uz.xtb
+++ b/ash/strings/ash_strings_uz.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">Taqvim, <ph name="CURRENT_MONTH_YEAR" />, hozir <ph name="DATE" /> tanlangan.</translation>
 <translation id="1787955149152357925">Oʻchiq</translation>
 <translation id="181103072419391116">Signal darajasi: <ph name="SIGNAL_STRENGTH" />, Administrator boshqaruvida</translation>
+<translation id="1815245884418711390">Hotspot tugmasi. Hotspot oʻchiq.</translation>
 <translation id="1816896987747843206">Bunda kameraga ruxsat beriladi. Barcha ilovalar va saytlar kameradan foydalana oladi</translation>
 <translation id="1823280932251546115">Holat qatori, vaqt <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">Tarmoq paketlarini olish jarayonini istalgan vaqtda toʻxtatish mumkin</translation>
 <translation id="2034971124472263449">Baribir saqlansin</translation>
 <translation id="2049240716062114887">Ish stoli nomi yangilandi: <ph name="DESK_NAME" /></translation>
+<translation id="206377500836174974">Toʻliq</translation>
 <translation id="2064048859448024834">Kamera orqali razm solish yoniq</translation>
 <translation id="2067602449040652523">Klaviatura yorqinligi</translation>
 <translation id="2075520525463668108"><ph name="CAPTURE_MEDIUM" /> tugmasi. <ph name="CAPTURE_MEDIUM" /> <ph name="CAPTURE_STATE" />.</translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">Eslatma va skrinshotlar olish hamda assistent, lazerli kursor yoki lupadan foydalanish uchun javondagi stilus tugmasini bosing.</translation>
 <translation id="2341729377289034582">Vertikal holatda qulflangan</translation>
 <translation id="2345226652884463045">Tahrirlash maqsadida matnni tanlash uchun Enter yoki Qidiruv + Boʻsh joy tugmalarini bosing.</translation>
+<translation id="2349785431103945039">Hotspot axborotini ochish. Hotspot ishlatish uchun mobil internetga ulaning.</translation>
 <translation id="2350794187831162545"><ph name="LANGUAGE" /> tili qurilmada qayta ishlanadi va internetsiz ishlaydi. Ovoz bilan yozish tilini Sozlamalar &gt; Qulayliklar orqali oʻzgartirish mumkin.</translation>
 <translation id="2352467521400612932">Stilus sozlamalari</translation>
 <translation id="2354174487190027830"><ph name="NAME" /> faollashtirilmoqda</translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">qurilma sekin ishlayapti</translation>
 <translation id="2542089167727451762">Profil rasmingizni bosing</translation>
 <translation id="254900897760075745">Tanlangan kontentni vaqtincha xotiraga nusxalash</translation>
+<translation id="2549711466868162843">Yoritish darajasini yaxshilash</translation>
 <translation id="255671100581129685">Google Assistent demo seansda ishlamaydi.</translation>
 <translation id="256712445991462162">mahkamlangan lupa</translation>
 <translation id="2573588302192866788"><ph name="NAME" /> qurilmasi ulanmadi</translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">Chiqarish</translation>
 <translation id="3009958530611748826">Saqlash uchun jild tanlang</translation>
 <translation id="301282384882049174">Administrator tomonidan ulashilgan</translation>
+<translation id="301584155502740476">Hotspot axborotini ochish. Hotspot oʻchiq.</translation>
 <translation id="3018135054368884502">Mediani oldinga oʻtkazish</translation>
 <translation id="3033545621352269033">Yoniq</translation>
 <translation id="3033912566804961911"><ph name="DESK_NAME" /> bilan birlashtirish</translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">Avvalgi soʻz boshiga oʻtish</translation>
 <translation id="3294437725009624529">Mehmon</translation>
 <translation id="3298690094479023523">PIN kod yoki parolingiz haligacha tekshirilmadi. Qayta urining.</translation>
+<translation id="3300193645498960160">Ovozsiz rejimda gapirsangiz ham bildirishnoma olasiz. Audio faqat qurilmada saqlanadi.</translation>
 <translation id="3307642347673023554">Laptop rejimiga almashildi</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> keyinroq kira oladi.</translation>
 <translation id="3321628682574733415">Ota-ona kodi xato kiritildi</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">Kirish</translation>
 <translation id="3621712662352432595">Audio sozlamalari</translation>
 <translation id="3626281679859535460">Yorqinlik</translation>
+<translation id="3629640897379005903">Hotspot axborotini ochish. Hotspot oʻchirilmoqda.</translation>
 <translation id="3630697955794050612">oʻchiq</translation>
 <translation id="3631369015426612114">Quyidagilardan bildirishnomalar ko‘rsatilsin</translation>
 <translation id="3633097874324966332">Qurilmangizni ulash uchun Bluetooth sozlamalarini oching</translation>
@@ -701,6 +708,7 @@
 <translation id="423685346499232137">Ayni vaqtda kontentni nusxalash yoki joylash imkonsiz</translation>
 <translation id="4239069858505860023">GPRS</translation>
 <translation id="4240486403425279990">Umumiy axborot rejimi</translation>
+<translation id="4240756737570479726">Oʻchirilmoqda…</translation>
 <translation id="4242533952199664413">Sozlamalarni ochish</translation>
 <translation id="4247123849143712100">Yangilash va ishni yakunlash</translation>
 <translation id="4250229828105606438">Skrinshot</translation>
@@ -839,6 +847,7 @@
 <translation id="4864369630010738180">Kirilmoqda…</translation>
 <translation id="4864648187878336334">Desk 15</translation>
 <translation id="4868492592575313542">faollashtirildi</translation>
+<translation id="4871905435473761992">Hotspot axborotini ochish. Mobil tarmogʻingizda hotspot yaratish imkonsiz.</translation>
 <translation id="4872237917498892622">Alt+Search yoki Shift</translation>
 <translation id="4872852897273142380">Bukmarklar panelini fokuslash yoki ajratib belgilash (agar koʻrinsa)</translation>
 <translation id="4881695831933465202">Ochish</translation>
@@ -898,6 +907,7 @@
 <translation id="5104236669533825617">Skrinkast yaratilmadi</translation>
 <translation id="5107522548814527560">Veb</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">Orqa fonni xiralashtirish</translation>
 <translation id="5117590920725113268">Keyingi oyni ko‘rsatish</translation>
 <translation id="5121628974188116412">Sahifaning oxiriga o‘tish</translation>
 <translation id="5136175204352732067">Boshqa klaviatura ulandi</translation>
@@ -909,6 +919,7 @@
 <translation id="5168181903108465623">Translatsiya qurilmalari mavjud</translation>
 <translation id="5170568018924773124">&amp;Jildda ko‘rsatish</translation>
 <translation id="5176318573511391780">Ekran qismini yozib olish</translation>
+<translation id="5187627942836026988">Hotspot axborotini ochish. Hotspot xizmatini administrator bloklagan.</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> ta tadbir</translation>
 <translation id="5198715732953550718"><ph name="MOVED_APP_NAME" /> va <ph name="IN_PLACE_APP" /> ilovalari yangi jildga birlashtirildi.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1091,7 @@
 <translation id="595202126637698455">Unumdorlik kuzatuvi yoniq</translation>
 <translation id="5955304353782037793">app</translation>
 <translation id="5958529069007801266">Boshqariladigan profil</translation>
+<translation id="5961960957587052807">Yengil</translation>
 <translation id="5965524703725988602">Tungi mavzuni yoqish/oʻchirish <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">Oynani yozib olish uchun Enter tugmasini bosing</translation>
 <translation id="5978382165065462689">Ekraningiz boshqaruvini masofaviy yordamchi orqali ulashish.</translation>
@@ -1252,6 +1264,7 @@
 <translation id="6752912906630585008"><ph name="REMOVED_DESK" /> ish stoli olib tashlandi va oynalari <ph name="RECEIVE_DESK" /> ish stoliga birlashtirildi</translation>
 <translation id="6753390234084146956">varaqlar</translation>
 <translation id="6757237461819837179">Hech narsa ijro qilinmayapti</translation>
+<translation id="6759628406555734414">Hotspot axborotini ochish. Hotspot yoqilmoqda.</translation>
 <translation id="6768043681523654438">xotira</translation>
 <translation id="6777216307882431711">Ulangan USB-C qurilmalar quvvatlanmoqda</translation>
 <translation id="6781002679438061620">Desk 9</translation>
@@ -1276,6 +1289,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> soniya</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{Bitta raqam kiritilmadi}other{# ta raqam kiritilmadi}}</translation>
 <translation id="6867938213751067702">Yuklab olish pauza qilindi: <ph name="FILENAME" /></translation>
+<translation id="6874854809828346832">Hotspot axborotini ochish. Hotspot yoniq.</translation>
 <translation id="6878400149835617132">Yorliq yoqilmagan</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{1 ta ilova}other{# ta ilova}}</translation>
 <translation id="6884665277231944629">Bugunga qaytish</translation>
@@ -1285,6 +1299,7 @@
 <translation id="6896758677409633944">Nusxa olish</translation>
 <translation id="6901883536534621389">Boshqarish uchun ishoralardan foydalaning</translation>
 <translation id="6919251195245069855">Smart kartangiz aniqlanmadi. Qayta urining.</translation>
+<translation id="6920245099716267363">Hotspot tugmasi. Hotspot yoniq, 1 ta qurilma ulangan.</translation>
 <translation id="6931576957638141829">Saqlab olish</translation>
 <translation id="6941333068993625698">Fikr-mulohaza</translation>
 <translation id="6942518653766415536">Yozib olish formati menyusi</translation>
@@ -1374,6 +1389,7 @@
 <translation id="7378203170292176219">Yozib olinadigan hududni tanlash uchun suring</translation>
 <translation id="7378594059915113390">Media boshqaruv elementlari</translation>
 <translation id="7378889811480108604">Quvvat tejash rejimi oʻchiq</translation>
+<translation id="7382640522316003298">Hotspot tugmasi. Hotspot yoniq, <ph name="DEVICECOUNT" /> ta qurilma ulangan.</translation>
 <translation id="7382680553121047388">Yoniq</translation>
 <translation id="7384028040782072252">Ilovalarni qayta saralash uchun oʻng klikni istalgan joyga bosing</translation>
 <translation id="7386767620098596324">Tarmoq aloqasini yoqish/oʻchirish <ph name="STATE_TEXT" />.</translation>
@@ -1424,6 +1440,7 @@
 <translation id="7579778809502851308">Ekranni suratga olish</translation>
 <translation id="7593891976182323525">Search yoki Shift</translation>
 <translation id="7600875258240007829">Barcha bildirishnomalarni ochish</translation>
+<translation id="7601417191446344542">Ovozsiz qilish yoqilsinmi?</translation>
 <translation id="7607002721634913082">Vaqtincha to‘xtatildi</translation>
 <translation id="7609951632080598826">Taqvim shaklida, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">Kamera qayta ulandi.</translation>
@@ -1546,6 +1563,7 @@
 <translation id="8131740175452115882">Tasdiqlash</translation>
 <translation id="8131994907636310308">Tartiblash bildirgisini yopish</translation>
 <translation id="8132793192354020517"><ph name="NAME" /> tarmog‘iga ulanilgan</translation>
+<translation id="8135163608236671037">Hotspot tugmasi. Hotspot yoniq, hech qaysi qurilma ulanmagan</translation>
 <translation id="8138705869659070104">Qurilma sozlangandan keyin faollashtiriladi</translation>
 <translation id="813913629614996137">Ishga tushirilmoqda...</translation>
 <translation id="8142441511840089262">Ikki marta bosish</translation>
@@ -1726,6 +1744,7 @@
 <translation id="8990809378771970590"><ph name="IME_NAME" /> ishlatilmoqda</translation>
 <translation id="8991617137207906966">Ranglarni akslantirish usuli yoqildi. Uni oʻchirish uchun yana Ctrl+Search+H tugmalarini bosing.</translation>
 <translation id="899350903320462459">Bildirishnomani amalga oshirish uchun <ph name="LOGIN_ID" /> sifatida qurilmani qulfdan chiqaring</translation>
+<translation id="8993733019280019776">Gapiryapsizmi? Mikrofon oʻchiq. Uni yoqish uchun mikrofon ustiga bosing.</translation>
 <translation id="9000771174482730261">XOTIRANI BOSHQARISH</translation>
 <translation id="9005984960510803406">Crosh oynasini ochish</translation>
 <translation id="9017320285115481645">Family Link ota-ona kodini kiriting.</translation>
diff --git a/ash/strings/ash_strings_zu.xtb b/ash/strings/ash_strings_zu.xtb
index 484663d..f38ebdb 100644
--- a/ash/strings/ash_strings_zu.xtb
+++ b/ash/strings/ash_strings_zu.xtb
@@ -183,6 +183,7 @@
 <translation id="1774796056689732716">Ikhalenda, <ph name="CURRENT_MONTH_YEAR" />, okwamanje umhla ka-<ph name="DATE" /> ukhethiwe.</translation>
 <translation id="1787955149152357925">Valiwe</translation>
 <translation id="181103072419391116">Amandla esignali <ph name="SIGNAL_STRENGTH" />, Kuphethwe umlawuli wakho</translation>
+<translation id="1815245884418711390">Guqula I-hotspot. I-hotspot ivaliwe.</translation>
 <translation id="1816896987747843206">Lokhu kuvumela ukufinyelela kwekhamera kuwo wonke ama-app namawebhusayithi ngemvume yekhamera</translation>
 <translation id="1823280932251546115">Isimo sethreyi, isikhathi <ph name="TIME" />,
         <ph name="BATTERY" />
@@ -241,6 +242,7 @@
 <translation id="2023558322300866873">Ungavimba ukuthatha iphakethe noma kunini.</translation>
 <translation id="2034971124472263449">Londoloza nakuba kunjalo</translation>
 <translation id="2049240716062114887">Igama letafula lishintshelwe ku-<ph name="DESK_NAME" /></translation>
+<translation id="206377500836174974">Igcwele</translation>
 <translation id="2064048859448024834">Ukuhlola kuqala kwekhamera kuvuliwe</translation>
 <translation id="2067602449040652523">Ukukhanya kwekhibhodi</translation>
 <translation id="2075520525463668108">Guqula i-<ph name="CAPTURE_MEDIUM" />. I-<ph name="CAPTURE_MEDIUM" /> yi-<ph name="CAPTURE_STATE" /></translation>
@@ -293,6 +295,7 @@
 <translation id="2339073806695260576">Thepha inkinobho ye-stylus kushelufu ukuze uthathe inothi, isithombe-skrini sebenzisa isikhombi se-laser, noma ingilazi yokusondeza</translation>
 <translation id="2341729377289034582">Kukhiywe ngokuvundlile</translation>
 <translation id="2345226652884463045">Cindezela okuthi faka noma sesha + isikhala ukuze ukhethe umbhalo ozowuhlela.</translation>
+<translation id="2349785431103945039">Bonisa imininingwane ye-hotspot. Xhuma kunethiwekhi yeselula ukuze usebenzise i-hotspot.</translation>
 <translation id="2350794187831162545">Inkulumo yesi-<ph name="LANGUAGE" /> isiphroseswa endaweni futhi isebenza ngokungaxhunyiwe ku-inthanethi. Ungashintsha ulimi lwakho Lokubizela kokuthi Amasethingi &gt; Ukutholakala.</translation>
 <translation id="2352467521400612932">Izilungiselelo ze-stylus</translation>
 <translation id="2354174487190027830">Yenza kusebenze i-<ph name="NAME" /></translation>
@@ -335,6 +338,7 @@
 <translation id="2531025035050312891">idivayisi ihamba kancane</translation>
 <translation id="2542089167727451762">Thepha isithombe sakho sephrofayela</translation>
 <translation id="254900897760075745">Kopisha okuqukethwe okukhethiwe ebhodini lokunamathisela</translation>
+<translation id="2549711466868162843">Thuthukisa ukukhanya</translation>
 <translation id="255671100581129685">Umsizi we-Google akatholakali kuseshini esesidlangalaleni.</translation>
 <translation id="256712445991462162">isikhulisi esidokhiwe</translation>
 <translation id="2573588302192866788">Ayikwazanga ukuxhuma ku-<ph name="NAME" /></translation>
@@ -427,6 +431,7 @@
 <translation id="3009178788565917040">Okukhiphayo</translation>
 <translation id="3009958530611748826">Khetha ifolda ozolondoloza kuyo</translation>
 <translation id="301282384882049174">Kwabiwe ngumlawuli wakho</translation>
+<translation id="301584155502740476">Bonisa imininingwane ye-hotspot. I-hotspot ivaliwe.</translation>
 <translation id="3018135054368884502">Imidiya eya phambili ngokushesha</translation>
 <translation id="3033545621352269033">Vuliwe</translation>
 <translation id="3033912566804961911">Hlanganisa ne-<ph name="DESK_NAME" /></translation>
@@ -487,6 +492,7 @@
 <translation id="3291862315280588024">Hambisa ekuqaleni kwegama langaphambilini</translation>
 <translation id="3294437725009624529">Isivakashi</translation>
 <translation id="3298690094479023523">Iphinikhodi yakho noma iphasiwedi isengaqinisekiswa. Zama futhi.</translation>
+<translation id="3300193645498960160">Uzokwaziswa uma ukhuluma ngenkathi uthulisiwe. Umsindo awulokothi ushiye idivayisi yakho.</translation>
 <translation id="3307642347673023554">Ishintshele kumodi yekhompuyutha ephathekayo</translation>
 <translation id="3308453408813785101"><ph name="USER_EMAIL_ADDRESS" /> angasangena ngemvume kamuva.</translation>
 <translation id="3321628682574733415">Ikhodi yomzali engalungile</translation>
@@ -570,6 +576,7 @@
 <translation id="3621202678540785336">Okokufaka</translation>
 <translation id="3621712662352432595">Izilungiselelo zomsindo</translation>
 <translation id="3626281679859535460">Ukukhanya</translation>
+<translation id="3629640897379005903">Bonisa imininingwane ye-hotspot. I-hotspot iyakhutshazwa.</translation>
 <translation id="3630697955794050612">valiwe</translation>
 <translation id="3631369015426612114">Vumela izaziso kusukela kokulandelayo</translation>
 <translation id="3633097874324966332">Vula amasethingi we-Bluetooth ukuze ubhanqe idivayisi yakho</translation>
@@ -701,6 +708,7 @@
 <translation id="423685346499232137">Ayikwazi ukukopisha noma ukunamathisela okuqukethwe ngalesi sikhathi</translation>
 <translation id="4239069858505860023">I-GPRS</translation>
 <translation id="4240486403425279990">Imodi yokubuka konke</translation>
+<translation id="4240756737570479726">Iyakhubaza...</translation>
 <translation id="4242533952199664413">Vula izilungiselelo</translation>
 <translation id="4247123849143712100">Buyekeza bese uyacisha</translation>
 <translation id="4250229828105606438">Isithombe-skrini</translation>
@@ -839,6 +847,7 @@
 <translation id="4864369630010738180">Iyangena ngemvume...</translation>
 <translation id="4864648187878336334">Itafula 15</translation>
 <translation id="4868492592575313542">yenziwe yasebenza</translation>
+<translation id="4871905435473761992">Bonisa imininingwane ye-hotspot. Inethiwekhi yakho yeselula ayisekeli i-hotspot.</translation>
 <translation id="4872237917498892622">I-Alt+Search noma i-Shift</translation>
 <translation id="4872852897273142380">Gxilisa noma gqamisa ibha yamabhukhimakhi (uma kubonisiwe)</translation>
 <translation id="4881695831933465202">Vula</translation>
@@ -898,6 +907,7 @@
 <translation id="5104236669533825617">Ayikwazi ukusungula i-screencast</translation>
 <translation id="5107522548814527560">Iwebhu</translation>
 <translation id="5111318697104479778"><ph name="DESC" />, <ph name="STRENGTH" /></translation>
+<translation id="5111930673176965299">Ukufiphala kwengemuva</translation>
 <translation id="5117590920725113268">Bonisa inyanga elandelayo</translation>
 <translation id="5121628974188116412">Hamba ngaphansi kwekhasi</translation>
 <translation id="5136175204352732067">Ikhibhodi ehlukile ixhunyiwe</translation>
@@ -909,6 +919,7 @@
 <translation id="5168181903108465623">Amadivayisi wabalingisi ayatholakala</translation>
 <translation id="5170568018924773124">Bonisa kufolda</translation>
 <translation id="5176318573511391780">Rekhoda ingxenye yesikrini</translation>
+<translation id="5187627942836026988">Bonisa imininingwane ye-hotspot. I-hotspot ivinjwe umlawuli wakho.</translation>
 <translation id="5198413532174090167"><ph name="DATE" />, <ph name="NUMBER" /> imicimbi</translation>
 <translation id="5198715732953550718"><ph name="MOVED_APP_NAME" /> kuhlanganiswe ne-<ph name="IN_PLACE_APP" /> ukudala ifolda entsha.</translation>
 <translation id="5206028654245650022"><ph name="APP_NAME" />, <ph name="NOTIFICATION_TITLE" />: <ph name="MESSAGE" />, <ph name="PHONE_NAME" /></translation>
@@ -1080,6 +1091,7 @@
 <translation id="595202126637698455">Ukulandelela ukusebenza kunikwe amandla</translation>
 <translation id="5955304353782037793">uhlelo lokusebenza</translation>
 <translation id="5958529069007801266">Umsebenzisi ogadiwe</translation>
+<translation id="5961960957587052807">Ukukhanya</translation>
 <translation id="5965524703725988602">Guqula Itimu Emnyama <ph name="STATE_TEXT" />.</translation>
 <translation id="5976112937189445008">Cindezela u-enter ukuze urekhode iwindi</translation>
 <translation id="5978382165065462689">Ukulawula ukwabelana kwesikrini sakho nge-Remote Assistance.</translation>
@@ -1252,6 +1264,7 @@
 <translation id="6752912906630585008">Ideski <ph name="REMOVED_DESK" /> lisusiwe futhi lahlanganiswa nedeski <ph name="RECEIVE_DESK" /></translation>
 <translation id="6753390234084146956">amathebhu</translation>
 <translation id="6757237461819837179">Ayikho imidiya edlalayo</translation>
+<translation id="6759628406555734414">Bonisa imininingwane ye-hotspot. I-hotspot inikwa amandla.</translation>
 <translation id="6768043681523654438">isitoreji</translation>
 <translation id="6777216307882431711">Inika amandla amadivayisi axhunyiwe e-USB-C</translation>
 <translation id="6781002679438061620">Itafula 9</translation>
@@ -1276,6 +1289,7 @@
 <translation id="6857725247182211756"><ph name="SECONDS" /> isekhondi</translation>
 <translation id="685782768769951078">{NUM_DIGITS,plural, =1{Kusele idijithi elilodwa}one{kusele amadijithi angu-#}other{kusele amadijithi angu-#}}</translation>
 <translation id="6867938213751067702">Ukudawunilodwa kuphunyuziwe ku-<ph name="FILENAME" /></translation>
+<translation id="6874854809828346832">Bonisa imininingwane ye-hotspot. I-hotspot ivuliwe.</translation>
 <translation id="6878400149835617132">Isinqamuleli sivaliwe</translation>
 <translation id="6878701771800702153">{NUM_APPS,plural, =1{i-app e-1}one{ama-app angu-#}other{ama-app angu-#}}</translation>
 <translation id="6884665277231944629">Buyela emuva kunamuhla</translation>
@@ -1285,6 +1299,7 @@
 <translation id="6896758677409633944">Kopisha</translation>
 <translation id="6901883536534621389">Zama ukuthinta ukuze ufune</translation>
 <translation id="6919251195245069855">Ayikwazanga ukubona ikhadi lakho elisebenza ngobuchwepheshe besimanje. Zama futhi.</translation>
+<translation id="6920245099716267363">Guqula I-hotspot. I-hotspot ivuliwe, kuxhunywe idivayisi e-1.</translation>
 <translation id="6931576957638141829">Londoloza ku-</translation>
 <translation id="6941333068993625698">Hambisa impendulo</translation>
 <translation id="6942518653766415536">Irekhoda imenyu yefomethi</translation>
@@ -1374,6 +1389,7 @@
 <translation id="7378203170292176219">Hudula ukuze ukhethe indawo yokurekhoda</translation>
 <translation id="7378594059915113390">Izilawuli zemidiya</translation>
 <translation id="7378889811480108604">Imodi yesilondolozi sebhethri ivaliwe</translation>
+<translation id="7382640522316003298">Guqula I-hotspot. I-hotspot ivuliwe, kuxhunywe amadivayisi angu-<ph name="DEVICECOUNT" />.</translation>
 <translation id="7382680553121047388">Vuliwe</translation>
 <translation id="7384028040782072252">Chofoza ngakwesokudla noma yikuphi ukuze uhlele kabusha ama-app wakho</translation>
 <translation id="7386767620098596324">Ququla uxhumo lwenethiwekhi. <ph name="STATE_TEXT" />.</translation>
@@ -1424,6 +1440,7 @@
 <translation id="7579778809502851308">Ukuthatha isikrini</translation>
 <translation id="7593891976182323525">Usesho noma i-Shift</translation>
 <translation id="7600875258240007829">Bona zonke izaziso</translation>
+<translation id="7601417191446344542">Vula ukuthulisa isikhumbuzo?</translation>
 <translation id="7607002721634913082">Imiswe isikhashana</translation>
 <translation id="7609951632080598826">Ukubuka kwekhalenda, <ph name="DATE" />, <ph name="TIME" /></translation>
 <translation id="7611213136657090146">Ikhamera ixhunywe kabusha.</translation>
@@ -1546,6 +1563,7 @@
 <translation id="8131740175452115882">Qinisekisa</translation>
 <translation id="8131994907636310308">Vala ithosti yokuhlunga</translation>
 <translation id="8132793192354020517">Ixhumeke ku-<ph name="NAME" /></translation>
+<translation id="8135163608236671037">Guqula I-hotspot. I-hotspot ivuliwe, ayikho idivayisi exhunyiwe.</translation>
 <translation id="8138705869659070104">Yenza kusebenze ngemva kokusetha idivayisi</translation>
 <translation id="813913629614996137">Iyaqalisa...</translation>
 <translation id="8142441511840089262">Chofoza kabili</translation>
@@ -1726,6 +1744,7 @@
 <translation id="8990809378771970590">Usebenzisa i-<ph name="IME_NAME" /></translation>
 <translation id="8991617137207906966">Imodi Yokuguqulwa Kombala inikwe amandla. Cindezela okuthi Ctrl+Search+H futhi ukuze uyivale.</translation>
 <translation id="899350903320462459">Vula amadivayisi njenge-<ph name="LOGIN_ID" /> ukuze wenze isenzo sesaziso</translation>
+<translation id="8993733019280019776">Uyakhuluma? I-mic yakho ivaliwe. Khetha i-mic ukuze uyivule.</translation>
 <translation id="9000771174482730261">LAWULA ISITOREJI</translation>
 <translation id="9005984960510803406">Vula iwindi le-crosh</translation>
 <translation id="9017320285115481645">Faka ikhodi yokufinyelela yomzali ye-Family Link.</translation>
diff --git a/ash/system/eche/eche_tray.cc b/ash/system/eche/eche_tray.cc
index 637673b..c4607598 100644
--- a/ash/system/eche/eche_tray.cc
+++ b/ash/system/eche/eche_tray.cc
@@ -27,6 +27,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "ash/style/icon_button.h"
+#include "ash/style/typography.h"
 #include "ash/system/eche/eche_icon_loading_indicator_view.h"
 #include "ash/system/phonehub/phone_hub_tray.h"
 #include "ash/system/phonehub/ui_constants.h"
@@ -45,6 +46,7 @@
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "components/session_manager/session_manager_types.h"
 #include "components/vector_icons/vector_icons.h"
@@ -52,6 +54,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
@@ -166,9 +169,12 @@
     const gfx::VectorIcon& icon,
     int message_id) {
   auto button = views::CreateVectorImageButton(std::move(callback));
-  views::SetImageFromVectorIconWithColorId(button.get(), icon,
-                                           kColorAshIconColorPrimary,
-                                           kColorAshButtonIconDisabledColor);
+  views::SetImageFromVectorIconWithColorId(
+      button.get(), icon,
+      chromeos::features::IsJellyrollEnabled()
+          ? static_cast<ui::ColorId>(cros_tokens::kCrosSysOnSurface)
+          : kColorAshIconColorPrimary,
+      kColorAshButtonIconDisabledColor);
   button->SetTooltipText(l10n_util::GetStringUTF16(message_id));
   button->SizeToPreferredSize();
 
@@ -194,12 +200,18 @@
           .WithWeight(1));
   title->SetHorizontalAlignment(gfx::ALIGN_CENTER);
 
-  gfx::Font default_font;
-  gfx::Font text_font = default_font.Derive(
-      kAppStreamingTitleTextFontSize - default_font.GetFontSize(),
-      gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
-  gfx::FontList font_list(text_font);
-  title->SetFontList(font_list);
+  if (chromeos::features::IsJellyrollEnabled()) {
+    title->SetEnabledColorId(cros_tokens::kCrosSysOnSurface);
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosHeadline1,
+                                          *title);
+  } else {
+    gfx::Font default_font;
+    gfx::Font text_font = default_font.Derive(
+        kAppStreamingTitleTextFontSize - default_font.GetFontSize(),
+        gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+    gfx::FontList font_list(text_font);
+    title->SetFontList(font_list);
+  }
 }
 
 }  // namespace
diff --git a/ash/system/hotspot/hotspot_feature_pod_controller.cc b/ash/system/hotspot/hotspot_feature_pod_controller.cc
index 0136a96..abadb1d 100644
--- a/ash/system/hotspot/hotspot_feature_pod_controller.cc
+++ b/ash/system/hotspot/hotspot_feature_pod_controller.cc
@@ -52,6 +52,7 @@
       base::BindRepeating(&HotspotFeaturePodController::OnIconPressed,
                           weak_ptr_factory_.GetWeakPtr()));
   tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HOTSPOT));
+  tile_->CreateDecorativeDrillInArrow();
 
   // Default the visibility to false and update it in `UpdateTileState()` since
   // it should only be shown if user has used the Hotspot from Settings before.
diff --git a/ash/system/media/media_notification_provider.h b/ash/system/media/media_notification_provider.h
index 71dc7865..75f37e0 100644
--- a/ash/system/media/media_notification_provider.h
+++ b/ash/system/media/media_notification_provider.h
@@ -65,6 +65,10 @@
       const media_message_center::NotificationTheme& color_theme) = 0;
 
   virtual global_media_controls::MediaItemManager* GetMediaItemManager() = 0;
+
+  // Performs initialization that must be done after the user session is
+  // initialized.
+  virtual void OnPrimaryUserSessionStarted() {}
 };
 
 }  // namespace ash
diff --git a/ash/system/phonehub/app_stream_connection_error_dialog.cc b/ash/system/phonehub/app_stream_connection_error_dialog.cc
index 55db34e7..76eadb0 100644
--- a/ash/system/phonehub/app_stream_connection_error_dialog.cc
+++ b/ash/system/phonehub/app_stream_connection_error_dialog.cc
@@ -15,10 +15,13 @@
 #include "ash/style/ash_color_id.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/pill_button.h"
+#include "ash/style/typography.h"
 #include "base/memory/raw_ptr.h"
 #include "chromeos/ash/components/phonehub/url_constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point.h"
@@ -105,6 +108,11 @@
     title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     title_->SetAutoColorReadabilityEnabled(false);
 
+    if (chromeos::features::IsJellyrollEnabled()) {
+      TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosTitle1,
+                                            *title_);
+    }
+
     title_->SetPaintToLayer();
     title_->layer()->SetFillsBoundsOpaquely(false);
 
@@ -165,6 +173,9 @@
     body_->SetPaintToLayer();
     body_->layer()->SetFillsBoundsOpaquely(false);
 
+    // TODO(b/254874005): Migrate the |body_| font to Google Sans. Use the same
+    // TypographyProvider StyleLabel() but use ash::Typography::kCrosBody.
+
     // Add button row.
     auto* button_row = AddChildView(std::make_unique<views::View>());
     button_row
diff --git a/ash/system/phonehub/app_stream_launcher_list_item.cc b/ash/system/phonehub/app_stream_launcher_list_item.cc
index d218fc9..8d7cc95 100644
--- a/ash/system/phonehub/app_stream_launcher_list_item.cc
+++ b/ash/system/phonehub/app_stream_launcher_list_item.cc
@@ -6,6 +6,7 @@
 
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/style_util.h"
+#include "ash/style/typography.h"
 #include "base/hash/hash.h"
 #include "base/strings/string_piece_forward.h"
 #include "base/strings/utf_string_conversions.h"
@@ -51,6 +52,7 @@
 
   std::u16string accessible_name = GetAppAccessibleName(app_metadata);
 
+  // TODO(b/254874005): Migrate the |app_button_->label()| font to Google Sans.
   app_button_ = AddChildView(std::make_unique<views::LabelButton>(
       callback, app_metadata.visible_app_name));
 
diff --git a/ash/system/phonehub/app_stream_launcher_view.cc b/ash/system/phonehub/app_stream_launcher_view.cc
index c872c040..81b11e7 100644
--- a/ash/system/phonehub/app_stream_launcher_view.cc
+++ b/ash/system/phonehub/app_stream_launcher_view.cc
@@ -14,6 +14,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/style_util.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/app_stream_launcher_item.h"
 #include "ash/system/phonehub/app_stream_launcher_list_item.h"
 #include "ash/system/phonehub/app_stream_launcher_view.h"
@@ -266,6 +267,11 @@
   title->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_APP_STREAM_LAUNCHER_TITLE));
 
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosHeadline1,
+                                          *title);
+  }
+
   return header;
 }
 
diff --git a/ash/system/phonehub/camera_roll_view.cc b/ash/system/phonehub/camera_roll_view.cc
index cfa6022..2a8657b 100644
--- a/ash/system/phonehub/camera_roll_view.cc
+++ b/ash/system/phonehub/camera_roll_view.cc
@@ -8,13 +8,16 @@
 
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/camera_roll_thumbnail.h"
 #include "ash/system/phonehub/phone_hub_metrics.h"
 #include "ash/system/phonehub/phone_hub_view_ids.h"
 #include "ash/system/phonehub/ui_constants.h"
 #include "ash/system/tray/tray_constants.h"
 #include "base/strings/string_number_conversions.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/animation/animation_builder.h"
 #include "ui/views/controls/label.h"
@@ -48,17 +51,26 @@
  public:
   HeaderView() {
     SetText(l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_CAMERA_ROLL_TITLE));
-    SetLineHeight(kHeaderLabelLineHeight);
-    SetFontList(font_list()
-                    .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
-                                         font_list().GetFontSize())
-                    .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
     SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
     SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_MIDDLE);
     SetAutoColorReadabilityEnabled(false);
     SetSubpixelRenderingEnabled(false);
     SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
         AshColorProvider::ContentLayerType::kTextColorPrimary));
+
+    if (chromeos::features::IsJellyrollEnabled()) {
+      TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton1,
+                                            *this);
+    } else {
+      SetFontList(font_list()
+                      .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
+                                           font_list().GetFontSize())
+                      .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
+    }
+
+    // Overriding because the typography line height set does not match Phone
+    // Hub specs.
+    SetLineHeight(kHeaderLabelLineHeight);
   }
 
   ~HeaderView() override = default;
diff --git a/ash/system/phonehub/continue_browsing_chip.cc b/ash/system/phonehub/continue_browsing_chip.cc
index e89dad89..0cf2df4 100644
--- a/ash/system/phonehub/continue_browsing_chip.cc
+++ b/ash/system/phonehub/continue_browsing_chip.cc
@@ -10,6 +10,7 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/phone_hub_metrics.h"
 #include "ash/system/phonehub/phone_hub_tray.h"
 #include "ash/system/status_area_widget.h"
@@ -18,7 +19,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/phonehub/user_action_recorder.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/color/color_id.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/focus_ring.h"
@@ -100,6 +103,11 @@
       AshColorProvider::ContentLayerType::kTextColorPrimary));
   url_label->SetElideBehavior(gfx::ElideBehavior::ELIDE_TAIL);
 
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(
+        ash::TypographyToken::kCrosAnnotation1, *url_label);
+  }
+
   auto* title_label =
       AddChildView(std::make_unique<views::Label>(metadata.title));
   title_label->SetAutoColorReadabilityEnabled(false);
@@ -109,8 +117,14 @@
   title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   title_label->SetMultiLine(true);
   title_label->SetMaxLines(kTitleMaxLines);
-  title_label->SetFontList(
-      title_label->font_list().DeriveWithWeight(gfx::Font::Weight::BOLD));
+
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(
+        ash::TypographyToken::kCrosAnnotation2, *title_label);
+  } else {
+    title_label->SetFontList(
+        title_label->font_list().DeriveWithWeight(gfx::Font::Weight::BOLD));
+  }
 
   const std::u16string card_label = l10n_util::GetStringFUTF16(
       IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL,
diff --git a/ash/system/phonehub/onboarding_view.cc b/ash/system/phonehub/onboarding_view.cc
index 3d17f70d..4190968 100644
--- a/ash/system/phonehub/onboarding_view.cc
+++ b/ash/system/phonehub/onboarding_view.cc
@@ -28,6 +28,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/strings/strcat.h"
 #include "chromeos/ash/components/phonehub/onboarding_ui_tracker.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -76,6 +77,9 @@
         IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_DESCRIPTION));
 
     // Add "Dismiss" and "Get started" buttons.
+    // TODO(b/281844561): Migrate the "Dismiss" button to use
+    // |PillButton::Type::kSecondaryWithoutIcon| when the PillButton colors
+    // are updated with better contrast-ratios.
     auto dismiss = std::make_unique<PillButton>(
         base::BindRepeating(&OnboardingMainView::DismissButtonPressed,
                             base::Unretained(this)),
@@ -90,7 +94,10 @@
                             base::Unretained(this)),
         l10n_util::GetStringUTF16(
             IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_GET_STARTED_BUTTON),
-        PillButton::Type::kDefaultWithoutIcon, /*icon=*/nullptr);
+        chromeos::features::IsJellyrollEnabled()
+            ? PillButton::Type::kPrimaryWithoutIcon
+            : PillButton::Type::kDefaultWithoutIcon,
+        /*icon=*/nullptr);
     get_started->SetID(PhoneHubViewID::kOnboardingGetStartedButton);
     AddButton(std::move(get_started));
   }
diff --git a/ash/system/phonehub/phone_disconnected_view.cc b/ash/system/phonehub/phone_disconnected_view.cc
index 891e9b5..3065e98 100644
--- a/ash/system/phonehub/phone_disconnected_view.cc
+++ b/ash/system/phonehub/phone_disconnected_view.cc
@@ -18,6 +18,7 @@
 #include "base/functional/bind.h"
 #include "chromeos/ash/components/phonehub/connection_scheduler.h"
 #include "chromeos/ash/components/phonehub/url_constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -44,6 +45,9 @@
       IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION));
 
   // Add "Learn more" and "Refresh" buttons.
+  // TODO(b/281844561): Migrate the "Learn More" button to use
+  // |PillButton::Type::kSecondaryWithoutIcon| when the PillButton colors
+  // are updated with better contrast-ratios.
   auto learn_more = std::make_unique<PillButton>(
       base::BindRepeating(
           &PhoneDisconnectedView::ButtonPressed, base::Unretained(this),
@@ -69,7 +73,10 @@
               base::Unretained(connection_scheduler_))),
       l10n_util::GetStringUTF16(
           IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON),
-      PillButton::Type::kDefaultWithoutIcon, /*icon=*/nullptr);
+      chromeos::features::IsJellyrollEnabled()
+          ? PillButton::Type::kPrimaryWithoutIcon
+          : PillButton::Type::kDefaultWithoutIcon,
+      /*icon=*/nullptr);
   refresh->SetID(PhoneHubViewID::kDisconnectedRefreshButton);
   content_view_->AddButton(std::move(refresh));
 
diff --git a/ash/system/phonehub/phone_hub_interstitial_view.cc b/ash/system/phonehub/phone_hub_interstitial_view.cc
index b0319fd85..8ac5fd8 100644
--- a/ash/system/phonehub/phone_hub_interstitial_view.cc
+++ b/ash/system/phonehub/phone_hub_interstitial_view.cc
@@ -11,14 +11,17 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/ui_constants.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "skia/ext/image_operations.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
@@ -36,6 +39,7 @@
 
 namespace {
 constexpr auto kLabelInsets = gfx::Insets::VH(0, 4);
+constexpr int kTitleLabelLineHeight = 48;
 }
 
 PhoneHubInterstitialView::PhoneHubInterstitialView(bool show_progress,
@@ -81,12 +85,21 @@
   title_->SetProperty(views::kCrossAxisAlignmentKey,
                       views::LayoutAlignment::kStart);
   title_->SetProperty(views::kMarginsKey, kLabelInsets);
-  title_->SetLineHeight(48);
   auto label_color = color_provider->GetContentLayerColor(
       AshColorProvider::ContentLayerType::kTextColorPrimary);
   title_->SetEnabledColor(label_color);
-  TrayPopupUtils::SetLabelFontList(title_,
-                                   TrayPopupUtils::FontStyle::kSubHeader);
+
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton1,
+                                          *title_);
+  } else {
+    TrayPopupUtils::SetLabelFontList(title_,
+                                     TrayPopupUtils::FontStyle::kSubHeader);
+  }
+
+  // Overriding because the typography line height set does not match Phone
+  // Hub specs.
+  title_->SetLineHeight(kTitleLabelLineHeight);
 
   // Set up multi-line description view.
   description_ =
@@ -98,12 +111,20 @@
       views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
                                views::MaximumFlexSizeRule::kUnbounded, true));
   description_->SetEnabledColor(label_color);
-  TrayPopupUtils::SetLabelFontList(
-      description_, TrayPopupUtils::FontStyle::kDetailedViewLabel);
   description_->SetMultiLine(true);
-  description_->SetLineHeight(20);
   description_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
 
+  if (chromeos::features::IsJellyrollEnabled()) {
+    // TODO(b/281844561): Migrate the |description_| to usea slightly lighter
+    // text color when tokens have been finalized.
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosBody2,
+                                          *description_);
+  } else {
+    TrayPopupUtils::SetLabelFontList(
+        description_, TrayPopupUtils::FontStyle::kDetailedViewLabel);
+  }
+  description_->SetLineHeight(20);
+
   // Set up button container view, which should be right-aligned.
   button_container_ =
       content_container->AddChildView(std::make_unique<views::BoxLayoutView>());
diff --git a/ash/system/phonehub/phone_hub_recent_apps_view.cc b/ash/system/phonehub/phone_hub_recent_apps_view.cc
index 9a0635d..f53348d7 100644
--- a/ash/system/phonehub/phone_hub_recent_apps_view.cc
+++ b/ash/system/phonehub/phone_hub_recent_apps_view.cc
@@ -14,6 +14,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/phone_connected_view.h"
 #include "ash/system/phonehub/phone_hub_app_loading_icon.h"
 #include "ash/system/phonehub/phone_hub_metrics.h"
@@ -28,7 +29,9 @@
 #include "base/ranges/algorithm.h"
 #include "chromeos/ash/components/phonehub/notification.h"
 #include "chromeos/ash/components/phonehub/phone_hub_manager.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/image/image.h"
@@ -134,11 +137,6 @@
   auto* label = AddChildView(std::make_unique<views::Label>());
   label->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_RECENT_APPS_TITLE));
-  label->SetLineHeight(kHeaderLabelLineHeight);
-  label->SetFontList(label->font_list()
-                         .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
-                                              label->font_list().GetFontSize())
-                         .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
   label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
   label->SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_MIDDLE);
   label->SetAutoColorReadabilityEnabled(false);
@@ -146,6 +144,18 @@
   label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
       AshColorProvider::ContentLayerType::kTextColorPrimary));
 
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton1,
+                                          *label);
+  } else {
+    label->SetFontList(
+        label->font_list()
+            .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
+                                 label->font_list().GetFontSize())
+            .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
+  }
+  label->SetLineHeight(kHeaderLabelLineHeight);
+
   if (features::IsEcheNetworkConnectionStateEnabled()) {
     error_button_ =
         AddChildView(std::make_unique<views::ImageButton>(callback));
@@ -174,7 +184,6 @@
   PlaceholderView() {
     SetText(
         l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_RECENT_APPS_PLACEHOLDER));
-    SetLineHeight(kContentLabelLineHeightDip);
     SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
     SetAutoColorReadabilityEnabled(false);
     SetSubpixelRenderingEnabled(false);
@@ -182,6 +191,12 @@
         AshColorProvider::ContentLayerType::kTextColorPrimary));
     SetMultiLine(true);
     SetBorder(views::CreateEmptyBorder(kContentTextLabelInsetsDip));
+
+    if (chromeos::features::IsJellyrollEnabled()) {
+      TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosBody2,
+                                            *this);
+    }
+    SetLineHeight(kContentLabelLineHeightDip);
   }
   ~PlaceholderView() override = default;
   PlaceholderView(PlaceholderView&) = delete;
diff --git a/ash/system/phonehub/phone_status_view.cc b/ash/system/phonehub/phone_status_view.cc
index 6c10db8..7c7a14b 100644
--- a/ash/system/phonehub/phone_status_view.cc
+++ b/ash/system/phonehub/phone_status_view.cc
@@ -14,6 +14,7 @@
 #include "ash/style/ash_color_id.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/icon_button.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/phone_hub_tray.h"
 #include "ash/system/phonehub/phone_hub_view_ids.h"
 #include "ash/system/status_area_widget.h"
@@ -23,7 +24,9 @@
 #include "base/i18n/number_formatting.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/color/color_id.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/color_utils.h"
@@ -109,8 +112,15 @@
   phone_name_label_->SetEnabledColor(
       AshColorProvider::Get()->GetContentLayerColor(
           AshColorProvider::ContentLayerType::kTextColorPrimary));
-  TrayPopupUtils::SetLabelFontList(phone_name_label_,
-                                   TrayPopupUtils::FontStyle::kSubHeader);
+
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosHeadline1,
+                                          *phone_name_label_);
+  } else {
+    TrayPopupUtils::SetLabelFontList(phone_name_label_,
+                                     TrayPopupUtils::FontStyle::kSubHeader);
+  }
+
   phone_name_label_->SetElideBehavior(gfx::ElideBehavior::ELIDE_TAIL);
   AddView(TriView::Container::START, phone_name_label_);
 
@@ -126,9 +136,16 @@
   battery_label_->SetSubpixelRenderingEnabled(false);
   battery_label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
       AshColorProvider::ContentLayerType::kTextColorPrimary));
-  auto default_font = battery_label_->font_list();
-  battery_label_->SetFontList(default_font.DeriveWithSizeDelta(
-      kBatteryLabelFontSize - default_font.GetFontSize()));
+
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton2,
+                                          *battery_label_);
+  } else {
+    auto default_font = battery_label_->font_list();
+    battery_label_->SetFontList(default_font.DeriveWithSizeDelta(
+        kBatteryLabelFontSize - default_font.GetFontSize()));
+  }
+
   battery_label_->SetBorder(
       views::CreateEmptyBorder(kBatteryLabelBorderInsets));
   AddView(TriView::Container::CENTER, battery_label_);
@@ -320,6 +337,12 @@
   // Clear battery status.
   battery_icon_->SetImage(gfx::ImageSkia());
   battery_label_->SetText(std::u16string());
+
+  // TODO(b/281844561): When the phone is disconnected the |phone_name_label_|
+  // should have cros.sys.disabled. Setting that here and then re-setting the
+  // label to cros.sys.on-surface on Update() would handle this case, but it
+  // would also incorrectly show cros.sys.disabled for the Connecting and
+  // Onboarding UI states.
 }
 
 void PhoneStatusView::ConfigureTriViewContainer(TriView::Container container) {
diff --git a/ash/system/phonehub/quick_action_item.cc b/ash/system/phonehub/quick_action_item.cc
index de0af50..2ee34c71 100644
--- a/ash/system/phonehub/quick_action_item.cc
+++ b/ash/system/phonehub/quick_action_item.cc
@@ -7,8 +7,10 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/tray/tray_constants.h"
 #include "base/functional/bind.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/insets.h"
@@ -25,14 +27,19 @@
   label->SetSubpixelRenderingEnabled(false);
   label->SetCanProcessEventsWithinSubtree(false);
 
-  label->SetLineHeight(line_height);
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosBody1,
+                                          *label);
+  } else {
+    gfx::Font default_font;
+    gfx::Font label_font =
+        default_font.Derive(font_size - default_font.GetFontSize(),
+                            gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+    gfx::FontList font_list(label_font);
+    label->SetFontList(font_list);
+  }
 
-  gfx::Font default_font;
-  gfx::Font label_font =
-      default_font.Derive(font_size - default_font.GetFontSize(),
-                          gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
-  gfx::FontList font_list(label_font);
-  label->SetFontList(font_list);
+  label->SetLineHeight(line_height);
 }
 
 }  // namespace
@@ -70,6 +77,8 @@
   ConfigureLabel(sub_label_, kUnifiedFeaturePodSubLabelLineHeight,
                  kUnifiedFeaturePodSubLabelFontSize);
 
+  // TODO(b/281844561): Update |sub_label_color_| in accordance to the Phone Hub
+  // specs. Needs additional logic for the EnableHotspotQuickAction controls.
   sub_label_color_ = AshColorProvider::Get()->GetContentLayerColor(
       AshColorProvider::ContentLayerType::kTextColorSecondary);
 
diff --git a/ash/system/phonehub/sub_feature_opt_in_view.cc b/ash/system/phonehub/sub_feature_opt_in_view.cc
index 142271e..cadd7840 100644
--- a/ash/system/phonehub/sub_feature_opt_in_view.cc
+++ b/ash/system/phonehub/sub_feature_opt_in_view.cc
@@ -8,8 +8,10 @@
 
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/pill_button.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/phone_hub_view_ids.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/compositor/layer.h"
@@ -83,12 +85,17 @@
                                .DeriveWithSizeDelta(kLabelTextFontSizeDip -
                                                     default_font.GetFontSize())
                                .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
-  text_label_->SetLineHeight(kTextLabelLineHeightDip);
   text_label_->SetMultiLine(/*multi_line=*/true);
   text_label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
   text_label_->SetText(l10n_util::GetStringFUTF16(description_string_id_,
                                                   ui::GetChromeOSDeviceName()));
 
+  if (chromeos::features::IsJellyrollEnabled()) {
+    TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosHeadline1,
+                                          *text_label_);
+  }
+  text_label_->SetLineHeight(kTextLabelLineHeightDip);
+
   // Set up layout row for the buttons.
   auto* button_container =
       AddChildView(std::make_unique<views::BoxLayoutView>());
diff --git a/ash/system/phonehub/task_continuation_view.cc b/ash/system/phonehub/task_continuation_view.cc
index d70c9b4..7314c3a7 100644
--- a/ash/system/phonehub/task_continuation_view.cc
+++ b/ash/system/phonehub/task_continuation_view.cc
@@ -6,10 +6,12 @@
 
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/phonehub/continue_browsing_chip.h"
 #include "ash/system/phonehub/phone_hub_view_ids.h"
 #include "ash/system/phonehub/ui_constants.h"
 #include "ash/system/tray/tray_constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/text_constants.h"
@@ -45,17 +47,23 @@
   HeaderView() {
     SetText(
         l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_TASK_CONTINUATION_TITLE));
-    SetLineHeight(kHeaderLabelLineHeight);
-    SetFontList(font_list()
-                    .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
-                                         font_list().GetFontSize())
-                    .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
     SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
     SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_MIDDLE);
     SetAutoColorReadabilityEnabled(false);
     SetSubpixelRenderingEnabled(false);
     SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
         AshColorProvider::ContentLayerType::kTextColorPrimary));
+
+    if (chromeos::features::IsJellyrollEnabled()) {
+      TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton1,
+                                            *this);
+    } else {
+      SetFontList(font_list()
+                      .DeriveWithSizeDelta(kHeaderTextFontSizeDip -
+                                           font_list().GetFontSize())
+                      .DeriveWithWeight(gfx::Font::Weight::MEDIUM));
+    }
+    SetLineHeight(kHeaderLabelLineHeight);
   }
 
   ~HeaderView() override = default;
diff --git a/ash/system/time/calendar_model.h b/ash/system/time/calendar_model.h
index a50e3f6..21992ac4 100644
--- a/ash/system/time/calendar_model.h
+++ b/ash/system/time/calendar_model.h
@@ -142,6 +142,7 @@
   friend class CalendarUpNextViewPixelTest;
   friend class CalendarUpNextViewTest;
   friend class CalendarViewAnimationTest;
+  friend class CalendarViewAnimationWithJellyEnabledTest;
   friend class CalendarViewEventListViewTest;
   friend class CalendarViewTest;
   friend class CalendarViewWithJellyEnabledTest;
diff --git a/ash/system/time/calendar_view.cc b/ash/system/time/calendar_view.cc
index 0c61a5e..8f94ce3 100644
--- a/ash/system/time/calendar_view.cc
+++ b/ash/system/time/calendar_view.cc
@@ -11,6 +11,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_typography.h"
 #include "ash/public/cpp/ash_view_ids.h"
+#include "ash/public/cpp/metrics_util.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/icon_button.h"
@@ -170,6 +171,14 @@
 constexpr char kShowUpNextViewAnimationHistogram[] =
     "Ash.CalendarView.ShowUpNextView.AnimationSmoothness";
 
+constexpr char kSmoothScrollMonthViewWhenShowingTodaysDateCell[] =
+    "Ash.CalendarView.SmoothScrollToTodaysDateCell.MonthView."
+    "AnimationSmoothness";
+
+constexpr char kSmoothScrollLabelViewWhenShowingTodaysDateCell[] =
+    "Ash.CalendarView.SmoothScrollToTodaysDateCell.LabelView."
+    "AnimationSmoothness";
+
 std::unique_ptr<views::Label> HeaderView(const std::u16string& month) {
   return views::Builder<views::Label>(
              bubble_utils::CreateLabel(TypographyToken::kCrosDisplay7, month,
@@ -1415,6 +1424,7 @@
 }
 
 void CalendarView::ScrollOneMonthWithAnimation(bool scroll_up) {
+  user_has_scrolled_ = true;
   is_scrolling_up_ = scroll_up;
 
   if (event_list_view_) {
@@ -1752,6 +1762,8 @@
     return;
   }
 
+  user_has_scrolled_ = true;
+
   base::AutoReset<bool> disable_header_animation(&should_header_animate_,
                                                  false);
 
@@ -2062,6 +2074,10 @@
   views::AnimationBuilder()
       .SetPreemptionStrategy(
           ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnAborted(base::BindOnce(&CalendarView::OnShowUpNextAnimationEnded,
+                                weak_factory_.GetWeakPtr()))
+      .OnEnded(base::BindOnce(&CalendarView::OnShowUpNextAnimationEnded,
+                              weak_factory_.GetWeakPtr()))
       .Once()
       .SetOpacity(up_next_view_, 0.f)
       .At(base::Milliseconds(0))
@@ -2072,6 +2088,27 @@
                                 gfx::Tween::FAST_OUT_SLOW_IN_2);
 }
 
+void CalendarView::OnShowUpNextAnimationEnded() {
+  // If todays date cell is null or the user has scrolled at all, then don't
+  // auto scroll.
+  if (!calendar_view_controller_->todays_date_cell_view() ||
+      user_has_scrolled_) {
+    return;
+  }
+
+  // If todays date cell is not visible in the `scroll_view_`, i.e. it's hidden
+  // behind the up next view, then smooth scroll to it.
+  if (!scroll_view_->GetBoundsInScreen().Intersects(
+          calendar_view_controller_->todays_date_cell_view()
+              ->GetBoundsInScreen())) {
+    const int offset = calendar_view_controller_->todays_date_cell_view()
+                           ->GetBoundsInScreen()
+                           .bottom() -
+                       calendar_sliding_surface_->GetBoundsInScreen().y();
+    AnimateScrollByOffset(offset);
+  }
+}
+
 void CalendarView::RemoveUpNextView() {
   if (!up_next_view_) {
     return;
@@ -2120,6 +2157,60 @@
   }
 }
 
+void CalendarView::AnimateScrollByOffset(int offset) {
+  if (offset == 0) {
+    return;
+  }
+
+  if (IsAnimating()) {
+    RestoreMonthStatus();
+    scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
+                                   scroll_view_->GetVisibleRect().y() + offset);
+    return;
+  }
+
+  SetShouldMonthsAnimateAndScrollEnabled(false);
+  gfx::Vector2dF moving_up_location = gfx::Vector2dF(0, -offset);
+  gfx::Transform month_moving;
+  month_moving.Translate(moving_up_location);
+
+  auto month_reporter = calendar_metrics::CreateAnimationReporter(
+      current_month_, kSmoothScrollMonthViewWhenShowingTodaysDateCell);
+  auto label_reporter = calendar_metrics::CreateAnimationReporter(
+      current_label_, kSmoothScrollLabelViewWhenShowingTodaysDateCell);
+
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnEnded(base::BindOnce(&CalendarView::OnAnimateScrollByOffsetComplete,
+                              weak_factory_.GetWeakPtr(), offset))
+      .OnAborted(base::BindOnce(&CalendarView::OnAnimateScrollByOffsetComplete,
+                                weak_factory_.GetWeakPtr(), offset))
+      .Once()
+      .SetDuration(kAnimationDurationForClosingEvents)
+      .SetTransform(current_month_, month_moving,
+                    gfx::Tween::ACCEL_20_DECEL_100)
+      .SetTransform(current_label_, month_moving,
+                    gfx::Tween::ACCEL_20_DECEL_100)
+      .SetTransform(next_label_, month_moving, gfx::Tween::ACCEL_20_DECEL_100)
+      .SetTransform(next_month_, month_moving, gfx::Tween::ACCEL_20_DECEL_100)
+      .SetTransform(next_next_label_, month_moving,
+                    gfx::Tween::ACCEL_20_DECEL_100)
+      .SetTransform(next_next_month_, month_moving,
+                    gfx::Tween::ACCEL_20_DECEL_100);
+}
+
+void CalendarView::OnAnimateScrollByOffsetComplete(int offset) {
+  if (is_destroying_) {
+    return;
+  }
+
+  SetShouldMonthsAnimateAndScrollEnabled(true);
+  RestoreMonthStatus();
+  scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
+                                 scroll_view_->GetVisibleRect().y() + offset);
+}
+
 BEGIN_METADATA(CalendarView, views::View)
 END_METADATA
 
diff --git a/ash/system/time/calendar_view.h b/ash/system/time/calendar_view.h
index 37ce223..3c11fe4 100644
--- a/ash/system/time/calendar_view.h
+++ b/ash/system/time/calendar_view.h
@@ -341,6 +341,17 @@
   // Removes the `up_next_view_`.
   void RemoveUpNextView();
 
+  // Callback after the animation showing the up next view has ended.
+  void OnShowUpNextAnimationEnded();
+
+  // Animates scrolling the Calendar `scroll_view_` by the given offset. Uses
+  // layer transforms to mimic scrolling and then sets a final scroll position
+  // on the scroll view to give the illusion of animating scrolling.
+  void AnimateScrollByOffset(int offset);
+
+  // Post animation callback for `AnimateScrollByOffset()`.
+  void OnAnimateScrollByOffsetComplete(int offset);
+
   // Used by the `CalendarUpNextView` to open the event list for today's date.
   void OpenEventListForTodaysDate();
 
@@ -422,6 +433,11 @@
   // If the Calendar View destructor is being called.
   bool is_destroying_ = false;
 
+  // Set to true if the user has scrolled the Calendar at all, either via the
+  // scroll view directly or used the month arrow buttons, in the lifetime of
+  // the CalendarView.
+  bool user_has_scrolled_ = false;
+
   // Timer that fires when the calendar view is settled on, i.e. finished
   // scrolling to, a currently-visible month
   base::RetainingOneShotTimer scrolling_settled_timer_;
diff --git a/ash/system/time/calendar_view_unittest.cc b/ash/system/time/calendar_view_unittest.cc
index 4d40ea1b..7302f03 100644
--- a/ash/system/time/calendar_view_unittest.cc
+++ b/ash/system/time/calendar_view_unittest.cc
@@ -24,6 +24,7 @@
 #include "ash/system/time/calendar_utils.h"
 #include "ash/system/time/calendar_view_controller.h"
 #include "ash/system/tray/detailed_view_delegate.h"
+#include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_bubble.h"
 #include "ash/system/unified/unified_system_tray_view.h"
@@ -43,6 +44,7 @@
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/layer_animation_stopped_waiter.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/controls/button/label_button.h"
@@ -1509,6 +1511,7 @@
     return scroll_view()->GetVerticalScrollBarMode();
   }
 
+  views::Widget* widget() { return widget_.get(); }
   CalendarView* calendar_view() { return calendar_view_; }
 
   views::Label* month_header() { return calendar_view_->header_->header_; }
@@ -2806,4 +2809,217 @@
   EXPECT_EQ(size_t(2), up_next_scroll_contents()->children().size());
 }
 
+class CalendarViewAnimationWithJellyEnabledTest
+    : public CalendarViewAnimationTest {
+ public:
+  CalendarViewAnimationWithJellyEnabledTest() = default;
+  CalendarViewAnimationWithJellyEnabledTest(
+      const CalendarViewAnimationWithJellyEnabledTest&) = delete;
+  CalendarViewAnimationWithJellyEnabledTest& operator=(
+      const CalendarViewAnimationWithJellyEnabledTest&) = delete;
+  ~CalendarViewAnimationWithJellyEnabledTest() override = default;
+
+  void SetUp() override {
+    scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
+    scoped_feature_list_->InitWithFeatures({features::kCalendarJelly}, {});
+    CalendarViewAnimationTest::SetUp();
+  }
+
+  std::unique_ptr<google_apis::calendar::EventList> CreateUpcomingEvents(
+      base::Time date) {
+    const auto start_time = date + base::Minutes(5);
+    const auto end_time = start_time + base::Hours(1);
+    auto event_list = std::make_unique<google_apis::calendar::EventList>();
+    event_list->set_time_zone("Greenwich Mean Time");
+    event_list->InjectItemForTesting(calendar_test_utils::CreateEvent(
+        "id_0", "summary_0", start_time, end_time));
+
+    return event_list;
+  }
+
+  void MockEventsFetched(
+      base::Time date,
+      std::unique_ptr<google_apis::calendar::EventList> event_list) {
+    Shell::Get()->system_tray_model()->calendar_model()->OnEventsFetched(
+        calendar_utils::GetStartOfMonthUTC(date),
+        google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
+  }
+
+ private:
+  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
+};
+
+TEST_F(CalendarViewAnimationWithJellyEnabledTest,
+       ShouldScrollToShowTodaysCell_WhenUpNextViewCoversIt) {
+  auto histogram_tester = std::make_unique<base::HistogramTester>();
+  ui::ScopedAnimationDurationScaleMode test_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  base::Time date;
+  // Pick a date towards the end of the month so up next covers the bottom row.
+  ASSERT_TRUE(base::Time::FromString("25 Apr 2023 10:00 GMT", &date));
+  task_environment()->AdvanceClock(date - base::Time::Now());
+
+  CreateCalendarView();
+  // Force the size of the calendar to be small enough that the bottom row of
+  // date cells will be covered by the up next view.
+  widget()->SetFullscreen(false);
+  widget()->SetSize(gfx::Size(kTrayMenuWidth, 350));
+
+  histogram_tester->ExpectTotalCount(
+      "Ash.CalendarView.SmoothScrollToTodaysDateCell.MonthView."
+      "AnimationSmoothness",
+      0);
+  histogram_tester->ExpectTotalCount(
+      "Ash.CalendarView.SmoothScrollToTodaysDateCell.LabelView."
+      "AnimationSmoothness",
+      0);
+
+  const int initial_scroll_position = scroll_view()->GetVisibleRect().y();
+
+  // Fetch an upcoming event so up next is displayed.
+  MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date),
+                    CreateUpcomingEvents(date));
+
+  // Wait for the show up next animation and smooth scrolling to complete.
+  EXPECT_TRUE(calendar_view()->up_next_view());
+  ui::LayerAnimationStoppedWaiter animation_waiter;
+  animation_waiter.Wait(calendar_view()->up_next_view()->layer());
+  animation_waiter.Wait(current_month()->layer());
+
+  // After the up next view is shown, the scroll view should have moved to
+  // reveal todays date cell.
+  EXPECT_NE(initial_scroll_position, scroll_view()->GetVisibleRect().y());
+  const bool todays_date_cell_is_visible =
+      scroll_view()->GetBoundsInScreen().Intersects(
+          calendar_view()
+              ->calendar_view_controller()
+              ->todays_date_cell_view()
+              ->GetBoundsInScreen());
+  EXPECT_TRUE(todays_date_cell_is_visible);
+
+  // Histograms don't immediately fire after the animation completes, so wait
+  // for that to happen.
+  task_environment()->FastForwardBy(
+      calendar_test_utils::kAnimationSettleDownDuration);
+  histogram_tester->ExpectTotalCount(
+      "Ash.CalendarView.SmoothScrollToTodaysDateCell.MonthView."
+      "AnimationSmoothness",
+      1);
+  histogram_tester->ExpectTotalCount(
+      "Ash.CalendarView.SmoothScrollToTodaysDateCell.LabelView."
+      "AnimationSmoothness",
+      1);
+}
+
+TEST_F(CalendarViewAnimationWithJellyEnabledTest,
+       ShouldNotScrollToShowTodaysCell_WhenUpNextViewDoesNotCoverIt) {
+  ui::ScopedAnimationDurationScaleMode test_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  base::Time date;
+  // Pick a date at the start of the month so up next doesn't cover it.
+  ASSERT_TRUE(base::Time::FromString("1 Apr 2023 10:00 GMT", &date));
+  task_environment()->AdvanceClock(date - base::Time::Now());
+  CreateCalendarView();
+  // Force the size of the calendar to be small enough that the bottom row of
+  // date cells will be covered by the up next view.
+  widget()->SetFullscreen(false);
+  widget()->SetSize(gfx::Size(kTrayMenuWidth, 350));
+
+  const int initial_scroll_position = scroll_view()->GetVisibleRect().y();
+
+  // Fetch an upcoming event so up next is displayed.
+  MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date),
+                    CreateUpcomingEvents(date));
+
+  // Wait for the show up next animation to complete.
+  EXPECT_TRUE(calendar_view()->up_next_view());
+  ui::LayerAnimationStoppedWaiter().Wait(
+      calendar_view()->up_next_view()->layer());
+
+  // After the up next view is shown, the scroll view should not have moved as
+  // the today date cell should remain visible.
+  EXPECT_EQ(initial_scroll_position, scroll_view()->GetVisibleRect().y());
+  const bool todays_date_cell_is_visible =
+      scroll_view()->GetBoundsInScreen().Intersects(
+          calendar_view()
+              ->calendar_view_controller()
+              ->todays_date_cell_view()
+              ->GetBoundsInScreen());
+  EXPECT_TRUE(todays_date_cell_is_visible);
+}
+
+TEST_F(
+    CalendarViewAnimationWithJellyEnabledTest,
+    ShouldNotScrollToShowTodaysCell_WhenUserHasScrolled_AndAnUpcomingEventAppears) {
+  ui::ScopedAnimationDurationScaleMode test_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  base::Time date;
+  // Pick a date towards the end of the month so up next covers the bottom row.
+  ASSERT_TRUE(base::Time::FromString("25 Apr 2023 10:00 GMT", &date));
+  task_environment()->AdvanceClock(date - base::Time::Now());
+  CreateCalendarView();
+  // Force the size of the calendar to be small enough that the bottom row of
+  // date cells will be covered by the up next view.
+  widget()->SetFullscreen(false);
+  widget()->SetSize(gfx::Size(kTrayMenuWidth, 350));
+
+  // Fetch an event that starts in 11 mins so up next isn't showing.
+  MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date),
+                    CreateUpcomingEvents(date + base::Minutes(6)));
+  EXPECT_FALSE(calendar_view()->up_next_view());
+
+  // Scroll up a bit so that today is off the screen.
+  ScrollUpOneMonth();
+  ui::LayerAnimationStoppedWaiter animation_waiter;
+  animation_waiter.Wait(current_month()->layer());
+
+  const int initial_scroll_position = scroll_view()->GetVisibleRect().y();
+
+  // Now advance time so that our upcoming meeting is about to start and up next
+  // appears.
+  task_environment()->FastForwardBy(base::Minutes(5));
+  EXPECT_TRUE(calendar_view()->up_next_view());
+  animation_waiter.Wait(calendar_view()->up_next_view()->layer());
+
+  // After the up next view is shown, the scroll view should not have moved as
+  // the user has previously interacted with the scroll view.
+  EXPECT_EQ(initial_scroll_position, scroll_view()->GetVisibleRect().y());
+}
+
+TEST_F(CalendarViewAnimationWithJellyEnabledTest,
+       ShouldNotScrollToShowTodaysCell_WhenTodaysDateCellIsNull) {
+  ui::ScopedAnimationDurationScaleMode test_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  base::Time date;
+  // Pick a date towards the end of the month so up next covers the bottom row.
+  ASSERT_TRUE(base::Time::FromString("25 Apr 2023 10:00 GMT", &date));
+  task_environment()->AdvanceClock(date - base::Time::Now());
+  CreateCalendarView();
+  // Force the size of the calendar to be small enough that the bottom row of
+  // date cells will be covered by the up next view.
+  widget()->SetFullscreen(false);
+  widget()->SetSize(gfx::Size(kTrayMenuWidth, 350));
+
+  // Fetch an event that starts in 11 mins so up next isn't showing.
+  MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date),
+                    CreateUpcomingEvents(date + base::Minutes(6)));
+  EXPECT_FALSE(calendar_view()->up_next_view());
+
+  // Make todays date cell null. This would be null if the user had scrolled
+  // outside of the 4 months that are on screen.
+  calendar_view()->calendar_view_controller()->set_todays_date_cell_view(
+      nullptr);
+
+  const int initial_scroll_position = scroll_view()->GetVisibleRect().y();
+
+  // Now advance time so that our upcoming meeting is about to start and up next
+  // appears.
+  task_environment()->FastForwardBy(base::Minutes(5));
+  EXPECT_TRUE(calendar_view()->up_next_view());
+
+  // After the up next view is shown, the scroll view should not have moved as
+  // todays date cell is null.
+  EXPECT_EQ(initial_scroll_position, scroll_view()->GetVisibleRect().y());
+}
+
 }  // namespace ash
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 91ac4821..255cb77 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -617,8 +617,6 @@
   views::View::SetVisible(GetEffectiveVisibility());
 }
 
-void TrayBackgroundView::BubbleResized(const TrayBubbleView* bubble_view) {}
-
 void TrayBackgroundView::OnAnyBubbleVisibilityChanged(
     views::Widget* bubble_widget,
     bool visible) {}
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index b75344a..0a382b94 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -140,9 +140,6 @@
   // user logs in.
   virtual void HandleLocaleChange() = 0;
 
-  // Called when the bubble is resized.
-  virtual void BubbleResized(const TrayBubbleView* bubble_view);
-
   // Updates this bubble about visibility change of *ANY* tray bubble
   // including itself.
   // `bubble_widget` is the bubble with visibility change. Please note that it
diff --git a/ash/system/tray/tray_bubble_wrapper.cc b/ash/system/tray/tray_bubble_wrapper.cc
index 0abc37c..c0fc21c 100644
--- a/ash/system/tray/tray_bubble_wrapper.cc
+++ b/ash/system/tray/tray_bubble_wrapper.cc
@@ -89,12 +89,6 @@
   tray_->HideBubbleWithView(bubble_view_);  // May destroy |bubble_view_|
 }
 
-void TrayBubbleWrapper::OnWidgetBoundsChanged(views::Widget* widget,
-                                              const gfx::Rect& new_bounds) {
-  DCHECK_EQ(bubble_widget_, widget);
-  tray_->BubbleResized(bubble_view_);
-}
-
 void TrayBubbleWrapper::OnWindowActivated(ActivationReason reason,
                                           aura::Window* gained_active,
                                           aura::Window* lost_active) {
diff --git a/ash/system/tray/tray_bubble_wrapper.h b/ash/system/tray/tray_bubble_wrapper.h
index 8fea9f7d..13fe4b5 100644
--- a/ash/system/tray/tray_bubble_wrapper.h
+++ b/ash/system/tray/tray_bubble_wrapper.h
@@ -42,8 +42,6 @@
 
   // views::WidgetObserver overrides:
   void OnWidgetDestroying(views::Widget* widget) override;
-  void OnWidgetBoundsChanged(views::Widget* widget,
-                             const gfx::Rect& new_bounds) override;
 
   // ::wm::ActivationChangeObserver overrides:
   void OnWindowActivated(ActivationReason reason,
diff --git a/ash/user_education/user_education_ping_controller.cc b/ash/user_education/user_education_ping_controller.cc
index 9e33cecf..359de96 100644
--- a/ash/user_education/user_education_ping_controller.cc
+++ b/ash/user_education/user_education_ping_controller.cc
@@ -7,15 +7,24 @@
 #include "ash/public/cpp/style/dark_light_mode_controller.h"
 #include "ash/user_education/user_education_class_properties.h"
 #include "base/check_op.h"
-#include "base/memory/raw_ptr.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
+#include "base/time/time.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
 #include "ui/compositor/layer_owner.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/transform_util.h"
+#include "ui/views/animation/animation_builder.h"
+#include "ui/views/animation/animation_sequence_block.h"
 #include "ui/views/view.h"
 #include "ui/views/view_observer.h"
+#include "ui/views/view_tracker.h"
 
 namespace ash {
 namespace {
@@ -23,6 +32,9 @@
 // The singleton instance owned by the `UserEducationController`.
 UserEducationPingController* g_instance = nullptr;
 
+// Animation.
+constexpr auto kAnimationRepeatCount = 3u;
+
 // Helpers ---------------------------------------------------------------------
 
 // Comparable to `gfx::Rect::ClampToCenteredSize()` except max size is used
@@ -48,6 +60,10 @@
   return inset_rect;
 }
 
+gfx::Transform ScaleAboutCenter(const ui::Layer* layer, float scale) {
+  return gfx::GetScaleTransform(gfx::Rect(layer->size()).CenterPoint(), scale);
+}
+
 }  // namespace
 
 // UserEducationPingController::Ping -------------------------------------------
@@ -55,10 +71,10 @@
 class UserEducationPingController::Ping : public views::ViewObserver {
  public:
   explicit Ping(views::View* view)
-      : view_(view),
+      : view_tracker_(view),
         parent_(std::make_unique<ui::Layer>(ui::LAYER_NOT_DRAWN)),
         child_(std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR)) {
-    CHECK(view_->layer());
+    CHECK(view->layer());
 
     // Name ping layers so that they are easy to identify in debugging/testing.
     parent_.layer()->SetName(kPingParentLayerName);
@@ -66,34 +82,60 @@
 
     // Configure `child_` layer properties.
     child_.layer()->SetFillsBoundsOpaquely(false);
-    OnViewThemeChanged(view_);
+    OnViewThemeChanged(view);
 
-    // Add ping layers to the layer tree below `view_` layers. This is done so
-    // that the ping appears to be beneath the associated `view_` to the user.
+    // Add ping layers to the layer tree below `view` layers. This is done so
+    // that the ping appears to be beneath the associated `view` to the user.
     parent_.layer()->Add(child_.layer());
-    view_->AddLayerToRegion(parent_.layer(), views::LayerRegion::kBelow);
-
-    // Observe `view_` to keep ping layers in sync.
-    view_observation_.Observe(view_);
-
-    // Initialize.
-    Update();
+    view->AddLayerToRegion(parent_.layer(), views::LayerRegion::kBelow);
   }
 
   Ping(const Ping&) = delete;
   Ping& operator=(const Ping&) = delete;
   ~Ping() override = default;
 
-  // Returns the `view_` associated with this ping.
-  const views::View* view() const { return view_; }
+  // Returns the view associated with this ping. Note that this may return
+  // `nullptr` once the associated view has been destroyed.
+  const views::View* view() const { return view_tracker_.view(); }
+
+  // Starts the ping animation, invoking exactly one of either `ended_callback`
+  // or `aborted_callback` on animation completion. Note that it is safe to
+  // destroy `this` from either callback.
+  void Start(base::OnceClosure ended_callback,
+             base::OnceClosure aborted_callback) {
+    // Prohibit calling `Start()` when a ping animation is already in progress
+    // or after the associated `view()` has been destroyed.
+    CHECK(ended_callback_.is_null());
+    CHECK(aborted_callback_.is_null());
+    CHECK(view_tracker_.view());
+
+    // Cache and validate callbacks.
+    ended_callback_ = std::move(ended_callback);
+    aborted_callback_ = std::move(aborted_callback);
+    CHECK(!ended_callback_.is_null());
+    CHECK(!aborted_callback_.is_null());
+
+    // Observe the associated `view()` while the ping animation is in progress
+    // to keep ping layers in sync.
+    view_observation_.Observe(view_tracker_.view());
+
+    // Start the ping animation.
+    Update();
+  }
 
  private:
   // views::ViewObserver:
   void OnViewBoundsChanged(views::View* view) override {
-    // Update ping to stay in sync with `view_` bounds.
+    // Update ping to stay in sync with `view` bounds.
     Update();
   }
 
+  void OnViewIsDeleting(views::View* view) override {
+    // There's nothing to ping once `view` is deleted. Note that aborting the
+    // ping animation may result in the destruction of `this`.
+    Abort();
+  }
+
   void OnViewPropertyChanged(views::View* view,
                              const void* key,
                              int64_t old_value) override {
@@ -110,46 +152,153 @@
                                  : SK_ColorBLACK);
   }
 
-  // TODO(http://b/281536915): Implement animation.
-  // Updates the ping for the current state.
+  void OnViewVisibilityChanged(views::View* view,
+                               views::View* starting_view) override {
+    // There's nothing to ping once `view` is no longer drawn. Note that
+    // aborting the ping animation may result in the destruction of `this`.
+    if (!view->IsDrawn()) {
+      Abort();
+    }
+  }
+
+  // Aborts the ping animation, invoking the `aborted_callback_`. Note that
+  // aborting the ping animation may result in the destruction of `this`.
+  void Abort() {
+    // Prohibit calling when a ping animation is not in progress.
+    CHECK(!ended_callback_.is_null());
+    CHECK(!aborted_callback_.is_null());
+
+    // Abort the ping animation. May result in destruction of `this`.
+    EndOrAbort(std::move(aborted_callback_));
+  }
+
+  // Ends the ping animation, invoking the `ended_callback_`. Note that ending
+  // the ping animation may result in the destruction of `this`.
+  void End() {
+    // Prohibit calling when a ping animation is not in progress.
+    CHECK(!ended_callback_.is_null());
+    CHECK(!aborted_callback_.is_null());
+
+    // End the ping animation. May result in destruction of `this`.
+    EndOrAbort(std::move(ended_callback_));
+  }
+
+  // Ends/aborts the ping animation, invoking the appropriate callback. Note
+  // that ending/aborting the ping animation may result in the destruction of
+  // `this`.
+  void EndOrAbort(base::OnceClosure ended_or_aborted_callback) {
+    // Prohibit calling when a ping animation is not in progress.
+    CHECK(ended_callback_.is_null() != aborted_callback_.is_null());
+
+    // Prevent callbacks from running when stopping the ping animation.
+    weak_ptr_factory_.InvalidateWeakPtrs();
+    child_.layer()->GetAnimator()->StopAnimating();
+
+    // We no longer need to observe the associated `view()` to keep ping layers
+    // in sync once the ping animation has ended/aborted.
+    view_observation_.Reset();
+
+    // Reset both callbacks so that whichever does not correspond to the
+    // `ended_or_aborted_callback` invoked by this method will never be invoked.
+    // Note that whichever callback will be invoked has already been moved.
+    ended_callback_.Reset();
+    aborted_callback_.Reset();
+
+    // May result in destruction of `this`.
+    std::move(ended_or_aborted_callback).Run();
+  }
+
+  // Updates ping layers for the current state. Note that this causes preemption
+  // of any preexisting ping animation and the start of a new ping animation.
   void Update() {
+    // Prohibit calling `Update()` until `Start()` has been called. This should
+    // only be possible prior to destruction of the associated `view()`.
+    CHECK(!ended_callback_.is_null());
+    CHECK(!aborted_callback_.is_null());
+    CHECK(view());
+
+    // Prevent animation callbacks from running on preempted animations.
+    weak_ptr_factory_.InvalidateWeakPtrs();
+
+    // Cache ping layers.
     ui::Layer* const parent = parent_.layer();
     ui::Layer* const child = child_.layer();
 
-    // Match `parent` bounds to that of the associated `view_` layer. Because
-    // `parent` was added as a top-level layer beneath the `view_` layer, they
+    // Match `parent` bounds to that of the associated `view()` layer. Because
+    // `parent` was added as a top-level layer beneath the `view()` layer, they
     // are siblings and will share the same origin even if not explicitly set.
-    parent->SetBounds(view_->layer()->bounds());
+    parent->SetBounds(view()->layer()->bounds());
 
     // Set `child` bounds based on the size and center point of its `parent`.
     // Because `child` was added to the `parent` layer, it is not a top-level
-    // layer beneath the `view_` layer and will therefore not be forced to share
-    // the same origin. Note that `child` bounds respect ping insets and are
-    // always square.
+    // layer beneath the `view()` layer and will therefore not be forced to
+    // share the same origin. Note that `child` bounds respect ping insets and
+    // are always square.
     gfx::Rect bounds(parent->size());
-    bounds = Inset(bounds, view_->GetProperty(kPingInsetsKey));
+    bounds = Inset(bounds, view()->GetProperty(kPingInsetsKey));
     bounds = EnlargeToCenteredSize(bounds, EnlargeToSquare(bounds.size()));
     child->SetBounds(bounds);
 
     // Clip `child` to a circle.
     CHECK_EQ(bounds.width(), bounds.height());
     child->SetRoundedCornerRadius(gfx::RoundedCornersF(bounds.width() / 2.f));
+
+    // Invoke the appropriate callback on ping animation ended/aborted. Note
+    // that these callbacks will not be run for preempted animations.
+    views::AnimationBuilder builder;
+    builder
+        .OnAborted(base::BindOnce(&Ping::Abort, weak_ptr_factory_.GetWeakPtr()))
+        .OnEnded(base::BindOnce(&Ping::End, weak_ptr_factory_.GetWeakPtr()))
+        .SetPreemptionStrategy(ui::LayerAnimator::PreemptionStrategy::
+                                   IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+
+    // NOTE: This could alternatively have been implemented using a repeating
+    // animation, but `OnWillRepeat()` callbacks are not run when the first
+    // animation sequence block has zero duration, see http://crbug.com/1443543.
+    views::AnimationSequenceBlock* block = &builder.Once();
+    for (size_t i = 0u; i < kAnimationRepeatCount; ++i) {
+      if (i > 0u) {
+        block = &block->Then();
+      }
+      block = &block->SetDuration(base::TimeDelta())
+                   .SetOpacity(child, 0.5f)
+                   .SetTransform(child, ScaleAboutCenter(child, 0.f))
+                   .Then()
+                   .SetDuration(base::Seconds(2))
+                   .SetOpacity(child, 0.f, gfx::Tween::ACCEL_0_80_DECEL_80)
+                   .SetTransform(child, ScaleAboutCenter(child, 3.f),
+                                 gfx::Tween::ACCEL_0_40_DECEL_100);
+    }
   }
 
-  // Pointer to the view associated with this ping.
-  const raw_ptr<views::View> view_;
+  // Tracks the `view()` associated with this ping to prevent UAF, since `this`
+  // class does not require that the associated `view()` will outlive it.
+  views::ViewTracker view_tracker_;
 
-  // Owners for the ping layers which are added to the layer tree below `view_`
+  // Owners for the ping layers which are added to the layer tree below `view()`
   // layers. This is done so that the ping appears to be beneath the associated
-  // `view_` to the user. Note that top-level layers added below view layers
+  // `view()` to the user. Note that top-level layers added below view layers
   // always share the same origin as the view layer, so a `child_` layer is
   // needed in order to achieve desired bounds for the ping.
   ui::LayerOwner parent_;
   ui::LayerOwner child_;
 
-  // Observe `view_` in order to keep the associated ping in sync.
+  // Callback which is invoked when the ping animation ends. Invoking this
+  // callback may result in the destruction of `this`.
+  base::OnceClosure ended_callback_;
+
+  // Callback which is invoked when the ping animation aborts. Invoking this
+  // callback may result in the destruction of `this`.
+  base::OnceClosure aborted_callback_;
+
+  // Observes the associated `view()` while a ping animation is in progress in
+  // order to keep ping layers in sync.
   base::ScopedObservation<views::View, views::ViewObserver> view_observation_{
       this};
+
+  // Weak pointer factory whose weak pointers are invalidated during animation
+  // preemption to prevent ended/aborted callbacks from being run prematurely.
+  base::WeakPtrFactory<Ping> weak_ptr_factory_{this};
 };
 
 // UserEducationPingController -------------------------------------------------
@@ -169,6 +318,7 @@
   return g_instance;
 }
 
+// TODO(http://b/281536915): Expose ability to set ended/aborted callbacks.
 bool UserEducationPingController::CreatePing(PingId ping_id,
                                              views::View* view) {
   // A ping is not created if a ping already exists for `ping_id` or `view`.
@@ -183,8 +333,21 @@
     return false;
   }
 
-  // Create a ping and indicate success.
-  pings_by_id_[ping_id] = std::make_unique<Ping>(view);
+  // Create a ping for `view`.
+  auto entry = pings_by_id_.emplace(ping_id, std::make_unique<Ping>(view));
+
+  // Destroy the ping when its animation is ended/aborted. Note that this also
+  // ensures only one of either `ended_callback` or `aborted_callback` is run.
+  auto [ended_callback, aborted_callback] = base::SplitOnceCallback(
+      base::BindOnce([](UserEducationPingController* self,
+                        PingId ping_id) { self->pings_by_id_.erase(ping_id); },
+                     base::Unretained(this), ping_id));
+
+  // Start the ping animation.
+  entry.first->second->Start(std::move(ended_callback),
+                             std::move(aborted_callback));
+
+  // Indicate success.
   return true;
 }
 
diff --git a/ash/user_education/user_education_ping_controller.h b/ash/user_education/user_education_ping_controller.h
index aa1caf0..ac96f938 100644
--- a/ash/user_education/user_education_ping_controller.h
+++ b/ash/user_education/user_education_ping_controller.h
@@ -47,7 +47,8 @@
  private:
   class Ping;
 
-  // Owns pings, mapping them to their associated IDs.
+  // Owns pings, mapping them to their associated IDs. Note that pings are
+  // removed from the map on ping animation ended/aborted.
   std::map<PingId, std::unique_ptr<Ping>> pings_by_id_;
 };
 
diff --git a/ash/user_education/user_education_ping_controller_unittest.cc b/ash/user_education/user_education_ping_controller_unittest.cc
index eefd4f4..62ca256 100644
--- a/ash/user_education/user_education_ping_controller_unittest.cc
+++ b/ash/user_education/user_education_ping_controller_unittest.cc
@@ -12,11 +12,19 @@
 #include "ash/user_education/user_education_ash_test_base.h"
 #include "ash/user_education/user_education_class_properties.h"
 #include "ash/user_education/user_education_types.h"
+#include "base/barrier_closure.h"
+#include "base/functional/callback_helpers.h"
+#include "base/functional/function_ref.h"
+#include "base/test/gmock_callback_support.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_future.h"
+#include "base/time/time.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/compositor/layer.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/layer_observer.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/views/metadata/view_factory.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
@@ -25,12 +33,14 @@
 namespace {
 
 // Aliases.
+using ::base::test::RunClosure;
 using ::testing::AllOf;
 using ::testing::Conditional;
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::Mock;
+using ::testing::NiceMock;
 using ::testing::Property;
 
 // Helpers ---------------------------------------------------------------------
@@ -45,6 +55,14 @@
   return insets ? Inset(rect, *insets) : rect;
 }
 
+// MockLayerObserver -----------------------------------------------------------
+
+class MockLayerObserver : public ui::LayerObserver {
+ public:
+  // ui::LayerObserver:
+  MOCK_METHOD(void, LayerDestroyed, (ui::Layer * layer), (override));
+};
+
 }  // namespace
 
 // UserEducationPingControllerTest ---------------------------------------------
@@ -126,6 +144,49 @@
             Eq(view->layer())));
   }
 
+  // Asserts that a ping exists for `view()` and that the ping is destroyed by
+  // invoking the specified `destroy_function`. A ping is considered destroyed
+  // for `view()` when its associated ping layers are destroyed. The optionally
+  // specified `ping_layers_destroyed_callback` will be run immediately after
+  // destruction of all ping layers.
+  void AssertPingDestruction(
+      base::FunctionRef<void()> destroy_function,
+      base::OnceClosure ping_layers_destroyed_callback = base::DoNothing()) {
+    // Assert that a ping exists for `view()`.
+    ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+
+    // Observe ping layers.
+    NiceMock<MockLayerObserver> layer_observer;
+    view()->GetLayersInOrder()[0]->AddObserver(&layer_observer);
+    view()->GetLayersInOrder()[0]->children()[0]->AddObserver(&layer_observer);
+
+    // Create a barrier closure to invoke `ping_layers_destroyed_callback` once
+    // all ping layers have been destroyed.
+    base::RepeatingCallback ping_layer_destroyed_callback =
+        base::BarrierClosure(2u, std::move(ping_layers_destroyed_callback));
+
+    // Expect parent ping layer destruction and invoke
+    // `ping_layer_destroyed_callback` when that occurs.
+    EXPECT_CALL(layer_observer,
+                LayerDestroyed(Property(
+                    &ui::Layer::name,
+                    Eq(UserEducationPingController::kPingParentLayerName))))
+        .WillOnce(RunClosure(ping_layer_destroyed_callback));
+
+    // Expect child ping layer destruction and invoke
+    // `ping_layer_destroyed_callback` when that occurs.
+    EXPECT_CALL(layer_observer,
+                LayerDestroyed(Property(
+                    &ui::Layer::name,
+                    Eq(UserEducationPingController::kPingChildLayerName))))
+        .WillOnce(RunClosure(ping_layer_destroyed_callback));
+
+    // Invoked `destroy_function` and expect the ping has been destroyed.
+    destroy_function();
+    Mock::VerifyAndClearExpectations(&layer_observer);
+    ExpectNoPing();
+  }
+
  private:
   // UserEducationPingControllerTest:
   void SetUp() override {
@@ -140,6 +201,13 @@
     widget_->SetContentsView(
         views::Builder<views::View>().SetPaintToLayer().Build());
     widget_->CenterWindow(gfx::Size(100, 100));
+
+    // Use a non-zero animation duration so that an interval exists between
+    // ping creation and when we are able to check for ping existence since
+    // pings are automatically destroyed on animation ended/aborted.
+    scoped_animation_duration_scale_mode_ =
+        std::make_unique<ui::ScopedAnimationDurationScaleMode>(
+            ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
   }
 
   // Used to enable user education features which are required for existence of
@@ -148,10 +216,45 @@
 
   // Owns the `view()` to ping.
   std::unique_ptr<views::Widget> widget_;
+
+  // Used to force a non-zero animation duration.
+  std::unique_ptr<ui::ScopedAnimationDurationScaleMode>
+      scoped_animation_duration_scale_mode_;
 };
 
 // Tests -----------------------------------------------------------------------
 
+// Verifies that pings are destroyed if animations are aborted.
+TEST_F(UserEducationPingControllerTest, Abort) {
+  ExpectNoPing();
+
+  EXPECT_TRUE(CreatePing());
+  ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+
+  ASSERT_NO_FATAL_FAILURE(AssertPingDestruction([&]() {
+    view()
+        ->GetLayersInOrder()[0]
+        ->children()[0]
+        ->GetAnimator()
+        ->StopAnimating();
+  }));
+}
+
+// Verifies that pings are destroyed if animations are ended.
+TEST_F(UserEducationPingControllerTest, End) {
+  ExpectNoPing();
+
+  EXPECT_TRUE(CreatePing());
+  ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+
+  // Note that `ping_animation_ended_future` will wait until all ping layers
+  // have been destroyed due to the ping animation having ended.
+  base::test::TestFuture<void> ping_animation_ended_future;
+  ASSERT_NO_FATAL_FAILURE(AssertPingDestruction(
+      [&]() { EXPECT_TRUE(ping_animation_ended_future.Wait()); },
+      ping_animation_ended_future.GetCallback()));
+}
+
 // Verifies that a single view cannot be pinged multiple times concurrently but
 // that multiple concurrent pings may exist for distinct views.
 TEST_F(UserEducationPingControllerTest, MultipleConcurrent) {
@@ -183,6 +286,23 @@
   ASSERT_NO_FATAL_FAILURE(AssertPingProperties(another_view));
 }
 
+// Verifies that the same `view()` can be pinged multiple times sequentially.
+TEST_F(UserEducationPingControllerTest, MultipleSequential) {
+  ExpectNoPing();
+
+  {
+    // Use a zero duration animation scale mode so that the first ping animation
+    // will end instantaneously without requiring for us to wait.
+    ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+        ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+    EXPECT_TRUE(CreatePing());
+    ExpectNoPing();
+  }
+
+  EXPECT_TRUE(CreatePing());
+  ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+}
+
 // Verifies that a `view()` cannot be pinged if not drawn.
 TEST_F(UserEducationPingControllerTest, NotIsDrawn) {
   view()->SetVisible(false);
@@ -204,6 +324,20 @@
   ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
 }
 
+// Verifies that pings are destroyed when the associated `view()` is deleting.
+TEST_F(UserEducationPingControllerTest, OnViewIsDeleting) {
+  ExpectNoPing();
+
+  EXPECT_TRUE(CreatePing());
+  ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+
+  // Note that setting a new contents view will result in the destruction of
+  // the original contents `view()` associated with the ping.
+  ASSERT_NO_FATAL_FAILURE(AssertPingDestruction([&]() {
+    view()->GetWidget()->SetContentsView(views::Builder<views::View>().Build());
+  }));
+}
+
 // Verifies that pings will update bounds when ping insets are updated for the
 // associated `view()`.
 TEST_F(UserEducationPingControllerTest, OnViewPropertyChanged) {
@@ -229,4 +363,15 @@
   ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
 }
 
+// Verifies that pings are destroyed if `view()` stops being visible.
+TEST_F(UserEducationPingControllerTest, OnViewVisibilityChanged) {
+  ExpectNoPing();
+
+  EXPECT_TRUE(CreatePing());
+  ASSERT_NO_FATAL_FAILURE(AssertPingProperties());
+
+  ASSERT_NO_FATAL_FAILURE(
+      AssertPingDestruction([&]() { view()->SetVisible(false); }));
+}
+
 }  // namespace ash
diff --git a/ash/webui/camera_app_ui/resources.h b/ash/webui/camera_app_ui/resources.h
index 2d89e8c6..10d3071 100644
--- a/ash/webui/camera_app_ui/resources.h
+++ b/ash/webui/camera_app_ui/resources.h
@@ -61,6 +61,11 @@
      IDS_EXPERT_ENABLE_FULL_SIZED_VIDEO_SNAPSHOT},
     {"expert_enable_ptz_for_builtin", IDS_EXPERT_ENABLE_PTZ_FOR_BUILTIN},
     {"expert_multistream_recording", IDS_EXPERT_MULTISTREAM_RECORDING},
+    {"expert_multistream_recording_chrome",
+     IDS_EXPERT_MULTISTREAM_RECORDING_CHROME},
+    {"expert_multistream_recording_disabled",
+     IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED},
+    {"expert_multistream_recording_hal", IDS_EXPERT_MULTISTREAM_RECORDING_HAL},
     {"expert_mode_button", IDS_EXPERT_MODE_BUTTON},
     {"expert_preview_metadata", IDS_EXPERT_PREVIEW_METADATA},
     {"expert_print_performance_logs", IDS_EXPERT_PRINT_PERFORMANCE_LOGS},
diff --git a/ash/webui/camera_app_ui/resources/css/colors_default.css b/ash/webui/camera_app_ui/resources/css/colors_default.css
index 11bb0fd7..f2b9390 100644
--- a/ash/webui/camera_app_ui/resources/css/colors_default.css
+++ b/ash/webui/camera_app_ui/resources/css/colors_default.css
@@ -8,7 +8,31 @@
  * enabled by default.
  */
 :root {
+  /* Standard CrOS styles */
+  --blue-300-rgb: 138, 180, 248;
+  --blue-300: rgb(var(--blue-300-rgb));
+  --blue-500: rgb(66, 133, 244);
+  --blue-600: rgb(26, 115, 232);
+  --red-300-rgb: 242, 139, 130;
+  --red-300: rgb(var(--red-300-rgb));
+  --red-600: rgb(217, 48, 37);
+  --grey-100: rgb(241, 243, 244);
+  --grey-200-rgb: 233, 234, 237;
+  --grey-200: rgb(var(--grey-200-rgb));
+  --grey-400: rgb(189, 193, 198);
+  --grey-500: rgb(154, 160, 166);
+  --grey-600: rgb(128, 134, 139);
+  --grey-700: rgb(95, 99, 104);
+  --grey-900-rgb: 32, 33, 36;
+  --grey-900: rgb(var(--grey-900-rgb));
+  --yellow-300: rgb(253, 214, 99);
+
+  /* Note that in M2 blue-0 is lightest and blue-1000 is darkest, but in M3
+   * blue0 is darkest and blue100 is lightest. */
+  --cros-ref-blue40: var(--blue-600);
   --cros-ref-error40: #f44336;
+  --cros-ref-primary100: white;
+  --cros-ref-red40: var(--red-600);
   --cros-sys-app_base: var(--grey-900);
   --cros-sys-base_elevated: var(--grey-900);
   --cros-sys-error_container: rgba(var(--red-300-rgb), 0.3);
@@ -25,8 +49,12 @@
   --cros-sys-on_primary_container: var(--grey-200);
   --cros-sys-on_surface: var(--grey-200);
   --cros-sys-primary: var(--blue-300);
+  --cros-sys-primary_container: rgb(24, 24, 24);
+  --cros-sys-progress: var(--blue-300);
+  --cros-sys-ripple_primary: white;
   --cros-sys-scrim: rgba(0, 0, 0, 0.6);
   --cros-sys-scrim2: rgba(0, 0, 0, 0.6);
+  --cros-sys-scrollbar: rgba(255, 255, 255, 0.2);
   --cros-sys-secondary: var(--grey-400);
   --cros-sys-secondary_container: var(--grey-600);
   --cros-sys-separator: rgba(255, 255, 255, 0.14);
@@ -188,3 +216,7 @@
 .review-views .button-group button[i18n-text=label_share] svg-wrapper {
   color: var(--blue-300);
 }
+
+.review-frame {
+  border: 1px solid rgba(var(--grey-200-rgb), 0.38);
+}
diff --git a/ash/webui/camera_app_ui/resources/css/custom_toast.css b/ash/webui/camera_app_ui/resources/css/custom_toast.css
index 4e430b6af..4fffd63 100644
--- a/ash/webui/camera_app_ui/resources/css/custom_toast.css
+++ b/ash/webui/camera_app_ui/resources/css/custom_toast.css
@@ -175,7 +175,7 @@
 .ripple {
   --duration: 2s;
 
-  background: white;
+  background: var(--cros-sys-ripple_primary);
   border-radius: var(--border-radius-rounded-with-short-side);
   opacity: 0;
   pointer-events: none;
diff --git a/ash/webui/camera_app_ui/resources/css/flash.css b/ash/webui/camera_app_ui/resources/css/flash.css
index b19592e6..169246ac 100644
--- a/ash/webui/camera_app_ui/resources/css/flash.css
+++ b/ash/webui/camera_app_ui/resources/css/flash.css
@@ -3,8 +3,7 @@
  * found in the LICENSE file. */
 
 body.view-flash #view-flash {
-  backdrop-filter: blur(30px);
-  background: rgba(var(--grey-900-rgb), 0.8);
+  background: var(--cros-sys-scrim);
   transition: opacity var(--moderate2-duration);
 }
 
@@ -15,13 +14,13 @@
 }
 
 #processing-indicator .icon {
-  background-image: url(/images/document_mode_spinner.svg);
+  color: var(--cros-sys-progress);
   height: 40px;
   width: 40px;
 }
 
 #processing-indicator .msg {
-  color: var(--grey-200);
+  color: var(--cros-sys-on_surface);
   font: 14px/20px Roboto;
   margin-top: 16px;
 }
@@ -36,6 +35,8 @@
 }
 
 body.gif-capture-post-processing.view-flash #processing-indicator {
-  animation: show-processing-indicator-with-delay var(--fast1-duration) ease-in 500ms 1 normal forwards;
+  animation:
+      show-processing-indicator-with-delay
+      var(--fast1-duration) ease-in 500ms 1 normal forwards;
   opacity: 0;
 }
diff --git a/ash/webui/camera_app_ui/resources/css/inkdrop.css b/ash/webui/camera_app_ui/resources/css/inkdrop.css
index 88c67e2e..a4d02942 100644
--- a/ash/webui/camera_app_ui/resources/css/inkdrop.css
+++ b/ash/webui/camera_app_ui/resources/css/inkdrop.css
@@ -7,7 +7,7 @@
 }
 
 .inkdrop .inkdrop-ripple {
-  background: white;
+  background: var(--cros-sys-ripple_primary);
   border-radius: 50%;
   height: 0;
   left: var(--drop-x);
diff --git a/ash/webui/camera_app_ui/resources/css/main.css b/ash/webui/camera_app_ui/resources/css/main.css
index 09cb99ce..4df5e35 100644
--- a/ash/webui/camera_app_ui/resources/css/main.css
+++ b/ash/webui/camera_app_ui/resources/css/main.css
@@ -3,24 +3,6 @@
  * found in the LICENSE file. */
 
 :root {
-  /* Standard CrOS styles */
-  --blue-300-rgb: 138, 180, 248;
-  --blue-300: rgb(var(--blue-300-rgb));
-  --blue-500: rgb(66, 133, 244);
-  --blue-600: rgb(26, 115, 232);
-  --red-300-rgb: 242, 139, 130;
-  --red-300: rgb(var(--red-300-rgb));
-  --grey-100: rgb(241, 243, 244);
-  --grey-200-rgb: 233, 234, 237;
-  --grey-200: rgb(var(--grey-200-rgb));
-  --grey-400: rgb(189, 193, 198);
-  --grey-500: rgb(154, 160, 166);
-  --grey-600: rgb(128, 134, 139);
-  --grey-700: rgb(95, 99, 104);
-  --grey-900-rgb: 32, 33, 36;
-  --grey-900: rgb(var(--grey-900-rgb));
-  --yellow-300: rgb(253, 214, 99);
-
   --fast1-duration: 100ms;
   --fast2-duration: 200ms;
   --moderate1-duration: 250ms;
@@ -278,7 +260,7 @@
 }
 
 #modes-group::-webkit-scrollbar-thumb {
-  background: rgba(255, 255, 255, 0.2);
+  background: var(--cros-sys-scrollbar);
   border-radius: 2px;
   height: auto;
   width: auto;
@@ -385,7 +367,8 @@
 
 :is(#start-takephoto, #video-snapshot) svg-wrapper {
   color: var(--cros-sys-inverse_surface);
-  --secondary-color: white;
+  /* TODO(pihsun): Use cros.sys.white when it's available. */
+  --secondary-color: var(--cros-ref-primary100);
 }
 
 :is(#start-takephoto, #video-snapshot, #stop-takephoto):enabled:hover::after {
@@ -411,6 +394,16 @@
   --secondary-color: var(--cros-sys-secondary_container);
 }
 
+#recordvideo-container {
+  display: relative;
+  /*
+   * overflow: visible is needed since the progress bar for gif mode is larger
+   * than the button. This can't be set on the button itself since the ripple
+   * effect should be contained inside the button.
+   */
+  overflow: visible;
+}
+
 #recordvideo {
   --size: 60px;
 }
@@ -431,7 +424,8 @@
   --square-delay: 45ms;
   --square-size: calc(100% / 3);
 
-  background: white;
+  /* TODO(pihsun): Use cros.sys.white when it's available. */
+  background: var(--cros-ref-primary100);
   border-radius: 50%;
   height: var(--size);
   position: relative;
@@ -476,7 +470,8 @@
 }
 
 #recordvideo .white-square {
-  background: white;
+  /* TODO(pihsun): Use cros.sys.white when it's available. */
+  background: var(--cros-ref-primary100);
   border-radius: 2px;
   height: 0;
   left: 50%;
@@ -554,7 +549,7 @@
 }
 
 #timer-tick-msg {
-  color: white;
+  color: var(--cros-sys-on_surface);
   font-size: 72px;
   visibility: hidden;
 }
@@ -591,10 +586,10 @@
 }
 
 #gallery-enter {
-  background-color: rgba(24, 24, 24, 1);
-  height: var(--big-icon);
+  border: 2px var(--cros-sys-primary_container) solid;
+  height: calc(var(--big-icon) - 4px);
   overflow: hidden;
-  width: var(--big-icon);
+  width: calc(var(--big-icon) - 4px);
 }
 
 #gallery-enter>img {
@@ -907,9 +902,9 @@
 }
 
 #expert-controls .title {
-  background-color: rgb(0, 128, 0);
+  background-color: var(--cros-sys-primary);
   border-radius: 3px;
-  color: white;
+  color: var(--cros-sys-on_primary);
   display: inline;
   font-weight: bold;
   padding: 1px 3px 1px 3px;
@@ -921,23 +916,24 @@
 }
 
 #expert-controls .metadata-row:not(.mode-on) .title {
-  background-color: rgba(255, 255, 255, 0.7);
-  color: grey;
+  background: var(--cros-sys-inverse_surface);
+  color: var(--cros-sys-inverse_on_surface);
 }
 
 #expert-controls .value {
-  background-color: rgba(255, 255, 255, 0.3);
+  background: var(--cros-sys-base_elevated);
   border-radius: 3px;
+  color: var(--cros-sys-on_surface);
   display: inline;
   padding: 1px 3px 1px 3px;
 }
 
-#preview-wb-gain-red {
-  color: red;
+#expert-controls #preview-wb-gain-red {
+  background: var(--cros-ref-red40);
 }
 
-#preview-wb-gain-blue {
-  color: blue;
+#expert-controls #preview-wb-gain-blue {
+  background: var(--cros-ref-blue40);
 }
 
 #preview-grid {
@@ -972,8 +968,8 @@
 }
 
 #preview-grid-horizontal {
-  border-bottom: 1px solid white;
-  border-top: 1px solid white;
+  border-bottom: 1px solid var(--cros-ref-primary100);
+  border-top: 1px solid var(--cros-ref-primary100);
   height: 100%;
   left: 0;
   position: absolute;
@@ -987,7 +983,7 @@
 }
 
 body.grid.grid-4x4 #preview-grid-horizontal::before {
-  border-bottom: 1px solid white;
+  border-bottom: 1px solid var(--cros-ref-primary100);
   content: '';
   height: 0;
   left: 0;
@@ -1010,8 +1006,8 @@
 }
 
 #preview-grid-vertical {
-  border-inline-end: 1px solid white;
-  border-inline-start: 1px solid white;
+  border-inline-end: 1px solid var(--cros-ref-primary100);
+  border-inline-start: 1px solid var(--cros-ref-primary100);
   bottom: 0;
   left: 50%;
   position: absolute;
@@ -1021,7 +1017,8 @@
 }
 
 body.grid-4x4 #preview-grid-vertical::before {
-  border-right: 1px solid white;  /* csschecker-disable-line left-right */
+  border-right:  /* csschecker-disable-line left-right */
+      1px solid var(--cros-ref-primary100);
   bottom: 0;
   content: '';
   left: 0;
@@ -1068,10 +1065,16 @@
   pointer-events: none;
 }
 
-#record-time[hidden],
-.menu-item[hidden],
-#nudge[hidden] {
-  display: none;  /* Required for flexbox hidden. */
+/*
+ * Since the [hidden] attribute is done by user agent style, and any change to
+ * `display` will override it, add a rule to force `display: none` to element
+ * with hidden attribute. Note that there's another possible value of
+ * 'until-found' but we're not using it in CCA.
+ *
+ * See https://css-tricks.com/the-hidden-attribute-is-visibly-weak/
+ */
+[hidden] {
+  display: none !important;
 }
 
 #record-time .icon {
@@ -1088,7 +1091,7 @@
 }
 
 #record-time #record-time-msg {
-  color: white;
+  color: var(--cros-sys-on_surface);
   flex-shrink: 0;
 }
 
@@ -1175,7 +1178,7 @@
 .menu-header,
 .menu-item {
   align-items: center;
-  color: white;
+  color: var(--cros-sys-on_surface);
   display: flex;
   flex-shrink: 0;
   font-size: 13px;
@@ -1193,7 +1196,7 @@
 }
 
 .menu-header {
-  color: white;
+  color: var(--cros-sys-on_surface);
   cursor: default;
   font-size: 20px;
   height: 72px;
@@ -1303,14 +1306,14 @@
  */
 #view-splash {
   align-items: center;
-  background: var(--cros-sys-app_base, var(--grey-900));
+  background: var(--cros-sys-app_base, rgb(32, 33, 36));
   display: flex;
   justify-content: center;
 }
 
 #view-splash .icon {
   -webkit-mask: url(/images/camera_mode_photo.svg);
-  background: var(--cros-sys-on_surface, var(--grey-200));
+  background: var(--cros-sys-on_surface, rgb(233, 234, 237));
   height: 40px;
   width: 40px;
 }
@@ -1473,7 +1476,7 @@
 }
 
 .low-storage-dialog-popup .dialog-title {
-  color: white;
+  color: var(--cros-sys-on_surface);
   font: 500 16px/24px var(--default-font-family);
 }
 
diff --git a/ash/webui/camera_app_ui/resources/css/menu.css b/ash/webui/camera_app_ui/resources/css/menu.css
index 1910217..030a629 100644
--- a/ash/webui/camera_app_ui/resources/css/menu.css
+++ b/ash/webui/camera_app_ui/resources/css/menu.css
@@ -3,16 +3,11 @@
  * found in the LICENSE file. */
 
 .menu-root {
-  /* Use linear-gradient to apply multiple background colors. */
-  background: linear-gradient(
-    0deg,
-    rgba(255, 255, 255, 0.06),
-    rgba(255, 255, 255, 0.06)
-  ), var(--grey-900);
+  background: var(--cros-sys-base_elevated);
   border-radius: 4px;
   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px rgba(0, 0, 0, 0.15);
   box-sizing: border-box;
-  color: var(--grey-200);
+  color: var(--cros-sys-on_surface);
   display: none;
   font-size: 14px;
   margin: 0;
@@ -35,5 +30,5 @@
 }
 
 .menu-root > .item:is(:hover, :focus-visible) {
-  background-color: rgba(255, 255, 255, 0.08);
+  background: var(--cros-sys-hover_on_subtle);
 }
diff --git a/ash/webui/camera_app_ui/resources/css/mode/video.css b/ash/webui/camera_app_ui/resources/css/mode/video.css
index 0157c15..7e504409 100644
--- a/ash/webui/camera_app_ui/resources/css/mode/video.css
+++ b/ash/webui/camera_app_ui/resources/css/mode/video.css
@@ -38,8 +38,10 @@
 
   fill: transparent;
   height: var(--svg-size);
+  left: 50%;
   pointer-events: none;
   position: absolute;
+  top: 50%;
   transform: translate(-50%, -50%);
   width: var(--svg-size);
 }
@@ -48,7 +50,8 @@
   cx: 50%;
   cy: 50%;
   r: calc(var(--outer-radius) - var(--bar-width));
-  stroke: white;
+  /* TODO(pihsun): Use cros.sys.white when it's available. */
+  stroke: var(--cros-ref-primary100);
   stroke-width: var(--bar-width);
   /* The dash strip will appear from 3 o'clock direction while we want to start
    * from 12 o'clock. Rotate 90deg counterclockwise accordingly. */
diff --git a/ash/webui/camera_app_ui/resources/css/review.css b/ash/webui/camera_app_ui/resources/css/review.css
index 4cb49ad..8ed877bb 100644
--- a/ash/webui/camera_app_ui/resources/css/review.css
+++ b/ash/webui/camera_app_ui/resources/css/review.css
@@ -3,12 +3,11 @@
  * found in the LICENSE file. */
 
 .review-views {
-  background: var(--grey-900);
+  background: var(--cros-sys-app_base);
 }
 
 .review-frame {
   align-items: center;
-  border: 1px solid rgba(var(--grey-200-rgb), 0.38);
   bottom: calc(var(--bottom-line) * 2);
   display: flex;
   justify-content: center;
diff --git a/ash/webui/camera_app_ui/resources/images/document_mode_spinner.svg b/ash/webui/camera_app_ui/resources/images/document_mode_spinner.svg
index 45ea23d..3f7689b8 100644
--- a/ash/webui/camera_app_ui/resources/images/document_mode_spinner.svg
+++ b/ash/webui/camera_app_ui/resources/images/document_mode_spinner.svg
@@ -68,21 +68,13 @@
           transform: rotate(-360deg);
         }
       }
-      @keyframes colors {
-        from {
-          stroke: #C4C4C4;
-        }
-        to {
-          stroke: #C4C4C4;
-        }
-      }
       .qp-circular-loader-path {
-        animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
+        animation-duration: 1333ms, 5332ms; /* ARCTIME, 4*ARCTIME */
         animation-fill-mode: forwards;
-        animation-iteration-count: infinite, infinite, infinite;
-        animation-name: fillunfill, rot, colors;
-        animation-play-state: running, running, running;
-        animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
+        animation-iteration-count: infinite, infinite;
+        animation-name: fillunfill, rot;
+        animation-play-state: running, running;
+        animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4);
       }
   </style>
   <!-- 3= STROKEWIDTH -->
@@ -92,7 +84,7 @@
   <!-- ARCSIZE would affect the 1.5,14 part of this... 1.5,14 is specific to
        270 degrees -->
   <g class="qp-circular-loader">
-    <path class="qp-circular-loader-path" fill="none" 
+    <path class="qp-circular-loader-path" fill="none"
           d="M 14,1.5 A 12.5,12.5 0 1 1 1.5,14" stroke-width="3"
           stroke-linecap="round"></path>
   </g>
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
index 9eb4741a..3718363 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
@@ -31,6 +31,7 @@
 import {Preview} from './preview.js';
 import {StreamConstraints} from './stream_constraints.js';
 import {StreamManager} from './stream_manager.js';
+import {StreamManagerChrome} from './stream_manager_chrome.js';
 import {
   CameraConfig,
   CameraConfigCandidate,
@@ -310,6 +311,11 @@
    * Stop extra stream and preview stream.
    */
   private async stopStreams() {
+    if (expert.isEnabled(
+            expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME)) {
+      StreamManagerChrome.getInstance().stopCaptureStream();
+    }
+
     await this.modes.clear();
     await this.preview.close();
   }
diff --git a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
index c09c384..cadb7f6 100644
--- a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
@@ -431,7 +431,9 @@
     const cameraInfo = this.cameraInfos.get(deviceId);
     assert(cameraInfo !== undefined);
     const enableMultiStreamRecording =
-        expert.isEnabled(expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING);
+        expert.isEnabled(expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING) ||
+        expert.isEnabled(
+            expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME);
 
     const candidates = [];
     const prefLevel = this.prefVideoResolutionLevelMap[deviceId];
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
index 382d3a0..a247854 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
@@ -17,6 +17,7 @@
 } from '../../type.js';
 import {getFpsRangeFromConstraints} from '../../util.js';
 import {StreamConstraints} from '../stream_constraints.js';
+import {StreamManagerChrome} from '../stream_manager_chrome.js';
 
 import {
   ModeBase,
@@ -164,6 +165,19 @@
               expert.isEnabled(
                   expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING),
           );
+          if (expert.isEnabled(
+                  expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME)) {
+            const captureResolution =
+                assertExists(this.getCaptureParams().captureResolution);
+            await StreamManagerChrome.getInstance().prepare({
+              ...constraints,
+              video: {
+                ...constraints.video,
+                width: captureResolution.width,
+                height: captureResolution.height,
+              },
+            });
+          }
 
           if (await deviceOperator.isBlobVideoSnapshotEnabled(deviceId)) {
             await deviceOperator.setStillCaptureResolution(
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
index 93bf743..7f58e6f 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
@@ -45,6 +45,7 @@
 import {WaitableEvent} from '../../waitable_event.js';
 import {StreamConstraints} from '../stream_constraints.js';
 import {StreamManager} from '../stream_manager.js';
+import {StreamManagerChrome} from '../stream_manager_chrome.js';
 
 import {ModeBase, ModeFactory} from './mode_base.js';
 import {PhotoResult} from './photo.js';
@@ -302,7 +303,13 @@
   override async clear(): Promise<void> {
     await this.stopCapture();
     if (this.captureStream !== null) {
-      await StreamManager.getInstance().closeCaptureStream(this.captureStream);
+      if (expert.isEnabled(expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING)) {
+        await StreamManager.getInstance().closeCaptureStream(
+            this.captureStream);
+      } else if (expert.isEnabled(
+                     expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME)) {
+        StreamManagerChrome.getInstance().stopCaptureStream();
+      }
       this.captureStream = null;
     }
   }
@@ -573,9 +580,16 @@
       throw new CanceledError('Recording sound is canceled');
     }
 
-    if (this.captureConstraints !== null && this.captureStream === null) {
-      this.captureStream = await StreamManager.getInstance().openCaptureStream(
-          this.captureConstraints);
+    if (this.captureStream === null) {
+      if (expert.isEnabled(
+              expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME)) {
+        this.captureStream =
+            StreamManagerChrome.getInstance().getCaptureStream();
+      } else if (this.captureConstraints !== null) {
+        this.captureStream =
+            await StreamManager.getInstance().openCaptureStream(
+                this.captureConstraints);
+      }
     }
     if (this.recordingImageCapture === null) {
       this.recordingImageCapture = new CrosImageCapture(this.getVideoTrack());
diff --git a/ash/webui/camera_app_ui/resources/js/device/stream_manager_chrome.ts b/ash/webui/camera_app_ui/resources/js/device/stream_manager_chrome.ts
new file mode 100644
index 0000000..dab7b7a
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/js/device/stream_manager_chrome.ts
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assertExists} from '../assert.js';
+
+import {
+  StreamConstraints,
+  toMediaStreamConstraints,
+} from './stream_constraints.js';
+
+/**
+ * The singleton instance of StreamManagerChrome. Initialized by the first
+ * invocation of getInstance().
+ */
+let instance: StreamManagerChrome|null = null;
+
+/**
+ * Monitors device change and provides different listener callbacks for
+ * device changes. It also provides streams for different modes.
+ */
+export class StreamManagerChrome {
+  private captureStream: MediaStream|null = null;
+
+  static getInstance(): StreamManagerChrome {
+    if (instance === null) {
+      instance = new StreamManagerChrome();
+    }
+    return instance;
+  }
+
+  async prepare(constraints: StreamConstraints): Promise<void> {
+    this.captureStream = await navigator.mediaDevices.getUserMedia(
+        toMediaStreamConstraints(constraints));
+  }
+
+  getCaptureStream(): MediaStream {
+    return assertExists(this.captureStream);
+  }
+
+  stopCaptureStream(): void {
+    if (this.captureStream !== null) {
+      assertExists(this.captureStream.getVideoTracks()[0]).stop();
+      this.captureStream = null;
+    }
+  }
+}
diff --git a/ash/webui/camera_app_ui/resources/js/expert.ts b/ash/webui/camera_app_ui/resources/js/expert.ts
index df015cbf..cbc95ab 100644
--- a/ash/webui/camera_app_ui/resources/js/expert.ts
+++ b/ash/webui/camera_app_ui/resources/js/expert.ts
@@ -11,6 +11,7 @@
   ENABLE_FPS_PICKER_FOR_BUILTIN = 'enable-fps-picker-for-builtin',
   ENABLE_FULL_SIZED_VIDEO_SNAPSHOT = 'enable-full-sized-video-snapshot',
   ENABLE_MULTISTREAM_RECORDING = 'enable-multistream-recording',
+  ENABLE_MULTISTREAM_RECORDING_CHROME = 'enable-multistream-recording-chrome',
   ENABLE_PTZ_FOR_BUILTIN = 'enable-ptz-for-builtin',
   EXPERT = 'expert',
   PRINT_PERFORMANCE_LOGS = 'print-performance-logs',
diff --git a/ash/webui/camera_app_ui/resources/js/i18n_string.ts b/ash/webui/camera_app_ui/resources/js/i18n_string.ts
index 0f3a3ac..ec85c6b 100644
--- a/ash/webui/camera_app_ui/resources/js/i18n_string.ts
+++ b/ash/webui/camera_app_ui/resources/js/i18n_string.ts
@@ -52,6 +52,10 @@
   EXPERT_ENABLE_PTZ_FOR_BUILTIN = 'expert_enable_ptz_for_builtin',
   EXPERT_MODE_BUTTON = 'expert_mode_button',
   EXPERT_MULTISTREAM_RECORDING = 'expert_multistream_recording',
+  EXPERT_MULTISTREAM_RECORDING_CHROME = 'expert_multistream_recording_chrome',
+  EXPERT_MULTISTREAM_RECORDING_DISABLED =
+      'expert_multistream_recording_disabled',
+  EXPERT_MULTISTREAM_RECORDING_HAL = 'expert_multistream_recording_hal',
   EXPERT_PREVIEW_METADATA = 'expert_preview_metadata',
   EXPERT_PRINT_PERFORMANCE_LOGS = 'expert_print_performance_logs',
   EXPERT_SAVE_METADATA = 'expert_save_metadata',
diff --git a/ash/webui/camera_app_ui/resources/js/js.gni b/ash/webui/camera_app_ui/resources/js/js.gni
index c5102e5..670855b 100644
--- a/ash/webui/camera_app_ui/resources/js/js.gni
+++ b/ash/webui/camera_app_ui/resources/js/js.gni
@@ -26,6 +26,7 @@
   "device/preview.ts",
   "device/stream_constraints.ts",
   "device/stream_manager.ts",
+  "device/stream_manager_chrome.ts",
   "device/type.ts",
   "dom.ts",
   "error.ts",
diff --git a/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts b/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
index b59f532..c9cb6ae 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/svg_wrapper.ts
@@ -28,6 +28,8 @@
     svg {
       display: block;
       fill: currentColor;
+      stroke: currentColor;
+      stroke-width: 0;
     }
   `;
 
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts
index 2d2cb06..6b0f3d2 100644
--- a/ash/webui/camera_app_ui/resources/js/main.ts
+++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -147,14 +147,17 @@
           element.click();
         }
       });
-      const localStorageKey = element.dataset['key'] === undefined ?
-          null :
-          util.assertEnumVariant(LocalStorageKey, element.dataset['key']);
+      function getKey(element: HTMLInputElement) {
+        return element.dataset['key'] === undefined ?
+            null :
+            util.assertEnumVariant(LocalStorageKey, element.dataset['key']);
+      }
       const stateKey = element.dataset['state'] === undefined ?
           null :
           state.assertState(element.dataset['state']);
 
       function save(element: HTMLInputElement) {
+        const localStorageKey = getKey(element);
         if (localStorageKey !== null) {
           localStorage.set(localStorageKey, element.checked);
         }
@@ -185,6 +188,7 @@
           }
         });
       }
+      const localStorageKey = getKey(element);
       if (localStorageKey !== null) {
         const value = localStorage.getBool(localStorageKey, element.checked);
         util.toggleChecked(element, value);
diff --git a/ash/webui/camera_app_ui/resources/js/test/cca_test.ts b/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
index 556acfd8..c9449db 100644
--- a/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
+++ b/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
@@ -349,6 +349,14 @@
   }
 
   /**
+   * Gets current boolean value of |key|.
+   */
+  static getState(key: string): boolean {
+    const stateKey = state.assertState(key);
+    return state.get(stateKey);
+  }
+
+  /**
    * Calculates the expected duration of the time-lapse video recorded for
    * |recordDuration| seconds.
    */
@@ -524,4 +532,28 @@
   static getFpsObserver(): FpsObserver {
     return new FpsObserver(getPreviewVideo());
   }
+
+  /**
+   * Waits until the state |key| is changed to |expected| and resolves the
+   * millisecond unix timestamp of the state change.
+   */
+  static waitStateChange(key: string, expected: boolean): Promise<number> {
+    const stateKey = state.assertState(key);
+    const current = state.get(stateKey);
+    if (current === expected) {
+      throw new Error(`Cannot start observing because the state of ${
+          stateKey} is already ${expected}`);
+    }
+    return new Promise((resolve, reject) => {
+      function onChange(newState: boolean) {
+        state.removeObserver(stateKey, onChange);
+        if (newState !== expected) {
+          reject(
+              new Error(`The changed "${stateKey}" state is not ${expected}`));
+        }
+        resolve(Date.now());
+      }
+      state.addObserver(stateKey, onChange);
+    });
+  }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
index f5052979..c2bce5e 100644
--- a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
+++ b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
@@ -42,6 +42,8 @@
   expertModeButton: '#settings-expert',
   expertModeOption: '#expert-enable-expert-mode',
   expertMultiStreamRecordingOption: '#expert-enable-multistream-recording',
+  expertMultiStreamRecordingChromeOption:
+      '#expert-enable-multistream-recording-chrome',
   expertSaveMetadataOption: '#expert-save-metadata',
   expertShowMetadataOption: '#expert-show-metadata',
   feedbackButton: '#settings-feedback',
@@ -116,6 +118,10 @@
     component: 'expertMultiStreamRecordingOption',
     state: ExpertOption.ENABLE_MULTISTREAM_RECORDING,
   },
+  multiStreamRecordingChromeOption: {
+    component: 'expertMultiStreamRecordingChromeOption',
+    state: ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME,
+  },
   saveMetadataOption: {
     component: 'expertSaveMetadataOption',
     state: ExpertOption.SAVE_METADATA,
diff --git a/ash/webui/camera_app_ui/resources/js/type.ts b/ash/webui/camera_app_ui/resources/js/type.ts
index 0bd684a..b3afdf1 100644
--- a/ash/webui/camera_app_ui/resources/js/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/type.ts
@@ -476,6 +476,7 @@
   ENABLE_FPS_PICKER = 'enableFPSPicker',
   ENABLE_FULL_SIZED_VIDEO_SNAPSHOT = 'enableFullSizedVideoSnapshot',
   ENABLE_MULTISTREAM_RECORDING = 'enableMultistreamRecording',
+  ENABLE_MULTISTREAM_RECORDING_CHROME = 'enableMultistreamRecordingChrome',
   ENABLE_PTZ_FOR_BUILTIN = 'enablePTZForBuiltin',
   EXPERT_MODE = 'expert',
   GA_USER_ID = 'google-analytics.analytics.user-id',
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera.ts b/ash/webui/camera_app_ui/resources/js/views/camera.ts
index 29a74bf..1331364e 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera.ts
@@ -321,6 +321,9 @@
         expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING,
         () => this.cameraManager.reconfigure());
     expert.addObserver(
+        expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME,
+        () => this.cameraManager.reconfigure());
+    expert.addObserver(
         expert.ExpertOption.ENABLE_PTZ_FOR_BUILTIN,
         () => this.cameraManager.reconfigure());
 
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd
index d2dcb37..60dc76e 100644
--- a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd
+++ b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd
@@ -310,6 +310,15 @@
       <message desc="Label for expert mode option: Multi-stream video recording." name="IDS_EXPERT_MULTISTREAM_RECORDING">
         Multistream video recording
       </message>
+      <message desc="Label for multi-stream recording option: Scale frames by Chrome." name="IDS_EXPERT_MULTISTREAM_RECORDING_CHROME">
+        Scale frames by Chrome
+      </message>
+      <message desc="Label for multi-stream recording option: Disabled." name="IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED">
+        Disabled
+      </message>
+      <message desc="Label for multi-stream recording option: Scale frames by Camera HAL." name="IDS_EXPERT_MULTISTREAM_RECORDING_HAL">
+        Scale frames by Camera HAL
+      </message>
       <message desc="Label for expert mode option: enable video FPS picker for builtin camera." name="IDS_EXPERT_ENABLE_FPS_PICKER_FOR_BUILTIN">
         Enable video FPS picker
       </message>
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_CHROME.png.sha1 b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_CHROME.png.sha1
new file mode 100644
index 0000000..4856b29
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_CHROME.png.sha1
@@ -0,0 +1 @@
+99ea13c41d7d8f11b87d9b9cbd54bb41cb24c88c
\ No newline at end of file
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED.png.sha1 b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED.png.sha1
new file mode 100644
index 0000000..4856b29
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED.png.sha1
@@ -0,0 +1 @@
+99ea13c41d7d8f11b87d9b9cbd54bb41cb24c88c
\ No newline at end of file
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_HAL.png.sha1 b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_HAL.png.sha1
new file mode 100644
index 0000000..4856b29
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_EXPERT_MULTISTREAM_RECORDING_HAL.png.sha1
@@ -0,0 +1 @@
+99ea13c41d7d8f11b87d9b9cbd54bb41cb24c88c
\ No newline at end of file
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html
index fb87369c..ae168f3 100644
--- a/ash/webui/camera_app_ui/resources/views/main.html
+++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -230,14 +230,16 @@
                 data-svg="camera_shutter_video_snapshot.svg"></button>
       </div>
       <div id="shutters-group" class="buttons right-stripe circle">
-        <button id="recordvideo" class="shutter inkdrop" tabindex="0"
-                i18n-label="record_video_start_button">
-          <div class="red-dot"></div>
-          <div class="white-square"></div>
+        <div id="recordvideo-container">
+          <button id="recordvideo" class="shutter inkdrop" tabindex="0"
+                  i18n-label="record_video_start_button">
+            <div class="red-dot"></div>
+            <div class="white-square"></div>
+          </button>
           <svg id="shutter-progress-bar">
             <circle></circle>
           </svg>
-        </button>
+        </div>
         <button id="start-takephoto" class="shutter inkdrop" tabindex="0"
                 i18n-label="take_photo_button"
                 data-svg="camera_shutter_photo_start.svg"></button>
@@ -427,13 +429,29 @@
                  data-key="customVideoParameters">
           <span i18n-text="expert_custom_video_parameters"></span>
         </label>
-        <label class="menu-item inkdrop require-chromeos-vcd">
-          <input class="icon" id="expert-enable-multistream-recording"
-                 type="checkbox" tabindex="0"
-                 data-state="enable-multistream-recording"
-                 data-key="enableMultistreamRecording">
-          <span i18n-text="expert_multistream_recording"></span>
-        </label>
+        <div id="multistream-group" role="radiogroup">
+          <label class="menu-item inkdrop require-chromeos-vcd"
+                 i18n-text="expert_multistream_recording"></label>
+          <label class="menu-item inkdrop require-chromeos-vcd">
+            <input class="icon" type="radio" tabindex="0" name="multistream"
+                   checked>
+            <span i18n-text="expert_multistream_recording_disabled"></span>
+          </label>
+          <label class="menu-item inkdrop require-chromeos-vcd">
+            <input class="icon" id="expert-enable-multistream-recording"
+                   type="radio" tabindex="0" name="multistream"
+                   data-state="enable-multistream-recording"
+                   data-key="enableMultistreamRecording">
+            <span i18n-text="expert_multistream_recording_hal"></span>
+          </label>
+          <label class="menu-item inkdrop require-chromeos-vcd">
+            <input class="icon" id="expert-enable-multistream-recording-chrome"
+                   type="radio" tabindex="0" name="multistream"
+                   data-state="enable-multistream-recording-chrome"
+                   data-key="enableMultistreamRecordingChrome">
+            <span i18n-text="expert_multistream_recording_chrome"></span>
+          </label>
+        </div>
         <label class="menu-item inkdrop">
           <input id="expert-enable-full-sized-video-snapshot" class="icon"
                  type="checkbox" tabindex="0"
@@ -538,7 +556,8 @@
     </div>
     <div id="view-flash">
       <div id="processing-indicator" class="centered-overlay">
-        <div class="icon"></div>
+        <svg-wrapper class="icon" name="document_mode_spinner.svg">
+        </svg-wrapper>
         <div class="msg" tabindex="0" i18n-text="msg_processing_image"></div>
       </div>
     </div>
diff --git a/ash/webui/files_internals/files_internals_page_handler.cc b/ash/webui/files_internals/files_internals_page_handler.cc
index d047bb0..56bfc6db 100644
--- a/ash/webui/files_internals/files_internals_page_handler.cc
+++ b/ash/webui/files_internals/files_internals_page_handler.cc
@@ -26,14 +26,14 @@
   files_internals_ui_->delegate()->SetSmbfsEnableVerboseLogging(enabled);
 }
 
-void FilesInternalsPageHandler::GetOfficeSetupComplete(
-    GetOfficeSetupCompleteCallback callback) {
+void FilesInternalsPageHandler::GetOfficeFileHandlers(
+    GetOfficeFileHandlersCallback callback) {
   std::move(callback).Run(
-      files_internals_ui_->delegate()->GetOfficeSetupComplete());
+      files_internals_ui_->delegate()->GetOfficeFileHandlers());
 }
 
-void FilesInternalsPageHandler::SetOfficeSetupComplete(bool complete) {
-  files_internals_ui_->delegate()->SetOfficeSetupComplete(complete);
+void FilesInternalsPageHandler::ClearOfficeFileHandlers() {
+  files_internals_ui_->delegate()->ClearOfficeFileHandlers();
 }
 
 void FilesInternalsPageHandler::GetMoveConfirmationShownForDrive(
diff --git a/ash/webui/files_internals/files_internals_page_handler.h b/ash/webui/files_internals/files_internals_page_handler.h
index c8bb490..7cce3f1 100644
--- a/ash/webui/files_internals/files_internals_page_handler.h
+++ b/ash/webui/files_internals/files_internals_page_handler.h
@@ -29,8 +29,8 @@
   void GetSmbfsEnableVerboseLogging(
       GetSmbfsEnableVerboseLoggingCallback callback) override;
   void SetSmbfsEnableVerboseLogging(bool enabled) override;
-  void GetOfficeSetupComplete(GetOfficeSetupCompleteCallback callback) override;
-  void SetOfficeSetupComplete(bool complete) override;
+  void GetOfficeFileHandlers(GetOfficeFileHandlersCallback callback) override;
+  void ClearOfficeFileHandlers() override;
   void GetMoveConfirmationShownForDrive(
       GetMoveConfirmationShownForDriveCallback callback) override;
   void GetMoveConfirmationShownForOneDrive(
diff --git a/ash/webui/files_internals/files_internals_ui_delegate.h b/ash/webui/files_internals/files_internals_ui_delegate.h
index de6b214..3282541b 100644
--- a/ash/webui/files_internals/files_internals_ui_delegate.h
+++ b/ash/webui/files_internals/files_internals_ui_delegate.h
@@ -19,8 +19,8 @@
   virtual bool GetSmbfsEnableVerboseLogging() const = 0;
   virtual void SetSmbfsEnableVerboseLogging(bool enabled) = 0;
 
-  virtual bool GetOfficeSetupComplete() const = 0;
-  virtual void SetOfficeSetupComplete(bool complete) = 0;
+  virtual std::string GetOfficeFileHandlers() const = 0;
+  virtual void ClearOfficeFileHandlers() = 0;
 
   virtual bool GetMoveConfirmationShownForDrive() const = 0;
   virtual bool GetMoveConfirmationShownForOneDrive() const = 0;
diff --git a/ash/webui/files_internals/mojom/files_internals.mojom b/ash/webui/files_internals/mojom/files_internals.mojom
index ad2dfecb..6d4cfa2 100644
--- a/ash/webui/files_internals/mojom/files_internals.mojom
+++ b/ash/webui/files_internals/mojom/files_internals.mojom
@@ -11,10 +11,12 @@
   // Sets the smbfs.enable_verbose_logging pref.
   SetSmbfsEnableVerboseLogging(bool enabled);
 
-  // Gets the filebrowser.office.setup_complete pref.
-  GetOfficeSetupComplete() => (bool complete);
-  // Sets the filebrowser.office.setup_complete pref.
-  SetOfficeSetupComplete(bool complete);
+  // Gets the filebrowser.tasks sub-prefs for Office file types. Returns a
+  // base::Value as a debug string, which is allowed because this is a debug
+  // WebUI and the string is coming from the browser process.
+  GetOfficeFileHandlers() => (string handlers);
+  // Clears the filebrowser.tasks sub-prefs for Office file types.
+  ClearOfficeFileHandlers();
 
   // Gets the filebrowser.office.move_confirmation_shown_for_drive pref.
   GetMoveConfirmationShownForDrive() => (bool confirmation_shown);
diff --git a/ash/webui/files_internals/resources/index.html b/ash/webui/files_internals/resources/index.html
index dfc3feb..2739b88 100644
--- a/ash/webui/files_internals/resources/index.html
+++ b/ash/webui/files_internals/resources/index.html
@@ -33,14 +33,14 @@
 </div>
 
 <h2>Office file handlers</h2>
-<p>Office setup complete?: <span id="office-setup-complete-status"></span></p>
+<p>Office default file handlers: <span id="office-default-file-handlers"></span></p>
 <p>Move confirmation shown for Drive?: <span id="move-confirmation-shown-for-drive-status"></span></p>
 <p>Move confirmation shown for OneDrive?: <span id="move-confirmation-shown-for-onedrive-status"></span></p>
 <p>Move confirmation shown for local to Drive uploads?: <span id="move-confirmation-shown-for-local-to-drive-status"></span></p>
 <p>Move confirmation shown for local to OneDrive uploads?: <span id="move-confirmation-shown-for-local-to-onedrive-status"></span></p>
 <p>Move confirmation shown for cloud to Drive uploads?: <span id="move-confirmation-shown-for-cloud-to-drive-status"></span></p>
 <p>Move confirmation shown for cloud to OneDrive uploads?: <span id="move-confirmation-shown-for-cloud-to-onedrive-status"></span></p>
-<button id="clear-office-setup-complete">Clear Office setup complete</button>
+<button id="clear-office-file-handlers">Clear Office file handlers</button>
 <p>Always move files to Drive?: <span id="office-always-move-to-drive-status"></span></p>
 <button id="clear-office-always-move-to-drive">Clear always move to drive preference</button>
 <p>Always move files to OneDrive?: <span id="office-always-move-to-onedrive-status"></span></p>
diff --git a/ash/webui/files_internals/resources/index.js b/ash/webui/files_internals/resources/index.js
index 671f00d..3c406d7 100644
--- a/ash/webui/files_internals/resources/index.js
+++ b/ash/webui/files_internals/resources/index.js
@@ -6,12 +6,12 @@
 
 const pageHandler = PageHandler.getRemote();
 
-const refreshOfficeSetupComplete = async () => {
-  const officeSetupStatus =
-      document.getElementById('office-setup-complete-status');
-  const officeSetupComplete =
-      (await pageHandler.getOfficeSetupComplete()).complete;
-  officeSetupStatus.innerText = officeSetupComplete ? 'Yes' : 'No';
+const refreshOfficeFileHandlers = async () => {
+  const officeFileHandlersSpan =
+      document.getElementById('office-default-file-handlers');
+  const officeFileHandlers =
+      (await pageHandler.getOfficeFileHandlers()).handlers;
+  officeFileHandlersSpan.innerText = officeFileHandlers;
 };
 
 const refreshMoveConfirmationShownForDrive = async () => {
@@ -101,7 +101,7 @@
   });
 
   // Office file handlers
-  refreshOfficeSetupComplete();
+  refreshOfficeFileHandlers();
   refreshMoveConfirmationShownForDrive();
   refreshMoveConfirmationShownForOneDrive();
   refreshMoveConfirmationShownForLocalToDrive();
@@ -111,11 +111,11 @@
   refreshAlwaysMoveToDriveStatus();
   refreshAlwaysMoveToOneDriveStatus();
 
-  const clearSetupButton =
-      document.getElementById('clear-office-setup-complete');
-  clearSetupButton.addEventListener('click', () => {
-    pageHandler.setOfficeSetupComplete(false);
-    refreshOfficeSetupComplete();
+  const clearfileHandlers =
+      document.getElementById('clear-office-file-handlers');
+  clearfileHandlers.addEventListener('click', () => {
+    pageHandler.clearOfficeFileHandlers();
+    refreshOfficeFileHandlers();
     refreshMoveConfirmationShownForDrive();
     refreshMoveConfirmationShownForOneDrive();
     refreshMoveConfirmationShownForLocalToDrive();
diff --git a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
index 214cf13..0f2ee5f9 100644
--- a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
+++ b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
@@ -120,13 +120,13 @@
       hidden$="[[automaticSeedColorEnabled]]">
     <template is="dom-repeat" items="[[staticColors_]]" as="staticColor">
       <cr-button
-          tabindex$="[[getStaticColorTabIndex_(staticColor.hexVal)]]"
+          tabindex$="[[getStaticColorTabIndex_(staticColor.seedVal)]]"
           on-click="onClickStaticColorButton_"
-          aria-pressed$="[[getStaticColorAriaPressed_(staticColor.hexVal, staticColorSelected_)]]"
+          aria-pressed$="[[getStaticColorAriaPressed_(staticColor.seedVal, staticColorSelected_)]]"
           aria-description$="[[getStaticColorAriaDescription_(staticColor.enumVal)]]">
         <div class="container">
           <svg>
-            <circle style$="fill: [[staticColor.hexVal]]" cx="24" cy="24" r="24"></circle>
+            <circle style$="fill: [[staticColor.fillVal]]" cx="24" cy="24" r="24"></circle>
           </svg>
           <iron-icon icon="personalization:circle_checkmark"></iron-icon>
         </div>
diff --git a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
index b2450c7..575d672 100644
--- a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
+++ b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
@@ -39,9 +39,16 @@
   };
 }
 
+/**
+ * enumVal: the StaticColor enum value.
+ * fillVal: the color displayed on the button.
+ * seedVal: the color stored on the backend, used for calculating color
+ * palettes.
+ */
 export interface StaticColorInfo {
-  hexVal: string;
   enumVal: StaticColor;
+  fillVal: string;
+  seedVal: string;
 }
 
 interface OnStaticColorSelectedEvent {
@@ -119,22 +126,29 @@
   }
 
   private computePresetStaticColors_() {
+    const lightPink = convertToRgbHexStr(STATIC_COLOR_LIGHT_PINK);
+    const darkGreen = convertToRgbHexStr(STATIC_COLOR_DARK_GREEN);
+    const lightPurple = convertToRgbHexStr(STATIC_COLOR_LIGHT_PURPLE);
     return [
       {
-        hexVal: convertToRgbHexStr(STATIC_COLOR_GOOGLE_BLUE),
         enumVal: StaticColor.kGoogleBlue,
+        fillVal: '#4d72b4',
+        seedVal: convertToRgbHexStr(STATIC_COLOR_GOOGLE_BLUE),
       },
       {
-        hexVal: convertToRgbHexStr(STATIC_COLOR_LIGHT_PINK),
         enumVal: StaticColor.kLightPink,
+        fillVal: lightPink,
+        seedVal: lightPink,
       },
       {
-        hexVal: convertToRgbHexStr(STATIC_COLOR_DARK_GREEN),
         enumVal: StaticColor.kDarkGreen,
+        fillVal: darkGreen,
+        seedVal: darkGreen,
       },
       {
-        hexVal: convertToRgbHexStr(STATIC_COLOR_LIGHT_PURPLE),
         enumVal: StaticColor.kLightPurple,
+        fillVal: lightPurple,
+        seedVal: lightPurple,
       },
     ];
   }
@@ -150,7 +164,7 @@
     const staticColorInfo = event.model.staticColor;
     logDynamicColorStaticColorButtonClick(staticColorInfo.enumVal);
     setStaticColorPref(
-        hexColorToSkColor(staticColorInfo.hexVal), getThemeProvider(),
+        hexColorToSkColor(staticColorInfo.seedVal), getThemeProvider(),
         this.getStore());
   }
 
diff --git a/ash/webui/print_management/BUILD.gn b/ash/webui/print_management/BUILD.gn
index fd62ab6..97c3a13 100644
--- a/ash/webui/print_management/BUILD.gn
+++ b/ash/webui/print_management/BUILD.gn
@@ -16,6 +16,7 @@
 
   deps = [
     "//ash/constants:constants",
+    "//ash/webui/common:chrome_os_webui_config",
     "//ash/webui/print_management/resources:resources",
     "//ash/webui/web_applications",
     "//chromeos/components/print_management/mojom",
diff --git a/ash/webui/print_management/print_management_ui.h b/ash/webui/print_management/print_management_ui.h
index 350241e2..e2a70d4 100644
--- a/ash/webui/print_management/print_management_ui.h
+++ b/ash/webui/print_management/print_management_ui.h
@@ -7,7 +7,10 @@
 
 #include <memory>
 
+#include "ash/webui/common/chrome_os_webui_config.h"
+#include "ash/webui/print_management/url_constants.h"
 #include "chromeos/components/print_management/mojom/printing_manager.mojom-forward.h"
+#include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
@@ -20,6 +23,18 @@
 namespace printing {
 namespace printing_manager {
 
+class PrintManagementUI;
+
+// The WebUIConfig for chrome://print-management/.
+class PrintManagementUIConfig : public ChromeOSWebUIConfig<PrintManagementUI> {
+ public:
+  explicit PrintManagementUIConfig(
+      CreateWebUIControllerFunc create_controller_func)
+      : ChromeOSWebUIConfig(content::kChromeUIScheme,
+                            ash::kChromeUIPrintManagementHost,
+                            create_controller_func) {}
+};
+
 // The WebUI for chrome://print-management/.
 class PrintManagementUI : public ui::MojoWebUIController {
  public:
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
index 70c0f3eb..4813533 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -2067,6 +2067,56 @@
   EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos2[1]->type);
 }
 
+TEST_F(AcceleratorConfigurationProviderTest,
+       VerifyAllAcceleratorsHaveKeyString) {
+  // The following is a set of VKEYs that are ignored in this test. If there is
+  // a keycode that should be ignored, please add it to the following set. Only
+  // do this if the keycode does not require an icon, otherwise there is a risk
+  // that the shortcut app will display an empty icon for the accelerator.
+  std::set<ui::KeyboardCode> ignore_list = {
+      ui::KeyboardCode::VKEY_LSHIFT,  // kDisableCapsLock
+      ui::KeyboardCode::VKEY_RSHIFT,  // kDisableCapsLock
+  };
+
+  AshAcceleratorConfiguration* ash_config =
+      Shell::Get()->ash_accelerator_configuration();
+  ash_config->Initialize();
+  base::RunLoop().RunUntilIdle();
+
+  AcceleratorConfigurationProvider::AcceleratorConfigurationMap config =
+      provider_->GetAcceleratorConfig();
+  // Iterate through the entire config and check that all accelerators have a
+  // non-empty key string.
+  for (const auto& [source, id_to_accelerator_info] : config) {
+    for (const auto& [action_id, accelerators] : id_to_accelerator_info) {
+      for (const auto& accelerator : accelerators) {
+        if (!accelerator->layout_properties->is_standard_accelerator()) {
+          continue;
+        }
+
+        ui::KeyboardCode key_code =
+            accelerator->layout_properties->get_standard_accelerator()
+                ->accelerator.key_code();
+        // Ignore accelerators that have ignored keycodes or are disabled.
+        if (ignore_list.contains(key_code) ||
+            accelerator->state ==
+                mojom::AcceleratorState::kDisabledByUnavailableKeys) {
+          continue;
+        }
+
+        EXPECT_FALSE(ash::GetKeyDisplay(key_code).empty())
+            << "Missing display string for the keycode: " << key_code
+            << " if you are adding a new accelerator, "
+            << "please add a new mapping to `GetKeyDisplayMap()` in "
+            << "ash/webui/shortcut_customization_ui/backend/"
+            << "accelerator_layout_table.h along with the corresponding icon. "
+            << "See examples at "
+            << "ash/webui/shortcut_customization_ui/resources/js/input_key.ts.";
+      }
+    }
+  }
+}
+
 using FlagsKeyboardCodesVariant =
     std::variant<ui::EventFlags, ui::KeyboardCode, TextAcceleratorDelimiter>;
 using FlagsKeyboardCodeStringVariant = std::variant<ui::EventFlags,
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index 1bded1deb..fee85f9 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -414,6 +414,13 @@
   # enablement is already gated on BRP enablement.
   _enable_gwp_asan_support = put_ref_count_in_previous_slot
 
+  # Pools are a logical concept when address space is 32-bit.
+  _glue_core_pools = glue_core_pools && has_64_bit_pointers
+
+  # Pointer compression requires 64-bit pointers.
+  _enable_pointer_compression =
+      enable_pointer_compression_support && has_64_bit_pointers
+
   # TODO(crbug.com/1151236): Need to refactor the following buildflags.
   # The buildflags (except RECORD_ALLOC_INFO) are used by both chrome and
   # partition alloc. For partition alloc,
@@ -444,8 +451,8 @@
 
     "RECORD_ALLOC_INFO=$_record_alloc_info",
     "USE_FREESLOT_BITMAP=$use_freeslot_bitmap",
-    "GLUE_CORE_POOLS=$glue_core_pools",
-    "ENABLE_POINTER_COMPRESSION=$enable_pointer_compression_support",
+    "GLUE_CORE_POOLS=$_glue_core_pools",
+    "ENABLE_POINTER_COMPRESSION=$_enable_pointer_compression",
     "ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$enable_shadow_metadata",
 
     "USE_STARSCAN=$use_starscan",
diff --git a/base/allocator/partition_allocator/compressed_pointer.cc b/base/allocator/partition_allocator/compressed_pointer.cc
index d91ac34..a9e9853 100644
--- a/base/allocator/partition_allocator/compressed_pointer.cc
+++ b/base/allocator/partition_allocator/compressed_pointer.cc
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/allocator/partition_allocator/compressed_pointer.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 namespace partition_alloc::internal {
 
@@ -25,4 +26,4 @@
 
 }  // namespace partition_alloc::internal
 
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
diff --git a/base/allocator/partition_allocator/compressed_pointer.h b/base/allocator/partition_allocator/compressed_pointer.h
index 7432fb5..bbfad0bd 100644
--- a/base/allocator/partition_allocator/compressed_pointer.h
+++ b/base/allocator/partition_allocator/compressed_pointer.h
@@ -12,17 +12,18 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
-#if !PA_CONFIG(GLUE_CORE_POOLS)
+#if !BUILDFLAG(GLUE_CORE_POOLS)
 #error "Pointer compression only works with glued pools"
 #endif
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 #error "Pointer compression currently supports constant pool size"
 #endif
 
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 namespace partition_alloc {
 
@@ -32,7 +33,7 @@
 constexpr bool IsDecayedSame =
     std::is_same_v<std::decay_t<T1>, std::decay_t<T2>>;
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 // Pointer compression works by storing only the 'useful' 32-bit part of the
 // pointer. The other half (the base) is stored in a global variable
@@ -117,11 +118,11 @@
   friend class PartitionAddressSpace;
 };
 
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 }  // namespace internal
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 template <typename T>
 class PA_TRIVIAL_ABI CompressedPointer final {
@@ -443,7 +444,7 @@
   return static_cast<CompressedPointer<T>>(a) >= b;
 }
 
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 // Simple wrapper over the raw pointer.
 template <typename T>
diff --git a/base/allocator/partition_allocator/compressed_pointer_unittest.cc b/base/allocator/partition_allocator/compressed_pointer_unittest.cc
index 9ec1c10..2cf5548 100644
--- a/base/allocator/partition_allocator/compressed_pointer_unittest.cc
+++ b/base/allocator/partition_allocator/compressed_pointer_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/allocator/partition_allocator/compressed_pointer.h"
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace partition_alloc {
@@ -47,14 +48,14 @@
 }
 
 // Test that pointer types are trivial.
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 static_assert(
     std::is_trivially_default_constructible_v<CompressedPointer<Base>>);
 static_assert(std::is_trivially_copy_constructible_v<CompressedPointer<Base>>);
 static_assert(std::is_trivially_move_constructible_v<CompressedPointer<Base>>);
 static_assert(std::is_trivially_copy_assignable_v<CompressedPointer<Base>>);
 static_assert(std::is_trivially_move_assignable_v<CompressedPointer<Base>>);
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 static_assert(
     std::is_trivially_default_constructible_v<UncompressedPointer<Base>>);
 static_assert(
@@ -72,16 +73,16 @@
 template <typename TagType>
 class CompressedPointerTest : public ::testing::Test {
  public:
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   template <typename T>
   using PointerType =
       std::conditional_t<std::is_same_v<TagType, CompressedTypeTag>,
                          CompressedPointer<T>,
                          UncompressedPointer<T>>;
-#else   // PA_CONFIG(POINTER_COMPRESSION)
+#else   // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   template <typename T>
   using PointerType = UncompressedPointer<T>;
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
   CompressedPointerTest() {
     allocator_.init({PartitionOptions::AlignedAlloc::kDisallowed,
@@ -97,7 +98,7 @@
   internal::PartitionAllocator<internal::ThreadSafe> allocator_;
 };
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 using ObjectTypes = ::testing::Types<UncompressedTypeTag, CompressedTypeTag>;
 #else
 using ObjectTypes = ::testing::Types<UncompressedTypeTag>;
diff --git a/base/allocator/partition_allocator/partition_address_space.cc b/base/allocator/partition_allocator/partition_address_space.cc
index 2f5b2d01..b65e5d7b 100644
--- a/base/allocator/partition_allocator/partition_address_space.cc
+++ b/base/allocator/partition_allocator/partition_address_space.cc
@@ -147,7 +147,7 @@
   size_t regular_pool_size = RegularPoolSize();
   size_t brp_pool_size = BRPPoolSize();
 
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   // Gluing core pools (regular & BRP) makes sense only when both pools are of
   // the same size. This the only way we can check belonging to either of the
   // two with a single bitmask operation.
@@ -169,7 +169,7 @@
   }
   setup_.brp_pool_base_address_ =
       setup_.regular_pool_base_address_ + regular_pool_size;
-#else  // PA_CONFIG(GLUE_CORE_POOLS)
+#else  // BUILDFLAG(GLUE_CORE_POOLS)
 #if PA_CONFIG(ENABLE_SHADOW_METADATA)
   int regular_pool_fd = memfd_create("/regular_pool", MFD_CLOEXEC);
 #else
@@ -204,12 +204,12 @@
     HandlePoolAllocFailure();
   }
   setup_.brp_pool_base_address_ = base_address + kForbiddenZoneSize;
-#endif  // PA_CONFIG(GLUE_CORE_POOLS)
+#endif  // BUILDFLAG(GLUE_CORE_POOLS)
 
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
   setup_.regular_pool_base_mask_ = ~(regular_pool_size - 1);
   setup_.brp_pool_base_mask_ = ~(brp_pool_size - 1);
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   // When PA_GLUE_CORE_POOLS is on, the BRP pool is placed at the end of the
   // regular pool, effectively forming one virtual pool of a twice bigger
   // size. Adjust the mask appropriately.
@@ -226,7 +226,7 @@
   // Sanity check pool alignment.
   PA_DCHECK(!(setup_.regular_pool_base_address_ & (regular_pool_size - 1)));
   PA_DCHECK(!(setup_.brp_pool_base_address_ & (brp_pool_size - 1)));
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   PA_DCHECK(!(setup_.regular_pool_base_address_ & (glued_pool_sizes - 1)));
 #endif
 
@@ -241,7 +241,7 @@
   PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_));
   PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size - 1));
   PA_DCHECK(!IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size));
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   PA_DCHECK(!IsInCorePools(setup_.regular_pool_base_address_ - 1));
   PA_DCHECK(IsInCorePools(setup_.regular_pool_base_address_));
   PA_DCHECK(
@@ -252,7 +252,7 @@
   PA_DCHECK(IsInCorePools(setup_.brp_pool_base_address_));
   PA_DCHECK(IsInCorePools(setup_.brp_pool_base_address_ + brp_pool_size - 1));
   PA_DCHECK(!IsInCorePools(setup_.brp_pool_base_address_ + brp_pool_size));
-#endif  // PA_CONFIG(GLUE_CORE_POOLS)
+#endif  // BUILDFLAG(GLUE_CORE_POOLS)
 
 #if PA_CONFIG(STARSCAN_USE_CARD_TABLE)
   // Reserve memory for PCScan quarantine card table.
@@ -284,9 +284,9 @@
       brp_pool_shadow_address - setup_.brp_pool_base_address_;
 #endif
 
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   CompressedPointerBaseGlobal::SetBase(setup_.regular_pool_base_address_);
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 }
 
 void PartitionAddressSpace::InitConfigurablePool(uintptr_t pool_base,
@@ -364,18 +364,18 @@
 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
   UninitThreadIsolatedPoolForTesting();  // IN-TEST
 #endif
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   // The core pools (regular & BRP) were allocated using a single allocation of
   // double size.
   FreePages(setup_.regular_pool_base_address_, 2 * RegularPoolSize());
-#else   // PA_CONFIG(GLUE_CORE_POOLS)
+#else   // BUILDFLAG(GLUE_CORE_POOLS)
   FreePages(setup_.regular_pool_base_address_, RegularPoolSize());
   // For BRP pool, the allocation region includes a "forbidden zone" before the
   // pool.
   const size_t kForbiddenZoneSize = PageAllocationGranularity();
   FreePages(setup_.brp_pool_base_address_ - kForbiddenZoneSize,
             BRPPoolSize() + kForbiddenZoneSize);
-#endif  // PA_CONFIG(GLUE_CORE_POOLS)
+#endif  // BUILDFLAG(GLUE_CORE_POOLS)
   // Do not free pages for the configurable pool, because its memory is owned
   // by someone else, but deinitialize it nonetheless.
   setup_.regular_pool_base_address_ = kUninitializedPoolBaseAddress;
@@ -383,9 +383,9 @@
   setup_.configurable_pool_base_address_ = kUninitializedPoolBaseAddress;
   setup_.configurable_pool_base_mask_ = 0;
   AddressPoolManager::GetInstance().ResetForTesting();
-#if PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   CompressedPointerBaseGlobal::ResetBaseForTesting();
-#endif  // PA_CONFIG(POINTER_COMPRESSION)
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 }
 
 void PartitionAddressSpace::UninitConfigurablePoolForTesting() {
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h
index 0f9da77..bd8726d7 100644
--- a/base/allocator/partition_allocator/partition_address_space.h
+++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -150,7 +150,7 @@
     return (address & brp_pool_base_mask) == setup_.brp_pool_base_address_;
   }
 
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
   // Checks whether the address belongs to either regular or BRP pool.
   // Returns false for nullptr.
   PA_ALWAYS_INLINE static bool IsInCorePools(uintptr_t address) {
@@ -176,7 +176,7 @@
     return RegularPoolSize() * 2;
   }
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
-#endif  // PA_CONFIG(GLUE_CORE_POOLS)
+#endif  // BUILDFLAG(GLUE_CORE_POOLS)
 
   PA_ALWAYS_INLINE static uintptr_t OffsetInBRPPool(uintptr_t address) {
     PA_DCHECK(IsInBRPPool(address));
@@ -328,7 +328,7 @@
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
           regular_pool_base_mask_(0),
           brp_pool_base_mask_(0),
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
           core_pools_base_mask_(0),
 #endif
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
@@ -347,7 +347,7 @@
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
         uintptr_t regular_pool_base_mask_;
         uintptr_t brp_pool_base_mask_;
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
         uintptr_t core_pools_base_mask_;
 #endif
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
@@ -446,13 +446,13 @@
   return internal::PartitionAddressSpace::IsInBRPPool(address);
 }
 
-#if PA_CONFIG(GLUE_CORE_POOLS)
+#if BUILDFLAG(GLUE_CORE_POOLS)
 // Checks whether the address belongs to either regular or BRP pool.
 // Returns false for nullptr.
 PA_ALWAYS_INLINE bool IsManagedByPartitionAllocCorePools(uintptr_t address) {
   return internal::PartitionAddressSpace::IsInCorePools(address);
 }
-#endif  // PA_CONFIG(GLUE_CORE_POOLS)
+#endif  // BUILDFLAG(GLUE_CORE_POOLS)
 
 // Returns false for nullptr.
 PA_ALWAYS_INLINE bool IsManagedByPartitionAllocConfigurablePool(
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni
index 4f512dba5..a344a4fa 100644
--- a/base/allocator/partition_allocator/partition_alloc.gni
+++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -64,7 +64,8 @@
   # check "belongs to one of the two pools" with a single bitmask operation.
   glue_core_pools = false
 
-  # Introduces pointer compression support in PA.
+  # Introduces pointer compression support in PA. These are 4-byte
+  # pointers that can point within the core pools (regular and BRP).
   #
   # This is effective only for memory allocated from PartitionAlloc, so it is
   # recommended to enable PA-E above, but isn't strictly necessary. Embedders
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h
index a6671d6..2931396 100644
--- a/base/allocator/partition_allocator/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -54,16 +54,6 @@
 #define PA_CONFIG_DYNAMICALLY_SELECT_POOL_SIZE() 0
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(IS_IOS)
 
-// Puts the regular and BRP pools right next to each other, so that we can
-// check "belongs to one of the two pools" with a single bitmask operation.
-//
-// This setting is specific to 64-bit, as 32-bit has a different implementation.
-#if BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(GLUE_CORE_POOLS)
-#define PA_CONFIG_GLUE_CORE_POOLS() 1
-#else
-#define PA_CONFIG_GLUE_CORE_POOLS() 0
-#endif
-
 #if BUILDFLAG(HAS_64_BIT_POINTERS) && \
     (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
 #include <linux/version.h>
@@ -303,14 +293,8 @@
 #define PA_CONFIG_ENABLE_MAC11_MALLOC_SIZE_HACK() \
   (BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && BUILDFLAG(IS_MAC))
 
-// Enables compressed (4-byte) pointers that can point within the core pools
-// (Regular + BRP).
-#if BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_POINTER_COMPRESSION)
-#define PA_CONFIG_POINTER_COMPRESSION() 1
+#if BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
-#if !PA_CONFIG(GLUE_CORE_POOLS)
-#error "Pointer compression works only with contiguous pools"
-#endif
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 #error "Dynamically selected pool size is currently not supported"
 #endif
@@ -318,10 +302,8 @@
 // TODO(1376980): Address MTE once it's enabled.
 #error "Compressed pointers don't support tag in the upper bits"
 #endif
-#else  // BUILDFLAG(HAS_64_BIT_POINTERS) &&
-       // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
-#define PA_CONFIG_POINTER_COMPRESSION() 0
-#endif
+
+#endif  // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 
 // PA_CONFIG(IS_NONCLANG_MSVC): mimics the compound condition used by
 // Chromium's `//base/compiler_specific.h` to detect true (non-Clang)
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h
index 53eec16..d5a1a20c 100644
--- a/base/allocator/partition_allocator/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -293,7 +293,8 @@
 // When pointer compression is enabled, we cannot use large pools (at most
 // 8GB for each of the glued pools).
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) || PA_CONFIG(POINTER_COMPRESSION)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) || \
+    BUILDFLAG(ENABLE_POINTER_COMPRESSION)
 constexpr size_t kPoolMaxSize = 8 * kGiB;
 #else
 constexpr size_t kPoolMaxSize = 16 * kGiB;
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h
index 17c0482..826ee87 100644
--- a/base/allocator/partition_allocator/starscan/pcscan.h
+++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -225,8 +225,9 @@
 
 PA_ALWAYS_INLINE void PCScan::JoinScanIfNeeded() {
   PCScan& instance = Instance();
-  if (PA_UNLIKELY(instance.IsJoinable()))
+  if (PA_UNLIKELY(instance.IsJoinable())) {
     instance.JoinScan();
+  }
 }
 
 PA_ALWAYS_INLINE void PCScan::MoveToQuarantine(void* object,
@@ -251,8 +252,9 @@
   [[maybe_unused]] const bool succeeded =
       state_bitmap->Quarantine(slot_start, instance.epoch());
 #if PA_CONFIG(STARSCAN_EAGER_DOUBLE_FREE_DETECTION_ENABLED)
-  if (PA_UNLIKELY(!succeeded))
+  if (PA_UNLIKELY(!succeeded)) {
     DoubleFreeAttempt();
+  }
 #else
   // The compiler is able to optimize cmpxchg to a lock-prefixed and.
 #endif  // PA_CONFIG(STARSCAN_EAGER_DOUBLE_FREE_DETECTION_ENABLED)
@@ -260,8 +262,9 @@
   const bool is_limit_reached = instance.scheduler_.AccountFreed(slot_size);
   if (PA_UNLIKELY(is_limit_reached)) {
     // Perform a quick check if another scan is already in progress.
-    if (instance.IsInProgress())
+    if (instance.IsInProgress()) {
       return;
+    }
     // Avoid blocking the current thread for regular scans.
     instance.PerformScan(InvocationMode::kNonBlocking);
   }
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.h b/base/allocator/partition_allocator/starscan/pcscan_internal.h
index c5575aa..74bca4c4 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_internal.h
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.h
@@ -99,9 +99,9 @@
   void ProtectPages(uintptr_t begin, size_t size);
   void UnprotectPages(uintptr_t begin, size_t size);
 
-  void ClearRootsForTesting();                               // IN-TEST
-  void ReinitForTesting(PCScan::InitConfig);                 // IN-TEST
-  void FinishScanForTesting();                               // IN-TEST
+  void ClearRootsForTesting();                // IN-TEST
+  void ReinitForTesting(PCScan::InitConfig);  // IN-TEST
+  void FinishScanForTesting();                // IN-TEST
 
   void RegisterStatsReporter(partition_alloc::StatsReporter* reporter);
   partition_alloc::StatsReporter& GetReporter();
diff --git a/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc b/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
index c228e59..7fe50ad 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
@@ -32,8 +32,9 @@
 void PCScanSchedulingBackend::EnableScheduling() {
   scheduling_enabled_.store(true, std::memory_order_relaxed);
   // Check if *Scan needs to be run immediately.
-  if (NeedsToImmediatelyScan())
+  if (NeedsToImmediatelyScan()) {
     PCScan::PerformScan(PCScan::InvocationMode::kNonBlocking);
+  }
 }
 
 size_t PCScanSchedulingBackend::ScanStarted() {
@@ -182,8 +183,9 @@
     ScopedGuard guard(scheduler_lock_);
     // If |hard_limit_| was set to zero, the soft limit was reached. Bail out if
     // it's not.
-    if (hard_limit_)
+    if (hard_limit_) {
       return false;
+    }
 
     // Check if mutator utilization requiremet is satisfied.
     reschedule_delay = earliest_next_scan_time_ - base::TimeTicks::Now();
@@ -199,8 +201,9 @@
   }
   // Don't reschedule under the lock as the callback can call free() and
   // recursively enter the lock.
-  if (should_reschedule)
+  if (should_reschedule) {
     schedule_delayed_scan_(reschedule_delay.InMicroseconds());
+  }
   return false;
 }
 
diff --git a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
index 390d613..09b0ef3 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
@@ -145,10 +145,11 @@
   for (size_t i = 0; i < num_slots; ++i) {
     void* ptr = root.AllocWithFlagsNoHooks(0, object_size, PartitionPageSize());
     EXPECT_TRUE(ptr);
-    if (i == 0)
+    if (i == 0) {
       first = root.ObjectToSlotStart(ptr);
-    else if (i == num_slots - 1)
+    } else if (i == num_slots - 1) {
       last = root.ObjectToSlotStart(ptr);
+    }
   }
 
   EXPECT_EQ(SlotSpan::FromSlotStart(first), SlotSpan::FromSlotStart(last));
@@ -175,8 +176,9 @@
   auto* slot_span = SlotSpan::FromSlotStart(slot_start);
   for (auto* entry = slot_span->get_freelist_head(); entry;
        entry = entry->GetNext(slot_span->bucket->slot_size)) {
-    if (entry == slot_start_tagged)
+    if (entry == slot_start_tagged) {
       return true;
+    }
   }
   return false;
 }
@@ -830,8 +832,9 @@
 TEST_F(PartitionAllocPCScanWithMTETest, QuarantineOnlyOnTagOverflow) {
   using ListType = List<64>;
 
-  if (!base::CPU::GetInstanceNoAllocation().has_mte())
+  if (!base::CPU::GetInstanceNoAllocation().has_mte()) {
     return;
+  }
 
   {
     auto* obj1 = ListType::Create(root());
diff --git a/base/allocator/partition_allocator/starscan/raceful_worklist.h b/base/allocator/partition_allocator/starscan/raceful_worklist.h
index dc883ba..7eff9cc 100644
--- a/base/allocator/partition_allocator/starscan/raceful_worklist.h
+++ b/base/allocator/partition_allocator/starscan/raceful_worklist.h
@@ -37,9 +37,10 @@
    public:
     explicit RandomizedView(RacefulWorklist& worklist)
         : worklist_(worklist), offset_(0) {
-      if (worklist.data_.size() > 0)
+      if (worklist.data_.size() > 0) {
         offset_ = static_cast<size_t>(
             internal::base::RandGenerator(worklist.data_.size()));
+      }
     }
 
     RandomizedView(const RandomizedView&) = delete;
@@ -77,8 +78,9 @@
 template <typename T>
 template <typename Function>
 void RacefulWorklist<T>::VisitNonConcurrently(Function f) const {
-  for (const auto& t : data_)
+  for (const auto& t : data_) {
     f(t.value);
+  }
 }
 
 template <typename T>
@@ -91,15 +93,17 @@
 
   // To avoid worklist iteration, quick check if the worklist was already
   // visited.
-  if (worklist_.fully_visited_.load(std::memory_order_acquire))
+  if (worklist_.fully_visited_.load(std::memory_order_acquire)) {
     return;
+  }
 
   const auto offset_it = std::next(data.begin(), offset_);
 
   // First, visit items starting from the offset.
   for (auto it = offset_it; it != data.end(); ++it) {
-    if (it->is_visited.load(std::memory_order_relaxed))
+    if (it->is_visited.load(std::memory_order_relaxed)) {
       continue;
+    }
     if (it->is_being_visited.load(std::memory_order_relaxed)) {
       to_revisit.push_back(it);
       continue;
@@ -111,8 +115,9 @@
 
   // Then, visit items before the offset.
   for (auto it = data.begin(); it != offset_it; ++it) {
-    if (it->is_visited.load(std::memory_order_relaxed))
+    if (it->is_visited.load(std::memory_order_relaxed)) {
       continue;
+    }
     if (it->is_being_visited.load(std::memory_order_relaxed)) {
       to_revisit.push_back(it);
       continue;
@@ -124,8 +129,9 @@
 
   // Finally, racefully visit items that were scanned by some other thread.
   for (auto it : to_revisit) {
-    if (PA_LIKELY(it->is_visited.load(std::memory_order_relaxed)))
+    if (PA_LIKELY(it->is_visited.load(std::memory_order_relaxed))) {
       continue;
+    }
     // Don't bail out here if the item is being visited by another thread.
     // This is helpful to guarantee forward progress if the other thread
     // is making slow progress.
diff --git a/base/allocator/partition_allocator/starscan/scan_loop.h b/base/allocator/partition_allocator/starscan/scan_loop.h
index dae76ad..7619873a 100644
--- a/base/allocator/partition_allocator/starscan/scan_loop.h
+++ b/base/allocator/partition_allocator/starscan/scan_loop.h
@@ -79,13 +79,16 @@
 // 64bit regular pool, and only for x86 because a special instruction set is
 // required.
 #if defined(ARCH_CPU_X86_64)
-  if (simd_type_ == SimdSupport::kAVX2)
+  if (simd_type_ == SimdSupport::kAVX2) {
     return RunAVX2(begin, end);
-  if (simd_type_ == SimdSupport::kSSE41)
+  }
+  if (simd_type_ == SimdSupport::kSSE41) {
     return RunSSE4(begin, end);
+  }
 #elif PA_CONFIG(STARSCAN_NEON_SUPPORTED)
-  if (simd_type_ == SimdSupport::kNEON)
+  if (simd_type_ == SimdSupport::kNEON) {
     return RunNEON(begin, end);
+  }
 #endif  // PA_CONFIG(STARSCAN_NEON_SUPPORTED)
   return RunUnvectorized(begin, end);
 }
@@ -108,11 +111,13 @@
     // Keep it MTE-untagged. See DisableMTEScope for details.
     const uintptr_t maybe_ptr = *reinterpret_cast<uintptr_t*>(begin);
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
-    if (PA_LIKELY((maybe_ptr & mask) != base))
+    if (PA_LIKELY((maybe_ptr & mask) != base)) {
       continue;
+    }
 #else
-    if (!maybe_ptr)
+    if (!maybe_ptr) {
       continue;
+    }
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
     derived().CheckPointer(maybe_ptr);
   }
@@ -144,18 +149,23 @@
     const __m256i vand = _mm256_and_si256(maybe_ptrs, regular_pool_mask);
     const __m256i vcmp = _mm256_cmpeq_epi64(vand, vbase);
     const int mask = _mm256_movemask_pd(_mm256_castsi256_pd(vcmp));
-    if (PA_LIKELY(!mask))
+    if (PA_LIKELY(!mask)) {
       continue;
+    }
     // It's important to extract pointers from the already loaded vector.
     // Otherwise, new loads can break in-pool assumption checked above.
-    if (mask & 0b0001)
+    if (mask & 0b0001) {
       derived().CheckPointer(_mm256_extract_epi64(maybe_ptrs, 0));
-    if (mask & 0b0010)
+    }
+    if (mask & 0b0010) {
       derived().CheckPointer(_mm256_extract_epi64(maybe_ptrs, 1));
-    if (mask & 0b0100)
+    }
+    if (mask & 0b0100) {
       derived().CheckPointer(_mm256_extract_epi64(maybe_ptrs, 2));
-    if (mask & 0b1000)
+    }
+    if (mask & 0b1000) {
       derived().CheckPointer(_mm256_extract_epi64(maybe_ptrs, 3));
+    }
   }
   // Run unvectorized on the remainder of the region.
   RunUnvectorized(begin, end);
@@ -183,8 +193,9 @@
     const __m128i vand = _mm_and_si128(maybe_ptrs, regular_pool_mask);
     const __m128i vcmp = _mm_cmpeq_epi64(vand, vbase);
     const int mask = _mm_movemask_pd(_mm_castsi128_pd(vcmp));
-    if (PA_LIKELY(!mask))
+    if (PA_LIKELY(!mask)) {
       continue;
+    }
     // It's important to extract pointers from the already loaded vector.
     // Otherwise, new loads can break in-pool assumption checked above.
     if (mask & 0b01) {
@@ -222,14 +233,17 @@
     const uint64x2_t vand = vandq_u64(maybe_ptrs, regular_pool_mask);
     const uint64x2_t vcmp = vceqq_u64(vand, vbase);
     const uint32_t max = vmaxvq_u32(vreinterpretq_u32_u64(vcmp));
-    if (PA_LIKELY(!max))
+    if (PA_LIKELY(!max)) {
       continue;
+    }
     // It's important to extract pointers from the already loaded vector.
     // Otherwise, new loads can break in-pool assumption checked above.
-    if (vgetq_lane_u64(vcmp, 0))
+    if (vgetq_lane_u64(vcmp, 0)) {
       derived().CheckPointer(vgetq_lane_u64(maybe_ptrs, 0));
-    if (vgetq_lane_u64(vcmp, 1))
+    }
+    if (vgetq_lane_u64(vcmp, 1)) {
       derived().CheckPointer(vgetq_lane_u64(maybe_ptrs, 1));
+    }
   }
   // Run unvectorized on the remainder of the region.
   RunUnvectorized(begin, end);
diff --git a/base/allocator/partition_allocator/starscan/scan_loop_unittest.cc b/base/allocator/partition_allocator/starscan/scan_loop_unittest.cc
index 631864a..ba3b02a 100644
--- a/base/allocator/partition_allocator/starscan/scan_loop_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/scan_loop_unittest.cc
@@ -83,8 +83,9 @@
 #if defined(ARCH_CPU_X86_64)
 TEST(PartitionAllocScanLoopTest, VectorizedSSE4) {
   base::CPU cpu;
-  if (!cpu.has_sse41())
+  if (!cpu.has_sse41()) {
     return;
+  }
   {
     TestScanLoop sl(SimdSupport::kSSE41);
     TestOnRangeWithAlignment<16>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr);
@@ -105,8 +106,9 @@
 
 TEST(PartitionAllocScanLoopTest, VectorizedAVX2) {
   base::CPU cpu;
-  if (!cpu.has_avx2())
+  if (!cpu.has_avx2()) {
     return;
+  }
   {
     TestScanLoop sl(SimdSupport::kAVX2);
     TestOnRangeWithAlignment<32>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr,
diff --git a/base/allocator/partition_allocator/starscan/snapshot.cc b/base/allocator/partition_allocator/starscan/snapshot.cc
index 9efe8c4e..98183f5 100644
--- a/base/allocator/partition_allocator/starscan/snapshot.cc
+++ b/base/allocator/partition_allocator/starscan/snapshot.cc
@@ -28,16 +28,18 @@
     clear_worklist_.Push(super_pages.begin(), super_pages.end());
     scan_worklist_.Push(super_pages.begin(), super_pages.end());
     sweep_worklist_.Push(super_pages.begin(), super_pages.end());
-    if (pcscan.WriteProtectionEnabled())
+    if (pcscan.WriteProtectionEnabled()) {
       unprotect_worklist_.Push(super_pages.begin(), super_pages.end());
+    }
   }
 
   for (const auto& root : pcscan.nonscannable_roots()) {
     const auto& super_pages = root.second;
     clear_worklist_.Push(super_pages.begin(), super_pages.end());
     sweep_worklist_.Push(super_pages.begin(), super_pages.end());
-    if (pcscan.WriteProtectionEnabled())
+    if (pcscan.WriteProtectionEnabled()) {
       unprotect_worklist_.Push(super_pages.begin(), super_pages.end());
+    }
   }
 }
 
diff --git a/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc b/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
index ce9eebdc..d03c874 100644
--- a/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
@@ -261,8 +261,9 @@
     size_t count = 0;
     this->bitmap().IterateUnmarkedQuarantined(
         kTestEpoch, [&count, this](uintptr_t current) {
-          if (count == 0)
+          if (count == 0) {
             EXPECT_EQ(ObjectAddress(1), current);
+          }
           count++;
         });
 
@@ -295,8 +296,9 @@
     size_t count = 0;
     this->bitmap().IterateUnmarkedQuarantined(
         kTestEpoch, [&count, this](uintptr_t current) {
-          if (count == 0)
+          if (count == 0) {
             EXPECT_EQ(ObjectAddress(MiddleIndex() + 1), current);
+          }
           count++;
         });
 
@@ -331,8 +333,9 @@
     size_t count = 0;
     this->bitmap().IterateUnmarkedQuarantined(
         kTestEpoch, [&count, this](uintptr_t current) {
-          if (count == 0)
+          if (count == 0) {
             EXPECT_EQ(ObjectAddress(LastIndex() - 1), current);
+          }
           count++;
         });
 
diff --git a/base/allocator/partition_allocator/starscan/stats_collector.cc b/base/allocator/partition_allocator/starscan/stats_collector.cc
index 33944919..b06e2c0 100644
--- a/base/allocator/partition_allocator/starscan/stats_collector.cc
+++ b/base/allocator/partition_allocator/starscan/stats_collector.cc
@@ -70,11 +70,13 @@
     }
   }
   // Report UMA if process_name is set.
-  if (!process_name_)
+  if (!process_name_) {
     return;
+  }
   for (size_t id = 0; id < accumulated_events.size(); ++id) {
-    if (accumulated_events[id].is_zero())
+    if (accumulated_events[id].is_zero()) {
       continue;
+    }
     reporter.ReportStats(ToUMAString(static_cast<IdType<context>>(id)).c_str(),
                          accumulated_events[id].InMicroseconds());
   }
@@ -90,9 +92,10 @@
                     << survived_quarantine_size()
                     << ", swept bytes: " << swept_size()
                     << ", survival rate: " << survived_rate;
-  if (discarded_quarantine_size_)
+  if (discarded_quarantine_size_) {
     PA_PCSCAN_VLOG(2) << "discarded quarantine size: "
                       << discarded_quarantine_size_;
+  }
 }
 
 template base::TimeDelta StatsCollector::GetTimeImpl(
diff --git a/base/allocator/partition_allocator/starscan/write_protector.cc b/base/allocator/partition_allocator/starscan/write_protector.cc
index 98877928..dfd30a1 100644
--- a/base/allocator/partition_allocator/starscan/write_protector.cc
+++ b/base/allocator/partition_allocator/starscan/write_protector.cc
@@ -112,13 +112,15 @@
 }  // namespace
 
 void UserFaultFDWriteProtector::ProtectPages(uintptr_t begin, size_t length) {
-  if (IsSupported())
+  if (IsSupported()) {
     UserFaultFDWPSet(uffd_, begin, length, UserFaultFDWPMode::kProtect);
+  }
 }
 
 void UserFaultFDWriteProtector::UnprotectPages(uintptr_t begin, size_t length) {
-  if (IsSupported())
+  if (IsSupported()) {
     UserFaultFDWPSet(uffd_, begin, length, UserFaultFDWPMode::kUnprotect);
+  }
 }
 
 PCScan::ClearType UserFaultFDWriteProtector::SupportedClearType() const {
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 584fa4b..c59c226 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -659,7 +659,7 @@
   // Get a drive letter.
   std::wstring real_drive_letter = AsWString(
       ToUpperASCII(AsStringPiece16(temp_dir_.GetPath().value().substr(0, 2))));
-  if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
+  if (!IsAsciiAlpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
     LOG(ERROR) << "Can't get a drive letter to test with.";
     return;
   }
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 0367af55..43d36d89 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -419,6 +419,19 @@
 inline bool IsAsciiPrintable(Char c) {
   return c >= ' ' && c <= '~';
 }
+template <typename Char>
+inline bool IsAsciiControl(Char c) {
+  if constexpr (std::is_signed_v<Char>) {
+    if (c < 0) {
+      return false;
+    }
+  }
+  return c <= 0x1f || c == 0x7f;
+}
+template <typename Char>
+inline bool IsAsciiPunctuation(Char c) {
+  return c > 0x20 && c < 0x7f && !IsAsciiAlphaNumeric(c);
+}
 
 template <typename Char>
 inline bool IsHexDigit(Char c) {
diff --git a/base/values.cc b/base/values.cc
index 0b1b688..b4625137 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1152,10 +1152,6 @@
   return !(lhs < rhs);
 }
 
-absl::optional<int> Value::FindIntKey(StringPiece key) const {
-  return GetDict().FindInt(key);
-}
-
 Value* Value::SetKey(StringPiece key, Value&& value) {
   return GetDict().Set(key, std::move(value));
 }
@@ -1188,18 +1184,10 @@
   return GetDict().FindByDottedPath(path);
 }
 
-absl::optional<bool> Value::FindBoolPath(StringPiece path) const {
-  return GetDict().FindBoolByDottedPath(path);
-}
-
 absl::optional<int> Value::FindIntPath(StringPiece path) const {
   return GetDict().FindIntByDottedPath(path);
 }
 
-absl::optional<double> Value::FindDoublePath(StringPiece path) const {
-  return GetDict().FindDoubleByDottedPath(path);
-}
-
 const std::string* Value::FindStringPath(StringPiece path) const {
   return GetDict().FindStringByDottedPath(path);
 }
@@ -1208,18 +1196,6 @@
   return GetDict().FindStringByDottedPath(path);
 }
 
-const Value* Value::FindDictPath(StringPiece path) const {
-  const Value* cur = GetDict().FindByDottedPath(path);
-  if (!cur || cur->type() != Type::DICT) {
-    return nullptr;
-  }
-  return cur;
-}
-
-Value* Value::FindDictPath(StringPiece path) {
-  return const_cast<Value*>(std::as_const(*this).FindDictPath(path));
-}
-
 const Value* Value::FindListPath(StringPiece path) const {
   const Value* cur = GetDict().FindByDottedPath(path);
   if (!cur || cur->type() != Type::LIST) {
diff --git a/base/values.h b/base/values.h
index 1c393eb..dd3e0347 100644
--- a/base/values.h
+++ b/base/values.h
@@ -757,14 +757,6 @@
   };
 
   // ===== DEPRECATED methods that require `type() == Type::DICT` =====
-
-  // These are convenience forms of `FindKey`. They return `absl::nullopt` or
-  // `nullptr` if the value is not found or doesn't have the type specified in
-  // the function's name.
-  //
-  // DEPRECATED: prefer `Value::Dict::FindInt()`.
-  absl::optional<int> FindIntKey(StringPiece key) const;
-
   // `SetKey` looks up `key` in the underlying dictionary and sets the mapped
   // value to `value`. If `key` could not be found, a new element is inserted.
   // A pointer to the modified item is returned.
@@ -810,28 +802,15 @@
   // Convenience accessors used when the expected type of a value is known.
   // Similar to Find<Type>Key() but accepts paths instead of keys.
   //
-  // DEPRECATED: Use `Value::Dict::FindBoolByDottedPath()`, or
-  // `Value::Dict::FindBool()` if the path only has one component, i.e. has no
-  // dots.
-  absl::optional<bool> FindBoolPath(StringPiece path) const;
   // DEPRECATED: Use `Value::Dict::FindIntByDottedPath()`, or
   // `Value::Dict::FindInt()` if the path only has one component, i.e. has no
   // dots.
   absl::optional<int> FindIntPath(StringPiece path) const;
-  // DEPRECATED: Use `Value::Dict::FindDoubleByDottedPath()`, or
-  // `Value::Dict::FindDouble()` if the path only has one component, i.e. has no
-  // dots.
-  absl::optional<double> FindDoublePath(StringPiece path) const;
   // DEPRECATED: Use `Value::Dict::FindStringByDottedPath()`, or
   // `Value::Dict::FindString()` if the path only has one component, i.e. has no
   // dots.
   const std::string* FindStringPath(StringPiece path) const;
   std::string* FindStringPath(StringPiece path);
-  // DEPRECATED: Use `Value::Dict::FindDictByDottedPath()`, or
-  // `Value::Dict::FindDict()` if the path only has one component, i.e. has no
-  // dots.
-  Value* FindDictPath(StringPiece path);
-  const Value* FindDictPath(StringPiece path) const;
   // DEPRECATED: Use `Value::Dict::FindListByDottedPath()`, or
   // `Value::Dict::FindList()` if the path only has one component, i.e. has no
   // dots.
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 24931ef..12191722 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-12.20230501.2.1
+12.20230515.1.1
diff --git a/chrome/VERSION b/chrome/VERSION
index 91bae96..ec7b9b0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=115
 MINOR=0
-BUILD=5768
+BUILD=5773
 PATCH=0
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 3c711e17..984b4a7 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-115.0.5762.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-115.0.5771.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index cc0b9b6..f6700d100 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-115.0.5761.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-115.0.5771.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/app_management_strings.grdp b/chrome/app/app_management_strings.grdp
index 99864ac..0102d22 100644
--- a/chrome/app/app_management_strings.grdp
+++ b/chrome/app/app_management_strings.grdp
@@ -151,6 +151,9 @@
   <message name="IDS_APP_MANAGEMENT_ARC_MANAGE_PERMISSIONS" desc="Label for a link to manage permissions and more settings for an app.">
     Manage permissions and settings
   </message>
+  <message name="IDS_APP_MANAGEMENT_PERMISSION_ASK" desc="Label explaining that the user will be asked whether an app can access a permission (e.g. camera access) every time it is used.">
+    Ask every time
+  </message>
   <message name="IDS_APP_MANAGEMENT_PERMISSION_ALLOWED" desc="Label explaining that access to a permission (e.g. camera access) is allowed for an app.">
     Allowed
   </message>
diff --git a/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_PERMISSION_ASK.png.sha1 b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_PERMISSION_ASK.png.sha1
new file mode 100644
index 0000000..379d303
--- /dev/null
+++ b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_PERMISSION_ASK.png.sha1
@@ -0,0 +1 @@
+0ebfc899c99f27b04633aa9bb5e9a66a4884a5af
\ No newline at end of file
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index b9367bf..98fa770 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -127,6 +127,7 @@
 #define IDC_FOLLOW                      35033
 #define IDC_UNFOLLOW                    35034
 #define IDC_SAVE_IBAN_FOR_PAGE          35035
+#define IDC_AUTOFILL_MANDATORY_REAUTH   35036
 #define IDC_PASSWORDS_AND_AUTOFILL_MENU 35040
 #define IDC_SHOW_PASSWORD_MANAGER       35041
 #define IDC_SHOW_PAYMENT_METHODS        35042
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 10db077..57234c1 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6380,7 +6380,7 @@
     Emoji Picker
   </message>
   <message name="IDS_ASH_EMOJI_PICKER_COPY_GIF_TO_CLIPBOARD" translateable="false" desc="Message shown to users when they click a gif in emoji picker.">
-    GIF has been copied to your clipboard
+    GIF copied to clipboard
   </message>
 
   <!-- Strings for Custom Tab UI -->
@@ -6523,7 +6523,7 @@
   <message name="IDS_OS_URL_HANDLER_APP_NAME" translateable="false" desc="Name for a hidden app which shows os:// and chrome:// system pages in an app">
     ChromeOS-URLs
   </message>
-  
+
   <!-- Theme Selection -->
   <message name="IDS_THEME_SELECTION_TITLE" desc="Title of the theme selection screen.">
     Personalize your display theme
@@ -6673,27 +6673,12 @@
   <message name="IDS_OFFICE_FALLBACK_REASON_DRIVE_UNAVAILABLE" desc="Explanation for a dialog that appears when an office file is unable to be opened due to Google Drive not being available.">
     The application <ph name="APPLICATION_NAME">$1<ex>Google Docs</ex></ph> requires Drive to be available.
   </message>
-  <message name="IDS_OFFICE_FALLBACK_TITLE_ONEDRIVE_UNAVAILABLE" desc="Title for a dialog that appears when an office file is unable to be opened due to OneDrive not being available.">
-    Can't open <ph name="FILE_NAMES">$1<ex>file.docx</ex></ph> when OneDrive is not available
-  </message>
-  <message name="IDS_OFFICE_FALLBACK_REASON_ONEDRIVE_UNAVAILABLE" desc="Explanation for a dialog that appears when an office file is unable to be opened due to OneDrive not being available.">
-    The application <ph name="APPLICATION_NAME">$1<ex>Microsoft 365</ex></ph> requires OneDrive to be available.
-  </message>
-  <message name="IDS_OFFICE_FALLBACK_TITLE_ERROR_OPENING_WEB" desc="Title for a dialog that appears when an office file is unable to be opened due to an error opening the URL.">
-    Can't open the URL for <ph name="FILE_NAMES">$1<ex>file.docx</ex></ph>
-  </message>
-  <message name="IDS_OFFICE_FALLBACK_REASON_ERROR_OPENING_WEB" desc="Explanation for a dialog that appears when an office file is unable to be opened due to OneDrive not being available.">
-    The application <ph name="APPLICATION_NAME">$1<ex>Microsoft 365</ex></ph> requires OneDrive to be available.
-  </message>
-  <message name="IDS_OFFICE_FALLBACK_TITLE_INVALID_GOOGLE_DOCS_URL" desc="Title for a dialog that appears when an office file is unable to be opened due to the URL for the office file being inaccessible.">
-    Can't open the URL for <ph name="FILE_NAMES">$1<ex>file.docx</ex></ph>
-  </message>
-  <message name="IDS_OFFICE_FALLBACK_REASON_INVALID_GOOGLE_DOCS_URL" desc="Explanation for a dialog that appears when an office file is unable to be opened from Google Drive due to the URL for the office file being inaccessible.">
-    The application <ph name="APPLICATION_NAME">$1<ex>Google Docs</ex></ph> requires a valid <ph name="APPLICATION_NAME">$1<ex>Google Docs</ex></ph> URL.
-  </message>
   <message name="IDS_OFFICE_FALLBACK_INSTRUCTIONS" desc="Office Fallback dialog instructions for the choices (buttons) the user has available to open the office file.">
     Choose "Try again", or choose "Open in offline editor" to use limited view and editing options.
   </message>
+  <message name="IDS_OFFICE_FALLBACK_INSTRUCTIONS_DRIVE_UNAVAILABLE" desc="Office Fallback dialog instructions for when Google Drive is not available in Files app and the user should try to enable it." translateable="false">
+    Try enabling Google Drive in Settings.
+  </message>
 
   <!-- security curtain -->
   <message name="IDS_SECURITY_CURTAIN_TITLE" desc="Title text displayed to inform the user a remote admin has taken control of the ChromeOs device.">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ERROR_OPENING_WEB.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ERROR_OPENING_WEB.png.sha1
deleted file mode 100644
index bce4befb..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ERROR_OPENING_WEB.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-8e7190e7c7232d6448c920238023eb9bad80962b
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_INVALID_GOOGLE_DOCS_URL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_INVALID_GOOGLE_DOCS_URL.png.sha1
deleted file mode 100644
index 61eeebe9..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_INVALID_GOOGLE_DOCS_URL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-519af9404031cf2ef670033952aa03c9cb4161ba
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ONEDRIVE_UNAVAILABLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ONEDRIVE_UNAVAILABLE.png.sha1
deleted file mode 100644
index 203dae75..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_REASON_ONEDRIVE_UNAVAILABLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-183b34e2de10b368c0e679c9f39b053a17218bce
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ERROR_OPENING_WEB.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ERROR_OPENING_WEB.png.sha1
deleted file mode 100644
index 6cb311e..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ERROR_OPENING_WEB.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-90880b6e0076d74505e1ad2bdaa1660bc2131054
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_INVALID_GOOGLE_DOCS_URL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_INVALID_GOOGLE_DOCS_URL.png.sha1
deleted file mode 100644
index dd07022..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_INVALID_GOOGLE_DOCS_URL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6410e0c5627ca1edff602ec49c29de4635b241ed
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ONEDRIVE_UNAVAILABLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ONEDRIVE_UNAVAILABLE.png.sha1
deleted file mode 100644
index 0061ff2..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OFFICE_FALLBACK_TITLE_ONEDRIVE_UNAVAILABLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5741fb48c0aeeb8ab467e6877ca5b5b73141ea2e
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 932808ba..f73552e 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -660,10 +660,6 @@
                desc="Subpage summary for malware warning for the user.">
         Chromium blocked this file because it has malware
       </message>
-      <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT"
-               desc="Subpage summary of warning for Deep Scanning.">
-        Chromium recommends scanning this file because it may be dangerous
-      </message>
 
       <!-- Tailored Warning in Download Bubble Items -->
       <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_SUSPICIOUS_ARCHIVE"
diff --git a/chrome/app/chromium_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1 b/chrome/app/chromium_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
deleted file mode 100644
index f6509e9a..0000000
--- a/chrome/app/chromium_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a1014828ef495bc9f080b0a91ceb7dc637919ab9
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index c820c79..e25b8b4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2692,11 +2692,11 @@
       </message>
       <message name="IDS_DOWNLOAD_BUBBLE_SCAN"
                desc="Label for the button prompting for Deep Scanning">
-        Scan
+        Scan for malware
       </message>
       <message name="IDS_DOWNLOAD_BUBBLE_OPEN"
                desc="Label for the button prompting to bypass Deep Scanning">
-        Open
+        Open anyway
       </message>
       <message name="IDS_DOWNLOAD_BUBBLE_OPEN_NOW"
                desc="Label for the button prompting to open a download while deep scanning is in progress">
@@ -2834,6 +2834,20 @@
                desc="Subpage summary of warning for a file blocked for being too large.">
         Your organization blocked this file because it is too big for a security check. You can open files up to 50 MB.
       </message>
+      <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT"
+               desc="Subpage summary of warning for a file where we recommend sending the file for deep scanning.">
+        This file might be a virus or malware.
+
+You can send it to Google to check if it's unsafe. Scans usually take a few seconds.
+      </message>
+      <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER"
+        desc="Additional text describing the process of deep scanning a download">
+        Analysis done by <ph name="LINK">$1<ex>Google Safe Browsing</ex></ph>
+      </message>
+      <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK"
+        desc="Text of link within IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER">
+        Google Safe Browsing
+      </message>
       <message name="IDS_DOWNLOAD_BUBBLE_TRY_AGAIN"
                desc="Retry button when a download is failed">
         Try again
@@ -13024,6 +13038,16 @@
         <ph name="FILE_INFO">$2<ex>file:123</ex></ph>
         <ph name="EVENT_NAME">$3<ex>Event Description</ex></ph>
       </message>
+      <if expr="chromeos_ash">
+        <message name="IDS_DEVICE_LOG_OS_LINK_CONTAINER" desc="Text and link on the os://device-log page from ChromeOS which directs a user to a page showing Chrome browser specific device-log">
+          Looking for the browser device-log page? Visit<ph name="BEGIN_LINK">&lt;a href="#" id="os-link-href"&gt;</ph><ph name="CHROME_DEVICE_LOG_LINK">$1</ph><ph name="END_LINK">&lt;/a&gt;</ph>.
+        </message>
+      </if>
+      <if expr="chromeos_lacros">
+        <message name="IDS_DEVICE_LOG_OS_LINK_CONTAINER" desc="Text and link on the chrome://device-log page from ChromeOS which directs a user to a dialog showing OS specific device-log">
+          Looking for the system device-log page? Visit<ph name="BEGIN_LINK">&lt;a href="$1" id="os-link-href"&gt;</ph><ph name="OS_DEVICE_LOG_LINK">$1</ph><ph name="END_LINK">&lt;/a&gt;</ph>.
+        </message>
+      </if>
 
     <!-- WebUsb Notification -->
     <message name="IDS_WEBUSB_DEVICE_DETECTED_NOTIFICATION" desc="Content for notification shown to the user when a USB device gets plugged in.">
diff --git a/chrome/app/generated_resources_grd/IDS_DEVICE_LOG_OS_LINK_CONTAINER.png.sha1 b/chrome/app/generated_resources_grd/IDS_DEVICE_LOG_OS_LINK_CONTAINER.png.sha1
new file mode 100644
index 0000000..f42662b
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DEVICE_LOG_OS_LINK_CONTAINER.png.sha1
@@ -0,0 +1 @@
+a398a4254a34a2b936b25aa7f6244f263483c333
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_OPEN.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_OPEN.png.sha1
index b42072d..afda0909 100644
--- a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_OPEN.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_OPEN.png.sha1
@@ -1 +1 @@
-d6022e110b8cd372844715e36de245c0833fce19
\ No newline at end of file
+1b4a9021d96b254fb17691396a645c22dae1b09e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SCAN.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SCAN.png.sha1
index b42072d..afda0909 100644
--- a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SCAN.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SCAN.png.sha1
@@ -1 +1 @@
-d6022e110b8cd372844715e36de245c0833fce19
\ No newline at end of file
+1b4a9021d96b254fb17691396a645c22dae1b09e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK.png.sha1
new file mode 100644
index 0000000..afda0909
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK.png.sha1
@@ -0,0 +1 @@
+1b4a9021d96b254fb17691396a645c22dae1b09e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER.png.sha1
new file mode 100644
index 0000000..afda0909
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER.png.sha1
@@ -0,0 +1 @@
+1b4a9021d96b254fb17691396a645c22dae1b09e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
new file mode 100644
index 0000000..afda0909
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
@@ -0,0 +1 @@
+1b4a9021d96b254fb17691396a645c22dae1b09e
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 7937843..d7ce2b8 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -683,10 +683,6 @@
                desc="Subpage summary for malware warning for the user.">
         Chrome blocked this file because it has malware
       </message>
-      <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT"
-               desc="Subpage summary of warning for Deep Scanning.">
-        Chrome recommends scanning this file because it may be dangerous
-      </message>
 
       <!-- Tailored Warning in Download Bubble Items -->
       <message name="IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_SUSPICIOUS_ARCHIVE"
diff --git a/chrome/app/google_chrome_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
deleted file mode 100644
index f6509e9a..0000000
--- a/chrome/app/google_chrome_strings_grd/IDS_DOWNLOAD_BUBBLE_SUBPAGE_SUMMARY_DEEP_SCANNING_PROMPT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a1014828ef495bc9f080b0a91ceb7dc637919ab9
\ No newline at end of file
diff --git a/chrome/app/resources/chromium_strings_da.xtb b/chrome/app/resources/chromium_strings_da.xtb
index a90dabc1..995e6e9fe 100644
--- a/chrome/app/resources/chromium_strings_da.xtb
+++ b/chrome/app/resources/chromium_strings_da.xtb
@@ -43,7 +43,7 @@
 <translation id="2008474315282236005">Denne handling sletter ét element på denne enhed. Hvis du senere vil hente dine data igen, skal du logge ind på Chromium som <ph name="USER_EMAIL" />.</translation>
 <translation id="2018879682492276940">Installationen mislykkedes. Prøv igen.</translation>
 <translation id="2020032459870799438">Du kan tjekke, om dine andre adgangskoder er beskyttet mod brud på datasikkerheden og andre sikkerhedsproblemer ved at <ph name="BEGIN_LINK" />logge ind på Chromium<ph name="END_LINK" />.</translation>
-<translation id="2049376729098081731">Vælg, om du vil inkludere Chromium-historikken for at få mere tilpassede oplevelser i Googles tjenester</translation>
+<translation id="2049376729098081731">Vælg, om du vil inkludere Chromium-historikken for at få mere personligt tilpassede oplevelser i Googles tjenester</translation>
 <translation id="2088953378266246249">Oplysninger om, hvordan Chromium administrerer sine rodcertifikater</translation>
 <translation id="2174178932569897599">Tilpas Chromium</translation>
 <translation id="2174917724755363426">Installationen er ikke fuldført. Er du sikker på, at du vil annullere?</translation>
@@ -117,7 +117,7 @@
 <translation id="364817392622123556">{COUNT,plural, =0{Der er en ny Chromium-opdatering, som anvendes, så snart du genstarter.}=1{Der er en ny Chromium-opdatering, som anvendes, så snart du genstarter. Dit inkognitovindue åbnes ikke igen.}one{Der er en ny Chromium-opdatering, som anvendes, så snart du genstarter. # inkognitovindue åbnes ikke igen.}other{Der er en ny Chromium-opdatering, som anvendes, så snart du genstarter. Dine # inkognitovinduer åbnes ikke igen.}}</translation>
 <translation id="3651803019964686660">Hvis du vil sende et nummer fra <ph name="ORIGIN" /> til din Android-telefon, skal du logge ind på Chromium på begge enheder.</translation>
 <translation id="3685209450716071127">Chromium kan ikke tjekke dine adgangskoder. Prøv at tjekke din internetforbindelse.</translation>
-<translation id="3702352323269013324">Få flere oplysninger om personlig annoncetilpasning i Chromium</translation>
+<translation id="3702352323269013324">Få flere oplysninger om personlig tilpasning af annoncer i Chromium</translation>
 <translation id="370962675267501463">{COUNT,plural, =0{Din administrator anmoder om, at du genstarter Chromium for at anvende denne opdatering}=1{Din administrator anmoder om, at du genstarter Chromium for at anvende denne opdatering. Dit inkognitovindue åbnes ikke igen.}one{Din administrator anmoder om, at du genstarter Chromium for at anvende denne opdatering. # inkognitovindue åbnes ikke igen.}other{Din administrator anmoder om, at du genstarter Chromium for at anvende denne opdatering. Dine # inkognitovinduer åbnes ikke igen.}}</translation>
 <translation id="3713809861844741608">Åbn linket på en ny Chromium-&amp;fane</translation>
 <translation id="378917192836375108">Med Chromium kan du klikke på et telefonnummer på nettet og ringe op til det via Skype!</translation>
@@ -317,7 +317,7 @@
 <translation id="7682213815243802460">Du kan få flere oplysninger om disse funktioner i Chromium-indstillingerne.</translation>
 <translation id="7682601070171973634">Chromium afprøver nye funktioner, der giver websites mulighed for at levere den samme browseroplevelse med færre af dine data</translation>
 <translation id="7686590090926151193">Chromium er ikke din standardbrowser</translation>
-<translation id="7689606757190482937">Synkroniser og tilpas Chromium på alle dine enheder</translation>
+<translation id="7689606757190482937">Synkroniser og personligt tilpas Chromium på alle dine enheder</translation>
 <translation id="7745317241717453663">Denne handling sletter dine browserdata på denne enhed. Hvis du senere vil hente dine data igen, skal du logge ind på Chromium som <ph name="USER_EMAIL" />.</translation>
 <translation id="7747138024166251722">Installationsprogrammet kunne ikke oprette en midlertidig mappe. Tjek, om der er tilstrækkelig diskplads, og om der er tilladelse til at installere software.</translation>
 <translation id="7786760609782648049">Gør Chromium hurtigere</translation>
@@ -343,7 +343,7 @@
 <translation id="8290862415967981663">Denne fil kan være farlig, så Chromium har blokeret den.</translation>
 <translation id="8318772038038596122">Din organisation lukker Chromium, når browseren ikke har været i brug i <ph name="TIMEOUT_DURATION" />.</translation>
 <translation id="8325404639443959713">Gør mere med Chromium</translation>
-<translation id="8330519371938183845">Log ind for at synkronisere og tilpasse Chromium på alle dine enheder</translation>
+<translation id="8330519371938183845">Log ind for at synkronisere og personligt tilpasse Chromium på alle dine enheder</translation>
 <translation id="8340674089072921962"><ph name="USER_EMAIL_ADDRESS" /> brugte tidligere Chromium</translation>
 <translation id="8357820681460164151">Log ind, og aktivér derefter synkronisering for at få adgang til dine Chromium-ting på alle dine enheder</translation>
 <translation id="8360718212975266891">Hvis du vil have fremtidige Chromium-opdateringer, skal du have Windows 10 eller nyere. Denne computer har Windows 8.</translation>
diff --git a/chrome/app/resources/chromium_strings_lo.xtb b/chrome/app/resources/chromium_strings_lo.xtb
index 1ddfa3c..bf0a67c 100644
--- a/chrome/app/resources/chromium_strings_lo.xtb
+++ b/chrome/app/resources/chromium_strings_lo.xtb
@@ -94,6 +94,7 @@
 <translation id="3179665906251668410">ເປີດລິ້ງໃນໜ້າຈໍທີ່ບໍ່ເຜີຍຕົວຕົນຂອງ Chromium</translation>
 <translation id="3185330573522821672">ປັບແຕ່ງໂປຣໄຟລ໌ Chromium ໃໝ່ຂອງທ່ານ</translation>
 <translation id="3190315855212034486">ໂຮ້! Chromium ​ເກີດ​ຂັດຂ້ອງ. ເປີດໃຊ້ໃໝ່ດຽວນີ້ບໍ?</translation>
+<translation id="3255926992597692024">Chromium ກຳລັງພະຍາຍາມແກ້ໄຂການຕັ້ງຄ່າສຳລັບການຕື່ມວິທີການຈ່າຍເງິນ.</translation>
 <translation id="3258596308407688501">Chromium ບໍ່ສາມາດອ່ານ ແລະຂຽນໄປໃສ່ໄດເຣັກຕໍຣີຂໍ້ມູນຂອງມັນໄດ້:
 
 <ph name="USER_DATA_DIRECTORY" /></translation>
@@ -200,6 +201,7 @@
 <translation id="5653831366781983928">ກະລຸນາປິດເປີດ Chromium ຄືນໃໝ່ຕອນນີ້</translation>
 <translation id="5690427481109656848">Google LLC</translation>
 <translation id="5698481217667032250">ສະ​ແດງ Chromium ເປັນພາສານີ້</translation>
+<translation id="585620188971323280">ແກ້ໄຂການຕັ້ງຄ່າສຳລັບການຕື່ມວິທີການຈ່າຍເງິນ.</translation>
 <translation id="5862307444128926510">ຍິນ​ດີ​ຕ້ອນ​ຮັບສູ່ Chromium</translation>
 <translation id="5883558403894052917">Chromium ພົບວ່າລາຍການເຫຼົ່ານີ້ມີເມົາແວ:</translation>
 <translation id="5895138241574237353">ເລີ່ມຕົ້ນໃໝ່</translation>
diff --git a/chrome/app/resources/generated_resources_af.xtb b/chrome/app/resources/generated_resources_af.xtb
index 78f8c505..1c0d858 100644
--- a/chrome/app/resources/generated_resources_af.xtb
+++ b/chrome/app/resources/generated_resources_af.xtb
@@ -218,6 +218,7 @@
 <translation id="1176471985365269981">Mag nie lêers of vouers op jou toestel wysig nie</translation>
 <translation id="1177863135347784049">Gepasmaak</translation>
 <translation id="1178581264944972037">Laat wag</translation>
+<translation id="1178601482396475810">Bestuur toestelsinkronisering</translation>
 <translation id="117916940443676133">Jou sekuriteitsleutel word nie met 'n PIN beskerm nie. Om aanmelddata te bestuur, skep eers 'n PIN.</translation>
 <translation id="1181037720776840403">Verwyder</translation>
 <translation id="1181366777303791449">op <ph name="MAIN_FRAME_ETLD_PLUS_ONE" /></translation>
@@ -355,6 +356,7 @@
 <translation id="130097046531636712">Dit verleng die batterykrag deur agtergrondaktiwiteit en visuele effekte, soos gladde rollees, te beperk</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> kan die volgende lêers wysig</translation>
 <translation id="1302227299132585524">Laat JavaScript vanaf Apple-geleenthede toe</translation>
+<translation id="1302654693270046655"><ph name="GROUP_NAME" />-groep – <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">Boekmerk HTML-lêer</translation>
 <translation id="1303671224831497365">Geen Bluetooth-toestelle gevind nie</translation>
 <translation id="130491383855577612">Linux-programme en -lêers is suksesvol vervang</translation>
@@ -1062,6 +1064,7 @@
 <translation id="1877520246462554164">Kon nie stawingteken kry nie. Meld af en meld dan weer aan om weer te probeer.</translation>
 <translation id="1877860345998737529">Wissel handelingtoewysing</translation>
 <translation id="1878155070920054810">Dit lyk of jou Chromebook se krag op gaan wees voordat die opdatering voltooi is. Maak seker dat dit reg laai om onderbreking te vermy.</translation>
+<translation id="1878477879455105085">Oopgemaak</translation>
 <translation id="1878885068166344708">Item word gemerk wanneer jy fokus skuif. Druk Tab of kies ’n item om die fokus te verander.</translation>
 <translation id="1879000426787380528">Meld aan as</translation>
 <translation id="18802377548000045">Oortjies krimp na groot breedte</translation>
@@ -1446,6 +1449,7 @@
 <translation id="2204034823255629767">Lees en verander enigiets wat jy invoer</translation>
 <translation id="2204387456724731099">Hierdie keuse kon nie vertaal word nie</translation>
 <translation id="2210462644007531147">Kon nie installering voltooi nie</translation>
+<translation id="2211245494465528624">Bestuur sinkroniseringopsies</translation>
 <translation id="2212565012507486665">Laat webkoekies toe</translation>
 <translation id="2214018885812055163">Gedeelde vouers</translation>
 <translation id="2214884991347062907">Verkeerde wagwoord; probeer weer</translation>
@@ -1544,6 +1548,7 @@
 <translation id="2296218178174497398">Toestelopsporing</translation>
 <translation id="2297705863329999812">Soek drukkers</translation>
 <translation id="2297822946037605517">Deel hierdie bladsy</translation>
+<translation id="229871422646860597">Ontspeld van nutsbalk</translation>
 <translation id="2299734369537008228">Glyer: <ph name="MIN_LABEL" /> tot <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">Sluit alle loglêers wat deur debugd ingesamel is as 'n afsonderlike argief in.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2174,6 +2179,7 @@
 <translation id="2811205483104563968">Rekeninge</translation>
 <translation id="2811564570599779918">Vermindering van strooipos en bedrog</translation>
 <translation id="2812049959647166806">Thunderbolt word nie gesteun nie</translation>
+<translation id="2812171980080389735">Gestoorde netwerke en wagwoorde sodat jy in ’n kits kan koppel</translation>
 <translation id="2813094189969465044">Ouerkontroles</translation>
 <translation id="281390819046738856">Versoek kon nie onderteken word nie.</translation>
 <translation id="2814489978934728345">Hou op om hierdie bladsy te laai</translation>
@@ -2213,6 +2219,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">Jou PIN is bygevoeg</translation>
 <translation id="2849936225196189499">Kritiek</translation>
+<translation id="285033512555869047">Toe</translation>
 <translation id="2850541429955027218">Voeg tema by</translation>
 <translation id="2850672011315104382">Leestekenstyl</translation>
 <translation id="2852385257476173980">’n Lys werwe wat jy besoek, kan hier verskyn terwyl jy deur die web blaai</translation>
@@ -2256,6 +2263,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> en <ph name="NUMBER_OF_DEVICES" /> ander mense</translation>
 <translation id="2889043468805635730">Geen probleme gevind nie</translation>
 <translation id="2889064240420137087">Maak skakel oop met …</translation>
+<translation id="2890206081124517553">Onthou jou werkskermagtergrond op al jou toestelle</translation>
 <translation id="2891566119238851894">Maak soekbladsy in kantpaneel oop. Soekbladsy is nie oop in die kantpaneel nie.</translation>
 <translation id="2891922230654533301">Gebruik jou toestel om by <ph name="APP_NAME" /> aan te meld?</translation>
 <translation id="2893013536106749396">Kies kaarte wat jou op hoogte hou van dinge wat vir jou belangrik is</translation>
@@ -2277,6 +2285,7 @@
 <translation id="2907619724991574506">Afskop-URL'e</translation>
 <translation id="2907798539022650680">Kon nie aan "<ph name="NAME" />" koppel nie: <ph name="DETAILS" />
     Bedienerboodskap: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">Deel seine</translation>
 <translation id="2908162660801918428">Voeg mediagalery by gids</translation>
 <translation id="2908358077082926882">Druk "<ph name="CURRENTKEY" />" weer om toewysing te verwyder en <ph name="RESPONSE" /></translation>
 <translation id="2909506265808101667">Kon nie aan Google-dienste koppel nie. Gaan jou netwerkverbinding na en probeer weer. Foutkode: <ph name="ERROR_CODE" />.</translation>
@@ -2381,6 +2390,7 @@
 <translation id="3003828226041301643">Kan nie die toestel aan die domein koppel nie. Gaan jou rekening na om seker te maak dat jy voorregte het om toestelle by te voeg.</translation>
 <translation id="3003967365858406397">Jou <ph name="PHONE_NAME" /> sal 'n privaat Wi-Fi-verbinding skep.</translation>
 <translation id="3004385386820284928">Gepasmaakte sleutelbordsleutels</translation>
+<translation id="3005376701115952939">Apps-sinkronisering word in stelselinstellings gestel</translation>
 <translation id="3005574332301273731">Moenie wys nie</translation>
 <translation id="3006881078666935414">Geen gebruikdata nie</translation>
 <translation id="3007410324195400631">Voeg notas oor hierdie bladsy by</translation>
@@ -2762,6 +2772,7 @@
 <translation id="3369624026883419694">Los tans gasheer op …</translation>
 <translation id="3370260763947406229">Outoregstelling</translation>
 <translation id="3371140690572404006">USB C-toestel (voorste poort aan regterkant)</translation>
+<translation id="3371351218553893534">Reël is te lank: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">Lees vouers wat jy in die program oopmaak</translation>
 <translation id="3373059063088819384">Maak in leesmodus oop</translation>
 <translation id="3373701465337594448">Indien dit aan is, verskyn ’n lys werwe wat jy besoek wat jou belangstellings raai hier</translation>
@@ -2832,6 +2843,9 @@
 <translation id="3434272557872943250">As die bykomende Web- en App-aktiwiteit-instelling vir jou kind aangeskakel is, kan hierdie data in hul Google-rekening gestoor word. Kom by families.google.com meer te wete oor hierdie instellings en hoe om hulle te verstel.</translation>
 <translation id="3434475275396485144">Jou foon se administrateur bestuur hierdie instelling</translation>
 <translation id="3434512374684753970">Oudio en video</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />Meld op die volgende skerm aan met jou Google-rekening.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Dit is dieselfde rekening wat jy vir Gmail, YouTube, Chrome en ander Google-dienste gebruik. Gebruik jou rekening vir ’n gepersonaliseerde ervaring en maklike toegang tot al jou inligting.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />As jy nie ’n Google-rekening het nie, sal jy een op die volgende skerm kan skep.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">"<ph name="EXTENSION_NAME" />" versoek tans jou <ph name="CODE_TYPE" /></translation>
 <translation id="3435738964857648380">Sekuriteit</translation>
 <translation id="343578350365773421">Papier is op</translation>
@@ -2878,6 +2892,7 @@
 <translation id="346546413339447252">Kry afslag vir <ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> en meer</translation>
 <translation id="3468298837301810372">Etiket</translation>
 <translation id="3468999815377931311">Android-foon</translation>
+<translation id="3469345458390352459">Sodra dit aangeskakel is, sal jou apps op enige Chrome-toestelle beskikbaar wees nadat jy met jou Google-rekening aangemeld het.  Web-apps sal deur Chrome gesinkroniseer word selfs as ander blaaiersinkroniseringkenmerke afgeskakel is.</translation>
 <translation id="3469583217479686109">Selekteernutsding</translation>
 <translation id="3470392222765168737">Volg werf</translation>
 <translation id="3471876058939596279">HDMI- en USB Tipe C-poorte kan nie tegelyk vir video gebruik word nie. Gebruik 'n ander videopoort.</translation>
@@ -3340,6 +3355,7 @@
 <translation id="3855441664322950881">Pakketuitbreiding</translation>
 <translation id="3855676282923585394">Voer boekmerke en instellings in …</translation>
 <translation id="3856096718352044181">Bevestig dat dit 'n geldige verskaffer is of probeer later weer</translation>
+<translation id="3856470183388031602">Gebruik jou Google-rekening op jou <ph name="DEVICE_TYPE" /></translation>
 <translation id="3856800405688283469">Kies tydsone</translation>
 <translation id="3857807444929313943">Lig en raak dan weer</translation>
 <translation id="3858860766373142691">Naam</translation>
@@ -3379,6 +3395,7 @@
 <translation id="3894123633473837029">Sluit onlangse Assistent-geskiedenis deur Sherlog in. Dit kan jou identiteit, ligging en ontfoutinligting insluit. <ph name="BEGIN_LINK" />Kom meer te wete<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">Voeg vouer by</translation>
 <translation id="3894770151966614831">Skuif na Google-rekening toe?</translation>
+<translation id="3894983081771074056">Sleutelbord- en muisgedrag, taalvoorkeure, en meer</translation>
 <translation id="3895076768659607631">&amp;Bestuur soekenjins …</translation>
 <translation id="3895090224522145010">Kerberos-gebruikernaam</translation>
 <translation id="389521680295183045">Werwe kan vra om te weet wanneer jy jou toestel aktief gebruik</translation>
@@ -3514,6 +3531,7 @@
 <translation id="3994878504415702912">Zoem</translation>
 <translation id="3995138139523574647">USB C-toestel (agterste poort aan regterkant)</translation>
 <translation id="3995963973192100066">Speel animasie</translation>
+<translation id="399788104667917863">Spel aan nutsbalk vas</translation>
 <translation id="4001540981461989979">Merk muisskermpyltjie wanneer dit beweeg</translation>
 <translation id="4002440992267487163">PIN-opstelling</translation>
 <translation id="4005817994523282006">Tydsone-bespeuringsmetode</translation>
@@ -3672,12 +3690,16 @@
 <translation id="4147911968024186208">Herprobeer asseblief. Kontak jou steundiensverteenwoordiger as jy weer hierdie fout sien.</translation>
 <translation id="4150201353443180367">Vertoon</translation>
 <translation id="4150569944729499860">Skermkonteks</translation>
+<translation id="4151843924968445052">Deel toestelseine?</translation>
 <translation id="4152011295694446843">Jy sal jou boekmerke hier kry</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 oortjie}other{# oortjies}}</translation>
 <translation id="4154664944169082762">Vingerafdrukke</translation>
 <translation id="4157869833395312646">Microsoft-bediener hek-kriptografie</translation>
 <translation id="4158315983204257156">Webwerf se teksgrootte en lettertipe</translation>
 <translation id="4158364720893025815">Slaag</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />As jy jou Chrome-toestelle toelaat om outomatiese verslae te stuur, help dit ons om te prioritiseer wat om in ChromeOS reg te stel en te verbeter. Hierdie verslae kan dinge insluit soos wanneer ChromeOS omval, watter kenmerke jy gebruik, hoeveel geheue jy gewoonlik gebruik, en diagnostiese en gebruiksdata oor Android-apps. Sekere saamgestelde data sal ook Google-apps en -vennote, soos Android-ontwikkelaars, help. Ander appdiagnostiek en gebruiksdata, insluitend vir Android- en webapps, sal ingesamel word as appsinkronisering ook aangeskakel is.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Jy kan toestemming vir hierdie verslae enige tyd in jou ChromeOS-toestel se instellings begin of stop. As jy ’n domeinadmin is, kan jy hierdie instelling in die adminkonsole verander.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />As die Web- en Appaktiwiteit-instelling vir jou Google-rekening aangeskakel is, kan jou Android-data in jou Google-rekening gestoor word. Jy kan by account.google.com jou data sien, dit uitvee en jou rekeninginstellings verander.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;Google Wagwoordbestuurder</translation>
 <translation id="4163560723127662357">Onbekende sleutelbord</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> behoort nie aan 'n geldige organisasie nie. Kontak jou administrateur. As jy 'n administrateur is, kan jy jou organisasie opstel deur te gaan na: g.co/ChromeEnterpriseAccount</translation>
@@ -4001,6 +4023,9 @@
 <translation id="4452898361839215358">of kies PPD. <ph name="LINK_BEGIN" />Kom meer te wete<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">Raak die vingerafdruksensor bo regs op jou sleutelbord. Jou vingerafdrukdata word veilig geberg en verlaat nooit jou <ph name="DEVICE_TYPE" /> nie.</translation>
 <translation id="4453946976636652378">Soek met <ph name="SEARCH_ENGINE_NAME" /> of tik 'n URL in</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />As jy Chrome-toestelle toelaat om outomatiese verslae te stuur, help dit ons om te prioritiseer wat om in ChromeOS reg te stel en te verbeter. Hierdie verslae kan dinge insluit soos wanneer ChromeOS omval, watter kenmerke gebruik is, hoeveel geheue gewoonlik gebruik is, en diagnostiese en gebruiksdata oor Android-apps. Sekere saamgestelde data sal ook Google-apps en -vennote, soos Android-ontwikkelaars, help. Ander appdiagnostiek en gebruiksdata, insluitend vir Android- en webapps, sal ingesamel word as appsinkronisering ook aangeskakel is.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Jy kan toestemming vir hierdie verslae enige tyd in die instellings van jou kind se Chrome-toestel begin of stop. As jy ’n domeinadministrateur is, kan jy hierdie instelling in die adminkonsole verander.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />As die Web- en Appaktiwiteit-instelling vir jou kind se Google-rekening aangeskakel is, kan jou kind se data ook in hul Google-rekening gestoor word. Kom by families.google.com meer te wete oor hierdie instellings en hoe om hulle te verstel.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">Kies huidige stem:</translation>
 <translation id="4459169140545916303"><ph name="DEVICE_LAST_ACTIVATED_TIME" /> dae gelede aktief</translation>
 <translation id="4460014764210899310">Ongroepeer</translation>
@@ -4381,6 +4406,7 @@
 <translation id="4806457879608775995">Lees hierdie bepalings en beheer jou data</translation>
 <translation id="4807098396393229769">Naam op kaart</translation>
 <translation id="4808667324955055115">Opspringers geblokkeer:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Kontroleer <ph name="BEGIN_BOLD" />1 uitbreiding<ph name="END_BOLD" /> wat uit die Chrome Webwinkel verwyder is}other{Kontroleer <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} uitbreidings<ph name="END_BOLD" /> wat uit die Chrome Webwinkel verwyder is}}</translation>
 <translation id="4809079943450490359">Instruksies deur jou toesteladministrateur:</translation>
 <translation id="4809447465126035330">Vee uit</translation>
 <translation id="480990236307250886">Maak die tuisblad oop</translation>
@@ -4704,6 +4730,7 @@
 <translation id="5101839224773798795">Klik outomaties wanneer die merker stop</translation>
 <translation id="5106350808162641062">Verwyder</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> is onder toesig van Family Link. Jy kan skoolrekeninge byvoeg om met ouertoesig toegang tot skoolhulpbronne te kry.</translation>
+<translation id="5107093668001980925">Moet nooit <ph name="MODULE_NAME" /> wys nie</translation>
 <translation id="5107443654503185812">'n Uitbreiding het Veiligblaai afgeskakel</translation>
 <translation id="5108967062857032718">Instellings – Verwyder Android-programme</translation>
 <translation id="5109044022078737958">Mia</translation>
@@ -4714,6 +4741,7 @@
 <translation id="5111794652433847656">Daar is geen wagwoordsleutels vir <ph name="APP_NAME" /> op hierdie toestel nie</translation>
 <translation id="5112577000029535889">Ontwikkelaarnutsgoed</translation>
 <translation id="511313294362309725">Skakel Kitsbind aan</translation>
+<translation id="5113384440341086023">Apps uit die Play Winkel geïnstalleer en web-apps van Chrome-blaaier af</translation>
 <translation id="51143538739122961">Sit jou sekuriteitsleutel in en raak daaraan</translation>
 <translation id="5115309401544567011">Prop jou <ph name="DEVICE_TYPE" /> by 'n kragbron in.</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4759,6 +4787,7 @@
 <translation id="5154702632169343078">Onderwerp</translation>
 <translation id="5155327081870541046">Voer die kortpad vir die werf wat jy wil deursoek, soos "@boekmerke", by die adresbalk in. Druk dan jou voorkeurkortpadsleutel en voer jou soekterm in.</translation>
 <translation id="5156638757840305347">Skermpyltjie word gemerk wanneer dit verskyn of beweeg</translation>
+<translation id="5157250307065481244">Bekyk werfbesonderhede</translation>
 <translation id="5157635116769074044">Speld hierdie bladsy aan die beginskerm vas …</translation>
 <translation id="5158206172605340248">Aksentmerkkieslys is toegemaak.</translation>
 <translation id="5159094275429367735">Stel Crostini op</translation>
@@ -5819,6 +5848,7 @@
 <translation id="6104068876731806426">Google-rekeninge</translation>
 <translation id="6104311680260824317">Kan nie die toestel aan die domein koppel nie. Die bediener steun nie gespesifiseerde Kerberos-enkripsietipes nie. Besoek "Meer opsies" vir enkripsie-instellings.</translation>
 <translation id="6104796831253957966">Drukkerwaglys is vol</translation>
+<translation id="6106167152849320869">As jy ook kies om diagnostiese en gebruikdata in die vorige stap te stuur, sal hierdie data vir geïnstalleerde apps ingesamel word.</translation>
 <translation id="6111972606040028426">Aktiveer Google Assistent</translation>
 <translation id="6112294629795967147">Raak om grootte te verander</translation>
 <translation id="6112727384379533756">Voeg 'n kaartjie by</translation>
@@ -5949,6 +5979,7 @@
 <translation id="6226777517901268232">Private sleutellêer (opsioneel)</translation>
 <translation id="6227002569366039565">Druk |<ph name="ACCELERATOR" />| om hierdie borrel te fokus, en dan weer om die element waarheen dit wys, te fokus.</translation>
 <translation id="6227280783235722609">uitbreiding</translation>
+<translation id="6229062790325126537">Stel ApnMigrator terug</translation>
 <translation id="6229849828796482487">Ontkoppel Wi-Fi-netwerk</translation>
 <translation id="6231782223312638214">Voorgestelde</translation>
 <translation id="6231881193380278751">Voeg 'n navraagparameter in URL by om die bladsy te outoherlaai: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6226,6 +6257,7 @@
 <translation id="6478248366783946499">Hou gevaarlike lêer?</translation>
 <translation id="6479881432656947268">Besoek Chrome Webwinkel</translation>
 <translation id="6480327114083866287">Bestuur deur <ph name="MANAGER" /></translation>
+<translation id="6481978993812487794">Sodra dit aangeskakel is, sal jou apps op enige Chrome-toestelle beskikbaar wees nadat jy met jou Google-rekening aangemeld het. Web-apps sal deur Chrome gesinkroniseer word selfs as ander blaaiersinkroniseringkenmerke afgeskakel is.</translation>
 <translation id="6482559668224714696">Volskermvergrootglas</translation>
 <translation id="6483485061007832714">Maak aflaai oop</translation>
 <translation id="6483805311199035658">Maak tans <ph name="FILE" /> oop …</translation>
@@ -6240,6 +6272,7 @@
 <translation id="6497784818439587832">Verander skermgrootte om items op jou skerm groter of kleiner te maak</translation>
 <translation id="6497789971060331894">Muis – omgekeerde rollees</translation>
 <translation id="6498249116389603658">Al jou tale</translation>
+<translation id="6498583202177273322">Kry meer nuttige inligting terwyl jy hierdie bladsy verken</translation>
 <translation id="6499143127267478107">Los gasheer in instaanbedienerskrip op …</translation>
 <translation id="6499764981457476645">Geen toestelle in die omtrek gevind nie</translation>
 <translation id="6501957628055559556">Alle houers</translation>
@@ -6686,6 +6719,7 @@
 <translation id="688312408602122936">Enige speletjies en programme wat via Steam geïnstalleer is, sal ook van hierdie toestel verwyder word</translation>
 <translation id="6883319974225028188">Oeps! Die stelsel het nie toestelopstelling gestoor nie.</translation>
 <translation id="6884474387073389421">Is jy seker jy wil die geselekteerde aanmelddata uitvee?</translation>
+<translation id="6885122019363983153">Werkskermatergronde pas op alle toestelle</translation>
 <translation id="6885771755599377173">Voorskou van stelselinligting</translation>
 <translation id="6886380424988777998">Kon nie Linux opgradeer nie</translation>
 <translation id="6886871292305414135">Maak skakel in nuwe oortjie oop</translation>
@@ -6757,6 +6791,7 @@
 <translation id="6949434160682548041">Wagwoord (opsioneel)</translation>
 <translation id="6950627417367801484">Laai programme terug</translation>
 <translation id="6952242901357037157">Jy kan ook wagwoorde van jou <ph name="BEGIN_LINK" />Google-rekening<ph name="END_LINK" /> af hier wys</translation>
+<translation id="6954910832698269894">Skakel toestelsinkronisering aan om jou apps, instellings, wi-fi-netwerke en muurpapier van jou vorige Chromebook af te sinkroniseer. Maak enige tyd veranderinge in Instellings &gt; Rekeninge.</translation>
 <translation id="6954936693361896459">Saai eerder hierdie oortjie uit</translation>
 <translation id="6955446738988643816">Ondersoek opspringer</translation>
 <translation id="6955535239952325894">Hierdie instelling is in bestuurde blaaiers gedeaktiveer</translation>
@@ -6915,6 +6950,7 @@
 <translation id="7075513071073410194">PKCS #1 MD5 met RSA-enkripsie</translation>
 <translation id="7075625805486468288">Bestuur HTTPS/SSL-sertifikate en -instellings</translation>
 <translation id="7076875098323397992">Kan nie opgradering begin nie</translation>
+<translation id="7077751457066325012">Bekyk en pasmaak kortpadsleutels</translation>
 <translation id="7077829361966535409">Die aanmeldbladsy kon nie met die huidige instaanbedienerinstellings gelaai word nie. <ph name="GAIA_RELOAD_LINK_START" />Probeer asseblief weer om aan te meld<ph name="GAIA_RELOAD_LINK_END" />, of gebruik ander <ph name="PROXY_SETTINGS_LINK_START" />instaanbedienerinstellings<ph name="PROXY_SETTINGS_LINK_END" />.</translation>
 <translation id="7078120482318506217">Alle netwerke</translation>
 <translation id="708060913198414444">Kopieer oudioadres</translation>
@@ -6944,6 +6980,7 @@
 <translation id="7108933416628942903">Sluit nou</translation>
 <translation id="7109543803214225826">Kortpad is verwyder</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{Voeg oortjie by groep}other{Voeg oortjies by groep}}</translation>
+<translation id="7110684627876015299">Naamlose groep – <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">Gee hierdie venster 'n naam</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> item</translation>
 <translation id="7113502843173351041">Ken jou e-posadres</translation>
@@ -7158,6 +7195,7 @@
 <translation id="7328867076235380839">Ongeldige kombinasie</translation>
 <translation id="7329154610228416156">Kon nie aanmeld nie omdat dit opgestel is om 'n onveilige URL (<ph name="BLOCKED_URL" />) te gebruik. Kontak jou administrateur.</translation>
 <translation id="7332053360324989309">Toegewyde werker: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">Rugsteun jou apps en instellings en stel hulle terug</translation>
 <translation id="7335974957018254119">Gebruik speltoets vir</translation>
 <translation id="7336799713063880535">Kennisgewings geblok</translation>
 <translation id="7338630283264858612">Toestelreeksnommer is ongeldig.</translation>
@@ -7180,6 +7218,7 @@
 <translation id="7348093485538360975">Opskerm-sleutelbord</translation>
 <translation id="7349010927677336670">Videogladheid</translation>
 <translation id="7352651011704765696">Iets het verkeerd geloop</translation>
+<translation id="7352664183151911163">Oral in jou apps en Chrome-blaaier</translation>
 <translation id="7353261921908507769">Jou kontakte kan met jou deel wanneer hulle in die omtrek is. Oordragte sal nie begin voordat jy aanvaar het nie.</translation>
 <translation id="735361434055555355">Installeer tans Linux …</translation>
 <translation id="7354120289251608189">Jy kan nou enige tyd vir jou blaaier ’n nuwe voorkoms gee.</translation>
@@ -7319,6 +7358,8 @@
 <translation id="7458168200501453431">Gebruik dieselfde speltoetser wat in Google-soektog gebruik word. Teks wat jy in die blaaier tik, word na Google toe gestuur.</translation>
 <translation id="7458715171471938198">Laai programme terug?</translation>
 <translation id="7458933488302148148">Gaan jou gestoorde wagwoorde na om jou sekuriteit te versterk en veiliger te bly aanlyn</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />As jy jou Chrome-toestelle toelaat om outomatiese verslae te stuur, help dit ons om te prioritiseer wat om in ChromeOS reg te stel en te verbeter. Hierdie verslae kan dinge insluit soos wanneer ChromeOS omval, watter kenmerke jy gebruik, en hoeveel geheue jy gewoonlik gebruik. Ander appdiagnostiek en gebruiksdata, insluitend vir Android- en webapps, sal ingesamel word as appsinkronisering ook aangeskakel is.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Jy kan toestemming vir hierdie verslae enige tyd in jou Chrome-toestel se instellings begin of stop. As jy ’n domeinadmin is, kan jy hierdie instelling in die adminkonsole verander.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">Huidige tema wat jy geïnstalleer het</translation>
 <translation id="7461924472993315131">Pin</translation>
 <translation id="746216226901520237">Jou foon sal volgende keer jou <ph name="DEVICE_TYPE" /> ontsluit. Jy kan Smart Lock in Instellings afskakel.</translation>
@@ -7552,6 +7593,7 @@
 <translation id="7663719505383602579">Ontvanger: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">Kortpadsleutel is beskikbaar</translation>
 <translation id="7663859337051362114">Voeg e-SIM-profiel by</translation>
+<translation id="76641554187607347">Geen sleutelbord is gekoppel nie</translation>
 <translation id="7665082356120621510">Reserveer grootte</translation>
 <translation id="7665369617277396874">Voeg rekening by</translation>
 <translation id="766560638707011986">Wys domeine</translation>
@@ -7599,6 +7641,7 @@
 <translation id="769824636077131955">Hierdie dokument is te groot vir 'n sekuriteitkontrole. Jy kan dokumente van tot 50 MB druk.</translation>
 <translation id="7698507637739331665">Sommige items is geblokkeer</translation>
 <translation id="7701040980221191251">Geen</translation>
+<translation id="7701265686005869308">Maak profiel toe</translation>
 <translation id="7701869757853594372">GEBRUIKER-handvatsel</translation>
 <translation id="7702574632857388784">Verwyder <ph name="FILE_NAME" /> uit lys</translation>
 <translation id="7702907602086592255">Domein</translation>
@@ -8020,6 +8063,7 @@
 <translation id="8050191834453426339">Verifieer weer</translation>
 <translation id="8051193500142930381">Kenmerke wat 'n kamera nodig het, sal nie werk nie</translation>
 <translation id="8051390370038326517">Laat <ph name="HOST" /> altyd toe om volle beheer oor MIDI-toestelle te hê</translation>
+<translation id="8052218774860457016">Bestuur blaaiersinkronisering</translation>
 <translation id="8053278772142718589">PKCS #12-lêers</translation>
 <translation id="8053390638574070785">Herlaai hierdie bladsy</translation>
 <translation id="8054517699425078995">Hierdie tipe lêer kan jou toestel beskadig. Wil jy <ph name="FILE_NAME" /> nog hou?</translation>
@@ -8389,6 +8433,7 @@
 <translation id="8376137163494131156">Vertel ons wat met Google Cast gebeur.</translation>
 <translation id="8376384591331888629">Insluitend derdeparty-webkoekies op hierdie werf</translation>
 <translation id="8376451933628734023">Deïnstalleer hierdie webprogram as dit jou probeer mislei om te dink dat dit 'n ander program is.</translation>
+<translation id="8376752431516546391">Google Search-kantpaneel</translation>
 <translation id="8377625247046155446">Hierdie wagwoordsleutel sal net op hierdie toestel gestoor word. Dit sal op hierdie toestel bly nadat jy alle Incognito-vensters toegemaak het.</translation>
 <translation id="8378714024927312812">Bestuur deur jou organisasie</translation>
 <translation id="8379878387931047019">Hierdie toestel steun nie die tipe sekuriteitsleutel wat deur hierdie webwerf versoek word nie</translation>
@@ -8456,6 +8501,11 @@
 <translation id="8428628598981198790">Jou sekuriteitsleutel kan nie met hierdie werf gebruik word nie</translation>
 <translation id="84297032718407999">Jy sal oor <ph name="LOGOUT_TIME_LEFT" /> afgemeld word</translation>
 <translation id="8431190899827883166">Wys tikke</translation>
+<translation id="8431496281632382473"><ph name="DOMAIN" /> bestuur hierdie profiel. Jou organisasie vereis dat jy jou toestelseine deel om voort te gaan om hierdie bestuurde profiel te gebruik.
+
+Toestelsiene kan inligting oor jou blaaier, bedryfstelsel, toestel, geïnstalleerde sagteware en lêers bevat.
+
+As jy kies om nie seine te deel nie, sal hierdie profiel toegemaak word.</translation>
 <translation id="8434480141477525001">NaCl-ontfoutpoort</translation>
 <translation id="8437209419043462667">VSA</translation>
 <translation id="8438328416656800239">Wissel na 'n slimblaaier</translation>
@@ -8540,6 +8590,8 @@
 <translation id="851263357009351303">Laat <ph name="HOST" /> altyd toe om prente te wys</translation>
 <translation id="8513108775083588393">Outodraai</translation>
 <translation id="8513357934662532537">Kies ’n CSV-lêer om wagwoorde na <ph name="BRAND" /> in te voer vir <ph name="USER_EMAIL" />.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />As jy Chrome-toestelle toelaat om outomatiese verslae te stuur, help dit ons om te prioritiseer wat om in ChromeOS reg te stel en te verbeter. Hierdie verslae kan dinge insluit soos wanneer ChromeOS omval, watter kenmerke gebruik is, en hoeveel geheue gewoonlik gebruik is. Ander appdiagnostiek en gebruiksdata, insluitend vir Android- en webapps, sal ingesamel word as appsinkronisering ook aangeskakel is.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Jy kan toestemming vir hierdie verslae enige tyd in die instellings van jou kind se Chrome-toestel begin of stop. As jy ’n domeinadministrateur is, kan jy hierdie instelling in die adminkonsole verander.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">Probeer 'n ander sekuriteitsleutel</translation>
 <translation id="8514955299594277296">Moenie werwe toelaat om data op jou toestel te stoor nie (nie aanbeveel nie)</translation>
 <translation id="8517759303731677493">Wysig …</translation>
@@ -8900,6 +8952,7 @@
 <translation id="883062543841130884">Plaasvervangers</translation>
 <translation id="8830779999439981481">Herbegin tans om opdaterings toe te pas</translation>
 <translation id="8830796635868321089">Die opdateringkontrolering het misluk met die huidige instaanbedienerinstellings. Verstel asseblief jou <ph name="PROXY_SETTINGS_LINK_START" />instaanbedienerinstellings<ph name="PROXY_SETTINGS_LINK_END" />.</translation>
+<translation id="8830863983385452402">Die werf sal hierdie oortjie se inhoud kan sien</translation>
 <translation id="8831769650322069887">Maak <ph name="FILE_NAME" /> oop</translation>
 <translation id="8832781841902333794">Jou profiele</translation>
 <translation id="8834039744648160717">Netwerkopstelling word beheer deur <ph name="USER_EMAIL" />.</translation>
@@ -9031,6 +9084,7 @@
 <translation id="8946359700442089734">Ontfoutingkenmerke is nie heeltemal op hierdie <ph name="IDS_SHORT_PRODUCT_NAME" />-toestel geaktiveer nie.</translation>
 <translation id="894763922177556086">Goed</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> wil die maak en model van jou sekuriteitsleutel sien</translation>
+<translation id="8949304443659090542">Bestuur Chrome-blaaiersinkronisering</translation>
 <translation id="895054485242522631">Werwe kan bewegingsensors gebruik</translation>
 <translation id="8951256747718668828">Terugstelling kon weens 'n probleem nie voltooi word nie</translation>
 <translation id="8951465597020890363">Verlaat besoekermodus in elk geval?</translation>
@@ -9136,6 +9190,7 @@
 <translation id="9032097289595078011">Deaktiveer Kitsbind</translation>
 <translation id="9033765790910064284">Gaan in elk geval voort</translation>
 <translation id="9033857511263905942">Plak</translation>
+<translation id="9034408118624208974">Nuut by Chromebook? Skakel sinkronisering aan sodat jou voorkeure gerugsteun sal word.</translation>
 <translation id="903480517321259405">Tik die PIN weer in</translation>
 <translation id="9037054491984310631">Gekoppel aan Bluetooth-toestel genaamd <ph name="DEVICE" /></translation>
 <translation id="9037640663275993951">Toestel word nie toegelaat nie</translation>
@@ -9179,6 +9234,7 @@
 <translation id="9068298336633421551">Laat Android-programme en -dienste met liggingtoestemming toe om hierdie toestel se ligging te gebruik. Google kan van tyd tot tyd liggingdata insamel en hierdie data op anonieme wyse gebruik om liggingakkuraatheid en ligginggegronde dienste beter te maak.</translation>
 <translation id="9068598199622656904">Druk een sleutel op ’n slag vir kortpadsleutels pleks van om sleutels tegelyk in te hou</translation>
 <translation id="9068878141610261315">Ongesteunde lêertipe</translation>
+<translation id="9069665781180028115">Uitgesoekte items sal op hierdie Chromebook beskikbaar wees. As jy nuut is by Chromebook, moet jy alle items sinkroniseer sodat jou voorkeure gerugsteun word. Maak enige tyd veranderinge in Instellings &gt; Rekeninge.</translation>
 <translation id="9070342919388027491">Oortjie is na links geskuif</translation>
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9074836595010225693">USB-muis gekoppel</translation>
@@ -9352,6 +9408,7 @@
 <translation id="930268624053534560">Gedetailleerde tydstempels</translation>
 <translation id="930551443325541578">Herhaal sleutels en aksentmerke</translation>
 <translation id="930893132043726269">Swerf tans</translation>
+<translation id="930991362911221750">Laat <ph name="APP_NAME" /> toe om hierdie oortjie te sien?</translation>
 <translation id="93140074055951850">Android-programme is gestop</translation>
 <translation id="932327136139879170">Tuis</translation>
 <translation id="932508678520956232">Kon nie uitdruk begin nie.</translation>
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index 3a7a35aa..9a6f0965 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -216,6 +216,7 @@
 <translation id="1176471985365269981">በመሳሪያዎ ላይ ፋይሎችን ውይም አቃፊዎችን ለማርትዕ አልተፈቀደም</translation>
 <translation id="1177863135347784049">ብጁ</translation>
 <translation id="1178581264944972037">ለአፍታ አቁም</translation>
+<translation id="1178601482396475810">የመሣሪያ ስምረት ያስተዳድሩ</translation>
 <translation id="117916940443676133">የእርስዎ ደህንነት ቁልፍ በፒን ጥበቃ እየተደረገለት አይደለም ያለው። በመለያ መግቢያ ውሂብን ለማስተዳደር፣ በመጀመሪያ ፒን ይፍጠሩ።</translation>
 <translation id="1181037720776840403">አስወግድ</translation>
 <translation id="1181366777303791449">በ<ph name="MAIN_FRAME_ETLD_PLUS_ONE" /> ላይ</translation>
@@ -354,6 +355,7 @@
 <translation id="130097046531636712">ይህ እንደ ለስላሳ ሽብለላ ያሉ የዳራ እንቅስቃሴ እና ምስላዊ ተጽዕኖዎችን በመገደብ የባትሪ ኃይልን ያራዝማል</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> የሚከተሉትን ፋይሎች ማርትዕ ይችላል</translation>
 <translation id="1302227299132585524">ከApple Events ላይ ጃቫስክሪፕትን ይፍቀዱ</translation>
+<translation id="1302654693270046655"><ph name="GROUP_NAME" /> ቡድን - <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">ለኤችቲኤምኤል ፋይል እልባት ያደርጋል</translation>
 <translation id="1303671224831497365">ምንም የብሉቱዝ መሣሪያዎች አልተገኙም</translation>
 <translation id="130491383855577612">Linux መተግበሪያዎች እና ፋይሎች በተሳካ ሁኔታ ተተክተዋል</translation>
@@ -1058,6 +1060,7 @@
 <translation id="1877520246462554164">የማረጋገጫ ማስመሰያውን ማግኘት አልተሳካም። እንደገና ለመሞከር እባክዎ ዘግተው ይውጡና እንደገና ይግቡ።</translation>
 <translation id="1877860345998737529">የእርምጃ ምደባን ቀያይር</translation>
 <translation id="1878155070920054810">ዝማኔው ከመጠናቀቁ በፊት የእርስዎ Chromebook ኃይሉ ያልቅበታል። መቋረጥን ለመከላከል በትክክል ኃይል እየሞሉ መሆኑን ያረጋግጡ።</translation>
+<translation id="1878477879455105085">ተከፍቷል</translation>
 <translation id="1878885068166344708">ትኩረትን ሲያንቀሳቅሱ ንጥል ይደምቃል። ትኩረትን ለመቀየር ትርን ይጫኑ ወይም አንድን ንጥል ይምረጡ።</translation>
 <translation id="1879000426787380528">በመለያ ይግቡ እንደ</translation>
 <translation id="18802377548000045">ትሮች ወደ አንድ ትልቅ ስፋት ይሰበሰባሉ</translation>
@@ -1442,6 +1445,7 @@
 <translation id="2204034823255629767">የሚተይቡትን ማንኛውም ነገር ያነብባል እና ይቀይራል</translation>
 <translation id="2204387456724731099">ይህን ምርጫ መተርጎም አልተቻለም</translation>
 <translation id="2210462644007531147">መጫንን ማጠናቀቅ አልተቻለም</translation>
+<translation id="2211245494465528624">የስምረት አማራጮችን አስተዳድር</translation>
 <translation id="2212565012507486665">ኩኪዎችን ፍቀድ</translation>
 <translation id="2214018885812055163">የተጋሩ አቃፊዎች</translation>
 <translation id="2214884991347062907">የተሳሳተ የይለፍ ቃል። እንደገና ይሞክሩ</translation>
@@ -1538,6 +1542,7 @@
 <translation id="2296218178174497398">የመሳሪያ ግኝት</translation>
 <translation id="2297705863329999812">አታሚዎችን ይፈልጉ</translation>
 <translation id="2297822946037605517">ይህንን ገፅ ያጋሩ</translation>
+<translation id="229871422646860597">ከመሣሪያ አሞሌ ንቀል</translation>
 <translation id="2299734369537008228">ተንሸራታች፦ <ph name="MIN_LABEL" /> እስከ <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">በ debugd የተሰበሰቡ ሁሉም ምዝግብ ፋይሎችን እንደ የተለየ ማህደር አድርገው ያካትቱ።</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2168,6 +2173,7 @@
 <translation id="2811205483104563968">መለያዎች</translation>
 <translation id="2811564570599779918">የአይፈለጌ መልዕክት እና የማጭበርበር ቅነሳ</translation>
 <translation id="2812049959647166806">Thunderbolt አይደገፍም</translation>
+<translation id="2812171980080389735">በቅጽበት መገናኘት እንዲችሉ የተቀመጡ አውታረ መረቦች እና የይለፍ ቃላት</translation>
 <translation id="2813094189969465044">የወላጅ መቆጣጠሪያዎች</translation>
 <translation id="281390819046738856">ጥያቄ ሊፈረም አልተቻለም።</translation>
 <translation id="2814489978934728345">ይህን ገፅ መጫን አቁም</translation>
@@ -2207,6 +2213,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">የእርስዎ ፒን ታክሏል</translation>
 <translation id="2849936225196189499">ዋነኛ</translation>
+<translation id="285033512555869047">ዝግ ነው</translation>
 <translation id="2850541429955027218">ገጽታ አክል</translation>
 <translation id="2850672011315104382">የስርዓተ-ነጥብ ቅጥ</translation>
 <translation id="2852385257476173980">ድሩን ሲያስሱ የሚጎበኟቸው የጣቢያዎች ዝርዝር እዚህ ሊታይ ይችላል</translation>
@@ -2250,6 +2257,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> እና <ph name="NUMBER_OF_DEVICES" /> ሌሎች</translation>
 <translation id="2889043468805635730">ምንም ችግሮች አልተገኙም</translation>
 <translation id="2889064240420137087">አገናኝ ክፈት በ...</translation>
+<translation id="2890206081124517553">የእርስዎን ዴስክቶፕ ዳራ በመላው መሣሪያዎች ላይ ያስታውሱ</translation>
 <translation id="2891566119238851894">በጎን ፓነል ውስጥ ፍለጋን ክፈት ፍለጋ በጎን ፓነል ውስጥ አልተከፈተም።</translation>
 <translation id="2891922230654533301">ወደ <ph name="APP_NAME" /> ለመግባት መሣሪያዎን ይጠቀሙበት?</translation>
 <translation id="2893013536106749396">ለእርስዎ አስፈላጊ የሆኑ ነገሮችን የሚያሳውቁዎት ካርዶችን ይምረጡ</translation>
@@ -2271,6 +2279,7 @@
 <translation id="2907619724991574506">ጀማሪ ዩ አር ኤሎች</translation>
 <translation id="2907798539022650680">ከ«<ph name="NAME" />» ጋር መገናኘት አልተቻለም፦ <ph name="DETAILS" />
 የአገልጋይ መልዕክት፦ <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">ምልክቶችን አጋራ</translation>
 <translation id="2908162660801918428">የሚዲያ ማዕከለ ስዕላት በአቃፊ ያክሉ</translation>
 <translation id="2908358077082926882">ምደባን እና <ph name="RESPONSE" />ን ለማስወገድ «<ph name="CURRENTKEY" />»ን በድጋሜ ይጫኑ።</translation>
 <translation id="2909506265808101667">ከGoogle አገልግሎቶች ጋር መገናኘት አልተቻለም። የአውታረ መረብ ግንኙነትዎን ይፈትሹ እና እንደገና ይሞክሩ። የስህተት ኮድ፦ <ph name="ERROR_CODE" />።</translation>
@@ -2375,6 +2384,7 @@
 <translation id="3003828226041301643">መሣሪያውን ከጎራው ጋር ማቀላቀል አልተቻለም። መሣሪያዎችን የማከል ልዩ መብቶች እንዳለዎት ለማረጋገጥ መለያዎን ይፈትሹ።</translation>
 <translation id="3003967365858406397">የእርስዎ <ph name="PHONE_NAME" /> የግል Wi-Fi ግንኙነት ይፈጥራል።</translation>
 <translation id="3004385386820284928">የቁልፍ ሰሌዳ ቁልፎችን ያብጁ</translation>
+<translation id="3005376701115952939">የመተግበሪያዎች ስምረት የሥርዓት ቅንብሮች ውስጥ ይቀናበራል</translation>
 <translation id="3005574332301273731">አታሳይ</translation>
 <translation id="3006881078666935414">ምንም የአጠቃቀም ውሂብ የለም</translation>
 <translation id="3007410324195400631">ስለዚህ ገፅ ማስታወሻዎችን ያክሉ</translation>
@@ -2756,6 +2766,7 @@
 <translation id="3369624026883419694">ለአስተናጋጅ መፍትሄ በመፈለግ ላይ…</translation>
 <translation id="3370260763947406229">ራስ-እርማት</translation>
 <translation id="3371140690572404006">የUSB-C መሣሪያ (የቀኝ ጎን የፊት ወደብ)</translation>
+<translation id="3371351218553893534">መስመሩ በጣም ረጅም ነው፦ <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">በመተግበሪያው ውስጥ የሚከፍቷቸውን አቃፊዎች ያነባል</translation>
 <translation id="3373059063088819384">በንባብ ሁነታ ውስጥ ክፈት</translation>
 <translation id="3373701465337594448">በሚበራበት ጊዜ ፍላጎቶችዎን የሚገምቱ የሚጎበኟቸው ጣቢያዎች ዝርዝር እዚህ ይታያል</translation>
@@ -2826,6 +2837,9 @@
 <translation id="3434272557872943250">የተጨማሪ የድር እና መተግበሪያ እንቅስቃሴ ቅንብር ለልጅዎ በርቶ ከሆነ ይህ ውሂብ ወደ የGoogle መለያቸው ሊቀመጥ ይችላል። families.google.com ላይ ስለእነዚህ ቅንብሮች እና እንዴት እነሱን ማስተካከል እንደሚችሉ የበለጠ ይረዱ።</translation>
 <translation id="3434475275396485144">ይህ ቅንብር የሚቀናበረው በስልክዎ አስተዳዳሪ ነው</translation>
 <translation id="3434512374684753970">ኦዲዮ እና ቪዲዮ</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />በቀጣዩ ማያ ገጽ ላይ፣ በእርስዎ የGoogle መለያ ይግቡ።<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ይህ ለGmail፣ YouTube፣ Chrome፣ እና ሌሎች የGoogle አገልግሎቶች የሚጠቀሙት ተመሳሳይ መለያ ነው። ግላዊነትን ለተላበሰ ተሞክሮ እና ለሁሉም መረጃዎ ቀላል መዳረሻ መለያዎን ይጠቀሙ።<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />የGoogle መለያ ከሌለዎት በቀጣዩ ማያ ገጽ ላይ አንድ ለመፍጠር ይችላሉ።<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">«<ph name="EXTENSION_NAME" />» የእርስዎን <ph name="CODE_TYPE" /> እየጠየቀ ነው</translation>
 <translation id="3435738964857648380">የደህንነት ጥበቃ</translation>
 <translation id="343578350365773421">ወረቀት ጨርሷል</translation>
@@ -2872,6 +2886,7 @@
 <translation id="346546413339447252">ለ<ph name="MERCHANT_NAME_1" />፣ <ph name="MERCHANT_NAME_2" /> እና ሌሎችም የዋጋ ቅናሾችን ያግኙ</translation>
 <translation id="3468298837301810372">መለያ</translation>
 <translation id="3468999815377931311">የAndroid ስልክ</translation>
+<translation id="3469345458390352459">አንዴ ከበራ በኋላ፣ በGoogle መለያዎ ከገቡ በኋላ የእርስዎ መተግበሪያዎች በማናቸውም ChromeOS መሣሪያዎች ላይ ይገኛሉ።  ሌሎች የአሳሽ ስምረት ባህሪያት ቢጠፉም እንኳን የድር መተግበሪያዎች በChrome በኩል ይሰምራሉ።</translation>
 <translation id="3469583217479686109">የመምረጫ መሣሪያ</translation>
 <translation id="3470392222765168737">የክትትል ጣቢያ</translation>
 <translation id="3471876058939596279">HDMI እና USB Type-C ወደቦች በተመሳሳይ ጊዜ አንድ ላይ ጥቅም ላይ ሊውሉ አይችሉም። የተለየ ቪዲዮ ወደብ ይጠቀሙ።</translation>
@@ -3334,6 +3349,7 @@
 <translation id="3855441664322950881">ቅጥያን ጠቅልል</translation>
 <translation id="3855676282923585394">ዕልባቶችን እና ቅንብሮችን ያስመጡ...</translation>
 <translation id="3856096718352044181">ይህ ልክ የሆነ አገልግሎት አቅራቢ መሆኑን እባክዎ ያረጋግጡ ወይም ቆይተው እንደገና ይሞክሩ</translation>
+<translation id="3856470183388031602">የእርስዎን Google መለያ በእርስዎ <ph name="DEVICE_TYPE" /> ላይ ይጠቀሙ</translation>
 <translation id="3856800405688283469">የሰዓት ሰቅ ይምረጡ</translation>
 <translation id="3857807444929313943">ያንሱ፣ ከዚያ እንደገና ይንኩ</translation>
 <translation id="3858860766373142691">ስም</translation>
@@ -3373,6 +3389,7 @@
 <translation id="3894123633473837029">በSherlog በኩል የቅርብ ጊዜ የረዳት ታሪክን አካትት። ይህ የእርስዎን ማንነት፣ አካባቢ እና የማረሚያ መረጃን ሊያካትት ይችላል። <ph name="BEGIN_LINK" />የበለጠ ለመረዳት<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">አቃፊ ያክሉ</translation>
 <translation id="3894770151966614831">ወደ Google መለያ ይወሰድ?</translation>
+<translation id="3894983081771074056">የቁልፍ ሰሌዳ እና መዳፊት ጸባይ፣ የቋንቋ ምርጫዎች እና ሌሎችም</translation>
 <translation id="3895076768659607631">&amp;የፍለጋ ፕሮግራሞችን ያስተዳድሩ...</translation>
 <translation id="3895090224522145010">የKerberos ተጠቃሚ ስም</translation>
 <translation id="389521680295183045">የእርስዎን መሣሪያ በንቃት በሚጠቀሙበት ጊዜ ጣቢያዎች ለማወቅ ጥያቄ ማቅረብ ይችላሉ</translation>
@@ -3508,6 +3525,7 @@
 <translation id="3994878504415702912">&amp;ማጉሊያ</translation>
 <translation id="3995138139523574647">የUSB-C መሣሪያ (የቀኝ ጎን የኋላ ወደብ)</translation>
 <translation id="3995963973192100066">እነማ አጫውት</translation>
+<translation id="399788104667917863">ወደ የመሣሪያ አሞሌ ፒን አድርግ</translation>
 <translation id="4001540981461989979">በሚንቀሳቀስበት ጊዜ የመዳፊት ጠቋሚን አድምቅ</translation>
 <translation id="4002440992267487163">ፒን ውቅረት</translation>
 <translation id="4005817994523282006">የሰዓት ሰቅ ማወቂያ ዘዴ</translation>
@@ -3664,12 +3682,16 @@
 <translation id="4147911968024186208">እባክዎ እንደገና ይሞክሩ። ይህን ስህተት በድጋሚ ከተመለከቱ እባክዎ የድጋፍ ተወካይዎን ያነጋግሩ።</translation>
 <translation id="4150201353443180367">ማሳያ</translation>
 <translation id="4150569944729499860">የማያ ገፅ አውድ</translation>
+<translation id="4151843924968445052">የመተግበሪያ ምልክቶች ይጋሩ?</translation>
 <translation id="4152011295694446843">የእርስዎን እልባቶች እዚህ ያገኛሉ</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 ትር}one{# ትሮች}other{# ትሮች}}</translation>
 <translation id="4154664944169082762">የጣት አሻራዎች</translation>
 <translation id="4157869833395312646">Microsoft Server Gated Cryptography</translation>
 <translation id="4158315983204257156">የድር ጣቢያ የጽሑፍ መጠን እና ቅርጸ-ቁምፊ</translation>
 <translation id="4158364720893025815">እለፍ</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />የእርስዎ የChromeOS መሣሪያዎች ራስ-ሰር ሪፖርቶችን እንዲልኩ መፍቀድ እኛ በChromeOS ውስጥ ምንን መጠገን እና ማሻሻል እንዳለብን ቅድሚያ እንድንሰጥ ያግዘናል። እነዚህ ሪፖርቶች እንደ ChromeOS ሲበላሽ፣ የትኛዎቹን ባህሪያት እንደሚጠቀሙ፣ ምን ያህል ማህደረ ትውስታን በተለምዶ እንደሚጠቀሙ እና የAndroid መተግበሪያ የምርመራ እና የአጠቃቀም ውሂብን ሊያካትቱ ይችላሉ። እንዲሁም አንዳንድ ውሑድ ውሂብ የGoogle መተግበሪያዎችን እና እንደ የAndroid ገንቢዎች ያሉ አጋሮችን ያግዛል። እንዲሁም የመተግበሪያዎች ስምረት ከበራ የAndroid እና የድር መተግበሪያዎችን ጨምሮ ሌላ የመተግበሪያ ምርመራ እና የአጠቃቀም ውሂብ ይሰበሰባል።<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />በማንኛውም ጊዜ በእርስዎ የChromeOS መሣሪያ ቅንብሮች ውስጥ እነዚህን ሪፖርቶች መፍቀድ መጀመር ወይም ማቆም ይችላሉ። እርስዎ የጎራ አስተዳዳሪ ከሆኑ ይህን ቅንብር በአስተዳዳሪ ኮንሶል ውስጥ መለወጥ ይችላሉ።<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />የGoogle መለያዎ የድር እና የመተግበሪያ እንቅስቃሴ ቅንብር ከበራ የAndroid ውሂብዎ ወደ Google መለያዎ ሊቀመጥ ይችላል። account.google.com ላይ የእርስዎን ውሂብ ማየት፣ መሰረዝ እና የመለያ ቅንብሮችዎን መለወጥ ይችላሉ።<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;Google የይለፍ ቃል አስተዳዳሪ</translation>
 <translation id="4163560723127662357">ያልታወቀ የቁልፍ ሰሌዳ</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> ትክክለኛ የሆነ ድርጅት አካል አይደለም። የእርስዎን አስተዳዳሪ ያነጋግሩ። አስተዳዳሪ ከሆኑ የሚከተለውን በመጎብኘት ድርጅትዎን ማዋቀር ይችላሉ፦ g.co/ChromeEnterpriseAccount</translation>
@@ -3993,6 +4015,9 @@
 <translation id="4452898361839215358">ወይም PPD ይምረጡ። <ph name="LINK_BEGIN" />የበለጠ ለመረዳት<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">በእርስዎ የቁልፍ ሰሌዳ ከላይ በስተቀኝ ጥግ የሚገኘውን የጣት አሻራ ዳሳሽ ይንኩ። የጣት አሻራዎ ውሂብ ደህንነቱ በተጠበቀ ሁኔታ ይከማቻል እና በጭራሽ ከእርስዎ <ph name="DEVICE_TYPE" /> አይወጣም።</translation>
 <translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" /> ላይ ይፈልጉ ወይም ዩአርኤል ይተይቡ</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />የChromeOS መሣሪያዎች ራስ-ሰር ሪፖርቶችን እንዲልኩ መፍቀድ እኛ በChromeOS ውስጥ ምንን መጠገን እና ማሻሻል እንዳለብን ቅድሚያ እንድንሰጥ ያግዘናል። እነዚህ ሪፖርቶች እንደ ChromeOS ሲበላሽ፣ የትኛዎቹ ባህሪያት ሥራ ላይ እንደዋሉ፣ በተለምዶ ምን ያህል ማህደረ ትውስታ ሥራ ላይ ውሎ እንደነበር እና የAndroid መተግበሪያ የምርመራ እና የአጠቃቀም ውሂብ ያሉ ነገሮችን ሊያካትቱ ይችላሉ። እንዲሁም አንዳንድ ውሑድ ውሂብ የGoogle መተግበሪያዎችን እና እንደ የAndroid ገንቢዎች ያሉ አጋሮችን ያግዛል። እንዲሁም የመተግበሪያዎች ስምረት ከበራ የAndroid እና የድር መተግበሪያዎችን ጨምሮ ሌላ የመተግበሪያ ምርመራ እና የአጠቃቀም ውሂብ ይሰበሰባል።<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />በማንኛውም ጊዜ በልጅዎ የChromeOS መሣሪያ ቅንብሮች ውስጥ እነዚህን ሪፖርቶች መፍቀድ መጀመር ወይም ማቆም ይችላሉ። እርስዎ የጎራ አስተዳዳሪ ከሆኑ ይህን ቅንብር በአስተዳዳሪ ኮንሶል ውስጥ መለወጥ ይችላሉ።<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />የልጅዎ የGoogle መለያ የድር እና መተግበሪያ እንቅስቃሴ ቅንብሩ በርቶ ከሆነ የልጅዎ ውሂብ በGoogle መለያቸው ላይ ሊቀመጥ ይችላል። families.google.com ላይ ስለ እነዚህ ቅንብሮች እና እንዴት እነሱን ማስተካከል እንደሚችሉ የበለጠ ይወቁ።<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">አሁን ያለውን ድምፅ ይመረጡ፦</translation>
 <translation id="4459169140545916303">ገባሪ ከ<ph name="DEVICE_LAST_ACTIVATED_TIME" /> ቀናት በፊት</translation>
 <translation id="4460014764210899310">ነጥል</translation>
@@ -4372,6 +4397,7 @@
 <translation id="4806457879608775995">እነዚህን ደንቦች ይገምግሙ እና ውሂብዎን ይቆጣጠሩ</translation>
 <translation id="4807098396393229769">በካርድ ላይ ያለ ስም</translation>
 <translation id="4808667324955055115">ብቅ-ባዮች ታግደዋል፦</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{ከChrome የድር መደብር እንዲወርድ የተደረገን <ph name="BEGIN_BOLD" />1 ቅጥያ<ph name="END_BOLD" /> ይገምግሙ}one{ከChrome የድር መደብር እንዲወርድ የተደረገን <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} ቅጥያ<ph name="END_BOLD" /> ይገምግሙ}other{ከChrome የድር መደብር እንዲወርዱ የተደረጉ <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} ቅጥያዎችን<ph name="END_BOLD" /> ይገምግሙ}}</translation>
 <translation id="4809079943450490359">መመሪያዎች ከመሣሪያዎ አስተዳዳሪ፦</translation>
 <translation id="4809447465126035330">ሰርዝ</translation>
 <translation id="480990236307250886">መነሻ ገጹን ክፈት</translation>
@@ -4695,6 +4721,7 @@
 <translation id="5101839224773798795">ጠቋሚ ሲያቆም በራስሰር ጠቅ አድርግ</translation>
 <translation id="5106350808162641062">አስወግድ</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> በ Family Link ክትትል ይደረግበታል። በወላጆች ክትትል የትምህርት ቤት ንብረቶችን ለመድረስ የትምህርት ቤት መለያዎችን ማከል ይችላሉ።</translation>
+<translation id="5107093668001980925"><ph name="MODULE_NAME" /> የሚለውን በጭራሽ አታሳይ</translation>
 <translation id="5107443654503185812">አንድ ቅጥያ የጥንቃቄ አሰሳን አጥፍቷል</translation>
 <translation id="5108967062857032718">ቅንብሮች - የAndroid መተግበሪያዎችን አስወግድ</translation>
 <translation id="5109044022078737958">ሚያ</translation>
@@ -4705,6 +4732,7 @@
 <translation id="5111794652433847656">በዚህ መሣሪያ ላይ ለ<ph name="APP_NAME" /> ምንም የይለፍ ቁልፎች የሉም</translation>
 <translation id="5112577000029535889">&amp;የገንቢ መሳሪያዎች</translation>
 <translation id="511313294362309725">ፈጣን ጥምረትን ያብሩ</translation>
+<translation id="5113384440341086023">ከPlay መደብር የተጫኑ መተግበሪያዎች እና የድር መተግበሪያዎች ከChrome አሳሽ</translation>
 <translation id="51143538739122961">የእርስዎን የደህንነት ቁልፍ ያስገቡ እና ይንኩት</translation>
 <translation id="5115309401544567011">እባክዎ የእርስዎን <ph name="DEVICE_TYPE" /> ወደ የኃይል ምንጭ ይሰኩት።</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4750,6 +4778,7 @@
 <translation id="5154702632169343078">ርዕሰ ጉዳይ</translation>
 <translation id="5155327081870541046">በአድራሻ አሞሌው ላይ ሊፈልጉት ለሚፈልጉት ጣቢያ እንደ «@bookmarks» ያለ አቋራጭ ያስገቡ። ከዚያ የመረጡትን የቁልፍ ሰሌዳ አቋራጭ ይጫኑ እና የፍለጋ ቃልዎን ያስገቡ።</translation>
 <translation id="5156638757840305347">ጠቋሚ ሲታይ ወይም ሲንቀሳቀስ ይደምቃል።</translation>
+<translation id="5157250307065481244">የጣቢያ ዝርዝሮችን አሳይ</translation>
 <translation id="5157635116769074044">ይህን ገፅ የመነሻ ገጹ ላይ ይሰኩት...</translation>
 <translation id="5158206172605340248">የአጽንዖት ምልክቶች ምናሌ ተሰናብቷል።</translation>
 <translation id="5159094275429367735">Crostiniን ያዋቅሩ</translation>
@@ -5809,6 +5838,7 @@
 <translation id="6104068876731806426">የGoogle መለያዎች</translation>
 <translation id="6104311680260824317">መሣሪያን ከጎራው ጋር ማቀላቀል አልተቻለም። አገልጋዩ የተጠቀሱትን የKerberos ምሥጠራ ዓይነቶችን አይደግፍም። ለምሥጠራ ቅንብሮች «ተጨማሪ አማራጮች» ላይ ምልክት ያድርጉ።</translation>
 <translation id="6104796831253957966">የአታሚ ወረፋ ሙሉ ነው</translation>
+<translation id="6106167152849320869">እንዲሁም በቀዳሚው እርምጃ የምርመራ እና የአጠቃቀም ውሂብን ለመላክ ከመረጡ ይህ ውሂብ ለተጫኑ መተግበሪያዎች ይሰበሰባል።</translation>
 <translation id="6111972606040028426">Google ረዳትን አንቃ</translation>
 <translation id="6112294629795967147">መጠን ለመቀየር ይንኩ</translation>
 <translation id="6112727384379533756">ቲኬት ያክሉ</translation>
@@ -5939,6 +5969,7 @@
 <translation id="6226777517901268232">የግል ቁልፍ ፋይል (ከተፈለገ)</translation>
 <translation id="6227002569366039565">ይህንን ዓረፋ ለማነጣጠር |<ph name="ACCELERATOR" />|ን ይጫኑ፣ ከዚያም እንደገና የሚያመለክተውን አባለ ነገር ለማነጣጠር እንደገናን ይጫኑ።</translation>
 <translation id="6227280783235722609">ቅጥያ</translation>
+<translation id="6229062790325126537">ApnMigratorን ዳግም አስጀምር</translation>
 <translation id="6229849828796482487">የWi-Fi አውታረ መረብ ግንኙነትን አቋርጥ</translation>
 <translation id="6231782223312638214">በአስተያየት የተጠቆሙ</translation>
 <translation id="6231881193380278751">ገጹን በራስ-ለማደስ በዩአርኤል ውስጥ የመጠይቅ ልኬት ያክሉ፦ chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6216,6 +6247,7 @@
 <translation id="6478248366783946499">አደገኛ ፋይል ይቀመጥ?</translation>
 <translation id="6479881432656947268">Chrome የድር መደብርን ይጎብኙ</translation>
 <translation id="6480327114083866287">በ<ph name="MANAGER" /> የሚተዳደር</translation>
+<translation id="6481978993812487794">አንዴ ከበራ በኋላ፣ በGoogle መለያዎ ከገቡ በኋላ የእርስዎ መተግበሪያዎች በማናቸውም ChromeOS መሣሪያዎች ላይ ይገኛሉ። ሌሎች የአሳሽ ስምረት ባህሪያት ቢጠፉም እንኳን የድር መተግበሪያዎች በChrome በኩል ይሰምራሉ።</translation>
 <translation id="6482559668224714696">የሙሉ ማያ ገፅ ማጉያ</translation>
 <translation id="6483485061007832714">ውርድን ይክፈቱ</translation>
 <translation id="6483805311199035658"><ph name="FILE" /> በመክፈት ላይ…</translation>
@@ -6230,6 +6262,7 @@
 <translation id="6497784818439587832">በማያ ገጽዎ ላይ ያሉ ንጥሎችን ለማሳነስ ወይም ለማተለቅ የማሳያ መጠንን ይቀንሱ</translation>
 <translation id="6497789971060331894">የመዳፊት ኋሊዮሽ በሽብለላ ላይ</translation>
 <translation id="6498249116389603658">&amp;ሁሉም የእርስዎ ቋንቋዎች</translation>
+<translation id="6498583202177273322">ይህን ገጽ እያሰሱ ሳለ ተጨማሪ ጠቃሚ መረጃ ያግኙ</translation>
 <translation id="6499143127267478107">በተኪ ስክሪፕት ውስጥ ያለውን አስተናጋጅ በመቅረፍ ላይ...</translation>
 <translation id="6499764981457476645">በአቅራቢያ ምንም መሣሪያዎች አልተገኙም</translation>
 <translation id="6501957628055559556">ሁሉም መያዣዎች</translation>
@@ -6678,6 +6711,7 @@
 <translation id="688312408602122936">በSteam በኩል የተጫኑ ማናቸውምም ጨዋታዎች እና መተግበሪያዎች እንዲሁም ከዚህ መሣሪያ ይወገዳሉ።</translation>
 <translation id="6883319974225028188">ውይ! ሥርዓቱ የመሣሪያ ውቅረቱን ማስቀመጥ አልቻለም።</translation>
 <translation id="6884474387073389421">እርግጠኛ ነዎት የተመረጠውን የመለያ መግቢያ ውሂብ መሰረዝ ይፈልጋሉ?</translation>
+<translation id="6885122019363983153">የዴስክቶፕ ዳራዎች በመላው መሣሪያዎች ላይ ይዛመዳሉ</translation>
 <translation id="6885771755599377173">የሥርዓት መረጃ ቅድመ-ዕይታ</translation>
 <translation id="6886380424988777998">Linuxን ማሻሻል አልተቻለም</translation>
 <translation id="6886871292305414135">አገናኙን በአዲስ &amp;ትር ክፈት</translation>
@@ -6749,6 +6783,7 @@
 <translation id="6949434160682548041">የይለፍ ቃል (አማራጭ)</translation>
 <translation id="6950627417367801484">መተግበሪያዎች</translation>
 <translation id="6952242901357037157">እንዲሁም ከእርስዎ <ph name="BEGIN_LINK" />Google መለያ<ph name="END_LINK" /> የይለፍ ቃሎችን እዚህም ማሳየት ይችላሉ</translation>
+<translation id="6954910832698269894">ከእርስዎ የቀድሞ Chromebook የእርስዎን መተግበሪያዎች፣ ቅንብሮች፣ የWi-Fi አውታረ መረቦች እና ልጣፍ ወደነበሩበት ለመመለስ የመሣሪያ ማስመርን ያብሩ። በቅንብሮች &gt; መለያዎች ውስጥ በማንኛውም ጊዜ ለውጦችን ያድርጉ።</translation>
 <translation id="6954936693361896459">በምትኩ ይህን ትር cast ያድርጉ</translation>
 <translation id="6955446738988643816">ብቅ-ባይ ይመርምሩ</translation>
 <translation id="6955535239952325894">ይህ ቅንብር በሚተዳደሩ አሳሾች ላይ ተሰናክሏል</translation>
@@ -6907,6 +6942,7 @@
 <translation id="7075513071073410194">PKCS #1 MD5 ከRSA ምስጠራ ጋር</translation>
 <translation id="7075625805486468288">የኤችቲቲፒኤስ/ኤስኤስኤል ዕውቅና ማረጋገጫዎችን እና ቅንብሮችን ያቀናብሩ</translation>
 <translation id="7076875098323397992">ማሻሻልን መጀመር አልተቻለም</translation>
+<translation id="7077751457066325012">የቁልፍ ሰሌዳ አቋራጮችን ይመልከቱ እና ያብጁ</translation>
 <translation id="7077829361966535409">የመግቢያ ገጹ የአሁኑ የተኪ ቅንብሮች ተጠቅሞ መጫን አልቻለም። እባክዎ <ph name="GAIA_RELOAD_LINK_START" />እንደገና ለመግባት ይሞክሩ<ph name="GAIA_RELOAD_LINK_END" /> ወይም ደግሞ የተለየ <ph name="PROXY_SETTINGS_LINK_START" />የተኪ ቅንብሮች<ph name="PROXY_SETTINGS_LINK_END" />ን ይጠቀሙ።</translation>
 <translation id="7078120482318506217">ሁሉም አውታረ መረቦች</translation>
 <translation id="708060913198414444">የኦዲዮ አድራሻ &amp;ቅዳ</translation>
@@ -6936,6 +6972,7 @@
 <translation id="7108933416628942903">አሁን ቆልፍ</translation>
 <translation id="7109543803214225826">አቋራጭ ተወግዷል</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{ትርን ወደ ቡድን ያክሉ}one{ትሮችን ወደ ቡድን ያክሉ}other{ትሮችን ወደ ቡድን ያክሉ}}</translation>
+<translation id="7110684627876015299">ያልተሰየመ ቡድን - <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">ይህን መስኮት ስም ይስጡት</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> ንጥል</translation>
 <translation id="7113502843173351041">የኢሜይል አድራሻዎን ያውቃል</translation>
@@ -7150,6 +7187,7 @@
 <translation id="7328867076235380839">ልክ ያልሆነ ጥምረት</translation>
 <translation id="7329154610228416156">ደህንነቱ አስተማማኝ ያልሆነ ዩአርኤል (<ph name="BLOCKED_URL" />) እንዲጠቀም ስለተዋቀረ በመለያ መግባት አልተሳካም። እባክዎ የእርስዎን አስተዳዳሪ ያነጋግሩ።</translation>
 <translation id="7332053360324989309">ትጉህ ሰራተኛ፦ <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">የእርስዎን መተግበሪያዎች እና ቅንብሮች ምትኬ ያስቀምጡ እና ወደነበሩበት ይመልሱ</translation>
 <translation id="7335974957018254119">ለዚህ ፊደል ማረሚያን ይጠቀሙ፦</translation>
 <translation id="7336799713063880535">ማሳወቂያዎች ታግደዋል።</translation>
 <translation id="7338630283264858612">የመሣሪያ መለያ ቁጥር ልክ ያልሆነ ነው።</translation>
@@ -7172,6 +7210,7 @@
 <translation id="7348093485538360975">የታይታ የቁልፍ ሰሌዳ</translation>
 <translation id="7349010927677336670">የቪዲዮ ለስላሳነት</translation>
 <translation id="7352651011704765696">የሆነ ችግር ተፈጥሯል</translation>
+<translation id="7352664183151911163">በመላው የእርስዎ መተግበሪያዎች እና የChrome አሳሽ</translation>
 <translation id="7353261921908507769">እውቂያዎችዎ በአቅራቢያ ሲሆኑ ሊያጋሩዎት ይችላሉ። እስኪቀበሉ ድረስ ዝውውሮች አይጀምሩም።</translation>
 <translation id="735361434055555355">Linuxን በመጫን ላይ...</translation>
 <translation id="7354120289251608189">አሁን በማንኛውም ጊዜ ለአሳሽዎ አዲስ መልክ ሊሰጡት ይችላሉ።</translation>
@@ -7311,6 +7350,8 @@
 <translation id="7458168200501453431">በGoogle ፍለጋ ላይ ስራ ላይ የሚውለው ተመሳሳዩን ፊደል ማረሚያ ይጠቀማል። በአሳሹ ውስጥ የሚተይቡት ጽሁፍ ወደ Google ይላካል።</translation>
 <translation id="7458715171471938198">መተግበሪያዎች ወደነበሩበት ይመለሱ?</translation>
 <translation id="7458933488302148148">ደህንነትዎን ለማጠናከር እና በመስመር ላይ ይበልጥ ደህንነትዎ ተጠብቆ እንዲቆይ የተቀመጡ የይለፍ ቃላትዎን ይፈትሹ</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />የእርስዎ የChromeOS መሣሪያዎች ራስ-ሰር ሪፖርቶችን እንዲልኩ መፍቀድ እኛ በChromeOS ውስጥ ምንን መጠገን እና ማሻሻል እንዳለብን ቅድሚያ እንድንሰጥ ያግዘናል። እነዚህ ሪፖርቶች እንደ ChromeOS ሲበላሽ፣ የትኛዎቹን ባህሪያት እንደሚጠቀሙ እና በተለምዶ ምን ያህል ማህደረ ትውስታን እንደሚጠቀሙ ያሉ ነገሮችን ሊያካትቱ ይችላሉ። እንዲሁም የመተግበሪያዎች ስምረት ከበራ የAndroid እና የድር መተግበሪያዎችን ጨምሮ ሌላ የመተግበሪያ ምርመራ እና የአጠቃቀም ውሂብ ይሰበሰባል።<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />በማንኛውም ጊዜ በእርስዎ የChrome መሣሪያ ቅንብሮች ውስጥ እነዚህን ሪፖርቶች መፍቀድ መጀመር ወይም ማቆም ይችላሉ። እርስዎ የጎራ አስተዳዳሪ ከሆኑ ይህን ቅንብር በአስተዳዳሪ ኮንሶል ውስጥ መለወጥ ይችላሉ።<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">እርስዎ የጫኑት አሁን ያለ ገጽታ</translation>
 <translation id="7461924472993315131">ሰካ</translation>
 <translation id="746216226901520237">በሚቀጥለው ጊዜ ስልክዎ የእርስዎን <ph name="DEVICE_TYPE" /> ይከፍታል። በቅንብሮች ውስጥ Smart Lock ማጥፋት ይችላሉ።</translation>
@@ -7544,6 +7585,7 @@
 <translation id="7663719505383602579">ተቀባይ፦ <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">የቁልፍ ሰሌዳ አቋራጭ ይገኛል</translation>
 <translation id="7663859337051362114">የ ኢሲም መገለጫ ያክሉ</translation>
+<translation id="76641554187607347">ምንም የቁልፍ ሰሌዳ አልተገናኘም</translation>
 <translation id="7665082356120621510">የተጠባባቂ መጠን</translation>
 <translation id="7665369617277396874">መለያ ያክሉ</translation>
 <translation id="766560638707011986">ጎራዎችን አሳይ</translation>
@@ -7591,6 +7633,7 @@
 <translation id="769824636077131955">ይህ ሰነድ ለደህንነት ፍተሻ በጣም ትልቅ ነው። እስከ 50 ሜባ ድረስ የሆኑ ሰነዶችን ማተም ይችላሉ።</translation>
 <translation id="7698507637739331665">አንዳንድ ንጥሎች ተግደዋል</translation>
 <translation id="7701040980221191251">ምንም</translation>
+<translation id="7701265686005869308">መገለጫን ዝጋ</translation>
 <translation id="7701869757853594372">USER መያዣዎች</translation>
 <translation id="7702574632857388784"><ph name="FILE_NAME" />ን ከዝርዝር አስወግድ</translation>
 <translation id="7702907602086592255">ጎራ</translation>
@@ -8018,6 +8061,7 @@
 <translation id="8050191834453426339">እንደገና ያረጋግጡ</translation>
 <translation id="8051193500142930381">ካሜራ የሚያስፈልጋቸው ባህሪዎች አይሰሩም</translation>
 <translation id="8051390370038326517"><ph name="HOST" /> ሁልጊዜ የMIDI መሣሪያዎች ሙሉ ቁጥጥር እንዲኖረው ይፍቀዱ</translation>
+<translation id="8052218774860457016">የአሳሽ ስምረትን ያስተዳድሩ</translation>
 <translation id="8053278772142718589">PKCS #12 ፋይሎች</translation>
 <translation id="8053390638574070785">ይህን ገፅ ዳግም ጫን</translation>
 <translation id="8054517699425078995">የዚህ ዓይነት ፋይል መሣሪያዎን ሊጎዳ ይችላል። <ph name="FILE_NAME" />ን ለማንኛውም ማስቀመጥ ይፈልጋሉ?</translation>
@@ -8387,6 +8431,7 @@
 <translation id="8376137163494131156">Google Cast ላይ ምን እየተፈጠረ እንዳለ ይንገሩን።</translation>
 <translation id="8376384591331888629">በዚህ ጣቢያ ላይ የሶስተኛ ወገን ኩኪዎችን ጨምሮ</translation>
 <translation id="8376451933628734023">ይህ የድር መተግበሪያ ሌላ መተግበሪያ ነው ብለው እንዲያስቡት ለማታለል እየሞከረ ከሆነ ያራግፉት።</translation>
+<translation id="8376752431516546391">የGoogle ፍለጋ የጎን ፓነል</translation>
 <translation id="8377625247046155446">ይህ የይለፍ ቁልፍ እዚህ መሣሪያ ላይ ብቻ ይቀመጣል። እርስዎ ሁሉንም ማንነትዎን የማያሳውቁ መስኮቶችን ከዘጓቸው በኋላ እዚህ መሣሪያ ላይ እንዳለ ይቆያል።</translation>
 <translation id="8378714024927312812">በእርስዎ ድርጅት የሚተዳደር</translation>
 <translation id="8379878387931047019">ይህ መሣሪያ በዚህ ድር ጣቢያ የተጠየቀውን የደህንነት ቁልፍ ዓይነት አይደግፍም</translation>
@@ -8454,6 +8499,11 @@
 <translation id="8428628598981198790">የደህንነት ቅቁልፍዎ በዚህ ጣቢያ ላይ መጠቀም አይቻልም</translation>
 <translation id="84297032718407999">በ<ph name="LOGOUT_TIME_LEFT" /> ውስጥ ዘግተው እንዲወጡ ይደረጋሉ</translation>
 <translation id="8431190899827883166">መታ ማድረጎችን አሳይ</translation>
+<translation id="8431496281632382473">ይህ መገለጫ የሚተዳደረው በ<ph name="DOMAIN" /> ነው። ይህን የሚተዳደር መገለጫ መጠቀም ለመቀጠል ድርጅትዎ የመሣሪያዎን ምልክቶች እንዲያጋሩ ይፈልጋል።
+
+የመሣሪያ ምልክቶች ስለ እርስዎ አሳሽ፣ ሥርዓተ ክወና፣ መሣሪያ፣ የተጫነ ሶፍትዌር እና ፋይሎች መረጃዎችን ሊያካትቱ ይችላሉ።
+
+ምልክቶችን ላለማጋራት ከመረጡ ይህ መገለጫ ይዘጋል።</translation>
 <translation id="8434480141477525001">NaCl ስህተት ማረሚያ ወደብ</translation>
 <translation id="8437209419043462667">አሜሪካ</translation>
 <translation id="8438328416656800239">ወደ ዘመናዊ አሳሽ ቀይር</translation>
@@ -8538,6 +8588,8 @@
 <translation id="851263357009351303">ሁልጊዜ <ph name="HOST" /> ምስሎችን እዲያሳይ ፍቀድ</translation>
 <translation id="8513108775083588393">በራስ ሰር አሽከርክር</translation>
 <translation id="8513357934662532537">ለ<ph name="USER_EMAIL" /> የይለፍ ቃላትን ወደ <ph name="BRAND" /> ለማስመጣት የCSV ፋይልን ይምረጡ።</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />የChromeOS መሣሪያዎች ራስ-ሰር ሪፖርቶችን እንዲልኩ መፍቀድ እኛ በChromeOS ውስጥ ምንን መጠገን እና ማሻሻል እንዳለብን ቅድሚያ እንድንሰጥ ያግዘናል። እነዚህ ሪፖርቶች እንደ ChromeOS ሲበላሽ፣ የትኛዎቹ ባህሪያት ጥቅም ላይ እንደዋሉ እና በተለምዶ ምን ያህል ማህደረ ትውስታ ጥቅም ላይ ውሎ እንደነበር ያሉ ነገሮችን ሊያካትቱ ይችላሉ። እንዲሁም የመተግበሪያዎች ስምረት ከበራ የAndroid እና የድር መተግበሪያዎችን ጨምሮ ሌላ የመተግበሪያ ምርመራ እና የአጠቃቀም ውሂብ ይሰበሰባል።<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />በማንኛውም ጊዜ በልጅዎ የChromeOS መሣሪያ ቅንብሮች ውስጥ እነዚህን ሪፖርቶች መፍቀድ መጀመር ወይም ማቆም ይችላሉ። እርስዎ የጎራ አስተዳዳሪ ከሆኑ ይህን ቅንብር በአስተዳዳሪ ኮንሶል ውስጥ መለወጥ ይችላሉ።<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">የተለየ የደህንነት ቁልፍ ይሞክሩ</translation>
 <translation id="8514955299594277296">ጣቢያዎች በመሣሪያዎ ላይ ውሂብ እንዲያስቀምጡ አይፍቀዱ (አይመከርም)</translation>
 <translation id="8517759303731677493">አርትዕ…</translation>
@@ -8899,6 +8951,7 @@
 <translation id="883062543841130884">ምትኮች</translation>
 <translation id="8830779999439981481">ዝማኔዎችን ለመተግበር ዳግም በማስነሳት ላይ</translation>
 <translation id="8830796635868321089">የአሁኑ ተኪ ቅንብሮችን ተጠቅሞ የዝማኔ ፍተሻ አልተሳካም። እባክዎ <ph name="PROXY_SETTINGS_LINK_START" />የተኪ ቅንብሮችዎ<ph name="PROXY_SETTINGS_LINK_END" />ን ያስተካክሉ።</translation>
+<translation id="8830863983385452402">ጣቢያው የዚህን ትር ይዘቶች ማየት ይችላል</translation>
 <translation id="8831769650322069887"><ph name="FILE_NAME" />ን ይክፈቱ</translation>
 <translation id="8832781841902333794">የእርስዎ መገለጫዎች</translation>
 <translation id="8834039744648160717"><ph name="USER_EMAIL" /> ነው የአውታረ መረብ ውቅረትን የሚቆጣጠሩት።</translation>
@@ -9030,6 +9083,7 @@
 <translation id="8946359700442089734">የማረም ባህሪያት በዚህ የ<ph name="IDS_SHORT_PRODUCT_NAME" /> መሣሪያ ላይ ሙሉ ለሙሉ አልነቁም።</translation>
 <translation id="894763922177556086">ጥሩ</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> የደህንነት ቁልፍዎን ስሪት እና ሞዴል ማየት ይፈልጋል</translation>
+<translation id="8949304443659090542">የChrome አሳሽ ስምረትን ያስተዳድሩ</translation>
 <translation id="895054485242522631">ጣቢያዎች የእንቅስቃሴ ዳሳሾችን መጠቀም ይችላሉ</translation>
 <translation id="8951256747718668828">በስህተት ምክንያት እንደ ነበረ መመለስ ሊጠናቀቅ አልተቻለም</translation>
 <translation id="8951465597020890363">የሆነው ሆኖ ከእንግዳ ሁነታ ይወጣ?</translation>
@@ -9135,6 +9189,7 @@
 <translation id="9032097289595078011">ፈጣን ጥምረትን ያሰናክሉ</translation>
 <translation id="9033765790910064284">ለማንኛውም ቀጥል</translation>
 <translation id="9033857511263905942">&amp;ለጥፍ</translation>
+<translation id="9034408118624208974">ለChromebook አዲስ ነዎት? ምርጫዎችዎ ምትኬ እንዲቀመጥላቸው ስምረትን ያብሩ።</translation>
 <translation id="903480517321259405">ፒኑን እንደገና ይተይቡት</translation>
 <translation id="9037054491984310631"><ph name="DEVICE" /> ከተብሎ ከተሰየመ የብሉቱዝ መሣሪያ ጋር ተገናኝቷል</translation>
 <translation id="9037640663275993951">መሣሪያ አይፈቀድም</translation>
@@ -9178,6 +9233,7 @@
 <translation id="9068298336633421551">የአካባቢ ፈቃድ ያላቸው የAndroid መተግበሪያዎች እና አገልግሎቶች የዚህን መሣሪያ አካባቢ እንዲጠቀሙ ይፍቀዱ። Google የአካባቢ ትክክለኝነትን እና በአካባቢ ላይ የተመሠረቱ አገልግሎቶችን ለማሻሻል በየጊዜው የአካባቢ ውሂብ ሊሰበስብና ይህን ውሂብ ስም-አልባ በሆነ መልኩ ሊጠቀምበት ይችላል።</translation>
 <translation id="9068598199622656904">ለቁልፍ ሰሌዳ አቋራጮች በተመሳሳይ ጊዜ ቁልፎችን ወደታች ይዞ በመቆየት ምትክ በአንድ ጊዜ አንድ ቁልፍ ይጫኑ</translation>
 <translation id="9068878141610261315">የማይደገፍ የፋይል ዓይነት</translation>
+<translation id="9069665781180028115">በዚህ Chromebook ላይ የተመረጡ ንጥሎች ይገኛሉ። ለChromebook አዲስ ከሆኑ ምርጫዎችዎ ምትኬ እንዲቀመጥላቸው ሁሉንም ንጥሎች ያስምሩ። በቅንብሮች &gt; መለያዎች ውስጥ በማንኛውም ጊዜ ለውጦችን ያድርጉ።</translation>
 <translation id="9070342919388027491">ትር ወደ ግራ ተወስዷል</translation>
 <translation id="9074739597929991885">ብሉቱዝ</translation>
 <translation id="9074836595010225693">የUSB መዳፊት ተገናኝቷል</translation>
@@ -9351,6 +9407,7 @@
 <translation id="930268624053534560">ዝርዝር የጊዜ ማህተሞች</translation>
 <translation id="930551443325541578">የተደገሙ ቁልፎች እና የአጽንዖት ምልክቶች</translation>
 <translation id="930893132043726269">በአሁኑ ጊዜ በማዛወር ላይ</translation>
+<translation id="930991362911221750"><ph name="APP_NAME" /> ይህን ትር እንዲመለከት ይፈቀድለት?</translation>
 <translation id="93140074055951850">የAndroid መተግበሪያዎች ቆመዋል</translation>
 <translation id="932327136139879170">መነሻ</translation>
 <translation id="932508678520956232">ማተም ማስጀመር አልተቻለም።</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index d828337..ebac6ccf 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -590,6 +590,7 @@
 <translation id="1506187449813838456">زيادة درجة الصوت</translation>
 <translation id="1507170440449692343">تم حظر دخول هذه الصفحة إلى الكاميرا التابعة لك.</translation>
 <translation id="1507246803636407672">إل&amp;غاء</translation>
+<translation id="1508931164824684991">‏السماح للمواقع الإلكترونية باستخدام JavaScript</translation>
 <translation id="1509163368529404530">استعادة المجموعة</translation>
 <translation id="1509281256533087115">‏الوصول إلى أي <ph name="DEVICE_NAME_AND_VENDOR" /> عبر USB</translation>
 <translation id="1510238584712386396">مشغِّل التطبيقات</translation>
@@ -847,6 +848,7 @@
 <translation id="1708291623166985230">نقطة الاتصال غير مفعَّلة.</translation>
 <translation id="1708338024780164500">(غير نشطة)</translation>
 <translation id="1708713382908678956"><ph name="NAME_PH" /> (رقم التعريف: <ph name="ID_PH" />)</translation>
+<translation id="1708979186656821319">عدم العرض عند اكتمال عمليات التنزيل</translation>
 <translation id="1709106626015023981">‏<ph name="WIDTH" /> x <ph name="HEIGHT" /> (الأصلي)</translation>
 <translation id="1709217939274742847">اختَر تذكرة لاستخدامها في المصادقة. <ph name="LINK_BEGIN" />مزيد من المعلومات<ph name="LINK_END" /></translation>
 <translation id="1709762881904163296">إعدادات الشبكة</translation>
@@ -1670,6 +1672,7 @@
 <translation id="2398546389094871088">‏لن يؤدي إجراء عملية Powerwash لجهازك إلى إزالة الملفات التعريفية لشرائح eSIM. انتقِل إلى <ph name="LINK_BEGIN" />إعدادات الجوّال<ph name="LINK_END" /> لإزالة هذه الملفات التعريفية يدويًّا.</translation>
 <translation id="2399699884460174994">تم تفعيل الإشعارات</translation>
 <translation id="2399939490305346086">بيانات تسجيل الدخول على مفتاح الأمان</translation>
+<translation id="2400323785194108001">عدم إيقاف هذا الموقع الإلكتروني مطلقًا</translation>
 <translation id="2400664245143453337">مطلوب التحديث فورًا</translation>
 <translation id="2402226831639195063">النبرات</translation>
 <translation id="2406153734066939945">هل تريد حذف هذا الملف الشخصي وكل بياناته؟</translation>
@@ -1986,6 +1989,7 @@
 <translation id="2673135533890720193">قراءة سجل التصفح التابع لك</translation>
 <translation id="2674764818721168631">غير مفعَّل</translation>
 <translation id="2675570801872027281">‏حدث خطأ أثناء إزالة الجهاز الافتراضي Bruschetta. يُرجى إعادة المحاولة.</translation>
+<translation id="2676084251379299915">‏تم إيقاف هذه الإضافة بموجب سياسة المؤسسة لأنّها لم تعُد متوفّرة على "سوق Chrome الإلكتروني".</translation>
 <translation id="267708982776801183">فلتر للّونين الأحمر والأخضر (ضَعف إبصار الأحمر، غَطَشُ الأحمر)</translation>
 <translation id="2678063897982469759">إعادة تفعيل</translation>
 <translation id="2678100101831051676">تعذَّر البث</translation>
@@ -2084,6 +2088,7 @@
 <translation id="2755367719610958252">إدارة ميزات تسهيل الاستخدام
 </translation>
 <translation id="275662540872599901">الشاشة متوقفة</translation>
+<translation id="2756936198272359372">‏المواقع الإلكترونية التي لا يُسمح لها باستخدام JavaScript</translation>
 <translation id="2757161511365746634">عرض الطابعة</translation>
 <translation id="2757338480560142065">يُرجى التأكّد من أنّ كلمة المرور التي تريد حفظها تطابِق كلمة مرور <ph name="WEBSITE" />.</translation>
 <translation id="2761632996810146912"><ph name="HASHTAG_SETTINGS" /> لم يتم عرض نتائج بحث عن "<ph name="SEARCH_QUERY" />".</translation>
@@ -2115,6 +2120,7 @@
 <translation id="2781692009645368755">Google Pay</translation>
 <translation id="2781800772148653810">الإضافات مفعّلة على هذا الموقع الإلكتروني.</translation>
 <translation id="2782104745158847185">‏حدث خطأ أثناء تثبيت تطبيق Linux</translation>
+<translation id="2783024642731649028">سلعة واحدة في سلة التسوّق متوفّرة بخصم ‫<ph name="DISCOUNT_TEXT" /> من "<ph name="MERCHANT_NAME" />" على <ph name="MERCHANT_DOMAIN" />، وتم الاطّلاع عليها <ph name="RELATIVE_TIME" /></translation>
 <translation id="2783298271312924866">تم التنزيل</translation>
 <translation id="2783321960289401138">جارٍ إنشاء اختصار...</translation>
 <translation id="2783829359200813069">اختيار أنواع التشفير</translation>
@@ -2895,6 +2901,7 @@
 <translation id="3496213124478423963">تصغير</translation>
 <translation id="3496238553815913323">لم يتم اختيار <ph name="LANGUAGE" />.</translation>
 <translation id="3496689104192986836">مستوى شحن البطارية <ph name="PERCENTAGE" />%</translation>
+<translation id="3496995426334945408">‏تستخدم المواقع الإلكترونية عادةً JavaScript لعرض الميزات التفاعلية، مثل ألعاب الفيديو أو نماذج الويب.</translation>
 <translation id="3497501929010263034">‏أجهزة USB من <ph name="VENDOR_NAME" /> (المنتج <ph name="PRODUCT_ID" />)</translation>
 <translation id="3497560059572256875">مشاركة رسومات الشعار المبتكرة</translation>
 <translation id="3500417806337761827">‏حدث خطأ أثناء تثبيت المشاركة. سبَق وأن تمّ تثبيت العديد من مشاركات بروتوكول Server Message Block ‏(SMB).</translation>
@@ -2939,6 +2946,7 @@
 <translation id="354060433403403521">‏محول AC</translation>
 <translation id="354068948465830244">يمكن أن يؤدي ذلك إلى قراءة بيانات الموقع الإلكتروني وتغييرها</translation>
 <translation id="3541823293333232175">تم تخصيص المفتاح.</translation>
+<translation id="354204985370574425">عدم إيقاف هذا الموقع الإلكتروني مطلقًا</translation>
 <translation id="3543393733900874979">تعذّر التحديث (خطأ: <ph name="ERROR_NUMBER" />)</translation>
 <translation id="3543597750097719865">‏توقيع X9.62 ECDSA باستخدام SHA-512</translation>
 <translation id="3544058026430919413">يمكن للشركة تحديد مجموعة مواقع إلكترونية يمكنها استخدام ملفات تعريف الارتباط لمشاركة نشاطك في المجموعة. يتم إيقاف هذا الإعداد في "وضع التصفّح المتخفي".</translation>
@@ -3830,6 +3838,7 @@
 <translation id="4324577459193912240">ملف غير مكتمل</translation>
 <translation id="4325237902968425115">جارٍ إلغاء تثبيت <ph name="LINUX_APP_NAME" />...</translation>
 <translation id="4326146840124313313">‏يوفِّر Chrome أعلى مستويات الأمان لحمايتك من المواقع الإلكترونية وعمليات التنزيل والإضافات الخطيرة.</translation>
+<translation id="4326484226728068206">السلع في سلة التسوّق متوفّرة بخصم ‫<ph name="DISCOUNT_TEXT" /> من "<ph name="MERCHANT_NAME" />" على <ph name="MERCHANT_DOMAIN" />، وتم الاطّلاع عليها <ph name="RELATIVE_TIME" /></translation>
 <translation id="4330191372652740264">ماء مثلج</translation>
 <translation id="4330387663455830245">عدم ترجمة <ph name="LANGUAGE" /> مطلقًا</translation>
 <translation id="4332976768901252016">إعداد أدوات الرقابة الأبوية</translation>
@@ -4516,6 +4525,7 @@
 <translation id="4940448324259979830">تتم إدارة هذا الحساب من قِبل <ph name="PROFILE_NAME" />.</translation>
 <translation id="4940845626435830013">حجز حجم القرص</translation>
 <translation id="4941074198479265146">‏تتّصل المواقع الإلكترونية عادةً بأجهزة MIDI لتتيح ميزات إنشاء الموسيقى وتعديلها.</translation>
+<translation id="4941243352516004658">‫<ph name="PRODUCT_ITEM_COUNT" /> سلعة في سلة التسوّق متوفّرة بخصم ‫<ph name="DISCOUNT_TEXT" /> من "<ph name="MERCHANT_NAME" />" على <ph name="MERCHANT_DOMAIN" />، تم الاطّلاع عليها <ph name="RELATIVE_TIME" /></translation>
 <translation id="4941246025622441835">استخدام طلب الجهاز عند تسجيل الجهاز في إدارة المؤسسات:</translation>
 <translation id="4941627891654116707">حجم الخط</translation>
 <translation id="4941963255146903244">عرض الصور والوسائط والتطبيقات من هاتفك</translation>
@@ -5470,6 +5480,7 @@
 <translation id="5832970156002835240">السماح باستخدام الإضافة على جميع المواقع الإلكترونية</translation>
 <translation id="5833397272224757657">يتم استخدام المحتوى على المواقع الإلكترونية التي تزورها، بالإضافة إلى نشاط المتصفِّح وتفاعلاته للتخصيص.</translation>
 <translation id="5833726373896279253">يمكن تعديل هذه الإعدادات بواسطة المالك فقط: </translation>
+<translation id="5833899990800318936">‏عدم السماح للمواقع الإلكترونية باستخدام JavaScript</translation>
 <translation id="583431638776747">لم يكن الموقع الإلكتروني متاحًا.</translation>
 <translation id="5834581999798853053">تتبقى <ph name="TIME" /> دقيقة تقريبًا</translation>
 <translation id="5835360478055379192">{NUM_EXTENSION,plural, =1{‏الإضافة التي لديها إمكانية الوصول إلى أجهزة HID: <ph name="EXTENSION1" />}=2{الإضافات التي لديها إمكانية الوصول إلى الأجهزة: <ph name="EXTENSION1" /> و<ph name="EXTENSION2" />}zero{الإضافات التي لديها إمكانية الوصول إلى الأجهزة: <ph name="EXTENSION1" /> و<ph name="EXTENSION2" /> و{3} إضافة أخرى}few{الإضافات التي لديها إمكانية الوصول إلى الأجهزة: <ph name="EXTENSION1" /> و<ph name="EXTENSION2" /> و{3} إضافات أخرى}many{الإضافات التي لديها إمكانية الوصول إلى الأجهزة: <ph name="EXTENSION1" /> و<ph name="EXTENSION2" /> و{3} إضافة أخرى}other{الإضافات التي لديها إمكانية الوصول إلى الأجهزة: <ph name="EXTENSION1" /> و<ph name="EXTENSION2" /> و{3} إضافة أخرى}}</translation>
@@ -5700,6 +5711,7 @@
 <translation id="6026819612896463875">‏<ph name="WINDOW_TITLE" /> - تم توصيل جهاز USB</translation>
 <translation id="6027945736510816438">هل كنت تقصد <ph name="WEBSITE" />؟</translation>
 <translation id="6028117231645531007">إضافة بصمة الإصبع</translation>
+<translation id="6030719887161080597">إدارة المعلومات التي تستخدمها المواقع الإلكترونية لقياس أداء الإعلانات</translation>
 <translation id="6031600495088157824">خيارات الإدخال في شريط الأدوات</translation>
 <translation id="6032715498678347852">للسماح للإضافة بالوصول إلى بيانات هذا الموقع الإلكتروني، انقر على الإضافة.</translation>
 <translation id="6032912588568283682">نظام الملفات</translation>
@@ -5934,6 +5946,7 @@
 <translation id="623755660902014047">وضع القراءة</translation>
 <translation id="6238767809035845642">‏النص الذي تمت مشاركته من Other Device (جهاز آخر)</translation>
 <translation id="6238923052227198598">إبقاء آخر ملاحظة على شاشة القفل</translation>
+<translation id="6238982280403036866">‏المواقع الإلكترونية التي يُسمح لها باستخدام JavaScript</translation>
 <translation id="6239558157302047471">تحديث الإطار</translation>
 <translation id="6240821072888636753">السؤال في كل مرة</translation>
 <translation id="6241530762627360640">الوصول إلى معلومات حول أجهزة البلوتوث المقترنة بنظامك واكتشاف أجهزة البلوتوث القريبة.</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index d16ae33..0cfa10d 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -5993,6 +5993,7 @@
 <translation id="6266532094411434237">Установява се връзка с(ъс) <ph name="DEVICE" /></translation>
 <translation id="6267166720438879315">Изберете сертификат, за удостоверите самоличността си пред <ph name="HOST_NAME" /></translation>
 <translation id="6268252012308737255">Отваряне чрез <ph name="APP" /></translation>
+<translation id="6270309713620950855">Спиране на подсещането</translation>
 <translation id="6270391203985052864">Сайтовете могат да извеждат подкани за изпращане на известия</translation>
 <translation id="6270770586500173387">Изпращане на <ph name="BEGIN_LINK1" />информация за системата и приложенията<ph name="END_LINK1" />, както и за <ph name="BEGIN_LINK2" />показателите<ph name="END_LINK2" /></translation>
 <translation id="6270896861225278704">Карта на пътищата</translation>
@@ -6327,6 +6328,7 @@
 <translation id="657866106756413002">Моментна снимка на състоянието на мрежата</translation>
 <translation id="6579369886355986318">Показване на всички &amp;контроли</translation>
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> – съдържанието на работния плот е споделено</translation>
+<translation id="6580060371127789208">Завършено: <ph name="PERCENTAGE_COMPLETE" />%</translation>
 <translation id="6580203076670148210">Скорост на сканиране</translation>
 <translation id="6582080224869403177">Нулирайте устройството си <ph name="DEVICE_TYPE" />, за да надстроите функциите за сигурност.</translation>
 <translation id="6582274660680936615">Сърфирате като гост</translation>
@@ -6948,6 +6950,7 @@
 <translation id="7114054701490058191">Паролите не са идентични</translation>
 <translation id="7114648273807173152">За да използвате Smart Lock за влизане в профила ви в Google, отворете „Настройки &gt; Свързани устройства &gt; Вашият телефон &gt; Smart Lock“.</translation>
 <translation id="7115361495406486998">Няма налични контакти</translation>
+<translation id="7116554090938189816">SSL сертификатът на принтера е изтекъл. Рестартирайте принтера и опитайте отново.</translation>
 <translation id="7117228822971127758">Моля, опитайте отново по-късно</translation>
 <translation id="711840821796638741">Показване на управляваните отметки</translation>
 <translation id="711985611146095797">От тази страница можете да управлявате профилите си в Google, в които сте влезли. <ph name="LINK_BEGIN" />Научете повече<ph name="LINK_END" /></translation>
@@ -7232,6 +7235,7 @@
 <translation id="7392118418926456391">Сканирането за вируси не бе успешно</translation>
 <translation id="7392915005464253525">По&amp;вторно отваряне на затворен прозорец</translation>
 <translation id="7393073300870882456">{COUNT,plural, =1{Копирахте 1 елемент}other{Копирахте {COUNT} елемента}}</translation>
+<translation id="7393435859300249877">Ще получавате известия, ако говорите, докато микрофонът ви е заглушен, когато използвате определени приложения, като например тези за видеочат. Звукът никога не напуска устройството ви.</translation>
 <translation id="7395774987022469191">Цял екран</translation>
 <translation id="7396017167185131589">Споделените папки ще се показват тук</translation>
 <translation id="7396845648024431313"><ph name="APP_NAME" /> ще се изпълнява при стартиране на системата и ще продължи да работи на заден план дори след като затворите всички други прозорци на <ph name="PRODUCT_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index c4f5a3f..8ca550e3 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -4001,7 +4001,7 @@
 <translation id="4451479197788154834">এই ডিভাইসে এবং আপনার Google অ্যাকাউন্টে পাসওয়ার্ড সেভ করা আছে</translation>
 <translation id="4452898361839215358">অথবা PPD বেছে নিন। <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">আপনার কীবোর্ডের উপরের ডানদিকের কোণে থাকা ফিঙ্গারপ্রিন্ট সেন্সর টাচ করুন। আপনার ফিঙ্গারপ্রিন্ট ডেটা সুরক্ষিতভাবে স্টোর করে রাখা হয় এবং তা <ph name="DEVICE_TYPE" /> থেকে কখনও শেয়ার করা হয় না।</translation>
-<translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" />-এ সার্চ করুন অথবা ইউআরএল টাইপ করুন</translation>
+<translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" />-এ সার্চ করুন অথবা URL টাইপ করুন</translation>
 <translation id="4457472090507035117">এখনকার ভয়েসটি বেছে নিন:</translation>
 <translation id="4459169140545916303"><ph name="DEVICE_LAST_ACTIVATED_TIME" /> দিন আগে ব্যবহার করা হয়েছে</translation>
 <translation id="4460014764210899310">আলাদা করুন</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index 3b08245d..09e4d692 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -218,6 +218,7 @@
 <translation id="1176471985365269981">Har ikke tilladelse til at redigere filer og mapper på din enhed</translation>
 <translation id="1177863135347784049">Tilpasset</translation>
 <translation id="1178581264944972037">Pause</translation>
+<translation id="1178601482396475810">Administrer enhedssynkronisering</translation>
 <translation id="117916940443676133">Din sikkerhedsnøgle er ikke beskyttet med en pinkode. Opret en pinkode for at administrere logindata.</translation>
 <translation id="1181037720776840403">Fjern</translation>
 <translation id="1181366777303791449"><ph name="MAIN_FRAME_ETLD_PLUS_ONE" /></translation>
@@ -356,6 +357,7 @@
 <translation id="130097046531636712">Dette forlænger batteriets levetid ved at begrænse baggrundsaktivitet og visuelle effekter såsom jævn rulning</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> kan redigere følgende filer</translation>
 <translation id="1302227299132585524">Tillad JavaScript via Apple Events</translation>
+<translation id="1302654693270046655">Gruppen <ph name="GROUP_NAME" /> – <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">Tilføjer HTML-fil som bogmærke</translation>
 <translation id="1303671224831497365">Der blev ikke fundet nogen Bluetooth-enheder</translation>
 <translation id="130491383855577612">Linux-applikationerne og -filerne blev erstattet</translation>
@@ -365,7 +367,7 @@
 <translation id="1307165550267142340">Din pinkode blev oprettet</translation>
 <translation id="1307431692088049276">Spørg mig ikke igen</translation>
 <translation id="1307559529304613120">Ups! Systemet kunne ikke gemme det langfristede API-adgangstoken for denne enhed.</translation>
-<translation id="131112695174432497">Data, der påvirker personlig annoncetilpasning, slettes</translation>
+<translation id="131112695174432497">Data, der påvirker personlig tilpasning af annoncer, slettes</translation>
 <translation id="1312811472299082263">Opret via en Ansible Playbook eller en Crostini-backupfil</translation>
 <translation id="13130607084115184">Dine gemte adgangskoder vises her. <ph name="BEGIN_LINK" />Vælg en CSV-fil<ph name="END_LINK" /> for at importere adgangskoder til <ph name="BRAND" /> på denne enhed.</translation>
 <translation id="1313264149528821971"><ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="PERMISSION_3" /> blev fjernet</translation>
@@ -1063,6 +1065,7 @@
 <translation id="1877520246462554164">Der kunne ikke hentes noget godkendelsestoken. Log ud, og log derefter ind igen for at prøve igen.</translation>
 <translation id="1877860345998737529">Tildeling af handlinger for kontakter</translation>
 <translation id="1878155070920054810">Det ser ud til, at din Chromebook løber tør for strøm, før opdateringen er fuldført. Sørg for, at du oplader korrekt, så opdateringen ikke afbrydes.</translation>
+<translation id="1878477879455105085">Åbnet</translation>
 <translation id="1878885068166344708">Elementet fremhæves, når du flytter fokus. Tryk på Tab-tasten, eller vælg et element for at skifte fokus.</translation>
 <translation id="1879000426787380528">Log ind som</translation>
 <translation id="18802377548000045">Faner formindskes til stor bredde</translation>
@@ -1447,6 +1450,7 @@
 <translation id="2204034823255629767">Læs og rediger alt, hvad du indtaster</translation>
 <translation id="2204387456724731099">Dette valg kunne ikke oversættes</translation>
 <translation id="2210462644007531147">Installationen kunne ikke gennemføres</translation>
+<translation id="2211245494465528624">Administrer indstillinger for synkronisering</translation>
 <translation id="2212565012507486665">Tillad cookies</translation>
 <translation id="2214018885812055163">Delte mapper</translation>
 <translation id="2214884991347062907">Adgangskoden er forkert. Prøv igen.</translation>
@@ -1545,6 +1549,7 @@
 <translation id="2296218178174497398">Enhedsregistrering</translation>
 <translation id="2297705863329999812">Søg efter printere</translation>
 <translation id="2297822946037605517">Del denne side</translation>
+<translation id="229871422646860597">Frigør fra værktøjslinje</translation>
 <translation id="2299734369537008228">Skyder: <ph name="MIN_LABEL" /> til <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">Medtag alle logfiler, der indsamles af debugd, som adskilt arkiv.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2175,6 +2180,7 @@
 <translation id="2811205483104563968">Konti</translation>
 <translation id="2811564570599779918">Reducering af spam og svindel</translation>
 <translation id="2812049959647166806">Thunderbolt understøttes ikke</translation>
+<translation id="2812171980080389735">Gemte netværk og adgangskoder, så du kan oprette forbindelse med det samme</translation>
 <translation id="2813094189969465044">Børnesikring</translation>
 <translation id="281390819046738856">Anmodningen kunne ikke signeres.</translation>
 <translation id="2814489978934728345">Stop indlæsning af denne side</translation>
@@ -2214,6 +2220,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">Din pinkode er blevet tilføjet</translation>
 <translation id="2849936225196189499">Kritisk</translation>
+<translation id="285033512555869047">Lukket</translation>
 <translation id="2850541429955027218">Tilføj tema</translation>
 <translation id="2850672011315104382">Tegnsætningstypografi</translation>
 <translation id="2852385257476173980">En liste over websites, du besøger, kan vises her, når du surfer på nettet</translation>
@@ -2257,6 +2264,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> og <ph name="NUMBER_OF_DEVICES" /> andre</translation>
 <translation id="2889043468805635730">Der blev ikke fundet nogen problemer</translation>
 <translation id="2889064240420137087">Åbn link med...</translation>
+<translation id="2890206081124517553">Husk din skrivebordsbaggrund på alle enheder</translation>
 <translation id="2891566119238851894">Åbn søgning i sidepanel. Søgningen er ikke åben i sidepanelet.</translation>
 <translation id="2891922230654533301">Vil du logge ind på <ph name="APP_NAME" /> med din enhed?</translation>
 <translation id="2893013536106749396">Vælg kort, der holder dig orienteret om ting, der er vigtige for dig</translation>
@@ -2278,6 +2286,7 @@
 <translation id="2907619724991574506">Startwebadresser</translation>
 <translation id="2907798539022650680">Der kunne ikke oprettes forbindelse til "<ph name="NAME" />": <ph name="DETAILS" />
     Servermeddelelse: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">Del signaler</translation>
 <translation id="2908162660801918428">Tilføj mediegalleri efter mappe</translation>
 <translation id="2908358077082926882">Tryk på "<ph name="CURRENTKEY" />" igen for at fjerne tildelingen og <ph name="RESPONSE" /></translation>
 <translation id="2909506265808101667">Der kunne ikke oprettes forbindelse til Google-tjenester. Tjek din netværksforbindelse, og prøv igen. Fejlkode: <ph name="ERROR_CODE" />.</translation>
@@ -2382,6 +2391,7 @@
 <translation id="3003828226041301643">Enheden kunne ikke knyttes til domænet. Sørg for, at din konto har tilladelse til at tilføje enheder.</translation>
 <translation id="3003967365858406397">Din <ph name="PHONE_NAME" /> opretter en privat Wi-Fi-forbindelse.</translation>
 <translation id="3004385386820284928">Tilpas tastaturtaster</translation>
+<translation id="3005376701115952939">Synkronisering af apps angives i systemindstillingerne</translation>
 <translation id="3005574332301273731">Vis ikke</translation>
 <translation id="3006881078666935414">Ingen brugsdata</translation>
 <translation id="3007410324195400631">Tilføj noter om denne side</translation>
@@ -2763,6 +2773,7 @@
 <translation id="3369624026883419694">Identificerer vært...</translation>
 <translation id="3370260763947406229">Autokorrektur</translation>
 <translation id="3371140690572404006">USB-C-enhed (porten foran i højre side)</translation>
+<translation id="3371351218553893534">Linjen er for lang: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">Læse mapper, som du åbner i applikationen</translation>
 <translation id="3373059063088819384">Åbn i læsetilstand</translation>
 <translation id="3373701465337594448">Når denne indstilling er aktiveret, vises der en liste over websites, du besøger, og som prøver at estimere dine interesser, her</translation>
@@ -2833,6 +2844,9 @@
 <translation id="3434272557872943250">Hvis indstillingen for yderligere web- og appaktivitet er aktiveret for dit barn, gemmes disse data muligvis på barnets Google-konto. Få flere oplysninger om disse indstillinger og om, hvordan du ændrer dem, ved at gå til families.google.com.</translation>
 <translation id="3434475275396485144">Denne indstilling administreres af administratoren af din telefon</translation>
 <translation id="3434512374684753970">Lyd og video</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />Log ind med din Google-konto på næste skærm.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Dette er den samme konto, som den, du bruger til Gmail, YouTube, Chrome og andre Google-tjenester. Brug din konto for at få en personligt tilpasset oplevelse og nem adgang til alle dine oplysninger.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Hvis du endnu ikke har en Google-konto, kan du oprette en på den næste skærm.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">"<ph name="EXTENSION_NAME" />" anmoder om <ph name="CODE_TYPE" /></translation>
 <translation id="3435738964857648380">Sikkerhed</translation>
 <translation id="343578350365773421">Der mangler papir</translation>
@@ -2879,6 +2893,7 @@
 <translation id="346546413339447252">Få rabatter til <ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> og andre</translation>
 <translation id="3468298837301810372">Etiket</translation>
 <translation id="3468999815377931311">Android-telefon</translation>
+<translation id="3469345458390352459">Når dine apps er aktiveret, er de tilgængelige på alle ChromeOS-enheder, når du er logget ind med din Google-konto.  Webapps synkroniseres via Chrome, også selvom andre funktioner til browsersynkronisering er deaktiveret.</translation>
 <translation id="3469583217479686109">Opmærkningsværktøj</translation>
 <translation id="3470392222765168737">Følg website</translation>
 <translation id="3471876058939596279">Portene til HDMI og USB-C kan ikke bruges til video på samme tid. Brug en anden videoport.</translation>
@@ -3341,6 +3356,7 @@
 <translation id="3855441664322950881">Pak udvidelse</translation>
 <translation id="3855676282923585394">Importer bogmærker og indstillinger...</translation>
 <translation id="3856096718352044181">Verificer, at dette er en gyldig udbyder, eller prøv igen senere</translation>
+<translation id="3856470183388031602">Brug din Google-konto på din <ph name="DEVICE_TYPE" /></translation>
 <translation id="3856800405688283469">Vælg tidszone</translation>
 <translation id="3857807444929313943">Løft, og berør igen</translation>
 <translation id="3858860766373142691">Navn</translation>
@@ -3380,6 +3396,7 @@
 <translation id="3894123633473837029">Medtag seneste Assistent-historik via Sherlog. Dette kan omfatte din identitet, placering og fejlretningsoplysninger. <ph name="BEGIN_LINK" />Få flere oplysninger<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">Tilføj mappe</translation>
 <translation id="3894770151966614831">Vil du flytte den til en Google-konto?</translation>
+<translation id="3894983081771074056">Tastaturets og musens adfærd, sprogpræferencer og meget mere</translation>
 <translation id="3895076768659607631">&amp;Administrer søgemaskiner...</translation>
 <translation id="3895090224522145010">Kerberos-brugernavn</translation>
 <translation id="389521680295183045">Websites kan anmode om at få at vide, hvornår du aktivt bruger din enhed</translation>
@@ -3515,6 +3532,7 @@
 <translation id="3994878504415702912">&amp;Zoom</translation>
 <translation id="3995138139523574647">USB-C-enhed (porten bagpå i højre side)</translation>
 <translation id="3995963973192100066">Afspil animation</translation>
+<translation id="399788104667917863">Fastgør til værktøjslinje</translation>
 <translation id="4001540981461989979">Fremhæv musemarkøren ved bevægelse</translation>
 <translation id="4002440992267487163">Konfiguration af pinkode</translation>
 <translation id="4005817994523282006">Metode til registrering af tidszone</translation>
@@ -3673,12 +3691,16 @@
 <translation id="4147911968024186208">Prøv igen. Hvis du ser denne fejl igen, skal du kontakte din supportrepræsentant.</translation>
 <translation id="4150201353443180367">Skærm</translation>
 <translation id="4150569944729499860">Skærmkontekst</translation>
+<translation id="4151843924968445052">Vil du dele enhedssignaler?</translation>
 <translation id="4152011295694446843">Her finder du dine bogmærker</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 fane}one{# faner}other{# faner}}</translation>
 <translation id="4154664944169082762">Fingeraftryk</translation>
 <translation id="4157869833395312646">Microsoft-kryptering via server</translation>
 <translation id="4158315983204257156">Websitets tekststørrelse og skrifttype</translation>
 <translation id="4158364720893025815">Bestået</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />Ved at give dine ChromeOS-enheder tilladelse til at sende automatiske rapporter gør du det nemmere for os at prioritere, hvad der skal rettes og forbedres i ChromeOS. Disse rapporter kan f.eks. indeholde oplysninger om, hvornår ChromeOS oplever nedbrud, hvilke funktioner du bruger, hvor meget hukommelse du normalt anvender, samt diagnostik- og brugsdata for Android-apps. Visse samlede data hjælper også Google-apps og -partnere, f.eks. Android-udviklere. Andre data til appdiagnostik og brugsdata, bl.a. for Android- og webapps, indsamles, hvis synkronisering af apps også er aktiveret.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Du kan til enhver tid tillade eller fjerne tilladelsen for disse rapporter i indstillingerne for din ChromeOS-enhed. Hvis du er domæneadministrator, kan du ændre denne indstilling i Administrationskonsol.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Hvis indstillingen Web- og appaktivitet er aktiveret for din Google-konto, gemmes dine Android-data muligvis på din Google-konto. Du kan se og slette dine data samt ændre dine kontoindstillinger på account.google.com.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">Google Adgangskodeadministrator</translation>
 <translation id="4163560723127662357">Ukendt tastatur</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> tilhører ikke en gyldig organisation. Kontakt din administrator. Hvis du er administrator, kan du konfigurere din organisation ved at gå til: g.co/ChromeEnterpriseAccount</translation>
@@ -4002,6 +4024,9 @@
 <translation id="4452898361839215358">eller vælg PPD-fil. <ph name="LINK_BEGIN" />Få flere oplysninger<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">Sæt fingeren på fingeraftrykssensoren øverst til højre på dit tastatur. Dine fingeraftryksdata gemmes sikkert og forlader aldrig din <ph name="DEVICE_TYPE" />.</translation>
 <translation id="4453946976636652378">Søg på <ph name="SEARCH_ENGINE_NAME" />, eller angiv en webadresse</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />Ved at give ChromeOS-enheder tilladelse til at sende automatiske rapporter gør du det nemmere for os at prioritere, hvad der skal rettes og forbedres i ChromeOS. Disse rapporter kan f.eks. indeholde oplysninger om, hvornår ChromeOS oplever nedbrud, hvilke funktioner der blev brugt, hvor meget hukommelse der normalt bruges, samt diagnostik- og brugsdata for Android-apps. Visse samlede data hjælper også Google-apps og -partnere, f.eks. Android-udviklere. Andre data til appdiagnostik og brugsdata, bl.a. for Android- og webapps, indsamles, hvis synkronisering af apps også er aktiveret.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Du kan til enhver tid tillade eller fjerne tilladelsen for afsendelse af disse rapporter i indstillingerne på dit barns ChromeOS-enhed. Hvis du er domæneadministrator, kan du ændre denne indstilling i Administrationskonsol.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />Hvis indstillingen Web- og appaktivitet er aktiveret for dit barns Google-konto, gemmes dit barns data muligvis på barnets Google-konto. Få flere oplysninger om disse indstillinger og om, hvordan du ændrer dem, ved at gå til families.google.com.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">Vælg den aktuelle stemme:</translation>
 <translation id="4459169140545916303">Aktiv for <ph name="DEVICE_LAST_ACTIVATED_TIME" /> dage siden</translation>
 <translation id="4460014764210899310">Ophæv gruppering</translation>
@@ -4382,6 +4407,7 @@
 <translation id="4806457879608775995">Gennemgå disse vilkår, og administrer dine data</translation>
 <translation id="4807098396393229769">Navn på kort</translation>
 <translation id="4808667324955055115">Pop op-vinduer er blokeret:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Gennemgå <ph name="BEGIN_BOLD" />1 udvidelse<ph name="END_BOLD" />, der er fjernet fra Chrome Webshop}one{Gennemgå <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} udvidelse<ph name="END_BOLD" />, der er fjernet fra Chrome Webshop}other{Gennemgå <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} udvidelser<ph name="END_BOLD" />, der er fjernet fra Chrome Webshop}}</translation>
 <translation id="4809079943450490359">Vejledninger fra din enhedsadministrator:</translation>
 <translation id="4809447465126035330">Slet</translation>
 <translation id="480990236307250886">Åbn startsiden</translation>
@@ -4705,6 +4731,7 @@
 <translation id="5101839224773798795">Klik automatisk, når markøren stopper</translation>
 <translation id="5106350808162641062">Fjern</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> forældrestyres af Family Link. Du kan tilføje skolekonti for at få adgang til skoleressourcer med en forældrestyret konto.</translation>
+<translation id="5107093668001980925">Vis aldrig <ph name="MODULE_NAME" /></translation>
 <translation id="5107443654503185812">En udvidelse har deaktiveret Beskyttet browsing</translation>
 <translation id="5108967062857032718">Indstillinger – Fjern Android-apps</translation>
 <translation id="5109044022078737958">Caroline</translation>
@@ -4715,6 +4742,7 @@
 <translation id="5111794652433847656">Der er ingen adgangskoder for <ph name="APP_NAME" /> på denne enhed</translation>
 <translation id="5112577000029535889">&amp;Udviklerværktøjer</translation>
 <translation id="511313294362309725">Slå Hurtig parring til</translation>
+<translation id="5113384440341086023">Apps, der er installeret fra Play Butik, og webapps fra Chrome-browseren</translation>
 <translation id="51143538739122961">Indsæt din sikkerhedsnøgle, og tryk på den</translation>
 <translation id="5115309401544567011">Slut din <ph name="DEVICE_TYPE" /> til en strømkilde.</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4760,6 +4788,7 @@
 <translation id="5154702632169343078">Emne</translation>
 <translation id="5155327081870541046">I adresselinjen skal du angive genvejen til det website, du vil søge på, f.eks. "@bogmærker". Tryk derefter på din foretrukne tastaturgenvej, og angiv din søgeterm.</translation>
 <translation id="5156638757840305347">Markøren fremhæves, når den vises eller flyttes</translation>
+<translation id="5157250307065481244">Se websiteoplysninger</translation>
 <translation id="5157635116769074044">Fastgør denne side til startskærmen...</translation>
 <translation id="5158206172605340248">Menuen for accenttegn blev lukket.</translation>
 <translation id="5159094275429367735">Konfigurer Crostini</translation>
@@ -4919,7 +4948,7 @@
 <translation id="5299109548848736476">Do Not Track</translation>
 <translation id="5299558715747014286">Se og administrer dine fanegupper</translation>
 <translation id="529986401483187205">deaktiveret</translation>
-<translation id="5300426565656326054">Browserbaseret personlig annoncetilpasning</translation>
+<translation id="5300426565656326054">Browserbaseret personlig tilpasning af annoncer</translation>
 <translation id="5300589172476337783">Vis</translation>
 <translation id="5300719150368506519">Sender webadresserne for de sider, du besøger, til Google</translation>
 <translation id="5301751748813680278">Anvender som gæst.</translation>
@@ -5819,6 +5848,7 @@
 <translation id="6104068876731806426">Google Konti</translation>
 <translation id="6104311680260824317">Enheden kunne ikke knyttes til domænet. Serveren understøtter ikke de angivne Kerberos-krypteringstyper. Tjek krypteringsindstillingerne under "Flere valgmuligheder".</translation>
 <translation id="6104796831253957966">Printerkøen er fuld</translation>
+<translation id="6106167152849320869">Hvis du også valgte at sende diagnostik- og brugsdata i forrige trin, indsamles disse data for installerede apps.</translation>
 <translation id="6111972606040028426">Aktivér Google Assistent</translation>
 <translation id="6112294629795967147">Tryk for at vælge en anden størrelse</translation>
 <translation id="6112727384379533756">Tilføj en billet</translation>
@@ -5949,6 +5979,7 @@
 <translation id="6226777517901268232">Privat nøglefil (valgfrit)</translation>
 <translation id="6227002569366039565">Tryk på |<ph name="ACCELERATOR" />| for at fokusere på denne boble, og tryk igen for at fokusere på det element, den peger på.</translation>
 <translation id="6227280783235722609">udvidelse</translation>
+<translation id="6229062790325126537">Nulstil ApnMigrator</translation>
 <translation id="6229849828796482487">Afbryd forbindelsen til Wi-Fi-netværket</translation>
 <translation id="6231782223312638214">Foreslået</translation>
 <translation id="6231881193380278751">Tilføj en forespørgselsparameter i webadressen for at opdatere siden automatisk: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6226,6 +6257,7 @@
 <translation id="6478248366783946499">Vil du beholde den farlige fil?</translation>
 <translation id="6479881432656947268">Gå til Chrome Webshop</translation>
 <translation id="6480327114083866287">Administreres af <ph name="MANAGER" /></translation>
+<translation id="6481978993812487794">Når dine apps er aktiveret, er de tilgængelige på alle ChromeOS-enheder, når du er logget ind med din Google-konto. Webapps synkroniseres via Chrome, også selvom andre funktioner til browsersynkronisering er deaktiveret.</translation>
 <translation id="6482559668224714696">Forstørrelse af fuld skærm</translation>
 <translation id="6483485061007832714">Åbn download</translation>
 <translation id="6483805311199035658">Åbner <ph name="FILE" />...</translation>
@@ -6240,6 +6272,7 @@
 <translation id="6497784818439587832">Skift visningsstørrelse for at gøre elementer på skærmen mindre eller større</translation>
 <translation id="6497789971060331894">Omvendt rulning på mus</translation>
 <translation id="6498249116389603658">&amp;Alle dine sprog</translation>
+<translation id="6498583202177273322">Få yderligere nyttige oplysninger, mens du udforsker denne side</translation>
 <translation id="6499143127267478107">Værtsløsning i proxyscript...</translation>
 <translation id="6499764981457476645">Der blev ikke fundet nogen enheder i nærheden</translation>
 <translation id="6501957628055559556">Alle containere</translation>
@@ -6688,6 +6721,7 @@
 <translation id="688312408602122936">Spil og apps, der er installeret via Steam, fjernes også fra denne enhed</translation>
 <translation id="6883319974225028188">Ups! Systemet kunne ikke gemme enhedskonfigurationen.</translation>
 <translation id="6884474387073389421">Er du sikker på, at du vil slette de valgte logindata?</translation>
+<translation id="6885122019363983153">Baggrunde på computere matcher på alle enheder</translation>
 <translation id="6885771755599377173">Forhåndsvisning af systemoplysninger</translation>
 <translation id="6886380424988777998">Linux kunne ikke opgraderes</translation>
 <translation id="6886871292305414135">Åbn link i ny &amp;fane</translation>
@@ -6759,6 +6793,7 @@
 <translation id="6949434160682548041">Adgangskode (valgfrit)</translation>
 <translation id="6950627417367801484">Gendan apps</translation>
 <translation id="6952242901357037157">Du kan også vise adgangskoder fra din <ph name="BEGIN_LINK" />Google-konto<ph name="END_LINK" /> her</translation>
+<translation id="6954910832698269894">Aktivér enhedssynkronisering for at gendanne apps, indstillinger, Wi-Fi-netværk og baggrunden fra din tidligere Chromebook. Du kan til enhver tid foretage ændringer ved at gå til Indstillinger &gt; Konti.</translation>
 <translation id="6954936693361896459">Cast denne fane i stedet</translation>
 <translation id="6955446738988643816">Undersøg pop op-vindue</translation>
 <translation id="6955535239952325894">Denne indstilling er deaktiveret i administrerede browsere</translation>
@@ -6917,6 +6952,7 @@
 <translation id="7075513071073410194">PKCS #1 MD5 med RSA-kryptering</translation>
 <translation id="7075625805486468288">Administrer HTTPS-/SSL-certifikater og -indstillinger</translation>
 <translation id="7076875098323397992">Opgraderingen kan ikke startes</translation>
+<translation id="7077751457066325012">Se og tilpas tastaturgenveje</translation>
 <translation id="7077829361966535409">Loginsiden kunne ikke indlæses med de aktuelle proxyindstillinger. <ph name="GAIA_RELOAD_LINK_START" />Prøv at logge ind igen<ph name="GAIA_RELOAD_LINK_END" />, eller brug nogle andre <ph name="PROXY_SETTINGS_LINK_START" />proxyindstillinger<ph name="PROXY_SETTINGS_LINK_END" />.</translation>
 <translation id="7078120482318506217">Alle netværk</translation>
 <translation id="708060913198414444">K&amp;opiér webadressen til lyden</translation>
@@ -6946,6 +6982,7 @@
 <translation id="7108933416628942903">Lås nu</translation>
 <translation id="7109543803214225826">Genvejen blev fjernet</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{Føj fane til gruppe}one{Føj fane til gruppe}other{Føj faner til gruppe}}</translation>
+<translation id="7110684627876015299">Unavngiven gruppe – <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">Navngiv dette vindue</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> element</translation>
 <translation id="7113502843173351041">Kende din mailadresse</translation>
@@ -7160,6 +7197,7 @@
 <translation id="7328867076235380839">Ugyldig kombination</translation>
 <translation id="7329154610228416156">Login mislykkedes, da det er konfigureret til at anvende en webadresse, der ikke er sikker (<ph name="BLOCKED_URL" />). Kontakt din administrator.</translation>
 <translation id="7332053360324989309">Dedicated Worker: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">Sikkerhedskopiér og gendan dine apps og indstillinger</translation>
 <translation id="7335974957018254119">Brug stavekontrol for</translation>
 <translation id="7336799713063880535">Notifikationer blokeres.</translation>
 <translation id="7338630283264858612">Enhedens serienummer er ugyldigt.</translation>
@@ -7182,6 +7220,7 @@
 <translation id="7348093485538360975">Skærmtastatur</translation>
 <translation id="7349010927677336670">Videostabilitet</translation>
 <translation id="7352651011704765696">Noget gik galt</translation>
+<translation id="7352664183151911163">I alle dine apps og i din Chrome-browser</translation>
 <translation id="7353261921908507769">Dine kontakter kan dele med dig, når de er i nærheden. Overførsler starter først, når du har accepteret dem.</translation>
 <translation id="735361434055555355">Installerer Linux...</translation>
 <translation id="7354120289251608189">Nu kan du give din browser et nyt udseende, når du har lyst.</translation>
@@ -7321,6 +7360,8 @@
 <translation id="7458168200501453431">Bruger samme stavekontrol som Google-søgning. Tekst, som du angiver i browseren, sendes til Google.</translation>
 <translation id="7458715171471938198">Vil du gendanne apps?</translation>
 <translation id="7458933488302148148">Tjek dine gemte adgangskoder for at forbedre sikkerheden og beskytte dig selv online</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />Ved at give dine ChromeOS-enheder tilladelse til at sende automatiske rapporter gør du det nemmere for os at prioritere, hvad der skal rettes og forbedres i ChromeOS. Disse rapporter kan f.eks. indeholde oplysninger om, hvornår ChromeOS oplever nedbrud, hvilke funktioner du benytter, og hvor meget hukommelse du normalt bruger. Andre data til appdiagnostik og brugsdata, bl.a. for Android- og webapps, indsamles, hvis synkronisering af apps også er aktiveret.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Du kan til enhver tid tillade eller fjerne tilladelsen for afsendelse af disse rapporter i indstillingerne for din Chrome-enhed. Hvis du er domæneadministrator, kan du ændre denne indstilling i Administrationskonsol.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">Det aktuelle tema, du har installeret</translation>
 <translation id="7461924472993315131">Fastgør</translation>
 <translation id="746216226901520237">Næste gang låser din telefon din <ph name="DEVICE_TYPE" /> op. Du kan deaktivere Smart Lock i Indstillinger.</translation>
@@ -7554,6 +7595,7 @@
 <translation id="7663719505383602579">Modtager: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">Du kan bruge en tastaturgenvej</translation>
 <translation id="7663859337051362114">Tilføj eSIM-profil</translation>
+<translation id="76641554187607347">Der er ikke tilsluttet nogen tastatur</translation>
 <translation id="7665082356120621510">Reservér størrelse</translation>
 <translation id="7665369617277396874">Tilføj konto</translation>
 <translation id="766560638707011986">Vis domæner</translation>
@@ -7601,6 +7643,7 @@
 <translation id="769824636077131955">Dette dokument er for stort til, at der kan udføres et sikkerhedstjek. Du kan udskrive dokumenter med en størrelse på op til 50 MB.</translation>
 <translation id="7698507637739331665">Nogle elementer er blokeret</translation>
 <translation id="7701040980221191251">Ingen</translation>
+<translation id="7701265686005869308">Luk profil</translation>
 <translation id="7701869757853594372">BRUGER-håndtag</translation>
 <translation id="7702574632857388784">Fjern <ph name="FILE_NAME" /> fra listen</translation>
 <translation id="7702907602086592255">Domæne</translation>
@@ -7615,7 +7658,7 @@
 <translation id="7709152031285164251">Mislykket - <ph name="INTERRUPT_REASON" /></translation>
 <translation id="7710568461918838723">&amp;Cast...</translation>
 <translation id="7711900714716399411">Forbind din telefon til computeren med et USB-kabel. Hvis din telefon allerede er tilsluttet, skal du tage stikket ud og sætte det i igen.</translation>
-<translation id="7711968363685835633">Deaktiver brugerdefinerede konverteringer og forslag samt brugerordbog</translation>
+<translation id="7711968363685835633">Deaktiver personligt tilpassede konverteringer og forslag samt brugerordbog</translation>
 <translation id="7712739869553853093">Dialogboks for udskriftsvisning</translation>
 <translation id="7713139339518499741">Naturlig stemme</translation>
 <translation id="7714307061282548371">Cookies fra <ph name="DOMAIN" /> er tilladt</translation>
@@ -8022,6 +8065,7 @@
 <translation id="8050191834453426339">Verificer igen</translation>
 <translation id="8051193500142930381">Funktioner, der skal bruge et kamera, fungerer ikke</translation>
 <translation id="8051390370038326517">Tillad altid, at <ph name="HOST" /> kan få fuld kontrol over MIDI-enheder</translation>
+<translation id="8052218774860457016">Administrer browsersynkronisering</translation>
 <translation id="8053278772142718589">PKCS #12-filer</translation>
 <translation id="8053390638574070785">Genindlæs denne side</translation>
 <translation id="8054517699425078995">Denne type fil kan beskadige din enhed. Vil du beholde <ph name="FILE_NAME" /> alligevel?</translation>
@@ -8391,6 +8435,7 @@
 <translation id="8376137163494131156">Fortæl os, hvad der sker med Google Cast.</translation>
 <translation id="8376384591331888629">Medtag tredjepartscookies på dette websites</translation>
 <translation id="8376451933628734023">Hvis webappen forsøger at narre dig til at tro, det er en anden app, skal du afinstallere den.</translation>
+<translation id="8376752431516546391">Sidepanel i Google Søgning</translation>
 <translation id="8377625247046155446">Denne adgangsnøgle gemmes kun på denne enhed. Den forbliver på denne enhed, når du har lukket alle inkognitovinduer.</translation>
 <translation id="8378714024927312812">Administreret af din organisation</translation>
 <translation id="8379878387931047019">Denne enhed understøtter ikke den type sikkerhedsnøgle, der anmodes om på dette website</translation>
@@ -8458,6 +8503,11 @@
 <translation id="8428628598981198790">Din sikkerhedsnøgle kan ikke bruges på dette website</translation>
 <translation id="84297032718407999">Du logges ud om <ph name="LOGOUT_TIME_LEFT" /></translation>
 <translation id="8431190899827883166">Vis tryk</translation>
+<translation id="8431496281632382473">Denne profil administreres af <ph name="DOMAIN" />. Din organisation kræver, at du deler dine enhedssignaler, hvis du vil fortsætte med at bruge denne administrerede profil.
+
+Enhedssignaler kan omfatte oplysninger om browseren, operativsystemet, enheden, installeret software og filer.
+
+Hvis du vælger ikke at dele signaler, lukkes denne profil.</translation>
 <translation id="8434480141477525001">NaCl-fejlretningsport</translation>
 <translation id="8437209419043462667">Amerikansk</translation>
 <translation id="8438328416656800239">Skift til en smart browser</translation>
@@ -8542,6 +8592,8 @@
 <translation id="851263357009351303">Tillad altid, at <ph name="HOST" /> viser billeder</translation>
 <translation id="8513108775083588393">Autoroter</translation>
 <translation id="8513357934662532537">Vælg en CSV-fil for at importere adgangskoder til <ph name="BRAND" /> for <ph name="USER_EMAIL" />.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />Ved at give ChromeOS-enheder tilladelse til at sende automatiske rapporter gør du det nemmere for os at prioritere, hvad der skal rettes og forbedres i ChromeOS. Disse rapporter kan f.eks. indeholde oplysninger om, hvornår ChromeOS oplever nedbrud, hvilke funktioner der blev brugt, og hvor meget hukommelse der normalt bruges. Andre data til appdiagnostik og brugsdata, bl.a. for Android- og webapps, indsamles, hvis synkronisering af apps også er aktiveret.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Du kan til enhver tid tillade eller fjerne tilladelsen for afsendelse af disse rapporter i indstillingerne på dit barns ChromeOS-enhed. Hvis du er domæneadministrator, kan du ændre denne indstilling i Administrationskonsol.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">Prøv med en anden sikkerhedsnøgle</translation>
 <translation id="8514955299594277296">Tillad ikke, at websites gemmer data på din enhed (anbefales ikke)</translation>
 <translation id="8517759303731677493">Rediger…</translation>
@@ -8705,7 +8757,7 @@
 <translation id="8665180165765946056">Sikkerhedskopieringen blev fuldført</translation>
 <translation id="866611985033792019">Hav tillid til dette certifikat i forbindelse med identifikation af e-mailbrugere</translation>
 <translation id="8666321716757704924">Der er igen givet tilladelser for <ph name="WEBSITE" /></translation>
-<translation id="8666759526542103597">Om browserbaseret personlig annoncetilpasning</translation>
+<translation id="8666759526542103597">Om browserbaseret personlig tilpasning af annoncer</translation>
 <translation id="8667261224612332309">Du har adgangskoder, der kan forbedres</translation>
 <translation id="8667328578593601900"><ph name="FULLSCREEN_ORIGIN" /> er nu i fuld skærm og har deaktiveret din musemarkør.</translation>
 <translation id="8667760277771450375">Vi undersøger mulighederne for at begrænse sporing på tværs af websites og samtidig give websites mulighed for at forhindre annoncespam og -svindel.</translation>
@@ -8904,6 +8956,7 @@
 <translation id="883062543841130884">Erstatninger</translation>
 <translation id="8830779999439981481">Genstarter for at anvende opdateringer</translation>
 <translation id="8830796635868321089">Opdateringskontrollen kunne ikke anvende de aktuelle indstillinger for proxy. Tilpas dine <ph name="PROXY_SETTINGS_LINK_START" />Indstillinger for proxy<ph name="PROXY_SETTINGS_LINK_END" />.</translation>
+<translation id="8830863983385452402">Websitet kan se indholdet på denne fane</translation>
 <translation id="8831769650322069887">Åbn <ph name="FILE_NAME" /></translation>
 <translation id="8832781841902333794">Dine profiler</translation>
 <translation id="8834039744648160717">Netværkskonfiguration kontrolleres af <ph name="USER_EMAIL" />.</translation>
@@ -9035,6 +9088,7 @@
 <translation id="8946359700442089734">Fejlretningsfunktionerne blev ikke aktiveret korrekt på denne <ph name="IDS_SHORT_PRODUCT_NAME" />-enhed.</translation>
 <translation id="894763922177556086">God</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> anmoder om at se din sikkerhedsnøgles fabrikat og model</translation>
+<translation id="8949304443659090542">Administrer Chrome-browsersynkronisering</translation>
 <translation id="895054485242522631">Websites kan bruge bevægelsessensorer</translation>
 <translation id="8951256747718668828">Gendannelsen kunne ikke fuldføres på grund af en fejl</translation>
 <translation id="8951465597020890363">Vil du afslutte gæstesessionen?</translation>
@@ -9140,6 +9194,7 @@
 <translation id="9032097289595078011">Deaktiver Hurtig parring</translation>
 <translation id="9033765790910064284">Fortsæt alligevel</translation>
 <translation id="9033857511263905942">&amp;Indsæt</translation>
+<translation id="9034408118624208974">Har du ikke brugt Chromebook før? Aktivér synkronisering, så dine præferencer sikkerhedskopieres.</translation>
 <translation id="903480517321259405">Angiv pinkoden igen</translation>
 <translation id="9037054491984310631">Der er oprettet forbindelse til Bluetooth-enheden <ph name="DEVICE" /></translation>
 <translation id="9037640663275993951">Enheden er ikke tilladt</translation>
@@ -9183,6 +9238,7 @@
 <translation id="9068298336633421551">Tillad, at Android-apps og -tjenester med adgangstilladelse til lokation kan bruge denne enheds lokation. Google kan med jævne mellemrum indsamle lokationsdata og bruge oplysningerne anonymt til at forbedre lokationsnøjagtigheden og lokationsbaserede tjenester.</translation>
 <translation id="9068598199622656904">Tryk på én tast ad gangen for at bruge tastaturgenveje i stedet for at holde tasterne nede samtidigt</translation>
 <translation id="9068878141610261315">Filtypen understøttes ikke</translation>
+<translation id="9069665781180028115">De valgte elementer bliver tilgængelige på denne Chromebook. Hvis du ikke har brugt Chromebook før, skal du synkronisere alle elementer, så dine præferencer sikkerhedskopieres. Du kan til enhver tid foretage ændringer ved at gå til Indstillinger &gt; Konti.</translation>
 <translation id="9070342919388027491">Fanen blev flyttet til venstre</translation>
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9074836595010225693">USB-mus er tilsluttet</translation>
@@ -9356,6 +9412,7 @@
 <translation id="930268624053534560">Detaljerede tidsstempler</translation>
 <translation id="930551443325541578">Gentag taster og accenttegn</translation>
 <translation id="930893132043726269">Roamer</translation>
+<translation id="930991362911221750">Vil du give <ph name="APP_NAME" /> tilladelse til at se denne fane?</translation>
 <translation id="93140074055951850">Dine Android-apps er standset</translation>
 <translation id="932327136139879170">Start</translation>
 <translation id="932508678520956232">Udskrivningen blev ikke startet.</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index b654b40..5e9ff68 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -2246,7 +2246,7 @@
 <translation id="2891922230654533301">Utiliser cet appareil pour vous connecter à <ph name="APP_NAME" /> ?</translation>
 <translation id="2893013536106749396">Choisissez les fiches qui vous tiendront informé sur les sujets qui vous intéressent</translation>
 <translation id="2893168226686371498">Navigateur par défaut</translation>
-<translation id="2893180576842394309">Google peut utiliser votre historique pour personnaliser la recherche et d'autres services Google</translation>
+<translation id="2893180576842394309">Google pourra utiliser votre historique pour personnaliser la recherche et d'autres de ses services</translation>
 <translation id="2894757982205307093">Nouvel onglet dans le groupe</translation>
 <translation id="289695669188700754">ID de clé : <ph name="KEY_ID" /></translation>
 <translation id="2897713966423243833">Ce paramètre personnalisé sera supprimé lorsque vous fermerez toutes les fenêtres de navigation privée</translation>
diff --git a/chrome/app/resources/generated_resources_hy.xtb b/chrome/app/resources/generated_resources_hy.xtb
index 88f7d50..4040771 100644
--- a/chrome/app/resources/generated_resources_hy.xtb
+++ b/chrome/app/resources/generated_resources_hy.xtb
@@ -4484,7 +4484,7 @@
 <translation id="4893522937062257019">Կողպէկրանին</translation>
 <translation id="4898011734382862273">«<ph name="CERTIFICATE_NAME" />» հավաստագիրը ներկայացնում է հավաստագրման կենտրոնը</translation>
 <translation id="4899052647152077033">Շրջել գույները</translation>
-<translation id="4899696330053002588">Պարունակում է գովազդ</translation>
+<translation id="4899696330053002588">Կա գովազդ</translation>
 <translation id="489985760463306091">Վնասարար ծրագրի հեռացումն ավարտելու համար վերագործարկեք համակարգիչը</translation>
 <translation id="4900392736118574277">Մեկնարկի էջը փոխվել է: Նոր էջն է՝ <ph name="URL" />:</translation>
 <translation id="490051679772058907"><ph name="REFRESH_RATE" /> Հց, միահյուսված</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index 1a857b7..b4734c77 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -3606,7 +3606,7 @@
 <translation id="4097406557126260163">ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಎಕ್ಸ್‌ಟೆನ್ಷನ್‌‌ಗಳು</translation>
 <translation id="409742781329613461">Chrome ಗಾಗಿ ಸಲಹೆಗಳು</translation>
 <translation id="4097560579602855702">Google ನಲ್ಲಿ ಹುಡುಕಿ</translation>
-<translation id="4098667039111970300">ಪರಿಕರಪಟ್ಟಿಯಲ್ಲಿನ ಸ್ಟೈಲಸ್ ಪರಿಕರಗಳು</translation>
+<translation id="4098667039111970300">ಟೂಲ್‌ಬಾರ್‌ನಲ್ಲಿನ ಸ್ಟೈಲಸ್ ಟೂಲ್‌ಗಳು</translation>
 <translation id="4099060993766194518">ಡೀಫಾಲ್ಟ್ ಹುಡುಕಾಟ ಇಂಜಿನ್ ಅನ್ನು ಮರುಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಬೇಕೆ?</translation>
 <translation id="4099874310852108874">ನೆಟ್‍ವರ್ಕ್ ದೋಷ ಸಂಭವಿಸಿದೆ.</translation>
 <translation id="4100733287846229632">ಸಾಧನ ಸ್ಥಳಾವಕಾಶ ತೀರಾ ಕಡಿಮೆ ಇದೆ</translation>
@@ -8350,7 +8350,7 @@
 <translation id="8345848587667658367">ನೀವು ಈಗ ನಿಮ್ಮ ಫೋನ್‌ನ ಇತ್ತೀಚಿನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ, ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು</translation>
 <translation id="8347227221149377169">ಮುದ್ರಣ ಕಾರ್ಯಗಳು</translation>
 <translation id="834785183489258869">ಅಜ್ಞಾತ ಮೋಡ್‌ನಲ್ಲಿ ಇರುವಾಗ, ವಿವಿಧ ಸೈಟ್‌ಗಳಾದ್ಯಂತ ನಿಮ್ಮ ಬ್ರೌಸಿಂಗ್ ಚಟುವಟಿಕೆಯನ್ನು ನೋಡಲು, ಉದಾಹರಣೆಗೆ, ಜಾಹೀರಾತುಗಳನ್ನು ವೈಯಕ್ತೀಕರಿಸುವುದಕ್ಕಾಗಿ ನಿಮ್ಮ ಕುಕೀಗಳನ್ನು ಬಳಸಲು ಸೈಟ್‌ಗಳಿಗೆ ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಫೀಚರ್‌ಗಳು ಕೆಲವು ಸೈಟ್‌ಗಳಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು.</translation>
-<translation id="8350789879725387295">ಡಾಕ್‌ನಲ್ಲಿರುವ ಸ್ಟೈಲಸ್ ಪರಿಕರಗಳು</translation>
+<translation id="8350789879725387295">ಡಾಕ್‌ನಲ್ಲಿರುವ ಸ್ಟೈಲಸ್ ಟೂಲ್‌ಗಳು</translation>
 <translation id="8351316842353540018">ಯಾವಾಗಲೂ a11y ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸಿ</translation>
 <translation id="8351419472474436977">ನಿಮ್ಮ ಪ್ರಾಕ್ಸಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಈ ವಿಸ್ತರಣೆಯು ನಿಯಂತ್ರಣಕ್ಕೆ ತೆಗೆದುಕೊಂಡಿದೆ. ಅಂದರೆ, ನೀವು ಆನ್‌ಲೈನ್‌ನಲ್ಲಿ ಮಾಡುವ ಯಾವುದೇ ಕಾರ್ಯವನ್ನು ಇದು ಬದಲಾಯಿಸಬಹುದು, ಒಳನುಸುಳಬಹುದು ಅಥವಾ ಕದ್ದಾಲಿಸಬಹುದು ಎಂದರ್ಥ. ಇದು ಹೇಗೆ ಸಂಭವಿಸಿದೆ ಎಂಬುದೇ ನಿಮಗೆ ಖಚಿತವಿಲ್ಲದಿದ್ದರೆ, ನಿಮಗೆ ಬಹುಶಃ ಇದು ಬೇಕಾಗಿಲ್ಲ.</translation>
 <translation id="8351630282875799764">ಬ್ಯಾಟರಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ</translation>
diff --git a/chrome/app/resources/generated_resources_lo.xtb b/chrome/app/resources/generated_resources_lo.xtb
index 627f096..82bbf459 100644
--- a/chrome/app/resources/generated_resources_lo.xtb
+++ b/chrome/app/resources/generated_resources_lo.xtb
@@ -78,6 +78,7 @@
 <translation id="1061904396131502319">ໃກ້ຮອດເວລາພັກແລ້ວ</translation>
 <translation id="1062407476771304334">​ປ່ຽນ​ແທນ​</translation>
 <translation id="1062628064301375934">ຊ່ວຍພວກເຮົາປັບປຸງເວັບສ່ວນຕົວເພີ່ມເຕີມ</translation>
+<translation id="1066964438793906105">ສະແກນຫາເມົາແວ</translation>
 <translation id="1067048845568873861">ສ້າງຂຶ້ນແລ້ວ</translation>
 <translation id="1067661089446014701">ເພື່ອຄວາມປອດໄພທີ່ເພີ່ມຂຶ້ນ, ທ່ານສາມາດເຂົ້າລະຫັດຜ່ານຢູ່ອຸປະກອນຂອງທ່ານໄດ້ກ່ອນທີ່ພວກມັນຈະໄດ້ຮັບການບັນທຶກໃສ່ບັນຊີ Google ຂອງທ່ານ</translation>
 <translation id="1067922213147265141">ການບໍລິການອື່ນຂອງ Google</translation>
@@ -144,6 +145,7 @@
 <translation id="1116639326869298217">ບໍ່ສາມາດຢັ້ງຢືນຕົວຕົນຂອງທ່ານໄດ້</translation>
 <translation id="1116694919640316211">ກ່ຽວ​ກັບ</translation>
 <translation id="1116779635164066733">ການຕັ້ງຄ່ານີ້ຖືກບັງຄັບໃຊ້ໂດຍສ່ວນຂະຫຍາຍ "<ph name="NAME" />".</translation>
+<translation id="1118428905044642028">ລະຫັດຜ່ານ ແລະ &amp;ການຕື່ມຂໍ້ມູນອັດຕະໂນມັດ</translation>
 <translation id="1118738876271697201">ລະບົບບໍ່ສາມາດກຳນົດຮຸ່ນອຸປະກອນ ຫຼື ໝາຍເລກຊີຣຽວໄດ້.</translation>
 <translation id="1119447706177454957">ຜິດພາດພາຍໃນ</translation>
 <translation id="1122068467107743258">ວຽກ</translation>
@@ -218,6 +220,7 @@
 <translation id="1176471985365269981">ບໍ່ໄດ້ຮັບອະນຸຍາດໃຫ້ແກ້ໄຂໄຟລ໌ ຫຼື ໂຟນເດີຢູ່ອຸປະກອນຂອງທ່ານ</translation>
 <translation id="1177863135347784049">ກໍານົດເອງ</translation>
 <translation id="1178581264944972037">ຢຸດຊົ່ວຄາວ</translation>
+<translation id="1178601482396475810">ຈັດການການຊິ້ງອຸປະກອນ</translation>
 <translation id="117916940443676133">ກະແຈຄວາມປອດໄພຂອງທ່ານບໍ່ໄດ້ຮັບການປົກປ້ອງດ້ວຍ PIN. ເພື່ອຈັດການຂໍ້ມູນການເຂົ້າສູ່ລະບົບ, ກ່ອນອື່ນໃຫ້ສ້າງ PIN.</translation>
 <translation id="1181037720776840403">ລຶບອອກ</translation>
 <translation id="1181366777303791449">ໃນ <ph name="MAIN_FRAME_ETLD_PLUS_ONE" /></translation>
@@ -355,6 +358,7 @@
 <translation id="130097046531636712">ນີ້ຈະຍືດອາຍຸແບັດເຕີຣີໂດຍການຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ ແລະ ເອັບເຟັກດ້ານພາບ ເຊັ່ນ: ການເລື່ອນແບບນຸ້ມນວນ</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> ສາມາດແກ້ໄຂໄຟລ໌ຕໍ່ໄປນີ້ໄດ້</translation>
 <translation id="1302227299132585524">ອະນຸຍາດ JavaScript ຈາກ Apple Events</translation>
+<translation id="1302654693270046655">ກຸ່ມ <ph name="GROUP_NAME" /> - <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">ໄຟລ໌ HTML ບຸກມາກສ໌</translation>
 <translation id="1303671224831497365">ບໍ່ພົບອຸປະກອນ Bluetooth</translation>
 <translation id="130491383855577612">ປ່ຽນແທນແອັບ ແລະ ໄຟລ໌ Linux ສຳເລັດແລ້ວ</translation>
@@ -1059,6 +1063,7 @@
 <translation id="1877520246462554164">ຮັບເອົາໂທເຄັນການຮັບຮອງຄວາມຖືກຕ້ອງບໍ່ສຳເລັດ. ກະລຸນນາອອກຈາກລະບົບ ແລ້ວເຂົ້າສູ່ລະບົບຄືນໃໝ່ເພື່ອລອງອີກຄັ້ງ.</translation>
 <translation id="1877860345998737529">ການກຳນົດຄຳສັ່ງດ້ວຍສະວິດ</translation>
 <translation id="1878155070920054810">ປາກົດວ່າ Chromebook ຂອງທ່ານຈະໝົດໄຟກ່ອນທີ່ການອັບເດດຈະສຳເລັດ. ກວດໃຫ້ແນ່ໃຈວ່າມັນກຳລັງສາກຢ່າງຖືກຕ້ອງເພື່ອຫຼີກເວັ້ນການຂັດຈັງຫວະ.</translation>
+<translation id="1878477879455105085">ເປີດແລ້ວ</translation>
 <translation id="1878885068166344708">ລາຍການຈະຖືກໄຮໄລ້ເມື່ອທ່ານຍ້າຍໂຟກັສ. ກົດແຖບ ຫຼື ເລືອກລາຍການເພື່ອປ່ຽນໂຟກັສ.</translation>
 <translation id="1879000426787380528">ເຂົ້າສູ່ລະບົບເປັນ</translation>
 <translation id="18802377548000045">ຫຍໍ້ແຖບເປັນຄວາມກວ້າງຂະໜາດໃຫຍ່</translation>
@@ -1312,6 +1317,7 @@
     <ph name="BEGIN_BOLD" />ໝາຍເຫດ:<ph name="END_BOLD" /> ລະບົບຈະປິດເປີດໃໝ່ໃນລະຫວ່າງຂັ້ນຕອນ.</translation>
 <translation id="2095774564753225041">ປະເພດໄຟລ໌ທີ່ຮອງຮັບ</translation>
 <translation id="2097616539631531348">ໃນຂະນະທີ່ແຖບນີ້ບໍ່ມີການນຳໃຊ້, ຕົວປະຢັດໜ່ວຍຄວາມຈຳຈະສ້າງພື້ນທີ່ຫວ່າງໃນໜ່ວຍຄວາມຈຳເພື່ອໃຫ້ໜ້າວຽກອື່ນໆໃຊ້ໄດ້.</translation>
+<translation id="2097950021134740304">ຍົກເລີກການລືມການສະໝັກສະມາຊິກ</translation>
 <translation id="2098805196501063469">ກວດລະຫັດຜ່ານທີ່ເຫຼືອ</translation>
 <translation id="2099686503067610784">ລຶບໃບຢັ້ງຢືນເຊີບເວີ "<ph name="CERTIFICATE_NAME" />" ບໍ?</translation>
 <translation id="2100273922101894616">ເຂົ້າສູ່​ລະບົບ​ອັດຕະໂນມັດ</translation>
@@ -1444,6 +1450,7 @@
 <translation id="2204034823255629767">ອ່ານ​ ແລະ​​ປ່ຽນອັນໃດໜຶ່ງທີ່​ທ່ານ​ພິມ</translation>
 <translation id="2204387456724731099">ບໍ່ສາມາດແປພາສາການເລືອກນີ້ໄດ້</translation>
 <translation id="2210462644007531147">ບໍ່ສາມາດຕິດຕັ້ງໃຫ້ສຳເລັດໄດ້</translation>
+<translation id="2211245494465528624">ຈັດການຕົວເລືອກການຊິ້ງ</translation>
 <translation id="2212565012507486665">ອະນຸຍາດຄຸກກີ້</translation>
 <translation id="2214018885812055163">ໂຟນເດີທີ່ໃຊ້ຮ່ວມກັນ</translation>
 <translation id="2214884991347062907">ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ. ກະລຸນາລອງໃໝ່</translation>
@@ -1542,6 +1549,7 @@
 <translation id="2296218178174497398">ການຄົ້ນພົບອຸປະກອນ</translation>
 <translation id="2297705863329999812">ຊອກຫາເຄື່ອງພິມ</translation>
 <translation id="2297822946037605517">ແບ່ງປັນໜ້ານີ້</translation>
+<translation id="229871422646860597">ຖອນໝຸດຈາກແຖບເຄື່ອງມື</translation>
 <translation id="2299734369537008228">ຕົວເລື່ອນ: <ph name="MIN_LABEL" /> ຫາ <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">ຮວມມີໄຟລ໌ບັນທຶກທັງໝົດທີ່ເກັບກຳໂດຍ debugd ເປັນແຟ້ມຈັດເກັບແຍກຕ່າງຫາກ.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2173,6 +2181,7 @@
 <translation id="2811205483104563968">ບັນຊີ</translation>
 <translation id="2811564570599779918">ການຫຼຸດສະແປມ ແລະ ການສໍ້ໂກງ</translation>
 <translation id="2812049959647166806">ບໍ່ຮອງຮັບ Thunderbolt</translation>
+<translation id="2812171980080389735">ເຄືອຂ່າຍ ແລະ ລະຫັດຜ່ານທີ່ບັນທຶກໄວ້ເພື່ອໃຫ້ທ່ານສາມາດເຊື່ອມຕໍ່ໄດ້ທັນທີ</translation>
 <translation id="2813094189969465044">ການຄວບຄຸມສຳລັບພໍ່ແມ່</translation>
 <translation id="281390819046738856">ບໍ່ສາມາດເຊັນຄຳຂໍໄດ້.</translation>
 <translation id="2814489978934728345">ຢຸດ​ໂຫຼດ​ຫນ້າ​ນີ້</translation>
@@ -2212,6 +2221,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">ເພີ່ມ PIN ຂອງທ່ານແລ້ວ</translation>
 <translation id="2849936225196189499">ສໍາຄັນ</translation>
+<translation id="285033512555869047">ປິດແລ້ວ</translation>
 <translation id="2850541429955027218">ເພີ່ມ​ຊຸດຮູບແບບ</translation>
 <translation id="2850672011315104382">ຮູບແບບເຄື່ອງໝາຍວັກຕອນ</translation>
 <translation id="2852385257476173980">ລາຍຊື່ຂອງເວັບໄຊທີ່ທ່ານເຂົ້າເບິ່ງອາດປາກົດຢູ່ບ່ອນນີ້ໃນເວລາທີ່ທ່ານທ່ອງເວັບ</translation>
@@ -2255,6 +2265,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> ແລະ ອີກ <ph name="NUMBER_OF_DEVICES" /> ອຸປະກອນອື່ນໆ</translation>
 <translation id="2889043468805635730">ບໍ່ພົບບັນຫາໃດໆ</translation>
 <translation id="2889064240420137087">ເປີດລິ້ງກັບ...</translation>
+<translation id="2890206081124517553">ຈື່ພາບພື້ນຫຼັງຂອງເດັສທັອບຂອງທ່ານໃນທົ່ວອຸປະກອນຕ່າງໆໄດ້</translation>
 <translation id="2891566119238851894">ເປີດການຊອກຫາໃນແຜງຄວບຄຸມດ້ານຂ້າງ. ບໍ່ໄດ້ເປີດການຊອກຫາໃນແຜງຄວບຄຸມດ້ານຂ້າງ.</translation>
 <translation id="2891922230654533301">ໃຊ້ອຸປະກອນຂອງທ່ານເພື່ອເຂົ້າສູ່ລະບົບ <ph name="APP_NAME" /> ບໍ?</translation>
 <translation id="2893013536106749396">ເລືອກບັດທີ່ອັບເດດສິ່ງຕ່າງໆທີ່ສຳຄັນກັບທ່ານຢູ່ສະເໝີ</translation>
@@ -2276,6 +2287,7 @@
 <translation id="2907619724991574506">ເລີ່ມຕົ້ນ URLs</translation>
 <translation id="2907798539022650680">ເຊື່ອມຕໍ່ກັບ '<ph name="NAME" />': <ph name="DETAILS" /> ບໍ່ສໍາເລັດ
     ຂໍ້ຄວາມຈາກເຊີບເວີ: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">ແບ່ງປັນສັນຍານ</translation>
 <translation id="2908162660801918428">ເພີ່ມແກເລີຣີມີເດຍຕາມໄດເຣັກຕໍຣີ</translation>
 <translation id="2908358077082926882">ກົດ “<ph name="CURRENTKEY" />” ອີກເທື່ອໜຶ່ງເພື່ອລຶບການມອບໝາຍອອກ ແລະ <ph name="RESPONSE" /></translation>
 <translation id="2909506265808101667">ບໍ່ສາມາດເຊື່ອມຕໍ່ກັບບໍລິການຂອງ Google ໄດ້. ກະລຸນາກວດສອບການເຊື່ອມຕໍ່ອິນເຕີເນັດຂອງທ່ານແລ້ວລອງໃໝ່. ລະຫັດຂໍ້ຜິດພາດ: <ph name="ERROR_CODE" />.</translation>
@@ -2380,6 +2392,7 @@
 <translation id="3003828226041301643">ບໍ່ສາມາດເພີ່ມອຸປະກອນເຂົ້າຮ່ວມໂດເມນໄດ້. ກະລຸນາກວດໃຫ້ແນ່ໃຈວ່າບັນຊີຂອງທ່ານມີສິດເພີ່ມອຸປະກອນ.</translation>
 <translation id="3003967365858406397"><ph name="PHONE_NAME" /> ຂອງທ່ານຈະສ້າງການເຊື່ອມຕໍ່ Wi-Fi ສ່ວນບຸກຄົນ.</translation>
 <translation id="3004385386820284928">ປັບແຕ່ງປຸ່ມໃນແປ້ນພິມ</translation>
+<translation id="3005376701115952939">ມີການຕັ້ງຄ່າການຊິ້ງແອັບໃນການຕັ້ງຄ່າລະບົບ</translation>
 <translation id="3005574332301273731">ບໍ່ສະແດງ</translation>
 <translation id="3006881078666935414">ບໍ່ມີຂໍ້ມູນການໃຊ້</translation>
 <translation id="3007410324195400631">ເພີ່ມບັນທຶກກ່ຽວກັບໜ້ານີ້</translation>
@@ -2761,6 +2774,7 @@
 <translation id="3369624026883419694">ກໍາລັງແກ້ໄຂ​ແມ່​ຂ່າຍ...</translation>
 <translation id="3370260763947406229">ຕົວແກ້ໄຂໃຫ້ຖືກຕ້ອງອັດຕະໂນມັດ</translation>
 <translation id="3371140690572404006">ອຸປະກອນ USB-C (ຊ່ອງທາງໜ້າເບື້ອງຂວາ)</translation>
+<translation id="3371351218553893534">ແຖວຍາວເກີນໄປ: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">ອ່ານ​​ໂຟລ​ເດີ​ທີ່​ທ່ານ​ເປີດ​ໃນ​ແອ​ັບພະລິ​ເຄຊັນ</translation>
 <translation id="3373059063088819384">ເປີດໃນໂໝດການອ່ານ</translation>
 <translation id="3373701465337594448">ເມື່ອເປີດໃຊ້, ລາຍຊື່ເວັບໄຊທີ່ທ່ານເຂົ້າເບິ່ງເຊິ່ງຄາດເດົາຄວາມສົນໃຈຂອງທ່ານຈະປາກົດຢູ່ບ່ອນນີ້</translation>
@@ -2831,6 +2845,9 @@
 <translation id="3434272557872943250">ຖ້າເປີດການຕັ້ງຄ່າການເຄື່ອນໄຫວເວັບ ແລະ ແອັບເພີ່ມເຕີມສໍາລັບລູກຂອງທ່ານ, ລະບົບອາດຈະບັນທຶກຂໍ້ມູນນີ້ໄວ້ໃນບັນຊີ Google ຂອງເຂົາເຈົ້າ. ສຶກສາເພີ່ມເຕີມກ່ຽວກັບການຕັ້ງຄ່າເຫຼົ່ານີ້ ແລະ ວິທີປັບການຕັ້ງຄ່າໄດ້ທີ່ families.google.com.</translation>
 <translation id="3434475275396485144">ການຕັ້ງຄ່ານີ້ແມ່ນຈັດການໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງໂທລະສັບຂອງທ່ານ</translation>
 <translation id="3434512374684753970">ສຽງ ແລະ ວິດີໂອ</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />ຢູ່ໜ້າຈໍຖັດໄປ, ໃຫ້ເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ເຊິ່ງນີ້ຈະເປັນບັນຊີດຽວກັນກັບທີ່ທ່ານໃຊ້ສຳລັບ Gmail, YouTube, Chrome ແລະ ບໍລິການ Google ອື່ນໆ. ໃຊ້ບັນຊີຂອງທ່ານເພື່ອຮັບປະສົບການໃນການໃຊ້ທີ່ປັບແຕ່ງສ່ວນຕົວ ແລະ ເຂົ້າເຖິງຂໍ້ມູນທັງໝົດຂອງທ່ານໄດ້ຢ່າງງ່າຍດາຍ.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />ຫາກທ່ານບໍ່ມີບັນຊີ Google, ທ່ານຈະສາມາດສ້າງບັນຊີໄດ້ໃນໜ້າຈໍຖັດໄປ.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">"<ph name="EXTENSION_NAME" />" ກຳລັງຮ້ອງຂໍ <ph name="CODE_TYPE" /> ຂອງທ່ານ</translation>
 <translation id="3435738964857648380">ຄວາມ​ປອດ​ໄພ</translation>
 <translation id="343578350365773421">ເຈ້ຍໝົດ</translation>
@@ -2877,6 +2894,7 @@
 <translation id="346546413339447252">ຮັບສ່ວນຫຼຸດສຳລັບ <ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> ແລະ ອື່ນໆ</translation>
 <translation id="3468298837301810372">ປ້າຍກຳກັບ</translation>
 <translation id="3468999815377931311">ໂທລະສັບ Android</translation>
+<translation id="3469345458390352459">ເມື່ອເປີດໄວ້, ແອັບຂອງທ່ານຈະພ້ອມໃຫ້ນຳໃຊ້ຢູ່ທຸກອຸປະກອນ ChromeOS ຫຼັງຈາກທີ່ທ່ານເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ.  ລະບົບຈະຊິ້ງເວັບແອັບຜ່ານ Chrome ເຖິງແມ່ນວ່າຄຸນສົມບັດການຊິ້ງໂປຣແກຣມທ່ອງເວັບອື່ນໆຈະປິດຢູ່ກໍຕາມ.</translation>
 <translation id="3469583217479686109">ເຄື່ອງມືການເລືອກ</translation>
 <translation id="3470392222765168737">ຕິດຕາມເວັບໄຊ</translation>
 <translation id="3471876058939596279">ບໍ່ສາມາດໃຊ້ຜອດ HDMI ແລະ USB ປະເພດ C ສຳລັບວິດີໂອໃນເວລາພ້ອມກັນໄດ້. ໃຊ້ຜອດວິດີໂອອື່ນ.</translation>
@@ -2899,6 +2917,7 @@
 <translation id="3484869148456018791">ເອົາໃບ​ຢັ້ງ​ຢືນ​ໃຫມ່</translation>
 <translation id="3486950712960783074">ການເດີນທາງຂອງທ່ານ</translation>
 <translation id="3487007233252413104">ຟັງຄ໌ຊັນບໍ່ເປີດເຜີຍຊື່</translation>
+<translation id="3487649228420469005">ສະແກນແລ້ວໆ</translation>
 <translation id="3490695139702884919">ກຳລັງດາວໂຫລດ... <ph name="PERCENT" />%</translation>
 <translation id="3491669675709357988">ບໍ່ໄດ້ຕັ້ງຄ່າບັນຊີຂອງລູກທ່ານສຳລັບການຄວບຄຸມຂອງພໍ່ແມ່ໃນ Family Link. ທ່ານສາມາດເພີ່ມການຄວບຄຸມຂອງພໍ່ແມ່ເມື່ອທ່ານສຳເລັດການຕັ້ງຄ່າແລ້ວ. ທ່ານຈະເຫັນຂໍ້ມູນກ່ຽວກັບການຄວບຄຸມຂອງພໍ່ແມ່ໃນແອັບສຳຫຼວດ.</translation>
 <translation id="3491678231052507920">ໂດຍປົກກະຕິແລ້ວ ເວັບໄຊຈະໃຊ້ອຸປະກອນເວີຊົວ ຣິອາລິຕີ ແລະ ຂໍ້ມູນເພື່ອຊ່ວຍທ່ານເຂົ້າເຊດຊັນ VR</translation>
@@ -3339,6 +3358,7 @@
 <translation id="3855441664322950881">ບັນຈຸກ່ອງສ່ວນຂະຫຍາຍ</translation>
 <translation id="3855676282923585394">ນໍາເອົາບຸກມາກສ໌ ແລະການຕັ້ງຄ່າເຂົ້າມາ...</translation>
 <translation id="3856096718352044181">ກະລຸນາຢັ້ງຢືນວ່ານີ້ແມ່ນຜູ້ໃຫ້ບໍລິການທີ່ຖືກຕ້ອງ ຫຼື ລອງໃໝ່ໃນພາຍຫຼັງ</translation>
+<translation id="3856470183388031602">ໃຊ້ບັນຊີ Google ຂອງທ່ານຢູ່ <ph name="DEVICE_TYPE" /> ຂອງທ່ານ</translation>
 <translation id="3856800405688283469">ເລືອກເຂດເວລາ</translation>
 <translation id="3857807444929313943">ຍົກຂຶ້ນ, ຈາກນັ້ນແຕະອີກຄັ້ງ</translation>
 <translation id="3858860766373142691">ຊື່</translation>
@@ -3378,6 +3398,7 @@
 <translation id="3894123633473837029">ຮວມເອົາປະຫວັດຜູ້ຊ່ວຍຫຼ້າສຸດຜ່ານ Sherlog. ນີ້ອາດຈະຮວມມີຕົວຕົນ, ສະຖານທີ່ ແລະ ຂໍ້ມູນດີບັກຂອງທ່ານ. <ph name="BEGIN_LINK" />ສຶກສາເພີ່ມເຕີມ<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">ເພີ່ມໂຟລເດີ</translation>
 <translation id="3894770151966614831">ຍ້າຍໄປໃສ່ບັນຊີ Google ບໍ?</translation>
+<translation id="3894983081771074056">ລັກສະນະການເຮັດວຽກຂອງແປ້ນພິມ ແລະ ເມົ້າ, ການຕັ້ງຄ່າພາສາ ແລະ ອື່ນໆ</translation>
 <translation id="3895076768659607631">&amp;ຈັດການໂປຣແກຣມຊອກຫາ...</translation>
 <translation id="3895090224522145010">ຊື່ຜູ້ໃຊ້ Kerberos</translation>
 <translation id="389521680295183045">ເວັບໄຊສາມາດຂໍຂໍ້ມູນວ່າທ່ານກຳລັງໃຊ້ອຸປະກອນຂອງທ່ານຢູ່ບໍ່</translation>
@@ -3459,6 +3480,7 @@
 <translation id="3957844511978444971">ແຕະທີ່ “ຍອມຮັບ” ເພື່ອຢືນຢັນການເລືອກການຕັ້ງຄ່າບໍລິການ Google ເຫຼົ່ານີ້.</translation>
 <translation id="3958088479270651626">ນໍາເອົາບຸກມາກສ໌ ແລະການຕັ້ງຄ່າເຂົ້າມາ</translation>
 <translation id="3958110062351175311">ໄດ້ຮັບອະນຸຍາດໃຫ້ສະແດງການຮ້ອງຂໍໃນແຖບເຄື່ອງມື</translation>
+<translation id="3959747296451923142">ຢືນຢັນການລຶບການສະໝັກສະມາຊິກອອກ</translation>
 <translation id="3960566196862329469">ONC</translation>
 <translation id="3961005895395968120">ຄຳສັ່ງເພີ່ມເຕີມສຳລັບ <ph name="IBAN_DESCRIPTION" /></translation>
 <translation id="3962119236270174787">ການປົກປ້ອງມາດຕະຖານຕໍ່ກັບເວັບໄຊ, ການດາວໂຫຼດ ແລະ ສ່ວນຂະຫຍາຍທີ່ຮູ້ວ່າເປັນອັນຕະລາຍ</translation>
@@ -3513,6 +3535,7 @@
 <translation id="3994878504415702912">ຊູມ</translation>
 <translation id="3995138139523574647">ອຸປະກອນ USB-C (ຊ່ອງທາງຫຼັງເບື້ອງຂວາ)</translation>
 <translation id="3995963973192100066">ຫຼິ້ນອະນິເມຊັນ</translation>
+<translation id="399788104667917863">ປັກໝຸດໄວ້ຢູ່ແຖບເຄື່ອງມື</translation>
 <translation id="4001540981461989979">ໄຮໄລ້ເຄີເຊີເມົ້າໃນເວລາເຄື່ອນຍ້າຍ</translation>
 <translation id="4002440992267487163">ການຕັ້ງຄ່າ PIN</translation>
 <translation id="4005817994523282006">ວິທີການກວດຫາເຂດເວລາ</translation>
@@ -3671,12 +3694,16 @@
 <translation id="4147911968024186208">ກະລຸນາລອງໃໝ່. ຖ້າທ່ານເຫັນຄວາມຜິດພາດນີ້ອີກຄັ້ງ ກະລຸນາຕິດຕໍ່ຫາຜູ້ຕາງໜ້າຝ່າຍຊ່ວຍເຫຼືອຂອງທ່ານ.</translation>
 <translation id="4150201353443180367">ການສະແດງຜົນ</translation>
 <translation id="4150569944729499860">ບໍລິບົດໜ້າຈໍ</translation>
+<translation id="4151843924968445052">ແບ່ງປັນສັນຍານຂອງອຸປະກອນບໍ?</translation>
 <translation id="4152011295694446843">ທ່ານຈະເຫັນບຸກມາກຂອງທ່ານຢູ່ບ່ອນນີ້</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 ແຖບ}other{# ​ແຖບ}}</translation>
 <translation id="4154664944169082762">ລາຍນີ້ວມື</translation>
 <translation id="4157869833395312646">Microsoft Server Gated Cryptography</translation>
 <translation id="4158315983204257156">ຟອນ ແລະ ຂະໜາດຂໍ້ຄວາມໃນເວັບໄຊ</translation>
 <translation id="4158364720893025815">ຜ່ານ</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />ການອະນຸຍາດໃຫ້ອຸປະກອນ ChromeOS ຂອງທ່ານສົ່ງລາຍງານອັດຕະໂນມັດຈະຊ່ວຍໃຫ້ພວກເຮົາຈັດລຳດັບຄວາມສຳຄັນໄດ້ວ່າຈະແກ້ໄຂ ແລະ ປັບປຸງຫຍັງໃນ ChromeOS. ລາຍງານເຫຼົ່ານີ້ສາມາດຮວມເອົາຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ChromeOS ຫຼົ້ມຕອນໃດ, ທ່ານໃຊ້ຄຸນສົມບັດໃດ, ປົກກະຕິທ່ານໃຊ້ໜ່ວຍຄວາມຈຳເທົ່າໃດ ຮວມທັງຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບ Android. ນອກຈາກນັ້ນ, ຂໍ້ມູນຮວມບາງສ່ວນຍັງຈະມີປະໂຫຍດຕໍ່ແອັບ ແລະ ຮຸ້ນສ່ວນຂອງ Google ນຳ, ເຊັ່ນ: ນັກພັດທະນາ Android. ຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບອື່ນໆ, ເຊິ່ງມີການຮວບຮວມສຳລັບແອັບ Android ແລະ ເວັບແອັບ ຫາກມີການເປີດການຊິ້ງແອັບ.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ທ່ານສາມາດເລີ່ມ ຫຼື ຢຸດການອະນຸຍາດລາຍງານເຫຼົ່ານີ້ໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າອຸປະກອນ ChromeOS ຂອງທ່ານ. ຫາກທ່ານເປັນຜູ້ເບິ່ງແຍງລະບົບໂດເມນ, ທ່ານສາມາດປ່ຽນການຕັ້ງຄ່ານີ້ໄດ້ໃນຄອນໂຊຜູ້ເບິ່ງແຍງ.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />ຫາກມີການເປີດໃຊ້ການຕັ້ງຄ່າການເຄື່ອນໄຫວເວັບ ແລະ ແອັບໄວ້ສຳລັບບັນຊີ Google ຂອງທ່ານ, ຂໍ້ມູນ Android ຂອງທ່ານອາດຖືກບັນທຶກໄວ້ໃນບັນຊີ Google ຂອງທ່ານນຳ. ທ່ານສາມາດເບິ່ງຂໍ້ມູນຂອງທ່ານ, ລຶບມັນອອກ ແລະ ປ່ຽນການຕັ້ງຄ່າບັນຊີຂອງທ່ານໄດ້ຢູ່ account.google.com.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;ຕົວຈັດການລະຫັດຜ່ານ Google</translation>
 <translation id="4163560723127662357">ຄີບອດທີ່ບໍ່ຮູ້​ຈັກ</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> ບໍ່ໄດ້ເປັນຂອງອົງການທີ່ຖືກຕ້ອງ. ກະລຸນາຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ. ຫາກທ່ານເປັນຜູ້ເບິ່ງແຍງລະບົບ, ທ່ານສາມາດຕັ້ງຄ່າອົງການຂອງທ່ານໄດ້ໂດຍການເຂົ້າໄປ: g.co/ChromeEnterpriseAccount</translation>
@@ -3944,6 +3971,7 @@
 <translation id="4408599188496843485">ຊ່ວຍເຫຼືອ</translation>
 <translation id="4409271659088619928">ໂປຣແກຣມຊອກຫາຂອງທ່ານແມ່ນ <ph name="DSE" />. ກະລຸນາອ່ານຄຳແນະນຳສຳລັບການລຶບປະຫວັດການຊອກຫາ, ຖ້າມີ.</translation>
 <translation id="4409697491990005945">ຂອບເຈ້ຍ</translation>
+<translation id="4409779593816003679">ລະຫັດຜ່ານ ແລະ &amp;ການຕື່ມຂໍ້ມູນອັດຕະໂນມັດ</translation>
 <translation id="4410545552906060960">ໃຊ້ຕົວເລກ (PIN) ແທນລະຫັດຜ່ານເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ. ເພື່ອຕັ້ງຄ່າ PIN ຂອງທ່ານໃນພາຍຫຼັງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ.</translation>
 <translation id="4411578466613447185">ເຄື່ອງເຊັນລະ​ຫັດ</translation>
 <translation id="4411719918614785832">ກະແຈຜ່ານເຫຼົ່ານີ້ຖືກບັນທຶກໄວ້ຢູ່ Windows Hello ຢູ່ຄອມພິວເຕີນີ້ເທົ່ານັ້ນ. ພວກມັນບໍ່ໄດ້ຖືກບັນທຶກໄວ້ໃນບັນຊີ Google ຂອງທ່ານ.</translation>
@@ -4000,6 +4028,9 @@
 <translation id="4452898361839215358">ຫຼື ເລືອກ PPD. <ph name="LINK_BEGIN" />ສຶກສາເພີ່ມເຕີມ<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືຢູ່ມຸມຂວາເທິງສຸດຂອງແປ້ນພິມຂອງທ່ານ. ຂໍ້ມູນລາຍນິ້ວມືຂອງທ່ານແມ່ນຖືກເກັບໄວ້ຢ່າງປອດໄພ ແລະ ຢູ່ໃນ <ph name="DEVICE_TYPE" /> ຂອງທ່ານສະເໝີ.</translation>
 <translation id="4453946976636652378">ຊອກຫາ <ph name="SEARCH_ENGINE_NAME" /> ຫຼື ພິມ URL</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />ການອະນຸຍາດໃຫ້ອຸປະກອນ ChromeOS ສົ່ງລາຍງານອັດຕະໂນມັດຈະຊ່ວຍໃຫ້ພວກເຮົາຈັດລຳດັບຄວາມສຳຄັນໄດ້ວ່າຈະແກ້ໄຂ ແລະ ປັບປຸງຫຍັງໃນ ChromeOS. ລາຍງານເຫຼົ່ານີ້ສາມາດຮວມເອົາຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ChromeOS ຫຼົ້ມຕອນໃດ, ມີການໃຊ້ຄຸນສົມບັດໃດ, ໂດຍປົກກະຕິແລ້ວໃຊ້ໜ່ວຍຄວາມຈຳເທົ່າໃດ ແລະ ຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບ Android. ນອກຈາກນັ້ນ, ຂໍ້ມູນຮວມບາງສ່ວນຍັງຈະມີປະໂຫຍດຕໍ່ແອັບ ແລະ ຮຸ້ນສ່ວນຂອງ Google ນຳ, ເຊັ່ນ: ນັກພັດທະນາ Android. ຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບອື່ນໆ, ເຊິ່ງມີການຮວບຮວມສຳລັບແອັບ Android ແລະ ເວັບແອັບ ຫາກມີການເປີດການຊິ້ງແອັບ.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ທ່ານສາມາດເລີ່ມ ຫຼື ຢຸດການອະນຸຍາດລາຍງານເຫຼົ່ານີ້ໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າອຸປະກອນ ChromeOS ຂອງລູກທ່ານ. ຫາກທ່ານເປັນຜູ້ເບິ່ງແຍງລະບົບໂດເມນ, ທ່ານສາມາດປ່ຽນການຕັ້ງຄ່ານີ້ໄດ້ໃນຄອນໂຊຜູ້ເບິ່ງແຍງ.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />ຫາກມີການເປີດໃຊ້ການເຄື່ອນໄຫວເວັບ ແລະ ແອັບສຳລັບບັນຊີ Google ຂອງລູກທ່ານໄວ້, ຂໍ້ມູນຂອງລູກທ່ານອາດຖືກບັນທຶກໄວ້ໃນບັນຊີ Google ຂອງເຂົາເຈົ້າ. ສຶກສາເພີ່ມເຕີມກ່ຽວກັບການຕັ້ງຄ່າເຫຼົ່ານີ້ ແລະ ວິທີປັບແກ້ພວກມັນໄດ້ຢູ່ families.google.com.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">ເລືອກສຽງປັດຈຸບັນ:</translation>
 <translation id="4459169140545916303">ເຂົ້າໃຊ້ເມື່ອ <ph name="DEVICE_LAST_ACTIVATED_TIME" /> ມື້ກ່ອນ</translation>
 <translation id="4460014764210899310">ຍົກເລີກການຈັດກຸ່ມ</translation>
@@ -4284,6 +4315,7 @@
 <translation id="470644585772471629">ການປີ້ນສີ</translation>
 <translation id="4707337002099455863">ເປີດຕະຫຼອດທຸກເວັບໄຊ</translation>
 <translation id="4708849949179781599">ອອກ <ph name="PRODUCT_NAME" /></translation>
+<translation id="4708892882822652439">ຍັງອະນຸຍາດສຽງແຖບນຳ</translation>
 <translation id="4711638718396952945">ຟື້ນ​ຄືນການຕັ້ງຄ່າ</translation>
 <translation id="4713409221649555176">ລຶບເມື່ອທ່ານປິດທຸກໜ້າຈໍ</translation>
 <translation id="4715631922189108923">ແກ້ໄຊຊື່ຜູ້ໃຊ້</translation>
@@ -4311,6 +4343,7 @@
 <translation id="4735506354605317060">ຕົວຊີ້ວົງມົນ</translation>
 <translation id="4735793370946506039">ສຶກສາເພີ່ມເຕີມກ່ຽວກັບ Safe Browsing ທີ່ປັບປຸງດີຂຶ້ນ.</translation>
 <translation id="4735803855089279419">ລະບົບກໍານົດຕົວລະບຸອຸປະກອນສໍາລັບອຸປະກອນນີ້ບໍ່ສຳເລັດ.</translation>
+<translation id="4735846817388402006">ຄລິກອະນຸຍາດ "<ph name="EXTENSIONS_REQUESTING_ACCESS" />" ຢູ່ <ph name="ORIGIN" /></translation>
 <translation id="473775607612524610">ອັບເດດ</translation>
 <translation id="473936925429402449">ເລືອກແລ້ວ, ເນື້ອຫາເພີ່ມເຕີມທີ <ph name="CURRENT_ELEMENT" /> ຈາກທັງໝົດ <ph name="TOTAL_ELEMENTS" /></translation>
 <translation id="4739639199548674512">ປີ້</translation>
@@ -4380,6 +4413,7 @@
 <translation id="4806457879608775995">ກວດສອບຂໍ້ກຳນົດເຫຼົ່ານີ້ ແລະ ຄວບຄຸມຂໍ້ມູນຂອງທ່ານ</translation>
 <translation id="4807098396393229769">ຊື່​ຢູ່ໃນ​ບັດ</translation>
 <translation id="4808667324955055115">ບລັອກປັອບອັບໄວ້ແລ້ວ:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{ກວດສອບ <ph name="BEGIN_BOLD" />1 ສ່ວນຂະຫຍາຍ<ph name="END_BOLD" /> ທີ່ຖືກລຶບອອກຈາກ Chrome Web Store}other{ກວດສອບ <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} ສ່ວນຂະຫຍາຍ<ph name="END_BOLD" /> ທີ່ຖືກລຶບອອກຈາກ Chrome Web Store}}</translation>
 <translation id="4809079943450490359">ຄຳແນະນຳຈາກຜູ້ເບິ່ງແຍງລະບົບອຸປະກອນຂອງທ່ານ:</translation>
 <translation id="4809447465126035330">ລຶບ</translation>
 <translation id="480990236307250886">ເປີດໜ້າຫຼັກ</translation>
@@ -4703,6 +4737,7 @@
 <translation id="5101839224773798795">ຄລິກອັດຕະໂນມັດເມື່ອເຄີເຊີຢຸດ</translation>
 <translation id="5106350808162641062">ລຶບອອກ</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> ໄດ້ຮັບການເບິ່ງແຍງກວດກາໂດຍ Family Link. ທ່ານສາມາດເພີ່ມບັນຊີໂຮງຮຽນເພື່ອເຂົ້າເຖິງຊັບພະຍາກອນໂຮງຮຽນທີ່ມີການເບິ່ງແຍງກວດກາຂອງພໍ່ແມ່.</translation>
+<translation id="5107093668001980925">ຢ່າສະແດງ <ph name="MODULE_NAME" /> ອີກ</translation>
 <translation id="5107443654503185812">ສ່ວນຂະຫຍາຍໄດ້ປິດ Safe Browsing ແລ້ວ</translation>
 <translation id="5108967062857032718">ການຕັ້ງຄ່າ - ເອົາແອັບ Android ອອກ</translation>
 <translation id="5109044022078737958">ເມັຍ</translation>
@@ -4713,6 +4748,7 @@
 <translation id="5111794652433847656">ບໍ່ມີກະແຈຜ່ານໃດໆສຳລັບ <ph name="APP_NAME" /> ຢູ່ອຸປະກອນນີ້</translation>
 <translation id="5112577000029535889">ເຄື່ອງ​ມື​ຜູ້ພັດ​ທະ​ນາ</translation>
 <translation id="511313294362309725">ເປີດໃຊ້ການຈັບຄູ່ດ່ວນ</translation>
+<translation id="5113384440341086023">ແອັບທີ່ຕິດຕັ້ງຈາກ Play Store ແລະ ເວັບແອັບຈາກໂປຣແກຣມທ່ອງເວັບ Chrome</translation>
 <translation id="51143538739122961">ສຽບກະແຈຄວາມປອດໄພຂອງທ່ານ ແລ້ວແຕະມັນ</translation>
 <translation id="5115309401544567011">ກະລຸນາສຽບ <ph name="DEVICE_TYPE" /> ຂອງທ່ານໃສ່ແຫຼ່ງໄຟຟ້າ.</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4758,6 +4794,7 @@
 <translation id="5154702632169343078">ເລື່ອງ</translation>
 <translation id="5155327081870541046">ໃນແຖບທີ່ຢູ່, ໃຫ້ລະບຸທາງລັດສຳລັບເວັບໄຊທີ່ທ່ານຕ້ອງການຊອກຫາ, ເຊັ່ນ: "@bookmarks". ຈາກນັ້ນ, ກົດຄີລັດທີ່ທ່ານຕ້ອງການ, ແລ້ວພິມຄຳຊອກຫາຂອງທ່ານ.</translation>
 <translation id="5156638757840305347">ເຄີເຊີຈະຖືກໄຮໄລ້ເມື່ອມັນປາກົດຂຶ້ນ ຫຼື ຍ້າຍໄປມາ</translation>
+<translation id="5157250307065481244">ເບິ່ງລາຍລະອຽດເວັບໄຊ</translation>
 <translation id="5157635116769074044">ປັກໝຸດຫນ້າ​ນີ້​ເພື່ອ​ເລີ່ມ​ຕົ້ນ​ຫນ້າ​ຈໍ...</translation>
 <translation id="5158206172605340248">ປິດເມນູເຄື່ອງໝາຍສຳນຽງ.</translation>
 <translation id="5159094275429367735">ຕັ້ງຄ່າ Crostini</translation>
@@ -5304,6 +5341,7 @@
 <translation id="5648166631817621825">7 ມື້ທີ່ຜ່ານມາ</translation>
 <translation id="5651308944918885595">ການຄົ້ນພົບການແບ່ງປັນໃກ້ຄຽງ</translation>
 <translation id="5653154844073528838">ທ່ານມີເຄື່ອງພິມທີ່ບັນທຶກໄວ້ <ph name="PRINTER_COUNT" /> ເຄື່ອງ.</translation>
+<translation id="565515993087783098">ໂດຍການລືມເຄືອຂ່າຍນີ້, ທ່ານຈະລຶບການສະໝັກໃຊ້ບໍລິການ Passpoint ແລະ ເຄືອຂ່າຍທີ່ກ່ຽວຂ້ອງຂອງມັນອອກນຳ.</translation>
 <translation id="5655296450510165335">ການລົງທະບຽນອຸປະກອນ</translation>
 <translation id="5656845498778518563">ສົ່ງຄຳຕິຊົມຫາ Google</translation>
 <translation id="5657156137487675418">ອະນຸຍາດຄຸກກີ້ທັງໝົດ</translation>
@@ -5816,6 +5854,7 @@
 <translation id="6104068876731806426">ບັນຊີ Google</translation>
 <translation id="6104311680260824317">ບໍ່ສາມາດເພີ່ມອຸປະກອນເຂົ້າຮ່ວມໂດເມນໄດ້. ເຊີບເວີບໍ່ຮອງຮັບການເຂົ້າລະຫັດປະເພດ Kerberos. ກະລຸນາກວດເບິ່ງ "ຕົວເລືອກເພີ່ມເຕີມ" ສຳລັບການຕັ້ງຄ່າການເຂົ້າລະຫັດ.</translation>
 <translation id="6104796831253957966">ຄິວເຄື່ອງພິມເຕັມແລ້ວ</translation>
+<translation id="6106167152849320869">ຫາກທ່ານຍັງເລືອກທີ່ຈະສົ່ງການວິນິໄສ ແລະ ຂໍ້ມູນການນຳໃຊ້ໃນຂັ້ນຕອນກ່ອນໜ້າ, ລະບົບຈະເກັບຮວບຮວມຂໍ້ມູນນີ້ສຳລັບແອັບທີ່ຕິດຕັ້ງ.</translation>
 <translation id="6111972606040028426">ເປີດການນຳໃຊ້ຜູ້ຊ່ວຍ Google</translation>
 <translation id="6112294629795967147">ແຕະເພື່ອປັບຂະໜາດ</translation>
 <translation id="6112727384379533756">ເພີ່ມປີ້</translation>
@@ -5946,6 +5985,7 @@
 <translation id="6226777517901268232">ໄຟລ​໌​ລະຫັດສ່ວນຕົວ (ເລືອກໄດ້​)​</translation>
 <translation id="6227002569366039565">ກົດ |<ph name="ACCELERATOR" />| ເພື່ອໂຟກັສໃສ່ຟອງນີ້, ຈາກນັ້ນກົດອີກເທື່ອໜຶ່ງເພື່ອໂຟກັສອົງປະກອບທີ່ມັນກຳລັງຊີ້ໄປຫາ.</translation>
 <translation id="6227280783235722609">ສ່ວນຂະຫຍາຍ</translation>
+<translation id="6229062790325126537">ຣີເຊັດ ApnMigrator</translation>
 <translation id="6229849828796482487">ຕັດການເຊື່ອມຕໍ່ເຄືອຂ່າຍ Wi-Fi</translation>
 <translation id="6231782223312638214">ແນະ​ນໍາແລ້ວ</translation>
 <translation id="6231881193380278751">ເພີ່ມ​ຕົວ​ລັບ​ການ​ສອບ​ຖາມ​ຢູ່​ໃນ URL ເພື່ອ​ຣີ​ເຟ​ຣ​ຊ​ໜ້າ​ອັດ​ຕະ​ໂນ​ມັດ: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6223,6 +6263,7 @@
 <translation id="6478248366783946499">ເກັບໄຟລ໌ອັນຕະລາຍໄວ້ບໍ?</translation>
 <translation id="6479881432656947268">ເຂົ້າເບິ່ງ Chrome Web Store</translation>
 <translation id="6480327114083866287">ຈັດການໂດຍ <ph name="MANAGER" /></translation>
+<translation id="6481978993812487794">ເມື່ອເປີດໄວ້, ແອັບຂອງທ່ານຈະພ້ອມໃຫ້ນຳໃຊ້ຢູ່ທຸກອຸປະກອນ ChromeOS ຫຼັງຈາກທີ່ທ່ານເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ. ລະບົບຈະຊິ້ງເວັບແອັບຜ່ານ Chrome ເຖິງແມ່ນວ່າຄຸນສົມບັດການຊິ້ງໂປຣແກຣມທ່ອງເວັບອື່ນໆຈະປິດຢູ່ກໍຕາມ.</translation>
 <translation id="6482559668224714696">ແວ່ນຂະຫຍາຍເຕັມຈໍ</translation>
 <translation id="6483485061007832714">ເປີດການດາວໂຫຼດ</translation>
 <translation id="6483805311199035658">ກໍາລັງເປີດ <ph name="FILE" />...</translation>
@@ -6237,6 +6278,7 @@
 <translation id="6497784818439587832">ປ່ຽນຂະໜາດການສະແດງຜົນເພື່ອເຮັດໃຫ້ລາຍການຕ່າງໆໃນໜ້າຈໍຂອງທ່ານນ້ອຍລົງ ຫຼື ໃຫຍ່ຂຶ້ນ</translation>
 <translation id="6497789971060331894">ການເລື່ອນເມົ້າຖອຍຫຼັງ</translation>
 <translation id="6498249116389603658">&amp;ທຸກພາສາຂອງທ່ານ</translation>
+<translation id="6498583202177273322">ເບິ່ງຂໍ້ມູນທີ່ເປັນປະໂຫຍດເພີ່ມເຕີມໃນລະຫວ່າງທີ່ທ່ານສຳຫຼວດໜ້ານີ້</translation>
 <translation id="6499143127267478107">ກໍາລັງແກ້ໄຂແມ່ຂ່າຍຢູ່ໃນຕົວໜັງສືພຣັອກຊີ...</translation>
 <translation id="6499764981457476645">ບໍ່ພົບອຸປະກອນຢູ່ໃກ້ຄຽງ</translation>
 <translation id="6501957628055559556">ກ່ອງບັນຈຸທັງໝົດ</translation>
@@ -6542,6 +6584,7 @@
 <translation id="6776589734354015877">ຮັບຄຸນສົມບັດເພີ່ມເຕີມ</translation>
 <translation id="6776729248872343918">ເປີດການນຳໃຊ້ການຈັບຄູ່ດ່ວນ</translation>
 <translation id="6777817260680419853">ບລັອກການປ່ຽນເສັ້ນທາງແລ້ວ</translation>
+<translation id="6777845730143344223">ສຶກສາເພີ່ມເຕີມກ່ຽວກັບການສະໝັກສະມາຊິກ Passpoint</translation>
 <translation id="6779092717724412415">ເພື່ອສ້າງໄຮໄລ້ແບບນີ້, ໃຫ້ເລືອກຂໍ້ຄວາມໃດກໍໄດ້ແລ້ວຄລິກຂວາ.</translation>
 <translation id="6779447100905857289">ກະຕ່າຂອງທ່ານ</translation>
 <translation id="677965093459947883">ນ້ອຍຫຼາຍ</translation>
@@ -6683,6 +6726,7 @@
 <translation id="688312408602122936">ເກມ ແລະ ແອັບໃດກໍຕາມທີ່ຕິດຕັ້ງຜ່ານ Steam ຈະຖືກລຶບອອກຈາກອຸປະກອນນີ້ນຳ</translation>
 <translation id="6883319974225028188">ອຸ້ຍ!  ລະບົບບັນທຶກການກຳນົດຄ່າອຸປະກອນບໍ່ສຳເລັດ.</translation>
 <translation id="6884474387073389421">ທ່ານແນ່ໃຈບໍ່ວ່າທ່ານຕ້ອງການລຶບຂໍ້ມູນການເຂົ້າສູ່ລະບົບທີ່ເລືອກອອກ?</translation>
+<translation id="6885122019363983153">ພາບພື້ນຫຼັງເດັສທັອບກົງກັນໃນທົ່ວອຸປະກອນຕ່າງໆ</translation>
 <translation id="6885771755599377173">ການສະແດງຕົວຢ່າງຂໍ້ມູນລະບົບ</translation>
 <translation id="6886380424988777998">ບໍ່ສາມາດອັບເກຣດ Linux ໄດ້</translation>
 <translation id="6886871292305414135">ເປີດລິ້ງຢູ່ໃນແຖບໃໝ່</translation>
@@ -6754,6 +6798,7 @@
 <translation id="6949434160682548041">ລະຫັດຜ່ານ (ບໍ່ບັງຄັບ)</translation>
 <translation id="6950627417367801484">ກູ້ຄືນແອັບ</translation>
 <translation id="6952242901357037157">ນອກນັ້ນທ່ານຍັງສາມາດສະແດງລະຫັດຜ່ານຈາກ <ph name="BEGIN_LINK" />ບັນຊີ Google<ph name="END_LINK" /> ຂອງທ່ານຢູ່ບ່ອນນີ້ໄດ້ນຳ</translation>
+<translation id="6954910832698269894">ເປີດການຊິ້ງອຸປະກອນເພື່ອກູ້ຄືນແອັບ, ການຕັ້ງຄ່າ, ເຄືອຂ່າຍ Wi-Fi ແລະ ຮູບພື້ນຫຼັງຂອງທ່ານຈາກ Chromebook ເຄື່ອງເກົ່າຂອງທ່ານ. ປ່ຽນແປງໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າ &gt; ບັນຊີ.</translation>
 <translation id="6954936693361896459">ສົ່ງສັນຍານແຖບນີ້ແທນ</translation>
 <translation id="6955446738988643816">ກວດກາປັອບອັບ</translation>
 <translation id="6955535239952325894">ການຕັ້ງຄ່ານີ້ຖືກປິດການນຳໃຊ້ໃນໂປຣແກຣມທ່ອງເວັບທີ່ມີການຈັດການ</translation>
@@ -6912,6 +6957,7 @@
 <translation id="7075513071073410194">PKCS #1 MD5 ດ້ວຍການໃສ່ລະຫັດ RSA</translation>
 <translation id="7075625805486468288">ຈັດການໃບຢັ້ງຢືນ ແລະ ການຕັ້ງຄ່າ HTTPS/SSL</translation>
 <translation id="7076875098323397992">ບໍ່ສາມາດເລີ່ມອັບເກຣດໄດ້</translation>
+<translation id="7077751457066325012">ເບິ່ງ ແລະ ປັບແຕ່ງຄີລັດ</translation>
 <translation id="7077829361966535409">ໜ້າລົງຊື່ເຂົ້າ​ໃຊ້ທີ່ໃຊ້ການຕັ້ງຄ່າພຣັອກຊີປະຈຸບັນໂຫຼດບໍ່ໄດ້. ກະລຸນາ <ph name="GAIA_RELOAD_LINK_START" />ລອງລົງຊື່ເຂົ້າ​ໃຊ້ອີກ<ph name="GAIA_RELOAD_LINK_END" />, ຫຼືໃຊ້ <ph name="PROXY_SETTINGS_LINK_START" />ການຕັ້ງຄ່າພຣັອກຊີ<ph name="PROXY_SETTINGS_LINK_END" /> ອື່ນ.</translation>
 <translation id="7078120482318506217">ທຸກເຄືອຂ່າຍ</translation>
 <translation id="708060913198414444">ອັດ​ສຳ​ເນົາ​ທີ່​ຢູ່​ສຽງ</translation>
@@ -6941,6 +6987,7 @@
 <translation id="7108933416628942903">ລັອກຕອນນີ້</translation>
 <translation id="7109543803214225826">ລຶບທາງລັດອອກແລ້ວ</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{ເພີ່ມແຖບໃສ່ກຸ່ມ}other{ເພີ່ມແຖບໃສ່ກຸ່ມ}}</translation>
+<translation id="7110684627876015299">ກຸ່ມທີ່ບໍ່ມີຊື່ - <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">ຕັ້ງຊື່ໜ້າຈໍນີ້</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> ລາຍການ</translation>
 <translation id="7113502843173351041">ຮູ້​ທີ່​ຢູ່​ອີ​ເມວ​ຂອງ​ທ່ານ</translation>
@@ -7155,6 +7202,7 @@
 <translation id="7328867076235380839">ການລວມເຂົ້າກັນບໍ່ຖືກຕ້ອງ</translation>
 <translation id="7329154610228416156">ລົງຊື່ເຂົ້າໃຊ້ບໍ່ສໍາເລັດ ເພາະວ່າມັນບໍ່ຖືກປັບ​ຕັ້ງ​ຄ່າໃຫ້ໃຊ້ URL ທີ່​ບໍ່​ປອດ​ໄພ  (<ph name="BLOCKED_URL" />). ກະລຸນາຕິດຕໍ່ຜູ້ຄວບຄຸມຂອງທ່ານ.</translation>
 <translation id="7332053360324989309">ຜູ້ເຮັດວຽກສະເພາະຢ່າງ: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">ສຳຮອງຂໍ້ມູນ ແລະ ກູ້ຄືນແອັບ ແລະ ການຕັ້ງຄ່າຂອງທ່ານ</translation>
 <translation id="7335974957018254119">ໃຊ້ການກວດການສະກົດຄໍາສຳລັບ</translation>
 <translation id="7336799713063880535">ບລັອກການແຈ້ງເຕືອນແລ້ວ.</translation>
 <translation id="7338630283264858612">ໝາຍເລກປະຈຳເຄື່ອງອຸປະກອນບໍ່ຖືກຕ້ອງ.</translation>
@@ -7177,6 +7225,7 @@
 <translation id="7348093485538360975">ຄີບອດເທິງຫນ້າ​ຈໍ​</translation>
 <translation id="7349010927677336670">ຄວາມມື່ນໄຫຼຂອງວິດີໂອ</translation>
 <translation id="7352651011704765696">ມີ​ບາງ​ອັນ​ຜິດ​ພາດ</translation>
+<translation id="7352664183151911163">ໃນທົ່ວແອັບ ແລະ ໂປຣແກຣມທ່ອງເວັບ Chrome ຂອງທ່ານ</translation>
 <translation id="7353261921908507769">ລາຍຊື່ຜູ້ຕິດຕໍ່ຂອງທ່ານສາມາດແບ່ງປັນກັບທ່ານເມື່ອພວກເຂົາຢູ່ໃກ້ຄຽງ. ການໂອນຍ້າຍຈະບໍ່ເລີ່ມຂຶ້ນຈົນກວ່າທ່ານຍອມຮັບ.</translation>
 <translation id="735361434055555355">ກຳລັງຕິດຕັ້ງ Linux...</translation>
 <translation id="7354120289251608189">ຕອນນີ້ທ່ານສາມາດໃຫ້ໂປຣແກຣມທ່ອງເວັບຂອງທ່ານມີຮູບລັກໃໝ່ໄດ້ເວລາໃດກໍໄດ້.</translation>
@@ -7219,6 +7268,7 @@
 <translation id="7380622428988553498">ຊື່ອຸປະກອນປະກອບມີຕົວອັກສອນທີ່ບໍ່ຖືກຕ້ອງ</translation>
 <translation id="7380768571499464492">ອັບເດດແລ້ວ <ph name="PRINTER_NAME" /></translation>
 <translation id="7382085868019811559">ການຮອງຮັບໂປຣແກຣມທ່ອງເວັບຮຸ່ນເກົ່າ (LBS) ຈະອະນຸຍາດໃຫ້ເປີດຮູບແບບ URL ສະເພາະໃນໂປຣແກຣມທ່ອງເວັບສຳຮອງທີ່ຮອງຮັບຄຸນສົມບັດຮຸ່ນເກົ່າເຊິ່ງຈຳເປັນຕ້ອງໃຊ້ເພື່ອເປີດເວັບເຫຼົ່ານັ້ນໄດ້ຢ່າງຖືກຕ້ອງ.</translation>
+<translation id="7382980704744807223">ໜ້າສົງໄສ</translation>
 <translation id="738322632977123193">ບໍ່ສາມາດອັບໂຫຼດໄດ້. ໃຊ້ຮູບທີ່ມີນາມສະກຸນໃດໜຶ່ງຕໍ່ໄປນີ້: .jpg, .gif, .png, .bmp, .tif ຫຼື .webp</translation>
 <translation id="73843634555824551">ການປ້ອນຂໍ້ມູນ ແລະ ແປ້ນພິມ</translation>
 <translation id="7384687527486377545">ການເຮັດຊໍ້າຄືນຂອງແປ້ນພິມໂດຍອັດຕະໂນມັດ</translation>
@@ -7315,6 +7365,8 @@
 <translation id="7458168200501453431">ໃຊ້ຕົວກວດການສະກົດຄໍາດຽວກັນກັບທີ່ໃຊ້ໃນ Google ຊອກຫາ. ລະບົບຈະສົ່ງຂໍ້ຄວາມທີ່ທ່ານພິມໃນໂປຣແກຣມທ່ອງເວັບໄປໃຫ້ Google.</translation>
 <translation id="7458715171471938198">ກູ້ຄືນແອັບບໍ?</translation>
 <translation id="7458933488302148148">ກວດສອບລະຫັດຜ່ານທີ່ບັນທຶກໄວ້ຂອງທ່ານເພື່ອເພີ່ມຄວາມປອດໄພຂອງທ່ານ ແລະ ໃຊ້ໂລກອອນລາຍຢ່າງປອດໄພຍິ່ງຂຶ້ນ</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />ການອະນຸຍາດໃຫ້ອຸປະກອນ ChromeOS ຂອງທ່ານສົ່ງລາຍງານອັດຕະໂນມັດຈະຊ່ວຍໃຫ້ພວກເຮົາຈັດລຳດັບຄວາມສຳຄັນໄດ້ວ່າຈະແກ້ໄຂ ແລະ ປັບປຸງຫຍັງໃນ ChromeOS. ລາຍງານເຫຼົ່ານີ້ສາມາດຮວມເອົາຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ChromeOS ຫຼົ້ມຕອນໃດ, ມີການໃຊ້ຄຸນສົມບັດໃດ ແລະ ໂດຍປົກກະຕິແລ້ວທ່ານໃຊ້ໜ່ວຍຄວາມຈຳເທົ່າໃດ. ຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບອື່ນໆ, ເຊິ່ງມີການຮວບຮວມສຳລັບແອັບ Android ແລະ ເວັບແອັບ ຫາກມີການເປີດການຊິ້ງແອັບ.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ທ່ານສາມາດເລີ່ມ ຫຼື ຢຸດການອະນຸຍາດລາຍງານເຫຼົ່ານີ້ໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າອຸປະກອນ Chrome ຂອງທ່ານ. ຫາກທ່ານເປັນຜູ້ເບິ່ງແຍງລະບົບໂດເມນ, ທ່ານສາມາດປ່ຽນການຕັ້ງຄ່ານີ້ໄດ້ໃນຄອນໂຊຜູ້ເບິ່ງແຍງ.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">ຮູບແບບສີສັນປັດຈຸບັນທີ່ທ່ານໄດ້ຕິດຕັ້ງ</translation>
 <translation id="7461924472993315131">ປັກໝຸດ</translation>
 <translation id="746216226901520237">ຄັ້ງຕໍ່ໄປ, ໂທລະສັບຂອງທ່ານຈະປົດລັອກ <ph name="DEVICE_TYPE" /> ຂອງທ່ານ. ທ່ານສາມາດປິດ Smart Lock ໄດ້ໃນການຕັ້ງຄ່າ.</translation>
@@ -7475,6 +7527,7 @@
 <translation id="7607002721634913082">ຢຸດແລ້ວ</translation>
 <translation id="7608810328871051088">ການຕັ້ງຄ່າ Android</translation>
 <translation id="7609148976235050828">ກະລຸນາເຊື່ອມຕໍ່ກັບອິນເຕີເນັດ ແລ້ວລອງໃໝ່.</translation>
+<translation id="7611713099524036757">Meta</translation>
 <translation id="7612401678989660900">ອະນຸຍາດສິດເຂົ້າເຖິງສຳລັບແອັບ ແລະ ເວັບໄຊທີ່ມີສິດອະນຸຍາດໄມໂຄຣໂຟນ</translation>
 <translation id="7612655942094160088">ເປີດການນຳໃຊ້ຄຸນສົມບັດໂທລະສັບທີ່ເຊື່ອມຕໍ່ຢູ່.</translation>
 <translation id="7612989789287281429">ກຳລັງພາທ່ານເຂົ້າສູ່ລະບົບ…</translation>
@@ -7548,6 +7601,7 @@
 <translation id="7663719505383602579">ຕົວຮັບ: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">ມີຄີລັດທີ່ສາມາດໃຊ້ໄດ້</translation>
 <translation id="7663859337051362114">ເພີ່ມໂປຣໄຟລ໌ eSIM</translation>
+<translation id="76641554187607347">ບໍ່ໄດ້ເຊື່ອມຕໍ່ແປ້ນພິມ</translation>
 <translation id="7665082356120621510">ຈອງຂະໜາດ</translation>
 <translation id="7665369617277396874">ເພີ່ມ​ບັນ​ຊີ</translation>
 <translation id="766560638707011986">ສະແດງໂດເມນ</translation>
@@ -7595,6 +7649,7 @@
 <translation id="769824636077131955">ເອກະສານນີ້ໃຫຍ່ເກີນໄປສຳລັບການກວດສອບຄວາມປອດໄພ. ທ່ານສາມາດພິມເອກະສານທີ່ມີຂະໜາດສູງສຸດໄດ້ 50 MB.</translation>
 <translation id="7698507637739331665">ບາງລາຍການຖືກບລັອກໄວ້</translation>
 <translation id="7701040980221191251">ບໍ່​ມີ​</translation>
+<translation id="7701265686005869308">ປິດໂປຣໄຟລ໌</translation>
 <translation id="7701869757853594372">ດ້າມຈັບ​ຜູ້​ໃຊ້</translation>
 <translation id="7702574632857388784">ລຶບ <ph name="FILE_NAME" /> ອອກຈາກລາຍການແລ້ວ</translation>
 <translation id="7702907602086592255">ໂດເມນ</translation>
@@ -8015,6 +8070,7 @@
 <translation id="8050191834453426339">ຢັ້ງຢືນອີກຄັ້ງ</translation>
 <translation id="8051193500142930381">ຄຸນສົມບັດທີ່ຈໍາເປັນຕ້ອງໃຊ້ກ້ອງຈະໃຊ້ບໍ່ໄດ້</translation>
 <translation id="8051390370038326517">ອະນຸຍາດໃຫ້ <ph name="HOST" /> ມີການຄວບຄຸມອຸປະກອນ MIDI ແບບເຕັມທຸກເທື່ອ</translation>
+<translation id="8052218774860457016">ຈັດການການຊິ້ງໂປຣແກຣມທ່ອງເວັບ</translation>
 <translation id="8053278772142718589">PKCS # 12 ໄຟລ​໌</translation>
 <translation id="8053390638574070785">​ໂຫຼດ​ຫນ້າ​ນີ້ຄືນອີກ</translation>
 <translation id="8054517699425078995">ໄຟລ໌ປະເພດນີ້ສາມາດເປັນອັນຕະລາຍຕໍ່ອຸປະກອນຂອງທ່ານໄດ້. ແນວໃດທ່ານກໍ່ຕ້ອງການເກັບ <ph name="FILE_NAME" /> ໄວ້ບໍ?</translation>
@@ -8384,6 +8440,7 @@
 <translation id="8376137163494131156">ບອກພວກເຮົາວ່າກຳລັງເກີດຫຍັງຂຶ້ນກັບ Google Cast.</translation>
 <translation id="8376384591331888629">ຮວມທັງຄຸກກີ້ພາກສ່ວນທີສາມໃນເວັບໄຊນີ້</translation>
 <translation id="8376451933628734023">ຫາກເວັບແອັບນີ້ພະຍາຍາມຫຼອກລໍ້ໃຫ້ທ່ານຄິດວ່າມັນເປັນແອັບອື່ນ, ໃຫ້ຖອນການຕິດຕັ້ງມັນອອກ.</translation>
+<translation id="8376752431516546391">ແຜງຄວບຄຸມດ້ານຂ້າງຂອງ Google ຊອກຫາ</translation>
 <translation id="8377625247046155446">ກະແຈຜ່ານນີ້ຈະຖືກບັນທຶກໄວ້ຢູ່ອຸປະກອນນີ້ເທົ່ານັ້ນ. ມັນຈະຍັງຄົງຢູ່ອຸປະກອນນີ້ຫຼັງຈາກທີ່ທ່ານປິດໜ້າຈໍທີ່ບໍ່ເປີດເຜີຍຕົວຕົນທັງໝົດແລ້ວ.</translation>
 <translation id="8378714024927312812">ຈັດການໂດຍອົງການຂອງທ່ານ</translation>
 <translation id="8379878387931047019">ອຸປະກອນນີ້ບໍ່ຮອງຮັບປະເພດກະແຈຄວາມປອດໄພທີ່ເວັບໄຊນີ້ຂໍເອົາ</translation>
@@ -8451,6 +8508,11 @@
 <translation id="8428628598981198790">ບໍ່ສາມາດໃຊ້ກະແຈຄວາມປອດໄພຂອງທ່ານກັບເວັບໄຊນີ້ໄດ້</translation>
 <translation id="84297032718407999">ທ່ານຈະຖືກນຳອອກຈາກລະບົບໃນ <ph name="LOGOUT_TIME_LEFT" /></translation>
 <translation id="8431190899827883166">ສະແດງການແຕະ</translation>
+<translation id="8431496281632382473">ໂປຣໄຟລ໌ນີ້ຖືກຈັດການໂດຍ <ph name="DOMAIN" />. ເພື່ອສືບຕໍ່ໃຊ້ໂປຣໄຟລ໌ທີ່ມີການຈັດການນີ້, ອົງກອນຂອງທ່ານກຳນົດໃຫ້ທ່ານຕ້ອງແບ່ງປັນສັນຍານຂອງອຸປະກອນຂອງທ່ານ.
+
+ສັນຍານຂອງອຸປະກອນອາດຮວມເຖິງຂໍ້ມູນກ່ຽວກັບໂປຣແກຣມທ່ອງເວັບ, ລະບົບປະຕິບັດການ, ອຸປະກອນ, ຊອບແວທີ່ຕິດຕັ້ງ ແລະ ໄຟລ໌ຕ່າງໆຂອງທ່ານ.
+
+ຫາກທ່ານເລືອກທີ່ຈະບໍ່ແບ່ງປັນສັນຍານ, ໂປຣໄຟລ໌ນີ້ຈະຖືກປິດ.</translation>
 <translation id="8434480141477525001">ຜອດແກ້ໄຂບັນຫາ NaCl</translation>
 <translation id="8437209419043462667">ສະ​ຫະ​ລັດ</translation>
 <translation id="8438328416656800239">ປ່ຽນເປັນໂປຣແກຣມທ່ອງເວັບທີ່ສະຫຼາດ</translation>
@@ -8535,6 +8597,8 @@
 <translation id="851263357009351303">​ອະ​ນຸ​ຍາດ​ໃຫ້ <ph name="HOST" /> ສະ​ແດງຮູບທຸກຄັ້ງ</translation>
 <translation id="8513108775083588393">ໝຸນອັດຕະໂນມັດ</translation>
 <translation id="8513357934662532537">ເພື່ອນຳເຂົ້າລະຫັດຜ່ານໄປໃສ່ <ph name="BRAND" /> ສຳລັບ <ph name="USER_EMAIL" />, ໃຫ້ເລືອກໄຟລ໌ CSV.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />ການອະນຸຍາດໃຫ້ອຸປະກອນ ChromeOS ສົ່ງລາຍງານອັດຕະໂນມັດຈະຊ່ວຍໃຫ້ພວກເຮົາຈັດລຳດັບຄວາມສຳຄັນໄດ້ວ່າຈະແກ້ໄຂ ແລະ ປັບປຸງຫຍັງໃນ ChromeOS. ລາຍງານເຫຼົ່ານີ້ສາມາດຮວມເອົາຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ChromeOS ຫຼົ້ມຕອນໃດ, ມີການໃຊ້ຄຸນສົມບັດໃດ ແລະ ໂດຍປົກກະຕິແລ້ວໃຊ້ໜ່ວຍຄວາມຈຳເທົ່າໃດ. ຂໍ້ມູນການວິນິໄສ ແລະ ການນຳໃຊ້ແອັບອື່ນໆ, ເຊິ່ງມີການຮວບຮວມສຳລັບແອັບ Android ແລະ ເວັບແອັບ ຫາກມີການເປີດການຊິ້ງແອັບ.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ທ່ານສາມາດເລີ່ມ ຫຼື ຢຸດການອະນຸຍາດລາຍງານເຫຼົ່ານີ້ໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າອຸປະກອນ ChromeOS ຂອງລູກທ່ານ. ຫາກທ່ານເປັນຜູ້ເບິ່ງແຍງລະບົບໂດເມນ, ທ່ານສາມາດປ່ຽນການຕັ້ງຄ່ານີ້ໄດ້ໃນຄອນໂຊຜູ້ເບິ່ງແຍງ.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">ລອງກະແຈຄວາມປອດໄພອື່ນ</translation>
 <translation id="8514955299594277296">ຢ່າອະນຸຍາດໃຫ້ເວັບໄຊບັນທຶກຂໍ້ມູນຢູ່ອຸປະກອນຂອງທ່ານ (ບໍ່ແນະນຳ)</translation>
 <translation id="8517759303731677493">ແກ້ໄຂ…</translation>
@@ -8895,6 +8959,7 @@
 <translation id="883062543841130884">ການແທນທີ່</translation>
 <translation id="8830779999439981481">ກຳລັງຣິສະຕາດເພື່ອນຳໃຊ້ການອັບເດດ</translation>
 <translation id="8830796635868321089">ການກວດຫາອັບເດດບໍ່ສໍາເລັດດ້ວຍການໃຊ້ການຕັ້ງຄ່າພຣັອກຊີປະຈຸບັນ. ກະລຸນາປັບ <ph name="PROXY_SETTINGS_LINK_START" />ການຕັ້ງຄ່າພຣັອກຊີ<ph name="PROXY_SETTINGS_LINK_END" /> ຂອງທ່ານ.</translation>
+<translation id="8830863983385452402">ເວັບໄຊຈະສາມາດເຫັນເນື້ອຫາຂອງແຖບນີ້ໄດ້</translation>
 <translation id="8831769650322069887">ເປີດ <ph name="FILE_NAME" /></translation>
 <translation id="8832781841902333794">ໂປຣໄຟລ໌ຂອງທ່ານ</translation>
 <translation id="8834039744648160717">ການກຳນົດຄ່າເຄືອຂ່າຍຖືກຄວບຄຸມໂດຍ <ph name="USER_EMAIL" />.</translation>
@@ -9026,6 +9091,7 @@
 <translation id="8946359700442089734">ຄຸນສົມບັດ​ແກ້​ໄຂ​ບັນ​ຫາ​ບໍ່​ຖືກ​ເປີດ​ໃຊ້​ງານ​ຢ່າງ​ເຕັມ​ທີ່​ຢູ່​ເທິງ​ອຸ​ປະ​ກອນ <ph name="IDS_SHORT_PRODUCT_NAME" /> ນີ້.</translation>
 <translation id="894763922177556086">ແຮງ​ດີ</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> ຕ້ອງການເບິ່ງຍີ່ຫໍ້ ແລະ ຮຸ່ນກະແຈຄວາມປອດໄພຂອງທ່ານ</translation>
+<translation id="8949304443659090542">ຈັດການການຊິ້ງໂປຣແກຣມທ່ອງເວັບ Chrome</translation>
 <translation id="895054485242522631">ເວັບໄຊສາມາດໃຊ້ເຊັນເຊີກວດຈັບການເຄື່ອນໄຫວໄດ້</translation>
 <translation id="8951256747718668828">ການກູ້ຄືນຂໍ້ມູນບໍ່ສຳເລັດເນື່ອງຈາກຂໍ້ຜິດພາດ</translation>
 <translation id="8951465597020890363">ແນວໃດກໍອອກຈາກໂໝດແຂກບໍ?</translation>
@@ -9131,6 +9197,7 @@
 <translation id="9032097289595078011">ປິດການນຳໃຊ້ການຈັບຄູ່ດ່ວນ</translation>
 <translation id="9033765790910064284">ຢືນຢັນດຳເນີນການຕໍ່</translation>
 <translation id="9033857511263905942">ແປະໃສ່</translation>
+<translation id="9034408118624208974">ຍັງບໍ່ເຄີຍໃຊ້ Chromebook ບໍ? ເປີດການຊິ້ງເພື່ອໃຫ້ລະບົບສຳຮອງຂໍ້ມູນການຕັ້ງຄ່າຂອງທ່ານ.</translation>
 <translation id="903480517321259405">ພິມ PIN ອີກເທື່ອໜຶ່ງ</translation>
 <translation id="9037054491984310631">ເຊື່ອມຕໍ່ຫາອຸປະກອນ Bluetooth ຊື່ <ph name="DEVICE" /> ແລ້ວ</translation>
 <translation id="9037640663275993951">ບໍ່ອະນຸຍາດອຸປະກອນ</translation>
@@ -9174,6 +9241,7 @@
 <translation id="9068298336633421551">ອະນຸຍາດໃຫ້ແອັບ ແລະ ບໍລິການ Android ຕ່າງໆທີ່ມີການອະນຸຍາດສະຖານທີ່ສາມາດໃຊ້ສະຖານທີ່ຂອງອຸປະກອນນີ້ໄດ້. Google ອາດເກັບກຳຂໍ້ມູນສະຖານທີ່ເປັນໄລຍະໆ ແລະ ໃຊ້ຂໍ້ມູນນີ້ໃນແບບບໍ່ລະບຸຕົວຕົນເພື່ອປັບປຸງຄວາມຖືກຕ້ອງຂອງສະຖານທີ່ ແລະ ບໍລິການທີ່ອ້າງອີງສະຖານທີ່.</translation>
 <translation id="9068598199622656904">ກົດເທື່ອລະປຸ່ມສໍາລັບຄີລັດແທນທີ່ຈະກົດປຸ່ມຄ້າງໄວ້ພ້ອມກັນ</translation>
 <translation id="9068878141610261315">ປະເພດໄຟລ໌ບໍ່ຮອງຮັບ</translation>
+<translation id="9069665781180028115">ລາຍການທີ່ເລືອກຈະພ້ອມນຳໃຊ້ຢູ່ Chromebook ເຄື່ອງນີ້. ຫາກທ່ານຍັງບໍ່ເຄີຍໃຊ້ Chromebook, ໃຫ້ຊິ້ງລາຍການທັງໝົດເພື່ອໃຫ້ລະບົບສຳຮອງຂໍ້ມູນການຕັ້ງຄ່າຂອງທ່ານ. ປ່ຽນແປງໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າ &gt; ບັນຊີ.</translation>
 <translation id="9070342919388027491">ຍ້າຍແຖບໄປເບື້ອງຊ້າຍແລ້ວ</translation>
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9074836595010225693">ເມົ້າສ໌ USB ເຊື່ອມ​ຕໍ່ແລ້ວ</translation>
@@ -9347,6 +9415,7 @@
 <translation id="930268624053534560">ສະແຕັມເວລາລະອຽດ</translation>
 <translation id="930551443325541578">ກົດປຸ່ມຊ້ຳ ແລະ ເຄື່ອງໝາຍສຳນຽງ</translation>
 <translation id="930893132043726269">ຕອນນີ້ກຳລັງໂຣມມິງຢູ່</translation>
+<translation id="930991362911221750">ອະນຸຍາດໃຫ້ <ph name="APP_NAME" /> ເບິ່ງແຖບນີ້ບໍ?</translation>
 <translation id="93140074055951850">ແອັບ Android ໄດ້ຢຸດເຮັດວຽກ</translation>
 <translation id="932327136139879170">ບ້ານ</translation>
 <translation id="932508678520956232">ບໍ່ສາມາດລິເລີ່ມການພິມໄດ້.</translation>
diff --git a/chrome/app/resources/generated_resources_ne.xtb b/chrome/app/resources/generated_resources_ne.xtb
index 551c7fc78..929a97a 100644
--- a/chrome/app/resources/generated_resources_ne.xtb
+++ b/chrome/app/resources/generated_resources_ne.xtb
@@ -214,6 +214,7 @@
 <translation id="1176471985365269981">तपाईंको डिभाइसमा भएका फाइल वा फोल्डरहरू परिवर्तन गर्ने अनुमति नदिइएका साइटहरू</translation>
 <translation id="1177863135347784049">अनुकूल</translation>
 <translation id="1178581264944972037">पज गर्नुहोस्</translation>
+<translation id="1178601482396475810">डिभाइस सिंक गर्ने सुविधा व्यवस्थापन गर्नुहोस्</translation>
 <translation id="117916940443676133">तपाईंको सुरक्षा साँचो PIN प्रयोग गरी सुरक्षित गरिएको छैन। साइन इन गर्न चाहिने डेटा व्यवस्थित गर्न सर्वप्रथम एउटा PIN सिर्जना गर्नुहोस्।</translation>
 <translation id="1181037720776840403">हटाउनुहोस्</translation>
 <translation id="1181366777303791449"><ph name="MAIN_FRAME_ETLD_PLUS_ONE" /> मा</translation>
@@ -351,6 +352,7 @@
 <translation id="130097046531636712">यसले निर्वाध रूपमा स्क्रोल गर्ने सुविधालगायतका ब्याकग्राउन्डमा हुने क्रियाकलाप र भिजुअल इफेक्टहरूलाई सीमित पारेर ब्याट्री टिक्ने अवधि बढाउँछ</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> ले निम्न फाइलहरू सम्पादन गर्न सक्छ</translation>
 <translation id="1302227299132585524">Apple Events मार्फत JavaScript लाई अनुमति दिनुहोस्</translation>
+<translation id="1302654693270046655"><ph name="GROUP_NAME" /> नामक समूह - <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">HTML फाइललाई बुकमार्क गर्छ</translation>
 <translation id="1303671224831497365">कुनै ब्लुटुथ यन्त्र भेट्टिएन</translation>
 <translation id="130491383855577612">Linux एप र फाइलहरू सफलतापूर्वक प्रतिस्थापन गरिएका छन्</translation>
@@ -1047,6 +1049,7 @@
 <translation id="1877520246462554164">प्रमाणीकरणको टोकन प्राप्त गर्न सकिएन। कृपया फेरि प्रयास गर्न साइन आउट गर्नुहोस्, त्यसपछि फेरि साइन इन गर्नुहोस्।</translation>
 <translation id="1877860345998737529">स्विचको कारबाही तोक्ने कार्य</translation>
 <translation id="1878155070920054810">अपडेट पूरा हुनुअगावै तपाईंको Chromebook को ब्याट्री सकिएला जस्तो छ। अपडेट प्रक्रिया अवरुद्ध हुन नदिन तपाईंको Chromebook सही तरिकाले चार्ज भइरहेको छ भन्ने कुरा सुनिश्चित गर्नुहोस्।</translation>
+<translation id="1878477879455105085">खोलिएको</translation>
 <translation id="1878885068166344708">तपाईंले फोकस सार्दा वस्तु हाइलाइट गरिन्छ। फोकस परिवर्तन गर्न ट्याब थिच्नुहोस् वा कुनै वस्तु चयन गर्नुहोस्।</translation>
 <translation id="1879000426787380528">निम्न व्यक्तिका रूपमा साइन इन गर्नुहोस्</translation>
 <translation id="18802377548000045">ट्याबहरू चौडाइ ठुलो हुने गरी साना हुन्छन्</translation>
@@ -1431,6 +1434,7 @@
 <translation id="2204034823255629767">तपाईंले टाइप गर्नुहुने कुनैपनि कुरालाई पढ्नुहोस् र परिवर्तन गर्नुहोस्</translation>
 <translation id="2204387456724731099">चयन गरिएको यो टेक्स्ट अनुवाद गर्न सकिँदैन</translation>
 <translation id="2210462644007531147">इन्स्टल गर्ने प्रक्रिया पूरा गर्न सकिएन</translation>
+<translation id="2211245494465528624">सिंकसम्बन्धी विकल्पहरू व्यवस्थापन गर्नुहोस्</translation>
 <translation id="2212565012507486665">कुकीहरूलाई अनुमति दिनुहोस्</translation>
 <translation id="2214018885812055163">आदान प्रदान गरिएका फोल्डरहरू</translation>
 <translation id="2214884991347062907">गलत पासवर्ड, फेरि प्रयास गर्नुहोस्</translation>
@@ -1526,6 +1530,7 @@
 <translation id="2296218178174497398">डिभाइस पत्ता लगाउन गरिने खोजी</translation>
 <translation id="2297705863329999812">प्रिन्टरहरू खोज्नुहोस्</translation>
 <translation id="2297822946037605517">यो पेज सेयर गर्नुहोस्</translation>
+<translation id="229871422646860597">टुलबारबाट अनपिन गर्नुहोस्</translation>
 <translation id="2299734369537008228">स्लाइडर: <ph name="MIN_LABEL" /> देखि <ph name="MAX_LABEL" /> सम्म</translation>
 <translation id="2299941608784654630">debugd ले सङ्कलन गरेका सबै लग फाइलहरूलाई बेग्लै अभिलेखका रूपमा समावेश गरियोस्।</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2156,6 +2161,7 @@
 <translation id="2811205483104563968">खाताहरू</translation>
 <translation id="2811564570599779918">स्प्याम तथा ठगी न्यूनीकरण गर्ने सुविधा</translation>
 <translation id="2812049959647166806">थन्डरबोल्ट प्रयोग गर्न मिल्दैन</translation>
+<translation id="2812171980080389735">तपाईं तुरुन्तै कनेक्ट गर्न सक्नुहोस् भन्नाका लागि नेटवर्क र पासवर्डहरू सेभ गरिएका छन्</translation>
 <translation id="2813094189969465044">अभिभावकीय नियन्त्रणहरू</translation>
 <translation id="281390819046738856">अनुरोधमा हस्ताक्षर गर्न सकिएन।</translation>
 <translation id="2814489978934728345">यो पृष्ठ लोड गर्न रोक्नुहोस्</translation>
@@ -2195,6 +2201,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">तपाईंको PIN हालिएको छ</translation>
 <translation id="2849936225196189499">नाजुक</translation>
+<translation id="285033512555869047">बन्द छ</translation>
 <translation id="2850541429955027218">विषयवस्तु थप्नुहोस्</translation>
 <translation id="2850672011315104382">विराम चिन्हको शैली</translation>
 <translation id="2852385257476173980">तपाईंले वेब ब्राउज गर्दै जाँदा तपाईंले खोल्ने साइटहरूको सूची यहाँ देखिन सक्छ</translation>
@@ -2238,6 +2245,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> र अन्य <ph name="NUMBER_OF_DEVICES" /> वटा डिभाइस</translation>
 <translation id="2889043468805635730">कुनै पनि समस्या भेटिएन</translation>
 <translation id="2889064240420137087">कृपया लिङ्क खोल्नुहोस्...</translation>
+<translation id="2890206081124517553">विभिन्न डिभाइसहरूमा तपाईंको डेस्कटपको ब्याकग्राउन्ड लागू गरियोस्</translation>
 <translation id="2891566119238851894">साइड प्यानलमा खोज्ने सुविधा खोल्नुहोस्। साइड प्यानलमा खोज्ने सुविधा बन्द छ।</translation>
 <translation id="2891922230654533301"><ph name="APP_NAME" /> मा साइन इन गर्न तपाईंको यन्त्र प्रयोग गर्ने हो?</translation>
 <translation id="2893013536106749396">तपाईंलाई महत्त्वपूर्ण कुराहरूका बारेमा जानकारी दिइराख्ने कार्डहरू रोज्नुहोस्</translation>
@@ -2260,6 +2268,7 @@
 <translation id="2907798539022650680">'<ph name="NAME" />'मा जडान गर्न सकिएन
         <ph name="DETAILS" />
     सर्भर सन्देश: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">सिग्नलहरू सेर गर्नुहोस्</translation>
 <translation id="2908162660801918428">डाइरेक्टरी अनुसार मिडिया ग्यालरी थप्नुहोस</translation>
 <translation id="2908358077082926882">तोकिएको की हटाएर <ph name="RESPONSE" /> "<ph name="CURRENTKEY" />" की फेरि थिच्नुहोस्</translation>
 <translation id="2909506265808101667">Google का सेवाहरूमा कनेक्ट गर्न सकिएन। इन्टरनेट जाँच्नुहोस् र फेरि प्रयास गर्नुहोस्। त्रुटिको कोड: <ph name="ERROR_CODE" />।</translation>
@@ -2364,6 +2373,7 @@
 <translation id="3003828226041301643">यन्त्रलाई उक्त डोमेनसँग जोड्न सकिँदैन। तपाईंसँग यन्त्रहरू थप्न सक्ने विशेषाधिकारहरू छ वा छैन भनेर आफ्नो खाताको जाँच गर्नुहोस्‌।</translation>
 <translation id="3003967365858406397">तपाईंको <ph name="PHONE_NAME" /> ले कुनै निजी Wi-Fi जडान सिर्जना गर्दछ।</translation>
 <translation id="3004385386820284928">किबोर्डका की कस्टमाइज गर्नुहोस्</translation>
+<translation id="3005376701115952939">सिस्टमका सेटिङमा गई एपहरू सिंक गर्ने सुविधा अन वा अफ गर्न सकिन्छ</translation>
 <translation id="3005574332301273731">नदेखाइयोस्</translation>
 <translation id="3006881078666935414">उपयोगसम्बन्धी कुनै डेटा छैन</translation>
 <translation id="3007410324195400631">यो पेजका बारेमा नोटहरू लेख्नुहोस्</translation>
@@ -2745,6 +2755,7 @@
 <translation id="3369624026883419694">होस्ट समाधान गर्दै...</translation>
 <translation id="3370260763947406229">स्वतः भूलसुधार</translation>
 <translation id="3371140690572404006">USB-C यन्त्र (दायाँ भागको अगाडिको पोर्ट)</translation>
+<translation id="3371351218553893534">लाइन एकदमै लामो छ: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">तपाईंले एप्लिकेसनमा खोल्ने फोल्डरहरू पढ्नुहोस्</translation>
 <translation id="3373059063088819384">रिडिङ मोडमा खोल्नुहोस्</translation>
 <translation id="3373701465337594448">यो सेटिङ अन भएका बेला यहाँ तपाईंले खोल्ने त्यस्ता साइटहरूको सूची देखिन्छ जसले तपाईंका रुचिहरू अनुमान लगाउँछन्</translation>
@@ -2815,6 +2826,9 @@
 <translation id="3434272557872943250">तपाईंका बच्चाका खातामा वेब तथा एपसम्बन्धी अतिरिक्त गतिविधिको सेटिङ सक्रिय गरिएको छ भने यो डेटा उनको Google खातामा सुरक्षित गरिन सक्छ। families.google.com मा गएर यी सेटिङहरू र यिनलाई मिलाउने तरिकाबारे थप जान्नुहोस्।</translation>
 <translation id="3434475275396485144">तपाईंको फोनका एड्मिन यो सेटिङ मिलाउनुहुन्छ।</translation>
 <translation id="3434512374684753970">अडियो तथा भिडियो</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />अर्को स्क्रिनमा आफ्नो Google खातामार्फत साइन इन गर्नुहोस्।<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />यो खाता भनेको तपाईंले Gmail, YouTube र Chrome लगायतका Google का सेवाहरूमा प्रयोग गर्ने खाता हो। आफ्नो खाता प्रयोग गरेर पर्सनलाइज गरिएको सुविधा प्राप्त गर्नुहोस् र आफ्ना सबै जानकारी सजिलैसँग हेर्नुहोस्।<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />तपाईंसँग Google खाता छैन भने तपाईं अर्को स्क्रिनमा नयाँ Google खाता बनाउन सक्नु हुने छ।<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">"<ph name="EXTENSION_NAME" />" ले तपाईंको <ph name="CODE_TYPE" /> को अनुरोध गर्दैछ</translation>
 <translation id="3435738964857648380">सुरक्षा</translation>
 <translation id="343578350365773421">पाना सकियो</translation>
@@ -2861,6 +2875,7 @@
 <translation id="346546413339447252"><ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> र अन्य व्यापारीको छुट प्राप्त गर्नुहोस्</translation>
 <translation id="3468298837301810372">लेबल</translation>
 <translation id="3468999815377931311">Android फोन</translation>
+<translation id="3469345458390352459">तपाईंले सिंक गर्ने सुविधा अन गर्नुभयो भने तपाईंले जुन जुन Chrome OS डिभाइसमा आफ्नो Google खातामार्फत साइन इन गर्नुहुन्छ ती डिभाइसहरूमा तपाईंका एपहरू उपलब्ध हुने छन्।  अन्य ब्राउजरका सिंक गर्ने सुविधा अफ भए तापनि वेब एपहरू Chrome मार्फत सिंक गरिने छन्।</translation>
 <translation id="3469583217479686109">चयन गर्ने टुल</translation>
 <translation id="3470392222765168737">साइट फलो गर्नुहोस्</translation>
 <translation id="3471876058939596279">भिडियोसम्बन्धी प्रयोजनका लागि HDMI र USB Type-C पोर्टहरू एकै समयमा प्रयोग गर्न मिल्दैन। कुनै अर्को भिडियो पोर्ट प्रयोग गर्नुहोस्।</translation>
@@ -3323,6 +3338,7 @@
 <translation id="3855441664322950881">प्याकको विस्तार</translation>
 <translation id="3855676282923585394">बुकमार्कहरू र सेटिङहरू आयात गर्नुहोस्...</translation>
 <translation id="3856096718352044181">कृपया यो एउटा मान्य प्रदायक हो भनी पुष्टि गर्नुहोस् वा पछि फेरि प्रयास गर्नुहोस्</translation>
+<translation id="3856470183388031602"><ph name="DEVICE_TYPE" /> मा आफ्नो Google खाता प्रयोग गर्नुहोस्</translation>
 <translation id="3856800405688283469">प्रामाणिक समय चयन गर्नुहोस्</translation>
 <translation id="3857807444929313943">औँला उठाई फेरि छुनुहोस्</translation>
 <translation id="3858860766373142691">नाम</translation>
@@ -3362,6 +3378,7 @@
 <translation id="3894123633473837029">Sherlog मार्फत सहायकका हालसालैका क्रियाकलापको इतिहास समावेश गर्नुहोस्। यसले तपाईंको पहिचान, स्थान तथा डिबगसम्बन्धी जानकारी समावेश गर्न सक्छ। <ph name="BEGIN_LINK" />थप जान्नुहोस्<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">फोल्डर थप्नुहोस्</translation>
 <translation id="3894770151966614831">पासवर्ड सारेर Google खातामा लैजाने हो?</translation>
+<translation id="3894983081771074056">किबोर्ड र माउसले काम गर्ने डिफल्ट तरिका, भाषासम्बन्धी प्राथमिकता र अन्य कुराहरू</translation>
 <translation id="3895076768659607631">&amp;सर्च इन्जिनहरू व्यवस्थापन गर्नुहोस्...</translation>
 <translation id="3895090224522145010">Kerberos को युजरनेम</translation>
 <translation id="389521680295183045">साइटहरूले तपाईं आफ्नो यन्त्र चलाउँदै हुनुहुन्छ कि हुनुहुन्न भन्ने कुराको जानकारी माग्न सक्छन्</translation>
@@ -3496,6 +3513,7 @@
 <translation id="3994878504415702912">&amp;जूम गर्नुहोस्</translation>
 <translation id="3995138139523574647">USB-C यन्त्र (दायाँ भागको पछाडिको पोर्ट)</translation>
 <translation id="3995963973192100066">प्ले गर्ने बटनको एनिमेसन</translation>
+<translation id="399788104667917863">टुलबारमा पिन गर्नुहोस्</translation>
 <translation id="4001540981461989979">माउसको कर्सर सारिँदा त्यसलाई हाइलाइट गरियोस्</translation>
 <translation id="4002440992267487163">Pin सेटअप गर्नुहोस्</translation>
 <translation id="4005817994523282006">प्रामाणिक समय पत्ता लगाउने विधि</translation>
@@ -3654,12 +3672,16 @@
 <translation id="4147911968024186208">कृपया पुनः प्रयास गर्नुहोस्। यो त्रुटि फेरि देख्नुभयो भने कृपया सहायता प्रतिनिधिलाई सम्पर्क गर्नुहोला।</translation>
 <translation id="4150201353443180367">प्रदर्शन</translation>
 <translation id="4150569944729499860">स्क्रिन कन्टेक्स्ट</translation>
+<translation id="4151843924968445052">डिभाइसका सिग्नलहरू सेर गर्ने हो?</translation>
 <translation id="4152011295694446843">तपाईंका बुकमार्कहरू यहाँ देखिने छन्</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{१ ट्याब}other{# ट्याबहरू}}</translation>
 <translation id="4154664944169082762">औँलाछापहरू</translation>
 <translation id="4157869833395312646">Microsoft सर्भर गेटेड क्रिप्टोग्राफी</translation>
 <translation id="4158315983204257156">वेबसाइटको टेक्स्टको आकार र फन्ट</translation>
 <translation id="4158364720893025815">सफ्टवेयर चलाउनका निम्ति आवश्यक पर्ने जाँच पूरा गरियो</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />तपाईंले ChromeOS डिभाइसहरूलाई रिपोर्ट स्वतः पठाउने अनुमति दिनुभयो भने हामी ChromeOS मा सबैभन्दा पहिले समाधान गर्नु पर्ने समस्या र सुधार्नु पर्ने कुराहरूका बारेमा थाहा पाउन सक्छौँ। यी रिपोर्टअन्तर्गत ChromeOS क्र्यास भएको समय, तपाईंले प्रयोग गर्ने सुविधाहरू, तपाईं सामान्यतया कति मेमोरी प्रयोग गर्नुहुन्छ भन्ने कुराको जानकारी र Android एपको डाइग्नोस्टिक तथा प्रयोगसम्बन्धी डेटालगायतका कुराहरू समावेश हुन सक्छन्। केही समग्र जानकारीले Google का एप तथा Android का विकासकर्ता जस्ता साझेदारहरूलाई पनि मद्दत गर्छन्। एपहरू सिंक गर्ने सुविधा पनि अन गरिएको खण्डमा Android तथा वेब एपका साथै अन्य एपका डाइग्नोस्टिक्स तथा प्रयोगसम्बन्धी डेटा सङ्कलन गरिने छ।<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />तपाईं जुनसुकै बेला आफ्नो ChromeOS डिभाइसका सेटिङमा गई यी रिपोर्ट पठाउने अनुमति दिन वा नदिन सक्नुहुन्छ। तपाईं कुनै डोमेनको एड्मिन हुनुहुन्छ भने तपाईं एड्मिन कन्सोलमा गई यो सेटिङ बदल्न सक्नुहुन्छ।<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />तपाईंको Google खाताका हकमा "वेब तथा एपसम्बन्धी गतिविधि" सेटिङ अन गरिएको छ भने Android मा भएको तपाईंको डेटा तपाईंको Google खातामा सेभ गरिन सक्छ। तपाईं account.google.com मा गई आफ्नो डेटा हेर्न, उक्त डेटा मेटाउन र आफ्नो खातासम्बन्धी सेटिङ बदल्न सक्नुहुन्छ।<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">Google पासवर्ड म्यानेजर</translation>
 <translation id="4163560723127662357">अज्ञात कुँजीपाटी</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> वैध सङ्गठनको इमेल ठेगाना होइन। आफ्ना एड्मिनलाई सम्पर्क गर्नुहोस्। तपाईं एड्मिन हुनुहुन्छ भने तपाईं निम्न लिंकमा गएर आफ्नो सङ्गठन सेटअप गर्न सक्नुहुन्छ: g.co/ChromeEnterpriseAccount</translation>
@@ -3983,6 +4005,9 @@
 <translation id="4452898361839215358">वा PPD चयन गर्नुहोस्। <ph name="LINK_BEGIN" />थप जान्नुहोस्<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">किबोर्डको सिरानको दायाँ कुनामा रहेको फिंगरप्रिन्ट सेन्सरमा छुनुहोस्। तपाईंको फिंगरप्रिन्ट डेटा सुरक्षित रूपमा भण्डारण गरिन्छ र यो डेटा कहिल्यै पनि तपाईंको <ph name="DEVICE_TYPE" /> बाट अन्यत्र पठाइँदैन।</translation>
 <translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" /> खोज्नुहोस्‌ वा URL टाइप गर्नुहोस्</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />तपाईंले आफ्ना ChromeOS डिभाइसहरूलाई रिपोर्ट स्वतः पठाउने अनुमति दिनुभयो भने हामी ChromeOS मा सबैभन्दा पहिले समाधान गर्नु पर्ने समस्या र सुधार्नु पर्ने कुराहरूका बारेमा थाहा पाउन सक्छौँ। यी रिपोर्टअन्तर्गत ChromeOS क्र्यास भएको समय, प्रयोग गरिएका सुविधा, सामान्यतया प्रयोग गरिएको मेमोरी र Android एपको डाइग्नोस्टिक तथा प्रयोगसम्बन्धी डेटालगायतका कुराहरू समावेश हुन सक्छन्। केही समग्र जानकारीले Google का एप तथा Android का विकासकर्ता जस्ता साझेदारहरूलाई पनि मद्दत गर्छन्। एपहरू सिंक गर्ने सुविधा पनि अन गरिएको खण्डमा Android तथा वेब एपका साथै अन्य एपका डाइग्नोस्टिक्स तथा प्रयोगसम्बन्धी डेटा सङ्कलन गरिने छ।<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />तपाईं जुनसुकै बेला आफ्ना बच्चाको ChromeOS डिभाइसका सेटिङमा गई यी रिपोर्ट पठाउने अनुमति दिन वा नदिन सक्नुहुन्छ। तपाईं कुनै डोमेनको एड्मिन हुनुहुन्छ भने तपाईं एड्मिन कन्सोलमा गई यो सेटिङ बदल्न सक्नुहुन्छ।<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />तपाईंका बच्चाको Google खाताका हकमा "वेब तथा एपसम्बन्धी गतिविधि" सेटिङ अन गरिएको छ भने Android मा भएको तपाईंका बच्चाको डेटा उहाँको Google खातामा सेभ गरिन सक्छ। तपाईं यी सेटिङका बारेमा र यी सेटिङ मिलाउने तरिकाका बारेमा थप जान्न चाहनुहुन्छ भने families.google.com मा जानुहोस्।<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">वर्तमान आवाज चयन गर्नुहोस्:</translation>
 <translation id="4459169140545916303"><ph name="DEVICE_LAST_ACTIVATED_TIME" /> दिन पहिले सक्रिय</translation>
 <translation id="4460014764210899310">समूह विघटन गर्नुहोस्</translation>
@@ -4362,6 +4387,7 @@
 <translation id="4806457879608775995">यी सर्तहरू पढ्नुहोस् र आफ्नो डेटा नियन्त्रण गर्नुहोस्</translation>
 <translation id="4807098396393229769">कार्डमा रहेको नाम</translation>
 <translation id="4808667324955055115">रोक लगाइएका पपअपहरू:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Chrome वेब स्टोरबाट हटाइएको <ph name="BEGIN_BOLD" />एउटा एक्स्टेन्सन<ph name="END_BOLD" />को समीक्षा गर्नुहोस्}other{Chrome वेब स्टोरबाट हटाइएको <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} वटा एक्स्टेन्सन<ph name="END_BOLD" />को समीक्षा गर्नुहोस्}}</translation>
 <translation id="4809079943450490359">तपाईंको डिभाइसको एड्मिनबाट प्राप्त भएका निर्देशनहरू:</translation>
 <translation id="4809447465126035330">मेटाउनुहोस्</translation>
 <translation id="480990236307250886">गृह पृष्ठ खोल्नुहोस्</translation>
@@ -4685,6 +4711,7 @@
 <translation id="5101839224773798795">कर्सर रोकिँदा स्वतः क्लिक गर्नुहोस्</translation>
 <translation id="5106350808162641062">हटाउनुहोस्</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> Family Link मार्फत सुपरिवेक्षण गरिएको छ। अभिभावकको निगरानीमा विद्यालयका स्रोत साधन प्रयोग गर्न तिमी विद्यालयका खाता थप्न सक्छौ।</translation>
+<translation id="5107093668001980925"><ph name="MODULE_NAME" /> कहिल्यै पनि नदेखाइयोस्</translation>
 <translation id="5107443654503185812">एउटा एक्स्टेन्सनले सुरक्षित ब्राउजिङ सेवा निष्क्रिय पारेको छ</translation>
 <translation id="5108967062857032718">सेटिङहरू - Android एपहरूलाई हटाउनुहोस्</translation>
 <translation id="5109044022078737958">मिया</translation>
@@ -4695,6 +4722,7 @@
 <translation id="5111794652433847656">यो डिभाइसमा <ph name="APP_NAME" /> को कुनै पनि पासकी छैन</translation>
 <translation id="5112577000029535889">&amp;विकासकर्ता उपकरणहरू</translation>
 <translation id="511313294362309725">फास्ट पेयर अन गर्नुहोस्</translation>
+<translation id="5113384440341086023">Play स्टोरबाट इन्स्टल गरिएका एप र Chrome ब्राउजरबाट प्राप्त गरिएका वेब एपहरू</translation>
 <translation id="51143538739122961">आफ्नो सुरक्षा साँचो प्रविष्टि गर्नुहोस् र यसलाई छोएर अन गर्नुहोस्</translation>
 <translation id="5115309401544567011">कृपया आफ्नो <ph name="DEVICE_TYPE" /> लाई पावर स्रोतमा जोड्नुहोस्‌।</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4740,6 +4768,7 @@
 <translation id="5154702632169343078">विषय</translation>
 <translation id="5155327081870541046">एड्रेस बारमा आफूले जुन साइटमा खोज्न चाहेको हो सो साइटको सर्टकट (जस्तै "@bookmarks") टाइप गर्नुहोस्। अनि किबोर्डमा आफ्नो रोजाइको सर्टकट थिचेर खोज पद हाल्नुहोस्।</translation>
 <translation id="5156638757840305347">कर्सर देखा पर्दा वा यताउता सर्दा त्यसलाई हाइलाइट गरिन्छ</translation>
+<translation id="5157250307065481244">साइटसम्बन्धी विवरणहरू हेर्नुहोस्</translation>
 <translation id="5157635116769074044">यस पृष्ठलाई सुरुवात स्क्रिनमा पिन गर्नुहोस्...</translation>
 <translation id="5158206172605340248">एक्सेन्ट चिन्हहरूको मेनु खारेज गरिएको छ।</translation>
 <translation id="5159094275429367735">Crostini सेटअप गर्नुहोस्</translation>
@@ -5798,6 +5827,7 @@
 <translation id="6104068876731806426">Google खाताहरू</translation>
 <translation id="6104311680260824317">यन्त्रलाई उक्त डोमेनसँग जोड्न सकिँदैन। सर्भरले तोकिएको Kerberos नामक इन्क्रिप्सनका प्रकारहरूलाई समर्थन गर्दैन। इन्क्रिप्सनसम्बन्धी सेटिङहरूका लागि "थप विकल्पहरू" जाँच गर्नुहोस्।</translation>
 <translation id="6104796831253957966">प्रिन्ट गर्नु पर्ने कार्यहरूको सूची भरिएको छ</translation>
+<translation id="6106167152849320869">तपाईंले यसअघिको चरणमा डाइग्नोस्टिक तथा प्रयोगसम्बन्धी डेटा पठाउने विकल्प पनि छनौट गर्नुभएको छ भने इन्स्टल गरिएका एपहरूबाट यो डेटा पनि सङ्कलन गरिने छ।</translation>
 <translation id="6111972606040028426">Google सहायक सक्षम पार्नुहोस्</translation>
 <translation id="6112294629795967147">पुनः आकार मिलाउन छुनुहोस्</translation>
 <translation id="6112727384379533756">एउटा टिकट थप्नुहोस्</translation>
@@ -5928,6 +5958,7 @@
 <translation id="6226777517901268232">निजी साँचोको फाइल (ऐच्छिक):</translation>
 <translation id="6227002569366039565">तपाईं यो बबलमा फोकस गर्न चाहनुहुन्छ भने |<ph name="ACCELERATOR" />| थिच्नुहोस्, अनि त्यसले इसारा गरिरहेको एलिमेन्टमा फोकस गर्न उक्त की फेरि थिच्नुहोस्।</translation>
 <translation id="6227280783235722609">एक्स्टेन्सन</translation>
+<translation id="6229062790325126537">ApnMigrator रिसेट गर्नुहोस्</translation>
 <translation id="6229849828796482487">Wi-Fi इन्टरनेट डिस्कनेक्ट गर्नुहोस्</translation>
 <translation id="6231782223312638214">सुझाव गरिएको</translation>
 <translation id="6231881193380278751">पृष्ठ स्वत:-रिफ्रेस गर्न URL मा क्वेरि पाराम थप्नुहोस्: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6205,6 +6236,7 @@
 <translation id="6478248366783946499">खतरनाक फाइल राख्ने हो?</translation>
 <translation id="6479881432656947268">Chrome वेब स्टोरमा जानुहोस्</translation>
 <translation id="6480327114083866287"><ph name="MANAGER" /> ले व्यवस्थापन गर्छ</translation>
+<translation id="6481978993812487794">तपाईंले सिंक गर्ने सुविधा अन गर्नुभयो भने तपाईंले जुन जुन Chrome OS डिभाइसमा आफ्नो Google खातामार्फत साइन इन गर्नुहुन्छ ती डिभाइसहरूमा तपाईंका एपहरू उपलब्ध हुने छन्। अन्य ब्राउजरका सिंक गर्ने सुविधा अफ भए तापनि वेब एपहरू Chrome मार्फत सिंक गरिने छन्।</translation>
 <translation id="6482559668224714696">फुल स्क्रिन म्याग्निफायर</translation>
 <translation id="6483485061007832714">डाउनलोड खोल्नुहोस्</translation>
 <translation id="6483805311199035658"><ph name="FILE" /> खोल्दै...</translation>
@@ -6219,6 +6251,7 @@
 <translation id="6497784818439587832">स्क्रिनमा भएका वस्तुहरूलाई अझ ठुलो वा सानो बनाउन डिस्प्लेको आकार परिवर्तन गर्नुहोस्</translation>
 <translation id="6497789971060331894">माउस विपरीत दिशामा स्क्रोल गर्ने कार्य</translation>
 <translation id="6498249116389603658">&amp;तपाईँका सबै भाषाहरू</translation>
+<translation id="6498583202177273322">यो पेज हेर्दै गर्दा अतिरिक्त उपयोगी जानकारी प्राप्त गर्नुहोस्</translation>
 <translation id="6499143127267478107">प्रोक्सी स्क्रिप्टमा होस्ट विघटन गर्दै...</translation>
 <translation id="6499764981457476645">वरपर कुनै पनि डिभाइस भेटिएन</translation>
 <translation id="6501957628055559556">सबै कन्टेनरहरू</translation>
@@ -6665,6 +6698,7 @@
 <translation id="688312408602122936">यो डिभाइसबाट Steam मार्फत इन्स्टल गरिएका सबै गेम तथा एपहरू पनि हटाइने छन्</translation>
 <translation id="6883319974225028188">हत्तेरिका! प्रणालीले यन्त्रको कन्फिगुरेसन सुरक्षित गर्न सकेन।</translation>
 <translation id="6884474387073389421">तपाईंले चयन गरिएका साइन इन डेटा मेटाउन खोज्नुभएकै हो?</translation>
+<translation id="6885122019363983153">सबै डिभाइसहरूमा डेस्कटप ब्याकग्राउन्ड सिंक गरियोस्</translation>
 <translation id="6885771755599377173">प्रणाली जानकारीको पूर्वावलोकन</translation>
 <translation id="6886380424988777998">Linux अपग्रेड गर्न सकिएन</translation>
 <translation id="6886871292305414135">लिङलाई नयाँ &amp;ट्याबमा खिल्नुहोस्</translation>
@@ -6736,6 +6770,7 @@
 <translation id="6949434160682548041">पासवर्ड (ऐच्छिक)</translation>
 <translation id="6950627417367801484">एपहरू पुनर्स्थापित गर्नुहोस्</translation>
 <translation id="6952242901357037157">तपाईं यहाँ आफ्नो <ph name="BEGIN_LINK" />Google खाता<ph name="END_LINK" />मा सुरक्षित गरिएका पासवर्डहरू पनि देखाउन सक्नुहुन्छ</translation>
+<translation id="6954910832698269894">आफ्नो पुरानो Chromebook मा भएका प, सेटिङ Wi-Fi नेटवर्क र वालपेपर रिस्टोर गर्न डिभाइस सिंक गर्ने सुविधा अन गर्नुहोस्। जुनसुकै बेला "सेटिङ &gt; खाताहरू" मा गई परिवर्तनहरू गर्नुहोस्।</translation>
 <translation id="6954936693361896459">यसको साटो यो ट्याब कास्ट गर्नुहोस्</translation>
 <translation id="6955446738988643816">पपअप निरीक्षण गर्नुहोस्</translation>
 <translation id="6955535239952325894">व्यवस्थापन गरिएका ब्राउजरहरूमा यो सेटिङ असक्षम पारिएको हुन्छ</translation>
@@ -6894,6 +6929,7 @@
 <translation id="7075513071073410194">PKCS #1 MD2 सँग RSA गुप्तलेखन</translation>
 <translation id="7075625805486468288">HTTPS/SSL सम्बन्धी प्रमाणपत्र र सेटिङहरूको व्यवस्थापन गर्नुहोस्</translation>
 <translation id="7076875098323397992">अपग्रेड गर्ने कार्य सुरु गर्न सकिएन</translation>
+<translation id="7077751457066325012">किबोर्डका सर्टकटहरू हेर्नुहोस् र कस्टमाइज गर्नुहोस्</translation>
 <translation id="7077829361966535409">साइन पृष्ठ हालको प्रोक्सी सेटिङहरू प्रयोग गरेर लोड हुन असफल भयो। कृपया <ph name="GAIA_RELOAD_LINK_START" />पुन: साइन इन गर्ने प्रयास गर्नुहोस्<ph name="GAIA_RELOAD_LINK_END" />, वा फरक <ph name="PROXY_SETTINGS_LINK_START" />प्रोक्सी सेटिङहरू<ph name="PROXY_SETTINGS_LINK_END" /> प्रयोग गर्नुहोस</translation>
 <translation id="7078120482318506217">सबै नेटवर्कहरू</translation>
 <translation id="708060913198414444">अडियो ठेगाना कपी गर्नुहोस्</translation>
@@ -6923,6 +6959,7 @@
 <translation id="7108933416628942903">अब लक गर्नुहोस्</translation>
 <translation id="7109543803214225826">सर्टकट हटाइयो</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{समूहमा ट्याब थप्नुहोस्}other{समूहमा ट्याबहरू थप्नुहोस्}}</translation>
+<translation id="7110684627876015299">नाम नभएको समूह - <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">यो विन्डोको नाम राख्नुहोस्</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> वटा वस्तु</translation>
 <translation id="7113502843173351041">आफ्नो इमेल ठेगाना थाहा पाउनुहोस्</translation>
@@ -7137,6 +7174,7 @@
 <translation id="7328867076235380839">अमान्य संयोजन</translation>
 <translation id="7329154610228416156">साइन इन विफल  भयो किनभने यसलाई एउटा गैर-सुरक्षित URL (<ph name="BLOCKED_URL" />) सँग कन्फिगर गरिएको थियो। कृपया तपाईँको प्रशासकसँग सम्पर्क गर्नुहोस्।</translation>
 <translation id="7332053360324989309">यसै कामको लागि तोकिएको कर्मचारी: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">आफ्ना एप र सेटिङहरू ब्याकअप र रिस्टोर गर्नुहोस्</translation>
 <translation id="7335974957018254119">यी भाषाहरूका लागि हिज्जे जाँच प्रयोग गर्नुहोस्</translation>
 <translation id="7336799713063880535">सूचनालाई रोक लगाइयो।</translation>
 <translation id="7338630283264858612">यन्त्रको क्रम सङ्ख्या अमान्य छ।</translation>
@@ -7159,6 +7197,7 @@
 <translation id="7348093485538360975">अन्-स्क्रिन कुञ्जीपाटी</translation>
 <translation id="7349010927677336670">अवरोधविना भिडियो चल्ने गति</translation>
 <translation id="7352651011704765696">कुनै त्रुटि भयो</translation>
+<translation id="7352664183151911163">आफ्ना Chrome ब्राउजर र आफ्ना एपहरू प्रयोग गर्नुहोस्</translation>
 <translation id="7353261921908507769">तपाईं वरपर हुँदा तपाईंको कन्ट्याक्टमा भएका व्यक्तिहरू सामग्री सेयर गर्न सक्छन्। तपाईंले सामग्री सार्ने निम्तो स्वीकार नगरेसम्म सामग्री सार्ने काम सुरु हुँदैन।</translation>
 <translation id="735361434055555355">Linux स्थापना गर्दै...</translation>
 <translation id="7354120289251608189">तपाईं अब जुनसुकै बेला आफ्नो ब्राउजरलाई नयाँ स्वरूप दिन सक्नुहुन्छ।</translation>
@@ -7298,6 +7337,8 @@
 <translation id="7458168200501453431">Google खोजमा प्रयोग हुने स्पेल चेकर नै प्रयोग गर्छ। तपाईंले ब्राउजरमा टाइप गर्नुभएको पाठ Google लाई पठाइन्छ।</translation>
 <translation id="7458715171471938198">एपहरू रिस्टोर गर्ने हो?</translation>
 <translation id="7458933488302148148">तपाईं आफ्नो खाता अझ सुरक्षित राख्नुका साथै इन्टरनेटमा अझ सुरक्षित रहन चाहनुहुन्छ भने आफूले सेभ गरेका पासवर्डहरू जाँच्नुहोस्</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />तपाईंले ChromeOS डिभाइसहरूलाई रिपोर्ट स्वतः पठाउने अनुमति दिनुभयो भने हामी ChromeOS मा सबैभन्दा पहिले समाधान गर्नु पर्ने समस्या र सुधार्नु पर्ने कुराहरूका बारेमा थाहा पाउन सक्छौँ। यी रिपोर्टअन्तर्गत ChromeOS क्र्यास भएको समय, तपाईंले प्रयोग गर्ने सुविधा र तपाईंले सामान्यतया प्रयोग गर्ने मेमोरीलगायतका कुराहरू समावेश हुन सक्छन्। एपहरू सिंक गर्ने सुविधा पनि अन गरिएको खण्डमा Android तथा वेब एपका साथै अन्य एपका डाइग्नोस्टिक्स तथा प्रयोगसम्बन्धी डेटा सङ्कलन गरिने छ।<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />तपाईं जुनसुकै बेला आफ्नो Chrome डिभाइसका सेटिङमा गई यी रिपोर्ट पठाउने अनुमति दिन वा नदिन सक्नुहुन्छ। तपाईं कुनै डोमेनको एड्मिन हुनुहुन्छ भने तपाईं एड्मिन कन्सोलमा गई यो सेटिङ बदल्न सक्नुहुन्छ।<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">तपाईंले स्थापना गर्नुभएको हालको विषयवस्तु</translation>
 <translation id="7461924472993315131">पिन</translation>
 <translation id="746216226901520237">अर्को पटकदेखि, तपाईंको फोनले तपाईंको <ph name="DEVICE_TYPE" /> अनलक गर्ने छ। तपाईं सेटिङहरूमा गई Smart Lock निष्क्रिय पार्न सक्नुहुन्छ।</translation>
@@ -7531,6 +7572,7 @@
 <translation id="7663719505383602579">रिसिभर: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">किबोर्डको सर्टकट उपलब्ध छ</translation>
 <translation id="7663859337051362114">eSIM प्रोफाइल हाल्नुहोस्</translation>
+<translation id="76641554187607347">कुनै पनि किबोर्ड कनेक्ट गरिएको छैन</translation>
 <translation id="7665082356120621510">आकार रिजर्भ गर्नुहोस्</translation>
 <translation id="7665369617277396874">खाता थप्नुहोस्</translation>
 <translation id="766560638707011986">डोमेनहरू देखाइयोस्</translation>
@@ -7578,6 +7620,7 @@
 <translation id="769824636077131955">यो डकुमेन्ट सुरक्षासम्बन्धी जाँच गर्नै नमिल्ने गरी ठुलो छ। तपाईं बढीमा ५० एम.बि. सम्मका डकुमेन्टहरू प्रिन्ट गर्न सक्नुहुन्छ।</translation>
 <translation id="7698507637739331665">केही वस्तुहरू ब्लक गरिएका छन्</translation>
 <translation id="7701040980221191251">कुनै पनि होइन</translation>
+<translation id="7701265686005869308">प्रोफाइल बन्द गर्नुहोस्</translation>
 <translation id="7701869757853594372">प्रयोगकर्ताले सम्हाल्नेहरू</translation>
 <translation id="7702574632857388784">सूचीबाट <ph name="FILE_NAME" /> हटाउनुहोस्</translation>
 <translation id="7702907602086592255">डोमेन</translation>
@@ -7999,6 +8042,7 @@
 <translation id="8050191834453426339">फेरि पुष्टि गर्नुहोस्</translation>
 <translation id="8051193500142930381">क्यामेरा प्रयोग गर्ने सुविधाहरूले काम गर्ने छैनन्</translation>
 <translation id="8051390370038326517"><ph name="HOST" /> लाई सधैँ MIDI यन्त्रहरू पूर्ण रूपमा नियन्त्रण गर्न दिनुहोस्</translation>
+<translation id="8052218774860457016">ब्राउजर सिंक गर्ने सेटिङ मिलाउनुहोस्</translation>
 <translation id="8053278772142718589">PKCS # 12 फाइलहरू</translation>
 <translation id="8053390638574070785">यो पृष्ठलाई पुन: लोड गर्नुहोस्</translation>
 <translation id="8054517699425078995">यस प्रकारको फाइल तपाइँको यन्त्रको लागि हानिकारक हुन सक्छ। के तपाइँ अझै पनि <ph name="FILE_NAME" /> राख्न चाहनुहुन्छ?</translation>
@@ -8368,6 +8412,7 @@
 <translation id="8376137163494131156">हामीलाई Google Cast मा के भइरहेको छ भन्ने कुरा बताउनुहोस्।</translation>
 <translation id="8376384591331888629">यस साइटका तेस्रो पक्षीय कुकीसमेत</translation>
 <translation id="8376451933628734023">यो वेब एपले अर्कै एप जस्तो बनेर तपाईंलाई झुक्याउन खोज्दै छ भने यसलाई अनइन्स्टल गरिहाल्नुहोस्।</translation>
+<translation id="8376752431516546391">Google Search को साइड प्यानल</translation>
 <translation id="8377625247046155446">यो पासकी यस डिभाइसमा मात्र सेभ गरिने छ। तपाईंले सबै इन्कोग्निटो विन्डो बन्द गरेपछि पनि यो पासकी यस डिभाइसमा रहने छ।</translation>
 <translation id="8378714024927312812">तपाईंको सङ्गठनले व्यवस्थापन गरेको</translation>
 <translation id="8379878387931047019">यस यन्त्रले यो वेबसाइटले अनुरोध गरेको प्रकारको सुरक्षा साँचो प्रयोग गर्दैन</translation>
@@ -8435,6 +8480,11 @@
 <translation id="8428628598981198790">तपाईंको सुरक्षा साँचो यस साइटमा प्रयोग गर्न सकिँदैन</translation>
 <translation id="84297032718407999"><ph name="LOGOUT_TIME_LEFT" /> मा तपाईंलाई साइन आउट गरिने छ</translation>
 <translation id="8431190899827883166">ट्याप देखाइयोस्</translation>
+<translation id="8431496281632382473">यो प्रोफाइल व्यवस्थापन गर्ने डोमेन: <ph name="DOMAIN" /> तपाईंको सङ्गठनले तोकेका मापदण्डअनुसार तपाईंले आफ्नो डिभाइसका सिग्नलहरू सेयर गर्नुभयो भने मात्र तपाईं यो व्यवस्थापन गरिएको प्रोफाइल प्रयोग गरिराख्न सक्नुहुन्छ।
+
+डिभाइसका सिग्नलहरूमा तपाईंका ब्राउजर, OS, डिभाइस, इन्स्टल गरिएका सफ्टवेयर र फाइलहरूसम्बन्धी जानकारी समावेश हुन सक्छन्।
+
+तपाईंले सिग्नलहरू सेर नगर्ने विकल्प छनौट गर्नुभयो भने यो प्रोफाइल बन्द गरिने छ।</translation>
 <translation id="8434480141477525001">NaCl डिबग पोर्ट</translation>
 <translation id="8437209419043462667">US</translation>
 <translation id="8438328416656800239">कुनै स्मार्ट ब्राउजरमा स्विच गर्नुहोस्</translation>
@@ -8519,6 +8569,8 @@
 <translation id="851263357009351303">फोटो देखाउन <ph name="HOST" /> लाई सधैँ अनुमति दिनुहोस्</translation>
 <translation id="8513108775083588393">स्वतः परिक्रमा</translation>
 <translation id="8513357934662532537">तपाईं <ph name="USER_EMAIL" /> का पासवर्डहरू <ph name="BRAND" /> मा इम्पोर्ट गर्न चाहनुहुन्छ भने कुनै CSV फाइल छनौट गर्नुहोस्।</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />तपाईंले आफ्ना ChromeOS डिभाइसहरूलाई रिपोर्ट स्वतः पठाउने अनुमति दिनुभयो भने हामी ChromeOS मा सबैभन्दा पहिले समाधान गर्नु पर्ने समस्या र सुधार्नु पर्ने कुराहरूका बारेमा थाहा पाउन सक्छौँ। यी रिपोर्टअन्तर्गत ChromeOS क्र्यास भएको समय, प्रयोग गरिएका सुविधा, सामान्यतया प्रयोग गरिएको मेमोरीलगायतका कुराहरू समावेश हुन सक्छन्। एपहरू सिंक गर्ने सुविधा पनि अन गरिएको खण्डमा Android तथा वेब एपका साथै अन्य एपका डाइग्नोस्टिक्स तथा प्रयोगसम्बन्धी डेटा सङ्कलन गरिने छ।<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />तपाईं जुनसुकै बेला आफ्ना बच्चाको ChromeOS डिभाइसका सेटिङमा गई यी रिपोर्ट पठाउने अनुमति दिन वा नदिन सक्नुहुन्छ। तपाईं कुनै डोमेनको एड्मिन हुनुहुन्छ भने तपाईं एड्मिन कन्सोलमा गई यो सेटिङ बदल्न सक्नुहुन्छ।<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">कुनै अर्को सुरक्षा साँचो प्रयोग गरी हेर्नुहोस्</translation>
 <translation id="8514955299594277296">साइटहरूलाई तपाईंको डिभाइसमा जानकारी सेभ गर्ने अनुमति नदिनुहोस् (सिफारिस गरिएको छैन)</translation>
 <translation id="8517759303731677493">सम्पादन गर्नुहोस्…</translation>
@@ -8879,6 +8931,7 @@
 <translation id="883062543841130884">प्रतिस्थापनहरू</translation>
 <translation id="8830779999439981481">अपडेटहरू लागू गर्न रिस्टार्ट गरिँदै छ</translation>
 <translation id="8830796635868321089">अद्यावधिक जाँच वर्तमान प्रोक्सी सेटिङ प्रयोग असफल भयो । आफ्नो समायोजन गर्नुहोस् <ph name="PROXY_SETTINGS_LINK_START" /> प्रोक्सी सेटिङ <ph name="PROXY_SETTINGS_LINK_END" /> गर्नुहोस् ।</translation>
+<translation id="8830863983385452402">यो साइटले यो ट्याबमा भएका सामग्री हेर्न सक्ने छ</translation>
 <translation id="8831769650322069887"><ph name="FILE_NAME" /> खोल्नुहोस्</translation>
 <translation id="8832781841902333794">तपाईंका प्रोफाइलहरू</translation>
 <translation id="8834039744648160717">नेटवर्कको कन्फिगुरेसन <ph name="USER_EMAIL" /> द्वारा नियन्त्रण गरिएको छ।</translation>
@@ -9010,6 +9063,7 @@
 <translation id="8946359700442089734">डिबग सुविधाहरु पूर्ण तरिकाले यस <ph name="IDS_SHORT_PRODUCT_NAME" /> उपकरणमा सक्षम थिएनन्।</translation>
 <translation id="894763922177556086">राम्रो</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> तपाईंको सुरक्षा साँचोको ब्रान्डको नाम र मोडेल हेर्न चाहन्छ</translation>
+<translation id="8949304443659090542">Chrome ब्राउजरको सिंक गर्ने सुविधा व्यवस्थापन गर्नुहोस्</translation>
 <translation id="895054485242522631">साइटहरूले मोसन सेन्सरहरू प्रयोग गर्न सक्छन्</translation>
 <translation id="8951256747718668828">कुनै त्रुटि भएका कारण पुनर्स्थापना पूरा गर्न सकिएन</translation>
 <translation id="8951465597020890363">जे भए पनि अतिथि मोड छाडेर बाहिरिने हो?</translation>
@@ -9115,6 +9169,7 @@
 <translation id="9032097289595078011">फास्ट पेयर अफ गर्नुहोस्</translation>
 <translation id="9033765790910064284">जे भए पनि जारी राख्नुहोस्</translation>
 <translation id="9033857511263905942">&amp;टाँस्नुहोस्</translation>
+<translation id="9034408118624208974">तपाईं Chromebook को नयाँ प्रयोगकर्ता हुनुहुन्छ? तपाईंका प्राथमिकताहरू ब्याकअप गरिऊन् भन्नाका लागि सिंक गर्ने सुविधा अन गर्नुहोस्।</translation>
 <translation id="903480517321259405">PIN फेरि टाइप गर्नुहोस्</translation>
 <translation id="9037054491984310631"><ph name="DEVICE" /> नामक ब्लुटुथ डिभाइसमा कनेक्ट गरिएको छ</translation>
 <translation id="9037640663275993951">यो डिभाइस प्रयोग गर्ने अनुमति दिइएको छैन</translation>
@@ -9158,6 +9213,7 @@
 <translation id="9068298336633421551">लोकेसन प्रयोग गर्ने अनुमति पाएका Android का एप तथा सेवाहरूलाई यस डिभाइसको लोकेसन प्रयोग गर्न दिनुहोस्। Google ले आवधिक रूपमा लोकेसन डेटा सङ्कलन गर्ने, सटीक लोकेसन पत्ता लगाउने र लोकेसनमा आधारित सेवाहरूको गुणस्तर सुधार्ने प्रयोजनका लागि व्यक्तिगत पहिचान नखुल्ने गरी यो डेटा प्रयोग गर्न सक्छ।</translation>
 <translation id="9068598199622656904">किबोर्डका सर्टकट प्रयोग गर्दा विभिन्न की एकै पटक थिच्नुको साटो एक पटकमा एउटा मात्र की थिच्नुहोस्</translation>
 <translation id="9068878141610261315">यस प्रकारको फाइल सेयर गर्न सकिँदैन</translation>
+<translation id="9069665781180028115">यो Chromebook मा उपलब्ध हुने सामग्रीहरू चयन गर्नुहोस्। तपाईं Chromebook को नयाँ प्रयोगकर्ता हुनुहुन्छ भने तपाईंका प्राथमिकताहरू ब्याक अप गरिऊन् भन्नाका लागि सबै सामग्रीहरू सिंक गर्नुहोस्। जुनसुकै बेला "सेटिङ &gt; खाताहरू" मा गई परिवर्तनहरू गर्नुहोस्।</translation>
 <translation id="9070342919388027491">यो ट्याब बायाँतिर सारियो</translation>
 <translation id="9074739597929991885">ब्लुटुथ</translation>
 <translation id="9074836595010225693">USB माउस जडित</translation>
@@ -9331,6 +9387,7 @@
 <translation id="930268624053534560">विस्तृत टाइमस्ट्याम्पहरू</translation>
 <translation id="930551443325541578">की र एक्सेन्ट चिन्हहरू दोहोर्‍याइयोस्</translation>
 <translation id="930893132043726269">हाल रोमिङ नेटवर्क प्रयोग गरिँदै छ</translation>
+<translation id="930991362911221750"><ph name="APP_NAME" /> लाई यो ट्याब हेर्न दिने हो?</translation>
 <translation id="93140074055951850">Android एपहरूले काम गर्न छाडेका छन्</translation>
 <translation id="932327136139879170">गृहपृष्ठ</translation>
 <translation id="932508678520956232">प्रिन्ट प्रारम्भ गर्न सकेन।</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 2db6999..95222d1 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -8378,7 +8378,7 @@
 <translation id="835951711479681002">Salvar na sua Conta do Google</translation>
 <translation id="8360140320636871023">Personalizar o tema da tela</translation>
 <translation id="8360267485906769442">Botão "Enviar feedback"</translation>
-<translation id="8362914115861174987">Traduzir para o</translation>
+<translation id="8362914115861174987">Traduzir para </translation>
 <translation id="8363095875018065315">estável</translation>
 <translation id="8363142353806532503">Microfone bloqueado</translation>
 <translation id="8366396658833131068">Sua conectividade de rede foi restaurada. Selecione outra rede ou pressione o botão "Continuar" abaixo para iniciar seu aplicativo de quiosque.</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index ab8ebf8..05173550 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -2348,7 +2348,7 @@
 <translation id="2989123969927553766">Accelerarea derulării cu mouse-ul</translation>
 <translation id="2989474696604907455">neconectat</translation>
 <translation id="2989786307324390836">Certificat unic, sub formă de fișier binar cu codificarea DER</translation>
-<translation id="2989805286512600854">Deschideți într-o filă nouă</translation>
+<translation id="2989805286512600854">Deschide într-o filă nouă</translation>
 <translation id="2990313168615879645">Adaugă Contul Google</translation>
 <translation id="2990583317361835189">Nu permite site-urilor să folosească senzori de mișcare</translation>
 <translation id="2992931425024192067">Afișează integral conținutul notificărilor</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index ac0ee5d..cc203f8 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -218,6 +218,7 @@
 <translation id="1176471985365269981">మీ పరికరంలోని ఫైళ్లు లేదా ఫోల్డర్‌లను ఎడిట్ చేయడానికి అనుమతించబడలేదు</translation>
 <translation id="1177863135347784049">అనుకూల</translation>
 <translation id="1178581264944972037">పాజ్ చేయి</translation>
+<translation id="1178601482396475810">పరికర సింక్‌ను మేనేజ్ చేయండి</translation>
 <translation id="117916940443676133">మీ 'సెక్యూరిటీ కీ'కి పిన్ రక్షణ లేదు. సైన్-ఇన్ డేటాను మేనేజ్ చేయడానికి, ముందు పిన్‌ను క్రియేట్ చేయండి.</translation>
 <translation id="1181037720776840403">తీసివేయండి</translation>
 <translation id="1181366777303791449"><ph name="MAIN_FRAME_ETLD_PLUS_ONE" />‌లో</translation>
@@ -355,6 +356,7 @@
 <translation id="130097046531636712">బ్యాక్‌గ్రౌండ్ యాక్టివిటీని, సున్నితమైన స్క్రోలింగ్ వంటి విజువల్ ఎఫెక్ట్‌లను పరిమితం చేయడం ద్వారా ఇది బ్యాటరీ పవర్‌ను పెంచుతుంది</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> కింది ఫైళ్లను సవరించగలదు</translation>
 <translation id="1302227299132585524">Apple ఈవెంట్‌ల నుండి JavaScriptని అనుమతించండి</translation>
+<translation id="1302654693270046655"><ph name="GROUP_NAME" /> గ్రూప్ - <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">HTML ఫైల్‌ని బుక్‌మార్క్ చేస్తుంది</translation>
 <translation id="1303671224831497365">బ్లూటూత్ పరికరాలు ఏవీ కనుగొనబడలేదు</translation>
 <translation id="130491383855577612">Linux యాప్‌లు, ఫైళ్లు విజయంతంగా భర్తీ చేయబడ్డాయి</translation>
@@ -1060,6 +1062,7 @@
 <translation id="1877520246462554164">ప్రమాణీకరణ టోకెన్‌ను పొందడం విఫలమైంది. దయచేసి సైన్ అవుట్ చేసి, సైన్ ఇన్ చేసిన తర్వాత మళ్లీ ట్రై చేయండి.</translation>
 <translation id="1877860345998737529">స్విచ్ చర్య కేటాయింపు</translation>
 <translation id="1878155070920054810">అప్‌డేట్ పూర్తయ్యే లోపు మీ Chromebook పవర్ అయిపోయేటట్లు కనిపిస్తోంది. అంతరాయాన్ని నివారించడానికి ఇది సరిగ్గా ఛార్జింగ్ అవుతోందని నిర్ధారించుకోండి.</translation>
+<translation id="1878477879455105085">తెరిచి ఉంది</translation>
 <translation id="1878885068166344708">మీరు ఐటెమ్‌పై ఫోకస్ చేసినప్పుడు, ఐటెమ్ హైలైట్ అవుతుంది. ఫోకస్‌ను మార్చడానికి ట్యాబ్‌ను నొక్కండి లేదా ఐటెమ్‌ను ఎంచుకోండి.</translation>
 <translation id="1879000426787380528">ఇలా సైన్ ఇన్ చేయండి</translation>
 <translation id="18802377548000045">ట్యాబ్‌లు అధిక వెడల్పునకు కుదించబడతాయి</translation>
@@ -1444,6 +1447,7 @@
 <translation id="2204034823255629767">మీరు టైప్ చేసేదాన్ని చదవడం మరియు మార్చడం</translation>
 <translation id="2204387456724731099">ఈ ఎంపికను అనువదించడం సాధ్యపడలేదు</translation>
 <translation id="2210462644007531147">ఇన్‌స్టాలేషన్‌ను పూర్తి చేయడం సాధ్యపడలేదు</translation>
+<translation id="2211245494465528624">సింక్ ఆప్షన్‌లను మేనేజ్ చేయండి</translation>
 <translation id="2212565012507486665">కుక్కీలను అనుమతించండి</translation>
 <translation id="2214018885812055163">షేర్ చేసిన ఫోల్డర్‌లు</translation>
 <translation id="2214884991347062907">పాస్‌వర్డ్ తప్పు, మళ్లీ ట్రై చేయండి</translation>
@@ -1542,6 +1546,7 @@
 <translation id="2296218178174497398">పరికర శోధన</translation>
 <translation id="2297705863329999812">ప్రింటర్‌లను వెతకండి</translation>
 <translation id="2297822946037605517">ఈ పేజీని షేర్ చేయండి</translation>
+<translation id="229871422646860597">టూల్‌బార్ నుండి పిన్‌ను తీసివేయండి</translation>
 <translation id="2299734369537008228">స్లయిడర్: <ph name="MIN_LABEL" /> నుండి <ph name="MAX_LABEL" /> వరకు</translation>
 <translation id="2299941608784654630">debugd ద్వారా సేకరించబడిన అన్ని లాగ్ ఫైళ్లను వేరుగా ఆర్కైవ్ లాగా చేర్చండి.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2172,6 +2177,7 @@
 <translation id="2811205483104563968">ఖాతాలు</translation>
 <translation id="2811564570599779918">స్పామ్, మోసాన్ని తగ్గించడం</translation>
 <translation id="2812049959647166806">Thunderboltలో మద్దతు లేదు</translation>
+<translation id="2812171980080389735">నెట్‌వర్క్‌లు, పాస్‌వర్డ్‌లను సేవ్ చేయండి, తద్వారా మీరు తక్షణమే కనెక్ట్ అవ్వగలరు</translation>
 <translation id="2813094189969465044">తల్లిదండ్రుల నియంత్రణలు</translation>
 <translation id="281390819046738856">రిక్వెస్ట్‌కు సంతకం అందించడం సాధ్యపడలేదు.</translation>
 <translation id="2814489978934728345">ఈ పేజిని లోడ్ చేయడం ఆపు</translation>
@@ -2211,6 +2217,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">మీ PINను జోడించడం జరిగింది</translation>
 <translation id="2849936225196189499">క్లిష్టమైన</translation>
+<translation id="285033512555869047">మూసివేసి ఉంది</translation>
 <translation id="2850541429955027218">థీమ్‌ను జోడించండి</translation>
 <translation id="2850672011315104382">విరామచిహ్న స్టయిల్</translation>
 <translation id="2852385257476173980">మీరు వెబ్‌లో బ్రౌజ్ చేస్తున్నప్పుడు, మీరు సందర్శించే సైట్‌ల లిస్ట్ ఇక్కడ కనిపించవచ్చు</translation>
@@ -2254,6 +2261,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" />, ఇంకా మరో <ph name="NUMBER_OF_DEVICES" /></translation>
 <translation id="2889043468805635730">సమస్యలు ఏవీ కనుగొనబడలేదు</translation>
 <translation id="2889064240420137087">దీనితో లింక్ తెరువు...</translation>
+<translation id="2890206081124517553">పరికరాల అంతటా మీ డెస్క్‌టాప్ బ్యాక్‌గ్రౌండ్‌ను గుర్తుంచుకోండి</translation>
 <translation id="2891566119238851894">సైడ్ ప్యానెల్‌లో సెర్చ్‌ను తెరవండి. సైడ్ ప్యానెల్‌లో సెర్చ్ తెరిచి లేదు.</translation>
 <translation id="2891922230654533301"><ph name="APP_NAME" />కు సైన్ ఇన్ చేయడానికి మీ పరికరాన్ని ఉపయోగించాలా?</translation>
 <translation id="2893013536106749396">మీరు ముఖ్యం అనుకునే విషయాల గురించి మీకు తెలియజేసే కార్డ్‌లను ఎంచుకోండి</translation>
@@ -2275,6 +2283,7 @@
 <translation id="2907619724991574506">ప్రారంభ URLలు</translation>
 <translation id="2907798539022650680">'<ph name="NAME" />'కు కనెక్ట్ చేయడంలో విఫలమైంది: <ph name="DETAILS" />
     సర్వర్ మెసేజ్‌: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">సిగ్నల్స్‌ను షేర్ చేయండి</translation>
 <translation id="2908162660801918428">డైరెక్టరీ ద్వారా మీడియా గ్యాలరీని జోడించండి</translation>
 <translation id="2908358077082926882">కేటాయింపును తీసివేసి, <ph name="RESPONSE" /> కోసం "<ph name="CURRENTKEY" />"ని మళ్లీ నొక్కండి</translation>
 <translation id="2909506265808101667">Google సర్వీస్‌లతో కనెక్ట్ చేయడం సాధ్యం కాలేదు. మీ నెట్‌వర్క్ కనెక్షన్‌ను చెక్ చేసి, మళ్లీ ట్రై చేయండి. ఎర్రర్ కోడ్: <ph name="ERROR_CODE" />.</translation>
@@ -2379,6 +2388,7 @@
 <translation id="3003828226041301643">పరికరాన్ని డొమైన్‌కు చేర్చడం సాధ్యపడలేదు. పరికరాలను జోడించగల అధికారాలు మీకు ఉన్నాయో లేదో మీ ఖాతాలో చెక్ చేయండి.</translation>
 <translation id="3003967365858406397">మీ <ph name="PHONE_NAME" /> ప్రైవేట్ Wi-Fi కనెక్షన్‌ని సృష్టిస్తుంది.</translation>
 <translation id="3004385386820284928">కీబోర్డ్ కీలను అనుకూలంగా మార్చండి</translation>
+<translation id="3005376701115952939">సిస్టమ్ సెట్టింగ్‌లలో యాప్‌ల సింక్ సెట్ చేసి ఉంది</translation>
 <translation id="3005574332301273731">చూపవద్దు</translation>
 <translation id="3006881078666935414">వినియోగ డేటా లేదు</translation>
 <translation id="3007410324195400631">ఈ పేజీకి సంబంధించిన గమనికలను జోడించండి</translation>
@@ -2760,6 +2770,7 @@
 <translation id="3369624026883419694">హోస్ట్‌ను పరిష్కరిస్తోంది...</translation>
 <translation id="3370260763947406229">ఆటోమేటిక్ కరెక్షన్</translation>
 <translation id="3371140690572404006">USB-C పరికరం (కుడివైపు ముందు పోర్ట్)</translation>
+<translation id="3371351218553893534">లైన్ మరీ పొడవుగా ఉంది: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">మీరు అప్లికేషన్‌లో తెరిచే ఫోల్డర్‌లను చదవండి</translation>
 <translation id="3373059063088819384">రీడింగ్ మోడ్‌లో తెరవబడుతుంది</translation>
 <translation id="3373701465337594448">ఈ సెట్టింగ్ ఆన్‌లో ఉన్నప్పుడు, మీ ఆసక్తులను అంచనా వేసే మీరు చూసే సైట్‌ల యొక్క లిస్ట్ ఇక్కడ కనిపిస్తుంది</translation>
@@ -2830,6 +2841,9 @@
 <translation id="3434272557872943250">మీ చిన్నారి కోసం అదనపు వెబ్ &amp; యాప్ యాక్టివిటీ సెట్టింగ్‌ను ఆన్ చేసినట్లయితే, ఈ డేటా వారి Google ఖాతాలో సేవ్ చేయబడవచ్చు. ఈ సెట్టింగ్‌ల గురించి, వాటిని ఎలా సర్దుబాటు చేయాలనే దాని గురించి families.google.comలో మరింత తెలుసుకోండి.</translation>
 <translation id="3434475275396485144">ఈ సెట్టింగ్‌ను మీ ఫోన్ అడ్మినిస్ట్రేటర్ మేనేజ్ చేస్తుంది</translation>
 <translation id="3434512374684753970">ఆడియో &amp; వీడియో</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />తర్వాతి స్క్రీన్‌లో, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />ఇదే ఖాతాను మీరు Gmail, YouTube, Chrome, ఇతర Google సర్వీస్‌లలో ఉపయోగిస్తారు. వ్యక్తిగతీకరించిన అనుభవం కోసం, మీ సమాచారం మొత్తాన్ని సులభంగా యాక్సెస్ చేయడం కోసం మీ ఖాతాను ఉపయోగించండి.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />మీకు Google ఖాతా లేకపోతే, తర్వాతి స్క్రీన్‌లో మీరు ఒక Google ఖాతాను క్రియేట్ చేయగలరు.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">"<ph name="EXTENSION_NAME" />" మీ <ph name="CODE_TYPE" />ని అభ్యర్థిస్తోంది</translation>
 <translation id="3435738964857648380">భద్రత</translation>
 <translation id="343578350365773421">కాగితం లేదు</translation>
@@ -2876,6 +2890,7 @@
 <translation id="346546413339447252"><ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" />, మరిన్నిటి కోసం డిస్కౌంట్‌లను పొందండి</translation>
 <translation id="3468298837301810372">లేబుల్</translation>
 <translation id="3468999815377931311">Android ఫోన్</translation>
+<translation id="3469345458390352459">ఒకసారి ఆన్ చేసి, మీ Google ఖాతాతో సైన్ ఇన్ చేసిన తర్వాత మీ యాప్‌లు ఏ Chrome OS పరికరాలలో అయినా అందుబాటులో ఉంటాయి.  ఇతర బ్రౌజర్ సింక్ ఫీచర్‌లు ఆఫ్ చేసి ఉన్నా, Chrome ద్వారా వెబ్ యాప్‌లు సింక్ అవుతాయి.</translation>
 <translation id="3469583217479686109">ఎంపిక టూల్</translation>
 <translation id="3470392222765168737">సైట్‌ను ఫాలో చేయండి</translation>
 <translation id="3471876058939596279">వీడియో కోసం HDMIని, USB రకం-C పోర్ట్‌లను ఒకే సమయంలో ఉపయోగించకూడదు. వేరే వీడియో పోర్ట్‌ను ఉపయోగించండి.</translation>
@@ -3338,6 +3353,7 @@
 <translation id="3855441664322950881">ప్యాక్ ఎక్స్‌టెన్షన్‌</translation>
 <translation id="3855676282923585394">బుక్‌మార్క్‌లు మరియు సెట్టింగ్‌లను దిగుమతి చేయండి...</translation>
 <translation id="3856096718352044181">దయచేసి ఇది చెల్లుబాటు అయ్యే ప్రొవైడర్ అని వెరిఫై చేయండి లేదా తర్వాత మళ్లీ ట్రై చేయండి</translation>
+<translation id="3856470183388031602">మీ <ph name="DEVICE_TYPE" />‌లో మీ Google ఖాతాను ఉపయోగించండి</translation>
 <translation id="3856800405688283469">సమయ మండలిని ఎంచుకోండి</translation>
 <translation id="3857807444929313943">పైకి ఎత్తి, మళ్లీ తాకండి</translation>
 <translation id="3858860766373142691">పేరు</translation>
@@ -3377,6 +3393,7 @@
 <translation id="3894123633473837029">ఇటీవలి అసిస్టెంట్ హిస్టరీని Sherlog ద్వారా చేర్చండి. ఇందులో మీ గుర్తింపు, స్థానం, డీబగ్ సమాచారం ఉండవచ్చు. <ph name="BEGIN_LINK" />మరింత తెలుసుకోండి<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">ఫోల్డర్‌ను జోడించండి</translation>
 <translation id="3894770151966614831">Google ఖాతాకు తరలించాలా?</translation>
+<translation id="3894983081771074056">కీబోర్డ్, మౌస్ ప్రవర్తన, భాష ప్రాధాన్యతలు, మరెన్నో</translation>
 <translation id="3895076768659607631">సెర్చ్ ఇంజిన్‌లను &amp;మేనేజ్ చేయండి...</translation>
 <translation id="3895090224522145010">Kerberos వినియోగదారు పేరు</translation>
 <translation id="389521680295183045">మీరు మీ పరికరాన్ని యాక్టివ్‌గా ఉపయోగించే సమయాలను తెలుసుకోవడానికి సైట్‌లు అడగవచ్చు</translation>
@@ -3512,6 +3529,7 @@
 <translation id="3994878504415702912">&amp;జూమ్ చేయి</translation>
 <translation id="3995138139523574647">USB-C పరికరం (కుడివైపు వెనుక పోర్ట్)</translation>
 <translation id="3995963973192100066">యానిమేషన్‌ను ప్లే చేయండి</translation>
+<translation id="399788104667917863">టూల్‌బార్‌కు పిన్ చేయండి</translation>
 <translation id="4001540981461989979">కదులుతున్నప్పుడు మౌస్ కర్సర్‌ను హైలైట్ చేయండి</translation>
 <translation id="4002440992267487163">పిన్ సెటప్</translation>
 <translation id="4005817994523282006">సమయ మండలి గుర్తింపు పద్ధతి</translation>
@@ -3670,12 +3688,16 @@
 <translation id="4147911968024186208">దయచేసి మళ్లీ ట్రై చేయండి. మీకు ఈ ఎర్రర్ మళ్లీ కనిపిస్తే, దయచేసి మీ మద్దతు ప్రతినిధిని సంప్రదించండి.</translation>
 <translation id="4150201353443180367">డిస్‌ప్లే</translation>
 <translation id="4150569944729499860">స్క్రీన్ కాంటెక్ట్స్</translation>
+<translation id="4151843924968445052">పరికర సిగ్నల్స్‌ను షేర్ చేస్తారా?</translation>
 <translation id="4152011295694446843">మీరు మీ బుక్‌మార్క్‌లను ఇక్కడ చూడవచ్చు</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 ట్యాబ్}other{# ట్యాబ్‌లు}}</translation>
 <translation id="4154664944169082762">వేలిముద్రలు</translation>
 <translation id="4157869833395312646">Microsoft Server Gated Cryptography</translation>
 <translation id="4158315983204257156">వెబ్‌సైట్ టెక్స్ట్ సైజ్, ఫాంట్</translation>
 <translation id="4158364720893025815">పాస్</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />ఆటోమేటిక్ రిపోర్ట్‌లను పంపడానికి మీ Chrome OS పరికరాలను అనుమతించడం ద్వారా, ChromeOSలో దేనిని ముందుగా పరిష్కరించి, మెరుగుపరచాలనే అంశం గురించి నిర్ణయం తీసుకోవడంలో మాకు సహాయపడుతుంది. ChromeOS ఎప్పుడు క్రాష్ అవుతుంది, మీరు ఏ ఫీచర్‌లను ఉపయోగిస్తున్నారు, సాధారణంగా మీరు ఎంత మెమరీని ఉపయోగిస్తారు, Android యాప్‌లో సమస్య విశ్లేషణ, వినియోగ డేటా వంటి అంశాలను ఈ రిపోర్ట్‌లు కలిగి ఉండవచ్చు. కొంత సమగ్ర డేటా కూడా Google యాప్‌లకు, Android డెవలపర్‌ల లాంటి పార్ట్‌నర్‌లకు సహాయపడుతుంది. యాప్‌ల సింక్ కూడా ఆన్ చేసి ఉంటే, Android, ఇంకా వెబ్ యాప్‌లతో సహా ఇతర యాప్‌ల నుండి సమస్య విశ్లేషణ సమాచారం, అలాగే వినియోగ డేటా సేకరించబడతాయి.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />మీ ChromeOS పరికర సెట్టింగ్‌లలో ఈ రిపోర్ట్‌లను అనుమతించడాన్ని మీరు ఎప్పుడైనా ప్రారంభించవచ్చు లేదా ఆపివేయవచ్చు. మీరు డొమైన్ అడ్మినిస్ట్రేటర్ అయితే, ఈ సెట్టింగ్‌ను అడ్మిన్ కన్సోల్‌లో మార్చవచ్చు.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />మీ Google ఖాతాకు వెబ్ &amp; యాప్ యాక్టివిటీ సెట్టింగ్‌ను ఆన్ చేసినట్లయితే, మీ Android డేటా మీ Google ఖాతాలో సేవ్ చేయబడవచ్చు. మీరు account.google.com సైట్‌లో మీ డేటాను చూడవచ్చు, తొలగించవచ్చు, మీ ఖాతా సెట్టింగ్‌లను మార్చవచ్చు.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;Google Password Manager</translation>
 <translation id="4163560723127662357">తెలియని కీబోర్డ్</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" />, చెల్లుబాటులో ఉన్న సంస్థకు చెందినది కాదు. మీ అడ్మినిస్ట్రేటర్‌ను కాంటాక్ట్ చేయండి. మీరు అడ్మినిస్ట్రేటర్ అయితే, ఈ సైట్‌ను సందర్శించడం ద్వారా మీరు మీ సంస్థను సెటప్ చేయవచ్చు: g.co/ChromeEnterpriseAccount</translation>
@@ -3999,6 +4021,9 @@
 <translation id="4452898361839215358">లేదా PPDని ఎంచుకోండి. <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">మీ కీబోర్డ్‌కు ఎగువ కుడి మూలన ఉన్న వేలిముద్ర సెన్సార్‌ను తాకండి. మీ వేలిముద్ర డేటా సురక్షితంగా స్టోర్ చేయబడుతుంది, ఎప్పటికీ మీ <ph name="DEVICE_TYPE" />‌లోనే ఉంటుంది.</translation>
 <translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" />లో వెతకండి లేదా URLని టైప్ చేయండి</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />ఆటోమేటిక్ రిపోర్ట్‌లను పంపడానికి Chrome OS పరికరాలను అనుమతించడం ద్వారా, ChromeOSలో దేనిని ముందుగా పరిష్కరించి, మెరుగుపరచాలనే అంశం గురించి నిర్ణయం తీసుకోవడంలో మాకు సహాయపడుతుంది. ChromeOS ఎప్పుడెప్పుడు క్రాష్ అవుతోంది, ఏ ఫీచర్‌లు ఉపయోగించబడ్డాయి, సాధారణంగా ఎంత మెమరీ ఉపయోగించబడింది, Android యాప్ సమస్య విశ్లేషణలు, వినియోగ డేటా వంటి వివరాలను ఈ రిపోర్ట్‌లు కలిగి ఉండవచ్చు. కొంత సమగ్ర డేటా కూడా Google యాప్‌లకు, Android డెవలపర్‌ల లాంటి పార్ట్‌నర్‌లకు సహాయపడుతుంది. యాప్‌ల సింక్ కూడా ఆన్ చేసి ఉంటే, Android, ఇంకా వెబ్ యాప్‌లతో సహా ఇతర యాప్‌ల నుండి సమస్య విశ్లేషణ సమాచారం, అలాగే వినియోగ డేటా సేకరించబడతాయి.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />మీ చిన్నారి Chrome OS పరికర సెట్టింగ్‌లలో ఈ రిపోర్ట్‌లను అనుమతించడాన్ని మీరు ఎప్పుడైనా ప్రారంభించవచ్చు లేదా ఆపివేయవచ్చు. మీరు డొమైన్ అడ్మినిస్ట్రేటర్ అయితే, ఈ సెట్టింగ్‌ను అడ్మిన్ కన్సోల్‌లో మార్చవచ్చు.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />మీ చిన్నారి Google ఖాతాకు వెబ్ &amp; యాప్ యాక్టివిటీ సెట్టింగ్‌ను ఆన్ చేసినట్లయితే, మీ చిన్నారి డేటా వారి Google ఖాతాలో సేవ్ చేయబడవచ్చు. ఈ సెట్టింగ్‌ల గురించి, వాటిని ఎలా సర్దుబాటు చేయాలనే దాని గురించి families.google.com‌లో మరింత తెలుసుకోండి.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">ప్రస్తుత వాయిస్‌ని ఎంచుకోండి:</translation>
 <translation id="4459169140545916303"><ph name="DEVICE_LAST_ACTIVATED_TIME" /> రోజుల క్రితం యాక్టివ్‌గా ఉంది</translation>
 <translation id="4460014764210899310">విడివిడిగా ఉంచు</translation>
@@ -4379,6 +4404,7 @@
 <translation id="4806457879608775995">ఈ నిబంధనలను రివ్యూ చేయండి, మీ డేటాను కంట్రోల్ చేయండి</translation>
 <translation id="4807098396393229769">కార్డ్‌పై పేరు</translation>
 <translation id="4808667324955055115">పాప్-అప్‌లు బ్లాక్ చేయబడ్డాయి:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Chrome వెబ్ స్టోర్ నుండి తీసివేసిన <ph name="BEGIN_BOLD" />1 ఎక్స్‌టెన్షన్‌<ph name="END_BOLD" />ను రివ్యూ చేయండి}other{Chrome వెబ్ స్టోర్ నుండి తీసివేసిన <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} ఎక్స్‌టెన్షన్‌ల<ph name="END_BOLD" />ను రివ్యూ చేయండి}}</translation>
 <translation id="4809079943450490359">మీ పరికర అడ్మినిస్ట్రేట‌ర్ నుండి సూచనలు:</translation>
 <translation id="4809447465126035330">తొలగించండి</translation>
 <translation id="480990236307250886">హోమ్ పేజీని తెరువు</translation>
@@ -4702,6 +4728,7 @@
 <translation id="5101839224773798795">కర్సర్ ఆపినప్పుడు ఆటోమేటిక్‌గా క్లిక్ అవుతుంది</translation>
 <translation id="5106350808162641062">తీసివేయండి</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> Family Link ద్వారా పర్యవేక్షించబడుతుంది. మీరు తల్లిదండ్రుల పర్యవేక్షణతో స్కూల్ రిసోర్స్‌లను యాక్సెస్ చేయడానికి స్కూల్ ఖాతాలను జోడించవచ్చు.</translation>
+<translation id="5107093668001980925"><ph name="MODULE_NAME" />‌ను ఎప్పుడూ చూపవద్దు</translation>
 <translation id="5107443654503185812">ఎక్స్‌టెన్షన్, సురక్షిత బ్రౌజింగ్‌ను ఆఫ్ చేసింది</translation>
 <translation id="5108967062857032718">సెట్టింగ్‌లు - Android యాప్‌లను తీసివేయండి</translation>
 <translation id="5109044022078737958">మియా</translation>
@@ -4712,6 +4739,7 @@
 <translation id="5111794652433847656">ఈ పరికరంలో <ph name="APP_NAME" /> కోసం పాస్-కీలు ఏవీ లేవు</translation>
 <translation id="5112577000029535889">&amp;డెవలపర్ ఉపకరణాలు</translation>
 <translation id="511313294362309725">ఫాస్ట్ పెయిర్‌ను ఆన్ చేయండి</translation>
+<translation id="5113384440341086023">Play Store నుండి ఇన్‌స్టాల్ చేసిన యాప్‌లు, Chrome బ్రౌజర్ నుండి ఇన్‌స్టాల్ చేసిన వెబ్ యాప్‌లు</translation>
 <translation id="51143538739122961">మీ సెక్యూరిటీ కీని ఇన్‌సర్ట్ చేసి, ఆపై దానిని తాకండి</translation>
 <translation id="5115309401544567011">దయచేసి మీ <ph name="DEVICE_TYPE" />ని ఛార్జింగ్ పెట్టండి</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4757,6 +4785,7 @@
 <translation id="5154702632169343078">విషయం</translation>
 <translation id="5155327081870541046">అడ్రస్ బార్‌లో, మీరు సెర్చ్ చేయాలనుకుంటున్న సైట్‌ షార్ట్‌కట్‌ను ఎంటర్ చేయండి, ఉదాహరణకు "@bookmarks". అప్పుడు, మీ ప్రాధాన్య కీబోర్డ్ షార్ట్‌కట్‌ను నొక్కి, ఆపై మీ సెర్చ్ క్వెరీని ఎంటర్ చేయండి.</translation>
 <translation id="5156638757840305347">అది కనిపించినప్పుడు లేదా కదలికలో ఉన్నప్పుడు కర్సర్ హైలైట్ అవుతుంది</translation>
+<translation id="5157250307065481244">సైట్ వివరాలు చూడండి</translation>
 <translation id="5157635116769074044">ఈ పేజీని ప్రారంభ స్క్రీన్‌కు పిన్ చేయి...</translation>
 <translation id="5158206172605340248">యాక్సెంట్ మార్క్‌ల మెనూ విస్మరించబడింది.</translation>
 <translation id="5159094275429367735">Crostiniని సెటప్ చేయి</translation>
@@ -5816,6 +5845,7 @@
 <translation id="6104068876731806426">Google ఖాతాలు</translation>
 <translation id="6104311680260824317">పరికరాన్ని డొమైన్‌కు చేర్చడం సాధ్యపడలేదు. పేర్కొనబడిన Kerberos ఎన్‌క్రిప్షన్ రకాలకు ఈ సర్వర్ మద్దతు ఇవ్వదు. ఎన్‌క్రిప్షన్ సెట్టింగ్‌ల కోసం "మరిన్ని ఆప్షన్‌లు" చూడండి.</translation>
 <translation id="6104796831253957966">ప్రింటర్ క్యూ నిండిపోయింది</translation>
+<translation id="6106167152849320869">మునుపటి దశలో సమస్య విశ్లేషణ, వినియోగ డేటాను పంపడానికి కూడా మీరు ఎంచుకున్నట్లయితే, ఇన్‌స్టాల్ చేసిన యాప్‌ల కోసం ఈ డేటాను సేకరించడం జరుగుతుంది.</translation>
 <translation id="6111972606040028426">Google Assistantను ఎనేబుల్ చేయండి</translation>
 <translation id="6112294629795967147">సైజ్‌ మార్చడం కోసం తాకండి</translation>
 <translation id="6112727384379533756">టిక్కెట్‌ను జోడించండి</translation>
@@ -5946,6 +5976,7 @@
 <translation id="6226777517901268232">ప్రైవేట్ కీ ఫైల్ (ఐచ్ఛికం)</translation>
 <translation id="6227002569366039565">ఈ బబుల్‌ను ఫోకస్ చేయడానికి, తర్వాత అది సూచిస్తున్న ఎలిమెంట్‌ను ఫోకస్ చేయడానికి |<ph name="ACCELERATOR" />| నొక్కండి.</translation>
 <translation id="6227280783235722609">ఎక్స్‌టెన్షన్</translation>
+<translation id="6229062790325126537">ApnMigratorను రీసెట్ చేయండి</translation>
 <translation id="6229849828796482487">Disconnect Wi-Fi నెట్‌వర్క్ డిస్‌కనెక్ట్ చేయడం</translation>
 <translation id="6231782223312638214">సూచించబడింది</translation>
 <translation id="6231881193380278751">పేజీని ఆటోమేటిక్‌గా రిఫ్రెష్ చేయడానికి URLలో ప్రశ్న పారామీట‌ర్‌ను జోడించండి: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6223,6 +6254,7 @@
 <translation id="6478248366783946499">అపాయకరమైన ఫైల్‌ను ఉంచాలా?</translation>
 <translation id="6479881432656947268">Chrome వెబ్ స్టోర్‌కు వెళ్లండి</translation>
 <translation id="6480327114083866287"><ph name="MANAGER" /> ద్వారా మేనేజ్ చేయబడుతోంది</translation>
+<translation id="6481978993812487794">ఒకసారి ఆన్ చేసి, మీ Google ఖాతాతో సైన్ ఇన్ చేసిన తర్వాత మీ యాప్‌లు ఏ Chrome OS పరికరాలలో అయినా అందుబాటులో ఉంటాయి. ఇతర బ్రౌజర్ సింక్ ఫీచర్‌లు ఆఫ్ చేసి ఉన్నా, Chrome ద్వారా వెబ్ యాప్‌లు సింక్ అవుతాయి.</translation>
 <translation id="6482559668224714696">ఫుల్-స్క్రీన్‌‌ మాగ్నిఫైయర్</translation>
 <translation id="6483485061007832714">డౌన్‌లోడ్ చేసినది తెరువు</translation>
 <translation id="6483805311199035658"><ph name="FILE" /> ని తెరుస్తుంది...</translation>
@@ -6237,6 +6269,7 @@
 <translation id="6497784818439587832">మీ స్క్రీన్‌పై ఉన్న ఐటెమ్‌లను పెద్దగా లేదా చిన్నగా చూపడానికి డిస్‌ప్లే సైజ్‌ను మార్చండి</translation>
 <translation id="6497789971060331894">మౌస్ రివర్స్ స్క్రోలింగ్</translation>
 <translation id="6498249116389603658">&amp;మీ అన్ని భాషలు</translation>
+<translation id="6498583202177273322">ఈ పేజీని అన్వేషిస్తున్నప్పుడు ఉపయోగకరమైన అదనపు సమాచారాన్ని పొందండి</translation>
 <translation id="6499143127267478107">ప్రాక్సీ స్క్రిప్ట్‌లో హోస్ట్‌ను పరిష్కరిస్తోంది...</translation>
 <translation id="6499764981457476645">సమీపంలో పరికరాలు ఏవీ కనుగొనబడలేదు</translation>
 <translation id="6501957628055559556">అన్ని కంటైనర్లు</translation>
@@ -6683,6 +6716,7 @@
 <translation id="688312408602122936">Steam ద్వారా ఇన్‌స్టాల్ చేయబడిన ఏవైనా గేమ్‌లు, యాప్‌లు కూడా ఈ పరికరం నుండి తీసివేయబడతాయి</translation>
 <translation id="6883319974225028188">అయ్యో!  పరికర కాన్ఫిగరేషన్‌ను సేవ్ చేయడంలో సిస్టమ్ విఫలమైంది.</translation>
 <translation id="6884474387073389421">ఎంపిక చేసిన సైన్-ఇన్ డేటాను మీరు ఖచ్చితంగా తొలగించాలనుకుంటున్నారా?</translation>
+<translation id="6885122019363983153">పరికరాల అంతటా డెస్క్‌టాప్ బ్యాక్‌గ్రౌండ్‌లను మ్యాచ్ చేయండి</translation>
 <translation id="6885771755599377173">సిస్టమ్ సమాచార ప్రివ్యూ</translation>
 <translation id="6886380424988777998">Linuxను అప్‌గ్రేడ్ చేయడం సాధ్యపడలేదు</translation>
 <translation id="6886871292305414135">కొత్త &amp;ట్యాబ్‌లో లింక్‌ను తెరువు</translation>
@@ -6754,6 +6788,7 @@
 <translation id="6949434160682548041">పాస్‌వర్డ్ (ఐచ్ఛికం)</translation>
 <translation id="6950627417367801484">యాప్‌లను పునరుద్ధరించండి</translation>
 <translation id="6952242901357037157">మీ <ph name="BEGIN_LINK" />Google ఖాతా<ph name="END_LINK" /> నుండి మీరు పాస్‌వర్డ్‌లను ఇక్కడ కూడా చూపవచ్చు</translation>
+<translation id="6954910832698269894">పరికర సింక్‌ను ఆన్ చేసి, మీ మునుపటి Chromebook నుండి మీ యాప్‌లు, సెట్టింగ్‌లు, Wi-Fi నెట్‌వర్క్‌లు, వాల్‌పేపర్‌ను రీస్టోర్ చేయండి. మార్పులను, సెట్టింగ్‌లు &gt; ఖాతాలు అనే ఆప్షన్‌లో ఎప్పుడైనా చేసుకోవచ్చు.</translation>
 <translation id="6954936693361896459">బదులుగా ఈ ట్యాబ్‌ను ప్రసారం చేయండి</translation>
 <translation id="6955446738988643816">పాప్‌అప్‌ను పరిశీలించు</translation>
 <translation id="6955535239952325894">మేనేజ్ అవుతోన్న బ్రౌజర్‌లలో ఈ సెట్టింగ్ డిజేబుల్ చేయబడింది.</translation>
@@ -6912,6 +6947,7 @@
 <translation id="7075513071073410194">RSA ఎన్‌క్రిప్షన్‌తో PKCS #1 MD5</translation>
 <translation id="7075625805486468288">HTTPS/SSLసర్టిఫికెట్లు మరియు సెట్టింగ్‌లను మేనేజ్ చేయండి</translation>
 <translation id="7076875098323397992">అప్‌గ్రేడ్‌ను ప్రారంభించడం సాధ్యం కాదు</translation>
+<translation id="7077751457066325012">కీబోర్డ్ షార్ట్‌కట్‌లను చూడండి, అనుకూలంగా మార్చండి</translation>
 <translation id="7077829361966535409">సైన్ ఇన్ పేజీ ప్రస్తుత ప్రాక్సీ సెట్టింగ్‌లను ఉపయోగించి లోడ్ కావడంలో విఫలమైంది. దయచేసి <ph name="GAIA_RELOAD_LINK_START" />మళ్లీ సైన్ ఇన్ చేయడానికి ప్రయత్నించండి<ph name="GAIA_RELOAD_LINK_END" /> లేదా విభిన్న <ph name="PROXY_SETTINGS_LINK_START" />ప్రాక్సీ సెట్టింగ్‌ల<ph name="PROXY_SETTINGS_LINK_END" />ను ఉపయోగించండి.</translation>
 <translation id="7078120482318506217">అన్ని నెట్‌వర్క్‌లు</translation>
 <translation id="708060913198414444">ఆడియో అడ్రస్‌ను కా&amp;పీ చేయి</translation>
@@ -6941,6 +6977,7 @@
 <translation id="7108933416628942903">ఇప్పుడు లాక్ చేయి</translation>
 <translation id="7109543803214225826">షార్ట్‌కట్ తీసివేయబడింది</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{ట్యాబ్‌ను గ్రూప్‌నకు జోడించండి}other{ట్యాబ్‌లను గ్రూప్‌నకు జోడించండి}}</translation>
+<translation id="7110684627876015299">పేరు లేని గ్రూప్ - <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">ఈ విండోకు పేరు పెట్టండి</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> ఐటెమ్</translation>
 <translation id="7113502843173351041">మీ ఈమెయిల్‌ అడ్రస్‌ను తెలియపరచడానికి అనుమతి</translation>
@@ -7155,6 +7192,7 @@
 <translation id="7328867076235380839">చెల్లని కాంబినేషన్</translation>
 <translation id="7329154610228416156">అసురక్షిత URL (<ph name="BLOCKED_URL" />)ను ఉపయోగించేలా కాన్ఫిగర్ చేయబడినందున సైన్-ఇన్ విఫలమైంది. దయచేసి మీ నిర్వాహకుడిని సంప్రదించండి.</translation>
 <translation id="7332053360324989309">డెడికేటెడ్ వర్కర్: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">మీ యాప్‌లు, సెట్టింగ్‌లను బ్యాకప్ చేయండి, రీస్టోర్ చేయండి</translation>
 <translation id="7335974957018254119">వీటికి స్పెల్ చెక్‌ను ఉపయోగించండి</translation>
 <translation id="7336799713063880535">నోటిఫి. బ్లాక్‌డ్</translation>
 <translation id="7338630283264858612">పరికరం క్రమ సంఖ్య చెల్లదు.</translation>
@@ -7177,6 +7215,7 @@
 <translation id="7348093485538360975">ఆన్-స్క్రీన్ కీబోర్డ్</translation>
 <translation id="7349010927677336670">వీడియో ప్రసార క్వాలిటీ</translation>
 <translation id="7352651011704765696">ఏదో తప్పు జరిగింది</translation>
+<translation id="7352664183151911163">మీ యాప్‌లు, Chrome బ్రౌజర్ అంతటా</translation>
 <translation id="7353261921908507769">మీ కాంటాక్ట్‌లు సమీపంలో ఉన్నప్పుడు వారు మీతో షేర్ చేయగలరు. మీరు అంగీకరించే వరకు బదిలీలు ప్రారంభం కావు.</translation>
 <translation id="735361434055555355">Linuxను ఇన్‌స్టాల్ చేస్తోంది...</translation>
 <translation id="7354120289251608189">మీరు ఇప్పుడు మీ బ్రౌజర్‌కు ఎప్పుడైనా కొత్త రూపాన్ని ఇవ్వవచ్చు.</translation>
@@ -7316,6 +7355,8 @@
 <translation id="7458168200501453431">Google Searchలో ఉపయోగించే స్పెల్ చెకర్‌నే ఇక్కడ ఉపయోగిస్తుంది. మీరు బ్రౌజర్‌లో టైప్ చేసే టెక్స్ట్‌ను Googleకు పంపుతుంది.</translation>
 <translation id="7458715171471938198">యాప్‌లను రీస్టోర్ చేయాలా?</translation>
 <translation id="7458933488302148148">మీ సెక్యూరిటీని బలపరచడానికి, ఆన్‌లైన్‌లో సురక్షితంగా ఉండటానికి మీ సేవ్ చేసిన పాస్‌వర్డ్‌లను చెక్ చేయండి</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />ఆటోమేటిక్ రిపోర్ట్‌లను పంపడానికి మీ Chrome OS పరికరాలను అనుమతించడం ద్వారా, ChromeOSలో దేనిని ముందుగా పరిష్కరించి, మెరుగుపరచాలనే అంశం గురించి నిర్ణయం తీసుకోవడంలో మాకు సహాయపడుతుంది. ChromeOS ఎప్పుడు క్రాష్ అవుతుంది మీరు ఏ ఫీచర్‌లను ఉపయోగిస్తున్నారు, సాధారణంగా మీరు ఎంత మెమరీని ఉపయోగిస్తారు, వంటి అంశాలను ఈ రిపోర్ట్‌లు కలిగి ఉండవచ్చు. యాప్‌ల సింక్ కూడా ఆన్ చేసి ఉంటే, Android, ఇంకా వెబ్ యాప్‌లతో సహా ఇతర యాప్‌ల నుండి సమస్య విశ్లేషణ సమాచారం, అలాగే వినియోగ డేటా సేకరించబడతాయి.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />మీ Chrome పరికర సెట్టింగ్‌లలో ఈ రిపోర్ట్‌లను అనుమతించడాన్ని మీరు ఎప్పుడైనా ప్రారంభించవచ్చు లేదా ఆపివేయవచ్చు. మీరు డొమైన్ అడ్మినిస్ట్రేటర్ అయితే, ఈ సెట్టింగ్‌ను అడ్మిన్ కన్సోల్‌లో మార్చవచ్చు.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">మీరు ప్రస్తుతం ఇన్‌స్టాల్ చేసుకున్న థీమ్</translation>
 <translation id="7461924472993315131">పిన్ చేయండి</translation>
 <translation id="746216226901520237">తదుపరిసారి మీ ఫోన్ మీ <ph name="DEVICE_TYPE" />‌ను అన్‌లాక్ చేస్తుంది. మీరు సెట్టింగ్‌లలో Smart Lockను ఆఫ్ చేయవచ్చు.</translation>
@@ -7549,6 +7590,7 @@
 <translation id="7663719505383602579">స్వీకర్త: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">కీబోర్డ్ షార్ట్‌కట్ అందుబాటులో ఉంది</translation>
 <translation id="7663859337051362114">eSIM ప్రొఫైల్‌ను జోడించండి</translation>
+<translation id="76641554187607347">కీబోర్డ్ ఏదీ కనెక్ట్ అయి లేదు</translation>
 <translation id="7665082356120621510">పరిమాణాన్ని రిజర్వ్ చేయి</translation>
 <translation id="7665369617277396874">ఖాతాను జోడించండి</translation>
 <translation id="766560638707011986">డొమైన్‌లను చూపించండి</translation>
@@ -7596,6 +7638,7 @@
 <translation id="769824636077131955">సెక్యూరిటీ చెక్ చేయడానికి వీల్లేనంతగా ఈ ఫైల్ చాలా పెద్దగా ఉంది. గరిష్ఠంగా 50 MB వరకు ఉన్న డాక్యుమెంట్‌లను మీరు ప్రింట్ చేయవచ్చు.</translation>
 <translation id="7698507637739331665">కోన్ని ఐటెమ్‌లు బ్లాక్ చేయబడ్డాయి</translation>
 <translation id="7701040980221191251">ఏదీ లేదు</translation>
+<translation id="7701265686005869308">ప్రొఫైల్‌ను మూసివేయండి</translation>
 <translation id="7701869757853594372">వినియోగదారు నిర్వహించేవి</translation>
 <translation id="7702574632857388784">లిస్ట్‌ నుంచి <ph name="FILE_NAME" />ని తొలగించండి</translation>
 <translation id="7702907602086592255">డొమైన్</translation>
@@ -8014,6 +8057,7 @@
 <translation id="8050191834453426339">మళ్లీ వెరిఫై చేయండి</translation>
 <translation id="8051193500142930381">ఏ ఫీచర్‌లకు కెమెరా అవసరం అవుతుందో అవి పని చేయవు</translation>
 <translation id="8051390370038326517">MIDI డివైజ్‌ల పూర్తి కంట్రోల్‌ను కలిగి ఉండటానికి <ph name="HOST" />ను ఎల్లప్పుడూ అనుమతించండి</translation>
+<translation id="8052218774860457016">బ్రౌజర్ సింక్‌ను మేనేజ్ చేయండి</translation>
 <translation id="8053278772142718589">PKCS #12 ఫైళ్ళు</translation>
 <translation id="8053390638574070785">ఈ పేజీని మళ్లీ లోడ్ చేయి</translation>
 <translation id="8054517699425078995">ఈ రకమైన ఫైల్ మీ పరికరానికి హాని కలిగించవచ్చు. ఏది ఏమైనా <ph name="FILE_NAME" />ను ఉంచాలని అనుకుంటున్నారా?</translation>
@@ -8383,6 +8427,7 @@
 <translation id="8376137163494131156">Google Castతో ఏమి జరుగుతోందో మాకు చెప్పండి.</translation>
 <translation id="8376384591331888629">ఈ సైట్‌లో థర్డ్ పార్టీ కుకీలు చేర్చబడుతున్నాయి</translation>
 <translation id="8376451933628734023">ఇది వేరే యాప్ అని మీరు అనుకునేలా మిమ్మల్ని ఈ వెబ్ యాప్ మోసగించడానికి ట్రై చేస్తున్నట్లయితే, దాన్ని అన్‌ఇన్‌స్టాల్ చేయండి.</translation>
+<translation id="8376752431516546391">Google Search సైడ్ ప్యానెల్</translation>
 <translation id="8377625247046155446">ఈ పాస్-కీ కేవలం ఈ పరికరంలో మాత్రమే సేవ్ చేయబడుతుంది. మీరు అజ్ఞాత విండోలన్నింటినీ మూసివేసిన తర్వాత, అది ఈ పరికరంలో అలాగే ఉంటుంది.</translation>
 <translation id="8378714024927312812">మీ సంస్థ ద్వారా నిర్వహించబడుతున్నవి</translation>
 <translation id="8379878387931047019">ఈ వెబ్‌సైట్ రిక్వెస్ట్ చేసిన భద్రతా కీ రకానికి ఈ పరికరం మద్దతు ఇవ్వదు</translation>
@@ -8450,6 +8495,11 @@
 <translation id="8428628598981198790">మీ సెక్యూరిటీ కీని ఈ సైట్‌తో ఉపయోగించలేరు</translation>
 <translation id="84297032718407999">మీరు <ph name="LOGOUT_TIME_LEFT" />లో సైన్ అవుట్ అవుతారు</translation>
 <translation id="8431190899827883166">నొక్కినవి చూపు</translation>
+<translation id="8431496281632382473">ఈ ప్రొఫైల్‌ను <ph name="DOMAIN" /> మేనేజ్ చేస్తోంది. మేనేజ్ చేయబడుతున్న ఈ ప్రొఫైల్‌ను ఉపయోగించడం కొనసాగించడానికి, మీ సంస్థకు మీరు పరికర సిగ్నల్స్‌ను షేర్ చేయాల్సి ఉంటుంది.
+
+పరికర సిగ్నల్స్‌లో మీ బ్రౌజర్, OS, పరికరం, ఇన్‌స్టాల్ చేసిన సాఫ్ట్‌వేర్, ఫైల్స్ ఉండవచ్చు.
+
+మీరు సిగ్నల్స్‌ను షేర్ చేయకూడదు అనుకుంటే, ఈ ప్రొఫైల్ మూసివేయబడుతుంది.</translation>
 <translation id="8434480141477525001">NaCl డీబగ్ పోర్ట్</translation>
 <translation id="8437209419043462667">యుఎస్</translation>
 <translation id="8438328416656800239">స్మార్ట్ బ్రౌజర్‌కు మారండి</translation>
@@ -8534,6 +8584,8 @@
 <translation id="851263357009351303">చిత్రాలను చూపించడానికి ఎల్లప్పుడూ <ph name="HOST" />ను అనుమతించండి</translation>
 <translation id="8513108775083588393">ఆటో-రొటేట్</translation>
 <translation id="8513357934662532537"><ph name="USER_EMAIL" /> కోసం <ph name="BRAND" />‌కు పాస్‌వర్డ్‌లను దిగుమతి చేయడానికి, CSV ఫైల్‌ను ఎంచుకోండి.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />ఆటోమేటిక్ రిపోర్ట్‌లను పంపడానికి Chrome OS పరికరాలను అనుమతించడం ద్వారా, ChromeOSలో దేనిని ముందుగా పరిష్కరించి, మెరుగుపరచాలనే అంశం గురించి నిర్ణయం తీసుకోవడంలో మాకు సహాయపడుతుంది. ChromeOS ఎప్పుడెప్పుడు క్రాష్ అవుతోంది, ఏ ఫీచర్‌లు ఉపయోగించబడ్డాయి, సాధారణంగా ఎంత మెమరీ ఉపయోగించడం జరుగుతోంది వంటి వివరాలను ఈ రిపోర్ట్‌లు కలిగి ఉండవచ్చు. యాప్‌ల సింక్ కూడా ఆన్ చేసి ఉంటే, Android, ఇంకా వెబ్ యాప్‌లతో సహా ఇతర యాప్‌ల నుండి సమస్య విశ్లేషణ సమాచారం, అలాగే వినియోగ డేటా సేకరించబడతాయి.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />మీ చిన్నారి Chrome OS పరికర సెట్టింగ్‌లలో ఈ రిపోర్ట్‌లను అనుమతించడాన్ని మీరు ఎప్పుడైనా ప్రారంభించవచ్చు లేదా ఆపివేయవచ్చు. మీరు డొమైన్ అడ్మినిస్ట్రేటర్ అయితే, ఈ సెట్టింగ్‌ను అడ్మిన్ కన్సోల్‌లో మార్చవచ్చు.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">వేరొక సెక్యూరిటీ కీని ప్రయత్నించండి</translation>
 <translation id="8514955299594277296">మీ పరికరంలో డేటాను సేవ్ చేయడానికి సైట్‌లను అనుమతించవద్దు (సిఫార్సు చేయబడలేదు)</translation>
 <translation id="8517759303731677493">ఎడిట్ చేయండి…</translation>
@@ -8894,6 +8946,7 @@
 <translation id="883062543841130884">ప్రత్యామ్నాయాలు</translation>
 <translation id="8830779999439981481">అప్‌డేట్‌లను వర్తింపజేయడానికి రీస్టార్ట్ అవుతోంది</translation>
 <translation id="8830796635868321089">ప్రస్తుత ప్రాక్సీ సెట్టింగ్‌లను ఉపయోగించి అప్‌‌డేట్‌ను చెక్ చేయడం విఫలమైంది. దయచేసి మీ <ph name="PROXY_SETTINGS_LINK_START" />ప్రాక్సీ సెట్టింగ్‌ల<ph name="PROXY_SETTINGS_LINK_END" />ను సర్దుబాటు చేయండి.</translation>
+<translation id="8830863983385452402">సైట్ ఈ ట్యాబ్ కంటెంట్‌లను చూడగలుగుతుంది</translation>
 <translation id="8831769650322069887"><ph name="FILE_NAME" />‌ను తెరవండి</translation>
 <translation id="8832781841902333794">మీ ప్రొఫైళ్లు</translation>
 <translation id="8834039744648160717">నెట్‌వర్క్ కాన్ఫిగరేషన్‌ను <ph name="USER_EMAIL" /> నియంత్రిస్తున్నారు.</translation>
@@ -9025,6 +9078,7 @@
 <translation id="8946359700442089734">డీబగ్గింగ్ ఫీచ‌ర్‌లు ఈ <ph name="IDS_SHORT_PRODUCT_NAME" /> పరికరంలో పూర్తిగా ప్రారంభించబడలేదు.</translation>
 <translation id="894763922177556086">బాగుంది</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> మీ సెక్యూరిటీ కీ తయారీదారు బ్రాండ్ పేరు మరియు మోడల్‌ను చూడాలనుకుంటోంది</translation>
+<translation id="8949304443659090542">Chrome బ్రౌజర్ సింక్‌ను మేనేజ్ చేయండి</translation>
 <translation id="895054485242522631">మోషన్ సెన్సార్‌లను సైట్‌లు ఉపయోగించగలవు</translation>
 <translation id="8951256747718668828">ఒక ఎర్రర్ కారణంగా పునరుద్ధరించడం పూర్తి కాలేదు</translation>
 <translation id="8951465597020890363">ఏదేమైనా అతిథి మోడ్‌ను మూసివేయాలా?</translation>
@@ -9130,6 +9184,7 @@
 <translation id="9032097289595078011">ఫాస్ట్ పెయిర్‌ను డిజేబుల్ చేయండి</translation>
 <translation id="9033765790910064284">ఏమైనప్పటికీ కొనసాగించండి</translation>
 <translation id="9033857511263905942">&amp;అతికించు</translation>
+<translation id="9034408118624208974">Chromebookను కొత్తగా వాడుతున్నారా? సింక్‌ను ఆన్ చేయండి, తద్వారా మీ ప్రాధాన్యతలు బ్యాకప్ అవుతాయి.</translation>
 <translation id="903480517321259405">PINను మళ్లీ టైప్ చేయండి</translation>
 <translation id="9037054491984310631"><ph name="DEVICE" /> అనే పేరుతో ఉన్న బ్లూటూత్ పరికరానికి కనెక్ట్ చేయబడింది</translation>
 <translation id="9037640663275993951">పరికరానికి అనుమతి లేదు</translation>
@@ -9173,6 +9228,7 @@
 <translation id="9068298336633421551">లొకేషన్ అనుమతిని కలిగిన Android యాప్‌లు, సర్వీస్‌లు ఈ పరికర లొకేషన్‌ను ఉపయోగించడానికి అనుమతించండి. Google కాలానుగుణంగా లొకేషన్ డేటాను సేకరించవచ్చు, లొకేషన్ ఖచ్చితత్వాన్ని, లొకేషన్-ఆధారిత సర్వీస్‌లను మెరుగుపరచడం కోసం ఈ డేటాను అజ్ఞాతంగా ఉపయోగించవచ్చు.</translation>
 <translation id="9068598199622656904">కీబోర్డ్ షార్ట్‌కట్‌ల కోసం ఒకే సమయంలో కీలను నొక్కి ఉంచడానికి బదులుగా, ఒకసారి ఒక కీని మాత్రమే నొక్కండి</translation>
 <translation id="9068878141610261315">సపోర్ట్ చేయని ఫైల్ రకం</translation>
+<translation id="9069665781180028115">ఎంపిక చేసిన ఐటెమ్‌లు ఈ Chromebookలో అందుబాటులో ఉంటాయి. మీరు Chromebookను కొత్తగా వాడుతున్నట్లయితే, ఐటెమ్‌లన్నింటిని సింక్ చేయండి, తద్వారా మీ ప్రాధాన్యతలు బ్యాకప్ అవుతాయి. మార్పులను, సెట్టింగ్‌లు &gt; ఖాతాలు అనే ఆప్షన్‌లో ఎప్పుడైనా చేసుకోవచ్చు.</translation>
 <translation id="9070342919388027491">ట్యాబ్ ఎడమ వైపునకు తరలించబడింది</translation>
 <translation id="9074739597929991885">బ్లూటూత్</translation>
 <translation id="9074836595010225693">USB మౌస్ కనెక్ట్ చేయబడింది</translation>
@@ -9346,6 +9402,7 @@
 <translation id="930268624053534560">వివరణాత్మక సమయముద్రలు</translation>
 <translation id="930551443325541578">కీలను, యాక్సెంట్ మార్క్‌లను రిపీట్ చేయండి</translation>
 <translation id="930893132043726269">ప్రస్తుతం రోమింగ్‌లో ఉంది</translation>
+<translation id="930991362911221750">ఈ ట్యాబ్‌ను చూడటానికి <ph name="APP_NAME" />‌ను అనుమతించాలా?</translation>
 <translation id="93140074055951850">Android యాప్‌లు ఆపివేయబడ్డాయి</translation>
 <translation id="932327136139879170">హోమ్</translation>
 <translation id="932508678520956232">ముద్రించడాన్ని ప్రారంభించడం సాధ్యం కాలేదు.</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb
index b4d242d..3e09d627 100644
--- a/chrome/app/resources/generated_resources_uz.xtb
+++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -216,6 +216,7 @@
 <translation id="1176471985365269981">Qurilmangizdagi fayl yoki jildlarni tahrirlash taqiqlangan</translation>
 <translation id="1177863135347784049">Boshqa</translation>
 <translation id="1178581264944972037">Pauza</translation>
+<translation id="1178601482396475810">Qurilma sinxronlanishini boshqarish</translation>
 <translation id="117916940443676133">Elektron kalit PIN kod bilan himoyalanmagan. Kirish maʼlumotlarini boshqarish uchun avval PIN kod yarating.</translation>
 <translation id="1181037720776840403">Olib tashlash</translation>
 <translation id="1181366777303791449"><ph name="MAIN_FRAME_ETLD_PLUS_ONE" /></translation>
@@ -353,6 +354,7 @@
 <translation id="130097046531636712">Bunda fondagi amallar hamda ravon varaqlash kabi vizual effektlarni cheklash orqali batareya quvvati tejaladi</translation>
 <translation id="1301135395320604080"><ph name="ORIGIN" /> quyidagi fayllarni tahrirlay oladi</translation>
 <translation id="1302227299132585524">Apple hodisalarida JavaScript ishga tushirilishiga ruxsat berish</translation>
+<translation id="1302654693270046655"><ph name="GROUP_NAME" /> guruhi — <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">Xatcho‘plar HTML-fayli</translation>
 <translation id="1303671224831497365">Bluetooth qurilmalari topilmadi</translation>
 <translation id="130491383855577612">Linux ilova va fayllarning yangi nusxalari tiklandi</translation>
@@ -1049,6 +1051,7 @@
 <translation id="1877520246462554164">Hisob tekshiruvi tokeni olinmadi. Qayta urinish uchun hisobingizdan chiqing va qaytadan kiring.</translation>
 <translation id="1877860345998737529">Switch harakatini tayinlash</translation>
 <translation id="1878155070920054810">Chromebook oxirigacha yangilanmasdan turib uning quvvati tugab qolishi mumkin. Uzilishlarning oldini olish uchun uning xatosiz quvvatlanayotganini tekshiring.</translation>
+<translation id="1878477879455105085">Ochilgan</translation>
 <translation id="1878885068166344708">Fokus surilganda element ajratib belgilanadi. Fokusni oʻzgartirish uchun tab tugmasini yoki element ustiga bosing.</translation>
 <translation id="1879000426787380528">Hisobni tanlang</translation>
 <translation id="18802377548000045">Varaqlar ikki marta kichraytiriladi</translation>
@@ -1433,6 +1436,7 @@
 <translation id="2204034823255629767">Kiritilayotgan matnni ko‘rish va o‘zagartirish</translation>
 <translation id="2204387456724731099">Bu tanlov tarjima qilinmaydi</translation>
 <translation id="2210462644007531147">Oʻrnatish yakunlanmadi</translation>
+<translation id="2211245494465528624">Sinxronlash parametrlarini boshqarish</translation>
 <translation id="2212565012507486665">Cookie fayllariga ruxsat berish</translation>
 <translation id="2214018885812055163">Umumiy jildlar</translation>
 <translation id="2214884991347062907">Parol xato. Qaytadan urining.</translation>
@@ -1531,6 +1535,7 @@
 <translation id="2296218178174497398">Qurilmalarni aniqlash</translation>
 <translation id="2297705863329999812">Printerlarni qidirish</translation>
 <translation id="2297822946037605517">Bu sahifani ulashish</translation>
+<translation id="229871422646860597">Asboblar panelidan yechish</translation>
 <translation id="2299734369537008228">Slayder: <ph name="MIN_LABEL" /> – <ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">debugd orqali yigʻilgan barcha jurnal fayllarini alohida arxivlash.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2161,6 +2166,7 @@
 <translation id="2811205483104563968">Hisoblar</translation>
 <translation id="2811564570599779918">Spam va firibgarlikka qarshi kurash</translation>
 <translation id="2812049959647166806">Thunderbolt qoʻllab-quvvatlanmaydi</translation>
+<translation id="2812171980080389735">Saqlangan tarmoqlar va parollar ulardan darhol foydalanish imkonini beradi</translation>
 <translation id="2813094189969465044">Ota-ona nazorati</translation>
 <translation id="281390819046738856">Soʻrov imzolanmadi.</translation>
 <translation id="2814489978934728345">Ushbu sahifa yuklanishini to‘xtatish</translation>
@@ -2200,6 +2206,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">PIN kod kiritildi</translation>
 <translation id="2849936225196189499">Jiddiy</translation>
+<translation id="285033512555869047">Yopilgan</translation>
 <translation id="2850541429955027218">Mavzuni o‘rnatish</translation>
 <translation id="2850672011315104382">Tinish belgilari uslubi</translation>
 <translation id="2852385257476173980">Internetdan foydalanishingiz davomida siz ochgan saytlar roʻyxati shu yerda chiqishi mumkin</translation>
@@ -2243,6 +2250,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> va yana <ph name="NUMBER_OF_DEVICES" /> ta qurilma</translation>
 <translation id="2889043468805635730">Hech qanday muammo topilmadi</translation>
 <translation id="2889064240420137087">Havolani ochish...</translation>
+<translation id="2890206081124517553">Ish stoli fon rasmi barcha qurilmalarda eslab qolinsin</translation>
 <translation id="2891566119238851894">Yon panelda qidiruvni oching. Yon panelda qidiruv yopiq.</translation>
 <translation id="2891922230654533301"><ph name="APP_NAME" /> ilovasiga qurilma orqali kirilsinmi?</translation>
 <translation id="2893013536106749396">Qiziqishingiz asosida xabar olishni istagan kartochkalarni tanlang</translation>
@@ -2264,6 +2272,7 @@
 <translation id="2907619724991574506">Ishga tushirish URL manzillari</translation>
 <translation id="2907798539022650680">“<ph name="NAME" />” tarmog‘iga ulanmadi: <ph name="DETAILS" />
     Server xabari: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">Signallarni ulashish</translation>
 <translation id="2908162660801918428">Media gallereyasini jilddan qo‘shish</translation>
 <translation id="2908358077082926882">Tayinlovni bekor qilish va <ph name="RESPONSE" /> uchun “<ph name="CURRENTKEY" />” tugmasini qayta bosing.</translation>
 <translation id="2909506265808101667">Google xizmatlari aloqada emas. Internetga ulanishni tekshiring va qayta urining. Xatolik kodi: <ph name="ERROR_CODE" />.</translation>
@@ -2368,6 +2377,7 @@
 <translation id="3003828226041301643">Qurilma domenga ulana olmadi. Qurilmalarni ulash huquqi sizga berilmaganga o‘xshaydi.</translation>
 <translation id="3003967365858406397"><ph name="PHONE_NAME" /> maxfiy Wi-Fi ulanish hosil qiladi.</translation>
 <translation id="3004385386820284928">Klaviatura tugmalarini moslash</translation>
+<translation id="3005376701115952939">Ilovalar sinxronlanishi tizim Sozlamalarida saqlandi</translation>
 <translation id="3005574332301273731">Koʻrsatilmasin</translation>
 <translation id="3006881078666935414">Sarf axboroti mavjud emas</translation>
 <translation id="3007410324195400631">“Bu sahifa haqida”ga qaydlar qoʻshish</translation>
@@ -2749,6 +2759,7 @@
 <translation id="3369624026883419694">Host aniqlanmoqda...</translation>
 <translation id="3370260763947406229">Avtomatik tuzatish</translation>
 <translation id="3371140690572404006">USB-C qurilma (o‘ng tomondagi old port)</translation>
+<translation id="3371351218553893534">Qator juda uzun: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">Ilovada ochilgan jildlardagi ma’lumotlarni o‘qish</translation>
 <translation id="3373059063088819384">Oʻqish rejimida ochish</translation>
 <translation id="3373701465337594448">Yoqilsa, qiziqishlarni aniqlovchi saytlar soʻyxati shu yerda chiqadi</translation>
@@ -2819,6 +2830,9 @@
 <translation id="3434272557872943250">Agar farzandingiz uchun Veb va ilovalardagi kengaytirilgan faoliyat tarixi yoqilgan boʻlsa, bu maʼlumotlar uning Google hisobiga saqlanadi. Bu parametr va uni sozlash haqidagi batafsil axborotni families.google.com sahifasidan olish mumkin.</translation>
 <translation id="3434475275396485144">Bu sozlama telefoningiz administratori tomonidan boshqariladi</translation>
 <translation id="3434512374684753970">Audio va video</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />Keyingi ekranda Google hisobingizga kiring.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Bu hisob Gmail, YouTube, Chrome va boshqa Google xizmatlarida ishlatiladi. Xizmatlar moslashtirilishi va axborotlarni oson olish uchun hisobingizdan foydalaning.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Google hisobingiz boʻlmasa, keyingi ekranda yaratishingiz mumkin.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">“<ph name="EXTENSION_NAME" />” kengaytmasi <ph name="CODE_TYPE" /> kod turini so‘rayapti</translation>
 <translation id="3435738964857648380">Xavfsizlik</translation>
 <translation id="343578350365773421">Qogʻoz tugagan</translation>
@@ -2865,6 +2879,7 @@
 <translation id="346546413339447252"><ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> va boshqa xaridlar uchun chegirma olish</translation>
 <translation id="3468298837301810372">Yorliq</translation>
 <translation id="3468999815377931311">Android telefon</translation>
+<translation id="3469345458390352459">Yoqilsa, ilovalaringiz Google hisobidan kirilgan barcha ChromeOS qurilamlarida chiqadi.  Veb ilovalar Chrome orqali sinxronlanadi, hatto brauzer sinxronlanishi yoniq boʻlmasa ham.</translation>
 <translation id="3469583217479686109">Tanlash vositasi</translation>
 <translation id="3470392222765168737">Saytga obuna boʻlish</translation>
 <translation id="3471876058939596279">HDMI va USB Type-C portlari birdaniga video chiqara olmaydi. Boshqa video portga ulang.</translation>
@@ -3327,6 +3342,7 @@
 <translation id="3855441664322950881">Kengaytmani arxivlash</translation>
 <translation id="3855676282923585394">Xatcho‘plar va sozlamalarni import qilish...</translation>
 <translation id="3856096718352044181">Bu ishonchli xizmat ekanini tekshiring yoki keyinroq qayta urining</translation>
+<translation id="3856470183388031602"><ph name="DEVICE_TYPE" /> qurilmasida Google hisobidan foydalaning</translation>
 <translation id="3856800405688283469">Vaqt mintaqasini tanlang</translation>
 <translation id="3857807444929313943">Barmoqni oling va qaytadan tekkizing</translation>
 <translation id="3858860766373142691">Ism</translation>
@@ -3366,6 +3382,7 @@
 <translation id="3894123633473837029">Sherlog orqali yozilgan Assistent tarixini biriktirish. Bunga shaxsiy axborotlaringiz, joylashuv va nosozliklarni aniqlash jurnali axborotlari ham kiritilishi mumkin. <ph name="BEGIN_LINK" />Batafsil<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">Jild qo‘shish</translation>
 <translation id="3894770151966614831">Parol Google hisobingizga oʻtkazilsinmi?</translation>
+<translation id="3894983081771074056">Klaviatura va sichqoncha harakatlari, til sozlamalari va boshqalar</translation>
 <translation id="3895076768659607631">Qidiruv tizimlarini &amp;boshqarish...</translation>
 <translation id="3895090224522145010">Kerberos uchun foydalanuvchi nomi</translation>
 <translation id="389521680295183045">Saytlarga qurilmadan foydalanishga oid axborotlarni soʻrashga ruxsat berish</translation>
@@ -3501,6 +3518,7 @@
 <translation id="3994878504415702912">&amp;Matn o‘lchami</translation>
 <translation id="3995138139523574647">USB-C qurilma (o‘ng tomondagi orqa port)</translation>
 <translation id="3995963973192100066">Animatsiyani ijro qilish</translation>
+<translation id="399788104667917863">Asboblar paneliga mahkamlash</translation>
 <translation id="4001540981461989979">Sichqoncha kursori harakatlanganda ajratib koʻrsatilsin</translation>
 <translation id="4002440992267487163">PIN-kodni sozlash</translation>
 <translation id="4005817994523282006">Vaqt mintaqasi aniqlanish uslubi</translation>
@@ -3659,12 +3677,16 @@
 <translation id="4147911968024186208">Qaytadan urining. Muammo qaytarilsa, mijozlar xizmatiga murojaat qiling.</translation>
 <translation id="4150201353443180367">Ekran</translation>
 <translation id="4150569944729499860">Ekran konteksti</translation>
+<translation id="4151843924968445052">Qurilma signallari ulashilsinmi?</translation>
 <translation id="4152011295694446843">Brauzer bukmarklari shu yerda chiqadi</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 ta ichki oyna}other{# ta ichki oyna}}</translation>
 <translation id="4154664944169082762">Barmoq izlari</translation>
 <translation id="4157869833395312646">Microsoft shifrlash serveri</translation>
 <translation id="4158315983204257156">Saytlardagi matn hajmi va shrifti</translation>
 <translation id="4158364720893025815">Tekshirildi</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />ChromeOS qurilmalariga hisobotlarni avtomatik yuborishga ruxsat bersangiz, xatolarni tuzatish va ChromeOS tizimini yaxshilashimizda yordam bergan boʻlasiz. Bunday hisobotlarga ChromeOS qachon ishlamay qolgani, qaysi funksiyalardan foydalanilgani, odatda qancha xotira ishlatilishi, Android ilovasi diagnostika va foydalanish statistikasi kabi maʼlumotlar kirishi mumkin. Ayrim jamlangan maʼlumotlar Google ilovalari va Android dasturchilar kabi hamkorlarga ham yordam beradi. Ilovalar sinxronizatsiyasi yoniq boʻlsa, Android va veb ilovalar diagnostika va foydlanish statistikasi ham jamlanadi.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Istalgan vaqtda ChromeOS qurilmasi sozlamalari orqali bu hisobotlarni yuborishni boshlash yoki toʻxtatishga ruxsat berishingiz mumkin. Agar domen administratori boʻlsangiz, bu sozlamani administrator konsoli orqali oʻzgartirishingiz mumkin.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Google hisobingiz uchun veb-qidiruv va ilovalar tarixi yoqilgan boʻlsa, Android maʼlumotlari Google hisobingizda saqlanadi. Maʼlumotlaringizni account.google.com orqali koʻrish, oʻchirib tashlash va oʻzgartirish mumkin.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;Google Parollar menejeri</translation>
 <translation id="4163560723127662357">Noma’lum klaviatura</translation>
 <translation id="4165942112764990069"><ph name="USER_EMAIL" /> ishonchli tashkilotga tegishli emas. Administratorga murojaat qiling. Administrator boʻlsangiz, tashkilotingizni quyidagi sahifa orqali sozlang: g.co/ChromeEnterpriseAccount</translation>
@@ -3988,6 +4010,9 @@
 <translation id="4452898361839215358">yoki PPD faylini tanlang. <ph name="LINK_BEGIN" />Batafsil<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">Klaviaturaning yuqori oʻng burchagidagi barmoq izi skaneriga tegining. Barmoq izlaringiz yaxshi himoya ostida va faqat <ph name="DEVICE_TYPE" /> qurilmangizda saqlanadi.</translation>
 <translation id="4453946976636652378"><ph name="SEARCH_ENGINE_NAME" /> orqali qidiring yoki URL manzilni kiriting</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />ChromeOS qurilmalariga hisobotlarni avtomatik yuborishga ruxsat bersangiz, xatolarni tuzatish va ChromeOS tizimini yaxshilashimizda yordam bergan boʻlasiz. Bunday hisobotlarga ChromeOS qachon ishlamay qolgani, qaysi funksiyalardan foydalanilgani, odatda qancha xotira ishlatilishi, Android ilovasi diagnostika va foydalanish statistikasi kabi maʼlumotlar kirishi mumkin. Ayrim jamlangan maʼlumotlar Google ilovalari va Android dasturchilar kabi hamkorlarga ham yordam beradi. Ilovalar sinxronizatsiyasi yoniq boʻlsa, Android va veb ilovalar diagnostika va foydlanish statistikasi ham jamlanadi.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Istalgan vaqtda farzandingizning ChromeOS qurilmasi sozlamalari orqali bu hisobotlarni yuborishni boshlash yoki toʻxtatishga ruxsat berishingiz mumkin. Agar domen administratori boʻlsangiz, bu sozlamani administrator konsoli orqali oʻzgartirishingiz mumkin.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />Farzandingizning Google hisobi uchun veb-qidiruv va ilovalar tarixi yoqilgan boʻlsa, Android maʼlumotlari uning Google hisobida saqlanadi. Bu parametr va uni sozlash haqidagi batafsil axborotni families.google.com sahifasidan olish mumkin.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">Joriy ovozni tanlash:</translation>
 <translation id="4459169140545916303"><ph name="DEVICE_LAST_ACTIVATED_TIME" /> kun oldin onlayn edi</translation>
 <translation id="4460014764210899310">Guruhni bekor qilish</translation>
@@ -4368,6 +4393,7 @@
 <translation id="4806457879608775995">Bu maʼlumotlar bilan tanishib chiqing va maʼlumotlaringizni nazorat qiling</translation>
 <translation id="4807098396393229769">Karta egasining ismi</translation>
 <translation id="4808667324955055115">Qalqib chiquvchi oynalar taqiqlangan</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Chrome Web Store omboridan oʻchirilgan <ph name="BEGIN_BOLD" />1 ta kengaytmani<ph name="END_BOLD" /> tekshiring}other{Chrome Web Store omboridan oʻchirilgan <ph name="BEGIN_BOLD" />{NUM_EXTENSIONS} ta kengaytmani<ph name="END_BOLD" /> tekshiring}}</translation>
 <translation id="4809079943450490359">Administrator korsatmalari:</translation>
 <translation id="4809447465126035330">Oʻchirish</translation>
 <translation id="480990236307250886">Bosh sahifani ochish</translation>
@@ -4691,6 +4717,7 @@
 <translation id="5101839224773798795">Kursor harakati toʻxtaganda avtomatik klik bosilsin</translation>
 <translation id="5106350808162641062">Olib tashlash</translation>
 <translation id="510695978163689362"><ph name="USER_EMAIL" /> Family Link bilan boshqariladi. Ota-ona nazorati bilan maktab resurslariga kirish uchun maktab hisoblarini kiritishingiz mumkin.</translation>
+<translation id="5107093668001980925"><ph name="MODULE_NAME" /> hech qachon chiqarilmasin</translation>
 <translation id="5107443654503185812">Saytlarni xavfsiz kezish kengaytma tomonidan faolsizlantirildi</translation>
 <translation id="5108967062857032718">Sozlamalar – Android ilovalarni olib tashlash</translation>
 <translation id="5109044022078737958">Mia</translation>
@@ -4701,6 +4728,7 @@
 <translation id="5111794652433847656">Bu qurilmada <ph name="APP_NAME" /> uchun hech qanday kod mavjud emas</translation>
 <translation id="5112577000029535889">&amp;Dasturchi vositalari</translation>
 <translation id="511313294362309725">Tezkor ulanish funksiyasini yoqish</translation>
+<translation id="5113384440341086023">Play Market orqali oʻrnatilgan ilovalar va Chrome brauzeridagi veb ilovalar</translation>
 <translation id="51143538739122961">Elektron kalitni qayta suqing va undagi tugmani bosing</translation>
 <translation id="5115309401544567011"><ph name="DEVICE_TYPE" /> qurilmangizni elektr quvvatiga ulang.</translation>
 <translation id="5115338116365931134">SSO</translation>
@@ -4746,6 +4774,7 @@
 <translation id="5154702632169343078">Subyekt</translation>
 <translation id="5155327081870541046">Manzil qatorida qidiriladigan sayt uchun “@bookmarks” kabi buyruqni kiriting. Keyin oldindan belgilangan tezkor tugmani bosib, qidiruv iborasini kiriting.</translation>
 <translation id="5156638757840305347">Kursor chiqqanda yoki surilganda ajratib belgilanadi</translation>
+<translation id="5157250307065481244">Sayt axborotini ochish</translation>
 <translation id="5157635116769074044">Ushbu sahifani bosh ekranga qadab qo‘yish...</translation>
 <translation id="5158206172605340248">Urgʻu belgilari menyusi yopildi.</translation>
 <translation id="5159094275429367735">Crostini taʼminotini sozlash</translation>
@@ -5805,6 +5834,7 @@
 <translation id="6104068876731806426">Google Hisoblar</translation>
 <translation id="6104311680260824317">Qurilma domenga ulanmadi. Serverda ko‘rsatilgan Kerberos kodlash usuli ta’minoti mavjud emas. Shifrlash usulini sozlash uchun “Qo‘shimcha parametrlar” bandini tekshiring.</translation>
 <translation id="6104796831253957966">Chop etish navbatida joy qolmadi</translation>
+<translation id="6106167152849320869">Avvalgi ekranda diagnostika va foydalanish statistikasi ham yuborilishi tanlansa, bu axborotlar oʻrnatilgan ilovalar uchun ham jamlanadi.</translation>
 <translation id="6111972606040028426">Google Assistentni yoqish</translation>
 <translation id="6112294629795967147">Hajmini moslash uchun tegining</translation>
 <translation id="6112727384379533756">Chipta kiritish</translation>
@@ -5935,6 +5965,7 @@
 <translation id="6226777517901268232">Yopiq kalit fayli (ixtiyoriy)</translation>
 <translation id="6227002569366039565">Bu bildirgini fokuslash uchun |<ph name="ACCELERATOR" />| ustiga bosing. Keyin esa koʻrsatish uchun yana element ustiga fokuslang.</translation>
 <translation id="6227280783235722609">kengaytma</translation>
+<translation id="6229062790325126537">ApnMigrator sozlamalarini tiklash</translation>
 <translation id="6229849828796482487">Wi-Fi tarmoqni uzish</translation>
 <translation id="6231782223312638214">Tavsiya etiladi</translation>
 <translation id="6231881193380278751">Sahifa avtomatik yangilanishi uchun URL manzilga so‘rov parametrini qo‘shing: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6212,6 +6243,7 @@
 <translation id="6478248366783946499">Xavfli fayl yuklab olinsinmi?</translation>
 <translation id="6479881432656947268">Chrome Web Store doʻkonini ochish</translation>
 <translation id="6480327114083866287"><ph name="MANAGER" /> tomonidan boshqariladi</translation>
+<translation id="6481978993812487794">Yoqilsa, ilovalaringiz Google hisobidan kirilgan barcha ChromeOS qurilamlarida chiqadi. Veb ilovalar Chrome orqali sinxronlanadi, hatto brauzer sinxronlanishi yoniq boʻlmasa ham.</translation>
 <translation id="6482559668224714696">Butun ekran rejimidagi lupa</translation>
 <translation id="6483485061007832714">Yuklanmani ochish</translation>
 <translation id="6483805311199035658"><ph name="FILE" /> ochilmoqda...</translation>
@@ -6226,6 +6258,7 @@
 <translation id="6497784818439587832">Ekrandagi elementlarni kichiklashtirish yoki kattalashtirish uchun ekran oʻlchamini oʻzgartiring</translation>
 <translation id="6497789971060331894">Sichqoncha bilan teskari aylantirish</translation>
 <translation id="6498249116389603658">Barcha tillar</translation>
+<translation id="6498583202177273322">Bu sahifani kezish vaqtida qoʻshimcha foydali axborot oling</translation>
 <translation id="6499143127267478107">Proksi-server skriptida host manzili aniqlanmoqda...</translation>
 <translation id="6499764981457476645">Yaqin-atrofda hech qanday qurilma topilmadi</translation>
 <translation id="6501957628055559556">Barcha konteynerlar</translation>
@@ -6672,6 +6705,7 @@
 <translation id="688312408602122936">Steam orqali oʻrnatilgan har qanday oʻyin va ilovalar bu qurilmadan olib tashlanadi</translation>
 <translation id="6883319974225028188">Tizim qurilma parametrlarini saqlay olmadi.</translation>
 <translation id="6884474387073389421">Ushbu tanlangan kirish maʼlumotlari oʻchirib tashlansinmi?</translation>
+<translation id="6885122019363983153">Qurilmalar ish stolida fon rasmini bir xil qilish</translation>
 <translation id="6885771755599377173">Tizim haqida ma’lumot</translation>
 <translation id="6886380424988777998">Linux yangilanmadi</translation>
 <translation id="6886871292305414135">&amp;Havolani yangi ichki oynada ochish</translation>
@@ -6743,6 +6777,7 @@
 <translation id="6949434160682548041">Parol (ixtiyoriy)</translation>
 <translation id="6950627417367801484">Ilovalarni tiklash</translation>
 <translation id="6952242901357037157">Shuningdek, bu yerda <ph name="BEGIN_LINK" />Google hisobingizdagi<ph name="END_LINK" /> parollarni chiqarish mumkin</translation>
+<translation id="6954910832698269894">Avvalgi Chromebookdagi ilovalar, sozlamalar, WI-Fi tarmoqlar va fon rasmlarini tiklash uchun brauzerda sinxronizatsiyani yoqing. Bu istalgan vaqt Sozlamalar &gt; Hisoblar orqali oʻzgartirish mumkin.</translation>
 <translation id="6954936693361896459">Oʻrniga bu varaqni uzatish</translation>
 <translation id="6955446738988643816">Qalqib chiquvchi oynani ko‘rish</translation>
 <translation id="6955535239952325894">Bu sozlama boshqaruv ostidagi brauzerlarda yoqilmagan</translation>
@@ -6901,6 +6936,7 @@
 <translation id="7075513071073410194">PKCS #1 MD5 algoritmli RSA shifrlash</translation>
 <translation id="7075625805486468288">HTTPS/SSL sertifikatlari va sozlamalarini boshqarish</translation>
 <translation id="7076875098323397992">Yangilash boshlanmadi</translation>
+<translation id="7077751457066325012">Maxsus klaviatura tugmalarini koʻrish va moslash</translation>
 <translation id="7077829361966535409">Bosh sahifada joriy proksi-server sozlamalarini yuklash vaqtida xatolik yuz berdi. <ph name="GAIA_RELOAD_LINK_START" />Tizimga qaytadan kiring<ph name="GAIA_RELOAD_LINK_END" /> yoki <ph name="PROXY_SETTINGS_LINK_START" />proksi-server sozlamalarini<ph name="PROXY_SETTINGS_LINK_END" /> o‘zgartiring.</translation>
 <translation id="7078120482318506217">Barcha tarmoqlar</translation>
 <translation id="708060913198414444">Audioning URL manzilini nusxalash</translation>
@@ -6930,6 +6966,7 @@
 <translation id="7108933416628942903">Hozir qulflash</translation>
 <translation id="7109543803214225826">Yorliq olib tashlandi</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{Varaqni guruhga kiritish}other{Varaqlarni guruhga kiritish}}</translation>
+<translation id="7110684627876015299">Nomsiz guruh – <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">Bu oynaga nom bering</translation>
 <translation id="7113102733263608554"><ph name="ITEM_COUNT_ONE" /> ta narsa</translation>
 <translation id="7113502843173351041">Email manzilingizni bilish</translation>
@@ -7144,6 +7181,7 @@
 <translation id="7328867076235380839">Xato kombinatsiya</translation>
 <translation id="7329154610228416156">Kirish amalga oshmadi, chunki u xavfli URL manzildan foydalanish uchun moslangan (<ph name="BLOCKED_URL" />). Administrator bilan bog‘laning.</translation>
 <translation id="7332053360324989309">Dedicated Worker: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">Ilova va sozlamalarni zaxiralash va tiklash</translation>
 <translation id="7335974957018254119">Imlo tekshiruvi quyidagilar uchun ishlatilsin:</translation>
 <translation id="7336799713063880535">Bildirishnomalar bloklandi.</translation>
 <translation id="7338630283264858612">Qurilma seriya raqami yaroqsiz.</translation>
@@ -7166,6 +7204,7 @@
 <translation id="7348093485538360975">Ekran klaviaturasi</translation>
 <translation id="7349010927677336670">Videoning ravonligi</translation>
 <translation id="7352651011704765696">Xatolik yuz berdi.</translation>
+<translation id="7352664183151911163">Ilovalar va Chrome brauzeri orasida</translation>
 <translation id="7353261921908507769">Kontaktlaringiz sizga yaqinligida sizga fayl ulasha oladi. Uzatmalar qabul qilinmaguncha boshlanmaydi.</translation>
 <translation id="735361434055555355">Linux o‘rnatilmoqda...</translation>
 <translation id="7354120289251608189">Endi istalgan vaqt brauzerni yangicha bezatish mumkin.</translation>
@@ -7305,6 +7344,8 @@
 <translation id="7458168200501453431">Google qidiruvida ishlatiladigan imlo tekshiruvi vositasidan foydalanadi. Brauzerda kiritiladigan matn Google serverlariga yuboriladi.</translation>
 <translation id="7458715171471938198">Ilovalar tiklansinmi?</translation>
 <translation id="7458933488302148148">Saqlangan parollarni xavfsizlikni kuchaytirish va onlaynda xavfsiz qolish maqsadlarida tekshiring</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />ChromeOS qurilmalariga hisobotlarni avtomatik yuborishga ruxsat bersangiz, xatolarni tuzatish va ChromeOS tizimini yaxshilashimizda yordam bergan boʻlasiz. Bunday hisobotlarga ChromeOS qachon ishlamay qolgani, qaysi funksiyalardan foydalanilgani va odatda qancha xotira ishlatilishi kabi maʼlumotlar kirishi mumkin. Ilovalar sinxronizatsiyasi yoniq boʻlsa, Android va veb ilovalar diagnostika va foydlanish statistikasi ham jamlanadi.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Istalgan vaqtda Chrome qurilmasi sozlamalari orqali bu hisobotlarni yuborishni boshlash yoki toʻxtatishga ruxsat berishingiz mumkin. Agar domen administratori boʻlsangiz, bu sozlamani administrator konsoli orqali oʻzgartirishingiz mumkin.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">Siz oʻrnatgan joriy mavzu</translation>
 <translation id="7461924472993315131">Qadab qo‘yish</translation>
 <translation id="746216226901520237">Keyingi safar telefoningiz <ph name="DEVICE_TYPE" /> qurilmasini qulfdan chiqara oladi. Sozlamalar orqali Smart Lock funksiyasini faolsizlantirish mumkin.</translation>
@@ -7538,6 +7579,7 @@
 <translation id="7663719505383602579">Qabul qiluvchi: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">Tezkor tugmadan foydalanish mumkin</translation>
 <translation id="7663859337051362114">eSIM profilini kiritish</translation>
+<translation id="76641554187607347">Hech qaysi klaviatura ulanmagan</translation>
 <translation id="7665082356120621510">Oʻlchamni saqlash</translation>
 <translation id="7665369617277396874">Hisob kiritish</translation>
 <translation id="766560638707011986">Domenlarni koʻrsatish</translation>
@@ -7585,6 +7627,7 @@
 <translation id="769824636077131955">Bu hujjat juda katta hajmdaligi uchun uni tekshirish imkonsiz. 50 MBdan katta hajmdagi hujjatlar chop etilmaydi.</translation>
 <translation id="7698507637739331665">Ayrim fayllar bloklandi</translation>
 <translation id="7701040980221191251">Hech qanday</translation>
+<translation id="7701265686005869308">Profilni yopish</translation>
 <translation id="7701869757853594372">USER deskriptorlari</translation>
 <translation id="7702574632857388784"><ph name="FILE_NAME" /> faylini roʻyxatdan olib tashlash</translation>
 <translation id="7702907602086592255">Domen</translation>
@@ -8005,6 +8048,7 @@
 <translation id="8050191834453426339">Qayta tasdiqlash</translation>
 <translation id="8051193500142930381">Kamera ishlatadigan funksiyalar ishlamaydi</translation>
 <translation id="8051390370038326517"><ph name="HOST" /> sayti doim MIDI qurilmalarni toʻliq boshqarishi mumkin</translation>
+<translation id="8052218774860457016">Brauzerni sinxronlash boshqaruvi</translation>
 <translation id="8053278772142718589">PKCS #12 fayllari</translation>
 <translation id="8053390638574070785">Sahifani yangilash</translation>
 <translation id="8054517699425078995">Bunday turdagi fayl qurilmangizga zarar yetkazishi mumkin. <ph name="FILE_NAME" /> baribir saqlansinmi?</translation>
@@ -8374,6 +8418,7 @@
 <translation id="8376137163494131156">Google Cast bilan bogʻliq fikr-mulohazalaringizni ulashing.</translation>
 <translation id="8376384591331888629">Bu saytdagi tashqi cookie fayllariga ham</translation>
 <translation id="8376451933628734023">Agar bu veb ilova shubhali ishlasa, uni oʻchirib tashlang.</translation>
+<translation id="8376752431516546391">Google qidiruv yon paneli</translation>
 <translation id="8377625247046155446">Bu kod faqat shu qurilmada saqlanadi Barcha inkognito oynalari yopilganidan keyin kod shu qurilmada qoladi.</translation>
 <translation id="8378714024927312812">Tashkilotingiz tomonidan boshqariladi</translation>
 <translation id="8379878387931047019">Bu qurilmada sayt so‘ragan kalit turi mavjud emas</translation>
@@ -8441,6 +8486,11 @@
 <translation id="8428628598981198790">Elektron kalitingiz bu saytda ishlamaydi</translation>
 <translation id="84297032718407999"><ph name="LOGOUT_TIME_LEFT" />dan keyin tizimdan chiqasiz</translation>
 <translation id="8431190899827883166">Vizual teginish</translation>
+<translation id="8431496281632382473">Bu profil boshqaruvchisi: <ph name="DOMAIN" /> Bu boshqaruvdagi profildan foydalanishda davom etish uchun tashkilot qurilma signallarini ulashishni talab qiladi.
+
+Qurilma signallari brauzer, OT, qurilma, oʻrnatilgan dasturlar va fayllar haqidagi axborotdan iborat boʻlishi mumkin.
+
+Signallar ulashilmasligi tanlansa, bu profil yopiladi.</translation>
 <translation id="8434480141477525001">NaCl nosozliklarni ko‘rib chiqish porti</translation>
 <translation id="8437209419043462667">Ingliz (AQSH)</translation>
 <translation id="8438328416656800239">Qulay brauzerdan foydalaning</translation>
@@ -8525,6 +8575,8 @@
 <translation id="851263357009351303"><ph name="HOST" /> rasmlarni doim ko‘rsatsin</translation>
 <translation id="8513108775083588393">Avto-burilish</translation>
 <translation id="8513357934662532537"><ph name="USER_EMAIL" /> parollarini <ph name="BRAND" /> ga import qilish uchun CSV faylni tanlang.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />ChromeOS qurilmalariga hisobotlarni avtomatik yuborishga ruxsat bersangiz, xatolarni tuzatish va ChromeOS tizimini yaxshilashimizda yordam bergan boʻlasiz. Bunday hisobotlarga ChromeOS qachon ishlamay qolgani, qaysi funksiyalardan foydalanilgani va odatda qancha xotira ishlatilishi kabi maʼlumotlar kirishi mumkin. Ilovalar sinxronizatsiyasi yoniq boʻlsa, Android va veb ilovalar diagnostika va foydlanish statistikasi ham jamlanadi.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Istalgan vaqtda farzandingizning ChromeOS qurilmasi sozlamalari orqali bu hisobotlarni yuborishni boshlash yoki toʻxtatishga ruxsat berishingiz mumkin. Agar domen administratori boʻlsangiz, bu sozlamani administrator konsoli orqali oʻzgartirishingiz mumkin.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">Boshqa elektron kalit bilan urining</translation>
 <translation id="8514955299594277296">Saytlarga maʼlumotlarni qurilmangizga saqlashga ruxsat bermang (tavsiya etilmaydi)</translation>
 <translation id="8517759303731677493">Tahrirlash…</translation>
@@ -8885,6 +8937,7 @@
 <translation id="883062543841130884">Almashtiruvlar</translation>
 <translation id="8830779999439981481">Yangilanishlarni qoʻllash uchun qayta ishga tushirilmoqda</translation>
 <translation id="8830796635868321089">Yangilanishlar tekshiruvini bajarib bo‘lmadi. <ph name="PROXY_SETTINGS_LINK_START" />Proksi-server sozlamalarini<ph name="PROXY_SETTINGS_LINK_END" /> tekshiring.</translation>
+<translation id="8830863983385452402">Sayt bu varaqdagi kontentni koʻra oladi</translation>
 <translation id="8831769650322069887">Ochish: <ph name="FILE_NAME" /></translation>
 <translation id="8832781841902333794">Profillaringiz</translation>
 <translation id="8834039744648160717">Tarmoq sozlamalari <ph name="USER_EMAIL" /> tomonidan boshqariladi.</translation>
@@ -9016,6 +9069,7 @@
 <translation id="8946359700442089734">Nosozliklarni ko‘rib chiqish xususiyatlari <ph name="IDS_SHORT_PRODUCT_NAME" /> qurilmaga to‘liq yoqilmagan.</translation>
 <translation id="894763922177556086">Yaxshi</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> elektron kalitingiz modeli va markasini koʻrmoqchi</translation>
+<translation id="8949304443659090542">Chrome brauzeri sinxronlanishini boshqarish</translation>
 <translation id="895054485242522631">Saytlar harakat sensorlaridan foydalanishi mumkin</translation>
 <translation id="8951256747718668828">Xato tufayli tiklanmadi</translation>
 <translation id="8951465597020890363">Mehmon rejimidan baribir chiqilsinmi?</translation>
@@ -9121,6 +9175,7 @@
 <translation id="9032097289595078011">Tezkor ulanish funksiyasini faolsizlantirish</translation>
 <translation id="9033765790910064284">Baribir davom ettirilsin</translation>
 <translation id="9033857511263905942">&amp;Joylash</translation>
+<translation id="9034408118624208974">Chromebookdan foydalanmaganmisiz? Sinxronizatsiya yoqilsa, sozlamalar zaxiralanadi.</translation>
 <translation id="903480517321259405">PIN kodni qayta kiriting</translation>
 <translation id="9037054491984310631"><ph name="DEVICE" /> nomli Bluetooth qurilmaga ulangan</translation>
 <translation id="9037640663275993951">Qurilmaga ruxsat berilmagan</translation>
@@ -9164,6 +9219,7 @@
 <translation id="9068298336633421551">Joylashuv axborotiga ruxsati bor Android ilova va xizmatlariga bu qurilma joylashuvi haqidagi axborotdan foydalanishiga ruxsat bering. Joylashuv axborotining aniqligini oshirish hamda ayrim xizmatlar sifatini yaxshilash maqsadida Google vaqti-vaqti bilan foydalanuvchilarning joylashuvi haqidagi anonimlashtirilgan axborotni olib turishi ham mumkin.</translation>
 <translation id="9068598199622656904">Tezkor tugma uchun tugmalarni birga bosib turish oʻrniga bir marta bosish</translation>
 <translation id="9068878141610261315">Bu fayl turi dastaklanmaydi</translation>
+<translation id="9069665781180028115">Bu Chromebookda quyidagi elementlar chiqadi. Chromebook bilan ishlamagan boʻlsangiz, sozlamalar zaxiralanishi uchun barcha elementlar sinxronlanishini tanlang. Bu istalgan vaqt Sozlamalar &gt; Hisoblar orqali oʻzgartirish mumkin.</translation>
 <translation id="9070342919388027491">Varaq chapga olindi</translation>
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9074836595010225693">USB sichqoncha ulanildi</translation>
@@ -9337,6 +9393,7 @@
 <translation id="930268624053534560">Batafsil vaqt nishonlari</translation>
 <translation id="930551443325541578">Qaytarish tugmalari va urgʻu belgilari</translation>
 <translation id="930893132043726269">Hozir roumingda</translation>
+<translation id="930991362911221750"><ph name="APP_NAME" /> bu varaqni koʻrishiga ruxsat berilsinmi?</translation>
 <translation id="93140074055951850">Android ilovalar toʻxtatildi</translation>
 <translation id="932327136139879170">Bosh sahifa</translation>
 <translation id="932508678520956232">Chop etishni boshlab bo‘lmadi.</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb
index 562c7e9..afd860a 100644
--- a/chrome/app/resources/generated_resources_zh-HK.xtb
+++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -5993,6 +5993,7 @@
 <translation id="6266532094411434237">正在連接 <ph name="DEVICE" /></translation>
 <translation id="6267166720438879315">請選取您在 <ph name="HOST_NAME" /> 的驗證憑證</translation>
 <translation id="6268252012308737255">使用 <ph name="APP" /> 開啟</translation>
+<translation id="6270309713620950855">靜音自動提醒</translation>
 <translation id="6270391203985052864">網站將可以要求向您傳送通知</translation>
 <translation id="6270770586500173387">傳送<ph name="BEGIN_LINK1" />系統和應用程式資訊<ph name="END_LINK1" />,以及<ph name="BEGIN_LINK2" />指標數據<ph name="END_LINK2" /></translation>
 <translation id="6270896861225278704">瀏覽過程資訊卡</translation>
@@ -6327,6 +6328,7 @@
 <translation id="657866106756413002">網絡健康快覽</translation>
 <translation id="6579369886355986318">顯示所有控制項(&amp;C)</translation>
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> - 已共用桌面內容</translation>
+<translation id="6580060371127789208">已完成 <ph name="PERCENTAGE_COMPLETE" />%</translation>
 <translation id="6580203076670148210">掃瞄速度</translation>
 <translation id="6582080224869403177">重設您的 <ph name="DEVICE_TYPE" />,以進行安全性升級。</translation>
 <translation id="6582274660680936615">您目前是以訪客身分瀏覽</translation>
@@ -6948,6 +6950,7 @@
 <translation id="7114054701490058191">密碼不符</translation>
 <translation id="7114648273807173152">如要使用 Smart Lock 登入 Google 帳戶,請前往 [設定] &gt; [已連接的裝置] &gt; [您的手機] &gt; [Smart Lock]。</translation>
 <translation id="7115361495406486998">沒有可用的聯絡人</translation>
+<translation id="7116554090938189816">打印機 SSL 憑證已過期。請重新啟動打印機,並再試一次。</translation>
 <translation id="7117228822971127758">請稍後再試</translation>
 <translation id="711840821796638741">顯示受管理書籤</translation>
 <translation id="711985611146095797">您可在此頁面管理已登入的 Google 帳戶。<ph name="LINK_BEGIN" />瞭解詳情<ph name="LINK_END" /></translation>
@@ -7232,6 +7235,7 @@
 <translation id="7392118418926456391">病毒掃描失敗</translation>
 <translation id="7392915005464253525">重新開啟已關閉視窗(&amp;E)</translation>
 <translation id="7393073300870882456">{COUNT,plural, =1{已複製 1 個項目}other{已複製 {COUNT} 個項目}}</translation>
+<translation id="7393435859300249877">如果您在使用特定應用程式 (例如視像通訊應用程式) 時向已靜音的麥克風說話,系統將會顯示通知。音訊資料絕不會外洩。</translation>
 <translation id="7395774987022469191">整個螢幕畫面</translation>
 <translation id="7396017167185131589">共用資料夾將會在這裡顯示</translation>
 <translation id="7396845648024431313"><ph name="APP_NAME" /> 會隨著系統一併啟動,即使在所有 <ph name="PRODUCT_NAME" /> 視窗都關閉後,仍會在背景繼續執行。</translation>
diff --git a/chrome/app/resources/generated_resources_zu.xtb b/chrome/app/resources/generated_resources_zu.xtb
index e97df90..ba3ec507 100644
--- a/chrome/app/resources/generated_resources_zu.xtb
+++ b/chrome/app/resources/generated_resources_zu.xtb
@@ -218,6 +218,7 @@
 <translation id="1176471985365269981">Ayivumelekile ukuhlela amafayela noma amafolda kudivayisi yakho</translation>
 <translation id="1177863135347784049">Ngokwezifiso</translation>
 <translation id="1178581264944972037">Misa isikhashana</translation>
+<translation id="1178601482396475810">Phatha ukuvumelanisa kwedivayisi</translation>
 <translation id="117916940443676133">Ukhiye wakho wokuqinisekisa ubunikazi awuvunyelwe ngephinikhodi. Ukuze uphathe idatha yokungena ngemvume, qala udale iphinikhodi</translation>
 <translation id="1181037720776840403">Susa</translation>
 <translation id="1181366777303791449">ngomhla ka-<ph name="MAIN_FRAME_ETLD_PLUS_ONE" /></translation>
@@ -356,6 +357,7 @@
 <translation id="130097046531636712">Lokhu kunweba amandla ebhethri ngokukhawulela umsebenzi ongemuva nemiphumela ebonakalayo njengokuskrola okubushelelezi</translation>
 <translation id="1301135395320604080">I-<ph name="ORIGIN" /> ingahlela amafayela alandelayo</translation>
 <translation id="1302227299132585524">Vumela i-JavaScript kusukela kumicimbi ye-Apple</translation>
+<translation id="1302654693270046655">Iqembu le-<ph name="GROUP_NAME" /> - <ph name="OPENED_STATE" /></translation>
 <translation id="1303101771013849280">Ifayela le-HTML lamabhukhimakhi</translation>
 <translation id="1303671224831497365">Awekho amadivayisi e-Bluetooth atholiwe</translation>
 <translation id="130491383855577612">Izinhlelo zokusebenza namafayela e-Linux amiselelwe ngempumelelo</translation>
@@ -1061,6 +1063,7 @@
 <translation id="1877520246462554164">Yehlulekile ukuthola ithokheni yokufakazela ubuqiniso. Sicela uphume ngemvume bese ungena ngemvume futhi ukuze uzame futhi.</translation>
 <translation id="1877860345998737529">Ukunikezwa kwesenzo sokushintshwa</translation>
 <translation id="1878155070920054810">Kubonakala sengathi i-Chromebook yakho izophelelwa amandla ngaphambi kokuthi isibuyekezo siqedele. Qiniseka ukuthi ishaja kahle ukugwema ukuphazamiseka.</translation>
+<translation id="1878477879455105085">Livuliwe</translation>
 <translation id="1878885068166344708">Into igqanyiswa lapho ususa ukugxila. Cindezela ithebhu noma khetha into ukuze ushintshe ukugxila.</translation>
 <translation id="1879000426787380528">Ngena ngemvume njengo-</translation>
 <translation id="18802377548000045">Amathebhu ayancipha abe ububanzi obukhulu</translation>
@@ -1446,6 +1449,7 @@
 <translation id="2204034823255629767">Funda futhi ushintshe noma yini oyithayiphayo</translation>
 <translation id="2204387456724731099">Lokhu okukhethiwe akukwazanga ukuhunyushwa</translation>
 <translation id="2210462644007531147">Ayikwazanga ukuqeda ukufaka</translation>
+<translation id="2211245494465528624">Phatha ongakhetha kukho kokuvumelanisa</translation>
 <translation id="2212565012507486665">Vumela amakhukhi</translation>
 <translation id="2214018885812055163">Amafolda abiwe</translation>
 <translation id="2214884991347062907">Iphasiwedi engalungile, zama futhi</translation>
@@ -1544,6 +1548,7 @@
 <translation id="2296218178174497398">Ukutholakala kwedivayisi</translation>
 <translation id="2297705863329999812">Sesha amaphrinta</translation>
 <translation id="2297822946037605517">Yaba leli khasi</translation>
+<translation id="229871422646860597">Susa ukuphina kwibha yamathuluzi</translation>
 <translation id="2299734369537008228">Isilayida: <ph name="MIN_LABEL" /> ku-<ph name="MAX_LABEL" /></translation>
 <translation id="2299941608784654630">Faka wonke amafayela elogu aqoqwe ngokususa iphutha njengengobo yomlando ehlukanisiwe.</translation>
 <translation id="2300214399009193026">PCIe</translation>
@@ -2175,6 +2180,7 @@
 <translation id="2811205483104563968">Ama-akhawunti</translation>
 <translation id="2811564570599779918">Ukwehliswa kogaxekile nokukhwabanisa</translation>
 <translation id="2812049959647166806">I-thunderbolt ayisekelwe</translation>
+<translation id="2812171980080389735">Amanethiwekhi alondoloziwe namaphasiwedi ukuze ukwazi ukuxhuma ngokushesha</translation>
 <translation id="2813094189969465044">Izilawuli zomzali</translation>
 <translation id="281390819046738856">Isicelo asikwazanga ukusayindwa</translation>
 <translation id="2814489978934728345">Misa ukulayisha leli khasi</translation>
@@ -2214,6 +2220,7 @@
 <translation id="284970761985428403"><ph name="ASCII_NAME" /> (<ph name="UNICODE_NAME" />)</translation>
 <translation id="2849767214114481738">Iphinikhodi yakho ifakiwe</translation>
 <translation id="2849936225196189499">Bucayi</translation>
+<translation id="285033512555869047">Valiwe</translation>
 <translation id="2850541429955027218">Engeza itimu</translation>
 <translation id="2850672011315104382">Isitayela Sezimpawu Zokubhala</translation>
 <translation id="2852385257476173980">Uhlu lwamasayithi owavakashelayo lungase luvele lapha njengoba ubhrawuza iwebhu</translation>
@@ -2257,6 +2264,7 @@
 <translation id="288734198558082692"><ph name="DEVICE" /> nabanye abangu-<ph name="NUMBER_OF_DEVICES" /></translation>
 <translation id="2889043468805635730">Azikho izinkinga ezitholiwe</translation>
 <translation id="2889064240420137087">Vula isixhumanisi nge...</translation>
+<translation id="2890206081124517553">Khumbula ingemuva ledeskithophu yakho kuwo wonke amadivayisi</translation>
 <translation id="2891566119238851894">Vula usesho kuphaneli eseceleni. Usesho aluvuliwe kuphaneli eseceleni.</translation>
 <translation id="2891922230654533301">Sebenzisa idivayisi yakho ukungena ngemvume ku-<ph name="APP_NAME" />?</translation>
 <translation id="2893013536106749396">Khetha amakhadi akugcina unolwazi lwakamuva ngezinto ezibalulekile kuwe</translation>
@@ -2278,6 +2286,7 @@
 <translation id="2907619724991574506">Ama-URL wokuqala</translation>
 <translation id="2907798539022650680">Yehlulekile ukuxhumeka ku-'<ph name="NAME" />': <ph name="DETAILS" />
     Umlayezo weseva: <ph name="SERVER_MSG" /></translation>
+<translation id="2908005622251445419">Yabelana ngamasignali</translation>
 <translation id="2908162660801918428">Engeza igalari yemidiya ngomkhombandlela</translation>
 <translation id="2908358077082926882">Cindezela futhi i-"<ph name="CURRENTKEY" />" ukuze ususe umsebenzi ne-<ph name="RESPONSE" /></translation>
 <translation id="2909506265808101667">Ayikwazanga ukuxhumana namasevisi e-Google. Hlola uxhumo lwakho lwenethiwekhi uphinde uzame futhi Ikhodi yephutha: <ph name="ERROR_CODE" />.</translation>
@@ -2382,6 +2391,7 @@
 <translation id="3003828226041301643">Ayikwazi ukujoyina isizinda. Hlola i-akhawunti yakho uphinde wenze isiqinisekiso sokuthi unamalungelo okungeza amadivayisi.</translation>
 <translation id="3003967365858406397">I-<ph name="PHONE_NAME" /> yakho izodala uxhumo lwe-Wi-Fi olungasese.</translation>
 <translation id="3004385386820284928">Enza ngokwezifiso okhiye bekhibhodi</translation>
+<translation id="3005376701115952939">Ukuvumelanisa ama-app kusethwe kumasethingi wesistimu</translation>
 <translation id="3005574332301273731">Ungabonisi</translation>
 <translation id="3006881078666935414">Ayikho idatha yokusebenza</translation>
 <translation id="3007410324195400631">Engeza Amanothi Mayelana Naleli Khasi</translation>
@@ -2763,6 +2773,7 @@
 <translation id="3369624026883419694">Ixazulula umsingathi...</translation>
 <translation id="3370260763947406229">Ukulungisa okuzenzakalelayo</translation>
 <translation id="3371140690572404006">Idivayisi ye-USB-C (imbobo ephambili yohlangothi lwesinxele)</translation>
+<translation id="3371351218553893534">Umugqa mude kakhulu: <ph name="ERROR_LINE" /></translation>
 <translation id="337286756654493126">Funda amafolda owavula kuhlelo lokusebenza</translation>
 <translation id="3373059063088819384">Vula Kumodi Yokufunda</translation>
 <translation id="3373701465337594448">Uma luvuliwe, uhlu lwamasayithi owavakashelayo aqagela izinto ongaba nentshisekelo kuzo zivela lapha</translation>
@@ -2833,6 +2844,9 @@
 <translation id="3434272557872943250">Uma isilungiselelo esingeziwe sewebhu nesohlelo lokusebenza sivulelwe ingane yakho, le datha ingalondolozwa ku-akhawunti yakhe ye-Google. Funda kabanzi ngalezi zilungiselelo nendlela yokuzilungisa kwethi families.google.com.</translation>
 <translation id="3434475275396485144">Le sethingi iphethwe ngumlawuli wefoni yakho</translation>
 <translation id="3434512374684753970">Umsindo Nevidiyo</translation>
+<translation id="343517373502662180"><ph name="BEGIN_PARAGRAPH1" />Esikrinini esilandelayo, ngena ngemvume ku-Google Account yakho.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Lena i-akhawunti efanayo oyisebenzisela i-Gmail, i-YouTube, i-Chrome, namanye amasevisi e-Google. Sebenzisa i-akhawunti yakho ukuze uthole ulwazi lomuntu siqu kanye nokufinyelela kalula kulo lonke ulwazi lwakho.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Uma ungenayo i-Google Account, uzokwazi ukusungula eyodwa esikrinini esilandelayo.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="3435688026795609344">I-"<ph name="EXTENSION_NAME" />" icela i-<ph name="CODE_TYPE" /> yakho</translation>
 <translation id="3435738964857648380">Ukuvikela</translation>
 <translation id="343578350365773421">Kuphele amaphepha</translation>
@@ -2879,6 +2893,7 @@
 <translation id="346546413339447252">Thola izaphulelo ze-<ph name="MERCHANT_NAME_1" />, <ph name="MERCHANT_NAME_2" /> nokuningi</translation>
 <translation id="3468298837301810372">Ilebula</translation>
 <translation id="3468999815377931311">Ifoni ye-Android</translation>
+<translation id="3469345458390352459">Uma sekuvuliwe, izinhlelo zakho zokusebenza zizotholakala kunoma imaphi amadivayisi e-ChromeOS ngemva kokungena ngemvume nge-Google Account yakho.  Ama-app ewebhu azovunyelaniswa nge-Chrome ngisho noma ezinye izakhi zokuvumelanisa ibhrawuza zivaliwe.</translation>
 <translation id="3469583217479686109">Ithuluzi Lokukhetha</translation>
 <translation id="3470392222765168737">Landela isayithi</translation>
 <translation id="3471876058939596279">Izimbobo ze-HDMI ne-USB Type-C azikwazi ukusetshenziselwa ividiyo ngesikhathi esifanayo. Sebenzisa imbobo ehlukile yevidiyo.</translation>
@@ -3341,6 +3356,7 @@
 <translation id="3855441664322950881">Pakisha isandiso</translation>
 <translation id="3855676282923585394">Ngenisa amabhukhimakhi nezilungiselelo...</translation>
 <translation id="3856096718352044181">Sicela uqinisekise ukuthi lo ngumhlinzeki wangempela noma uzame futhi kamuva</translation>
+<translation id="3856470183388031602">Sebenzisa i-Google Account yakho eku-<ph name="DEVICE_TYPE" /> yakho</translation>
 <translation id="3856800405688283469">Khetha indawo yesikhathi</translation>
 <translation id="3857807444929313943">Phakamisa, bese uyathinta futhi</translation>
 <translation id="3858860766373142691">Igama</translation>
@@ -3380,6 +3396,7 @@
 <translation id="3894123633473837029">Ifaka umlando wakamuva womsizi nge-Sherlog. Lokhu kungafaka ubunikazi bakho, umlando, nolwazi lokususa iphutha. <ph name="BEGIN_LINK" />Funda kabanzi<ph name="END_LINK" /></translation>
 <translation id="3894427358181296146">Engeza ifolda</translation>
 <translation id="3894770151966614831">Hambisa ku-Akhawunti ye-Google?</translation>
+<translation id="3894983081771074056">Ukuziphatha kwekhibhodi ne-mouse, okuncanyelwayo kolimi, nokuningi</translation>
 <translation id="3895076768659607631">&amp;Phatha Izinjini Zokusesha...</translation>
 <translation id="3895090224522145010">Igama lomsebenzisi le-Kerberos</translation>
 <translation id="389521680295183045">Amasayithi angabuza ukuze azi ukuthi uyisebenzisa nini idivayisi yakho</translation>
@@ -3514,6 +3531,7 @@
 <translation id="3994878504415702912">Sondeza isithombe</translation>
 <translation id="3995138139523574647">Idivayisi ye-USB-C (imbobo yasemuva yohlangothi lwesinxele)</translation>
 <translation id="3995963973192100066">Dlala upopayi</translation>
+<translation id="399788104667917863">Phina kwibha yamathuluzi</translation>
 <translation id="4001540981461989979">Gqamisa i-cursor yemawusi lapho unyakaza</translation>
 <translation id="4002440992267487163">Ukusetha iphini</translation>
 <translation id="4005817994523282006">Indlela yokutholwa kwendawo yesikhathi</translation>
@@ -3672,12 +3690,16 @@
 <translation id="4147911968024186208">Sicela uzame futhi. Uma ubona leli phutha futhi sicela uxhumane nommeli wakho wosekelo.</translation>
 <translation id="4150201353443180367">Isiboniso</translation>
 <translation id="4150569944729499860">Okuqukethwe kwesikrini</translation>
+<translation id="4151843924968445052">Yabelana ngamasignali edivayisi?</translation>
 <translation id="4152011295694446843">Uzothola amabhukhimakhi wakho lapha</translation>
 <translation id="4152670763139331043">{NUM_TABS,plural, =1{1 ithebhu}one{# amathebhu}other{# amathebhu}}</translation>
 <translation id="4154664944169082762">Izigxivizo zeminwe</translation>
 <translation id="4157869833395312646">I-Microsoft Server Gated Cryptography</translation>
 <translation id="4158315983204257156">Usayizi wombhalo wewebhusayithi nefonti</translation>
 <translation id="4158364720893025815">Dlula</translation>
+<translation id="4159501637165962616"><ph name="BEGIN_PARAGRAPH1" />Ukuvumela amadivayisi e-ChromeOS ukuthi athumele imibiko ezenzakalelayo kusisiza sikubeke phambili lokho okufanele sikulungise futhi sikuthuthukise ku-ChromeOS. Le mibiko ingabandakanya izinto ezifana nokuthi lapho i-ChromeOS iphahlazeka, izici ozisebenzisayo, ingakanani inkumbulo ovame ukuyisebenzisa, kanye nedatha yokuxilonga neyokusetshenziswa yi-app ye-Android. Enye idatha izophinda isize ama-app we-Google nozakwethu, abafana nonjiniyela be-Android. Enye idatha yokuxilonga neyokusetshenziswa kwe-app, ebandakanya eye-Android nama-app ewebhu, izoqoqwa uma ukuvumelanisa ama-app nakho kuvuliwe.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Ungaqala noma uyeke ukuvumela le mibiko noma nini kumasethingi edivayisi ye-ChromeOS yakho. Uma ungumqondisi wesizinda, ungakwazi ukushintsha leli sethingi kukhonsoli yomphathi.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH3" />Uma isethingi Lomsebenzi Wewebhu newe-App livuliwe ku-Google Account yakho, idatha yakho ye-Android ingase ilondolozwe ku-Google Account yakho. Ungabona idatha yakho, uyisule, futhi ushintshe amasethingi e-akhawunti yakho ku-account.google.com.<ph name="END_PARAGRAPH3" /></translation>
 <translation id="4161601078867475601">&amp;I-Google Password Manager</translation>
 <translation id="4163560723127662357">Ikhibhodi engaziwa</translation>
 <translation id="4165942112764990069">I-<ph name="USER_EMAIL" /> ayiyona eyenhlangano evumelekile. Xhumana nomlawuli wakho. Uma ungumphathi, ungasetha inhlangano yakho ngokuvakashela ku-: g.co/ChromeEnterpriseAccount</translation>
@@ -4001,6 +4023,9 @@
 <translation id="4452898361839215358">noma khetha i-PPD. <ph name="LINK_BEGIN" />Funda kabanzi<ph name="LINK_END" /></translation>
 <translation id="4453430595102511050">Thinta inzwa yesigxivizo somunwe phezulu kwesokudla kwekhibhodi yakho. Idatha yakho yesigxivizo somunwe igcinwe ngokuphephile futhi ayilokothi ishiye i-<ph name="DEVICE_TYPE" /> yakho.</translation>
 <translation id="4453946976636652378">Sesha i-<ph name="SEARCH_ENGINE_NAME" /> noma thayipha i-URL</translation>
+<translation id="4454537120672169656"><ph name="BEGIN_PARAGRAPH1" />Ukuvumela amadivayisi e-ChromeOS ukuthi athumele imibiko yokuzenzekelayo kusisiza sikubeke phambili lokho okufanele sikulungise futhi sikuthuthukise ku-ChromeOS. Le mibiko ingabandakanya izinto ezifana nokuthi i-ChromeOS iphahlazeka nini, yiziphi izakhi ezisetshenzisiwe, ingakanani inkumbulo evame ukusetshenziswa, kanye ne-app ye-Android yokuxilonga nedatha esetshenzisiwayo. Enye idatha izophinda isize ama-app we-Google nozakwethu, abafana nonjiniyela be-Android. Enye idatha yokuxilonga neyokusetshenziswa kwe-app, ebandakanya eye-Android nama-app ewebhu, izoqoqwa uma ukuvumelanisa ama-app nakho kuvuliwe.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Ungaqala noma uyeke ukuvumela le mibiko noma kunini kumasethingi edivayisi ye-ChromeOS yengane yakho. Uma ungumqondisi wesizinda, ungakwazi ukushintsha leli sethingi kukhonsoli yomphathi.<ph name="END_PARAGRAPH2" />
+    <ph name="BEGIN_PARAGRAPH4" />Uma isethingi Lomsebenzi Wewebhu nele-App livuliwe ku-Google Account yengane yakho, idatha yengane yakho ingase ilondolozwe ku-Google Account yayo. Funda kabanzi ngalamasethingi nendlela yokuwalungisa ku-families.google.com.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="4457472090507035117">Khetha izwi lamanje:</translation>
 <translation id="4459169140545916303">Isebenze ezinsukwini ezingu-<ph name="DEVICE_LAST_ACTIVATED_TIME" /> ezedlule</translation>
 <translation id="4460014764210899310">Khipha ukubuthana</translation>
@@ -4381,6 +4406,7 @@
 <translation id="4806457879608775995">Buyekeza le migomo futhi ulawule idatha yakho</translation>
 <translation id="4807098396393229769">Igama kukhadi</translation>
 <translation id="4808667324955055115">Okwesikhashana kuvinjelwe:</translation>
+<translation id="4808711719757110498">{NUM_EXTENSIONS,plural, =1{Buyekeza <ph name="BEGIN_BOLD" />isandiso esi-1<ph name="END_BOLD" /> esehlisiwe ku-Chrome Web Store}one{Buyekeza <ph name="BEGIN_BOLD" />izandiso ezingu-{NUM_EXTENSIONS}<ph name="END_BOLD" /> ezehlisiwe ku-Chrome Web Store}other{Buyekeza <ph name="BEGIN_BOLD" />izandiso ezingu-{NUM_EXTENSIONS}<ph name="END_BOLD" /> ezehlisiwe ku-Chrome Web Store}}</translation>
 <translation id="4809079943450490359">Imiyalelo esuka kumlawuli wedivayisi yakho:</translation>
 <translation id="4809447465126035330">Sula</translation>
 <translation id="480990236307250886">Vula ikhasi lasekhaya</translation>
@@ -4704,6 +4730,7 @@
 <translation id="5101839224773798795">Chofoza ngokuzenzakalela uma ikhesa ima</translation>
 <translation id="5106350808162641062">Susa</translation>
 <translation id="510695978163689362">U-<ph name="USER_EMAIL" /> ugadwe yi-Family Link. Ungangeza ama-akhawunti wesikole ukuze ufinyelele izinsiza zesikole ngokuqashelwa kwabazali.</translation>
+<translation id="5107093668001980925">Ungabonisi neze i-<ph name="MODULE_NAME" /></translation>
 <translation id="5107443654503185812">Isandiso sivale Ukuphequlula Okuphephile</translation>
 <translation id="5108967062857032718">Izilungiselelo - Susa izinhlelo zokusebenza ze-Android</translation>
 <translation id="5109044022078737958">I-Mia</translation>
@@ -4714,6 +4741,7 @@
 <translation id="5111794652433847656">Abekho okhiye bokudlula baka-<ph name="APP_NAME" /> kule divayisi</translation>
 <translation id="5112577000029535889">Amathuluzi onjiniyela</translation>
 <translation id="511313294362309725">Vula Ukuhlanganisa okusheshayo</translation>
+<translation id="5113384440341086023">Ama-app afakwe kusukela ku-Play Store nama-app ewebhu kusuka kwibhrawuza ye-Chrome</translation>
 <translation id="51143538739122961">Faka ukhiye wakho wokuqinisekisa ubunikazi bese uwuthinte</translation>
 <translation id="5115309401544567011">Sicela uxhume i-<ph name="DEVICE_TYPE" /> yakho kumthombo wamandla.</translation>
 <translation id="5115338116365931134">I-SSO</translation>
@@ -4759,6 +4787,7 @@
 <translation id="5154702632169343078">Isihloko</translation>
 <translation id="5155327081870541046">Kwibha yekheli, faka isinqamuleli sesayithi ofuna ukulisesha, njenge-"@bookmarks". Bese, cindezela isinqamuleli sekhibhodi, futhi ufake itemu yakho yosesho.</translation>
 <translation id="5156638757840305347">I-cursor iyagqanyiswa uma ivela noma inyakaza</translation>
+<translation id="5157250307065481244">Buka imininingwane yesayithi</translation>
 <translation id="5157635116769074044">Phina leli khasi kusikrini sokuqala...</translation>
 <translation id="5158206172605340248">Imenyu yezimpawu zesigqi ichithiwe.</translation>
 <translation id="5159094275429367735">Setha i-Crostini</translation>
@@ -5821,6 +5850,7 @@
 <translation id="6104068876731806426">Ama-akhawunti e-Google</translation>
 <translation id="6104311680260824317">Ayikwazi ukujoyina idivayisi kusukela kusizinda. Iseva ayisekeli izinhlobo zokubethelwa okucacisiwe kwe-Kerberos. Hlola "Izinketho eziningi" ukuze uthole izilungiselelo zokubethelwe.</translation>
 <translation id="6104796831253957966">Ulayini wephrinta ugcwele</translation>
+<translation id="6106167152849320869">Uma futhi ukhethe ukuthumela idatha yokuxilonga neyokusetshenziswa esinyathelweni sangaphambilini, le datha izoqoqelwa ama-app afakiwe.</translation>
 <translation id="6111972606040028426">Nika amandla umsizi we-Google</translation>
 <translation id="6112294629795967147">Thinta ukuze ushintshe usayizi</translation>
 <translation id="6112727384379533756">Engeza ithikithi</translation>
@@ -5951,6 +5981,7 @@
 <translation id="6226777517901268232">Ifayela elingukhiye oyimfihlo (ongakukhetha)</translation>
 <translation id="6227002569366039565">Cindezela i-|<ph name="ACCELERATOR" />| ukuze ugxilise le bhamuza losizo, bese futhi ukuze ugxilise i-elementi eyikhombayo.</translation>
 <translation id="6227280783235722609">isandiso</translation>
+<translation id="6229062790325126537">Setha kabusha i-ApnMigrator</translation>
 <translation id="6229849828796482487">Nqamula inethiwekhi ye-Wi-Fi</translation>
 <translation id="6231782223312638214">Okuphakanyisiwe</translation>
 <translation id="6231881193380278751">Engeza umbuzo we-param ku-URL ukuze uqalise ngokuzenzakalelayo ikhasi: chrome://device-log/?refresh=&lt;sec&gt;</translation>
@@ -6228,6 +6259,7 @@
 <translation id="6478248366783946499">Gcina ifayela eliyingozi?</translation>
 <translation id="6479881432656947268">Vakashela Isitolo Sewebhu Se-Chrome</translation>
 <translation id="6480327114083866287">Iphethwe yi-<ph name="MANAGER" /></translation>
+<translation id="6481978993812487794">Uma sekuvuliwe, izinhlelo zakho zokusebenza zizotholakala kunoma imaphi amadivayisi e-ChromeOS ngemva kokungena ngemvume nge-Google Account yakho. Ama-app ewebhu azovunyelaniswa nge-Chrome ngisho noma ezinye izakhi zokuvumelanisa ibhrawuza zivaliwe.</translation>
 <translation id="6482559668224714696">Isikhulisi sesikrini esidokhiwe</translation>
 <translation id="6483485061007832714">Vula ukulandwa</translation>
 <translation id="6483805311199035658">Ivula i-<ph name="FILE" />...</translation>
@@ -6242,6 +6274,7 @@
 <translation id="6497784818439587832">Shintsha usayizi wokubonisa ukuze wenze izinto esikrinini sakho zibe zincane noma zibe zinkulu</translation>
 <translation id="6497789971060331894">Ukuskrola ngokuphendukezela igundane</translation>
 <translation id="6498249116389603658">&amp;Zonke izilimi zakho</translation>
+<translation id="6498583202177273322">Thola ulwazi olwengeziwe oluwusizo njengoba uhlola leli khasi</translation>
 <translation id="6499143127267478107">Ixazulula isikhungo sesikripthi sommeleli...</translation>
 <translation id="6499764981457476645">Awekho amadivayisi atholakale eduze</translation>
 <translation id="6501957628055559556">Zonke iziqukathi</translation>
@@ -6690,6 +6723,7 @@
 <translation id="688312408602122936">Noma yimiphi imidlalo nama-app afakwe nge-Steam nawo azosuswa kule divayisi</translation>
 <translation id="6883319974225028188">Eshu!  Isistimu yehlulekile ukulondoloza ukulungiswa kwedivayisi.</translation>
 <translation id="6884474387073389421">Uqinisekile ukuthi ufuna ukusula idatha yokungena ngemvume ekhethiwe?</translation>
+<translation id="6885122019363983153">Ingemuva ledeskithophu liyafana kuwo wonke amadivayisi</translation>
 <translation id="6885771755599377173">Ukuhlola kuqala ulwazi lwesistimu</translation>
 <translation id="6886380424988777998">Ayikwazanga ukuthuthukisa i-Linux</translation>
 <translation id="6886871292305414135">Vula isixhumanisi kuthebhu entsha</translation>
@@ -6761,6 +6795,7 @@
 <translation id="6949434160682548041">Iphasiwedi (kuyakhetheka)</translation>
 <translation id="6950627417367801484">Buyisa izinhlelo zokusebenza</translation>
 <translation id="6952242901357037157">Ungakwazi nokubonisa amaphasiwedi avela ku-<ph name="BEGIN_LINK" />Akhawunti yakho ye-Google<ph name="END_LINK" /> lapha</translation>
+<translation id="6954910832698269894">Vula ukuvumelanisa kwedivayisi ukuze ubuyisele ama-app akho, amasethingi, amanethiwekhi e-Wi-Fi, nesithombe sangemuva kusuka ku-Chromebook yakho yangaphambilini. Yenza izinguquko noma nini Kumasethingi &gt; Ama-akhawunti.</translation>
 <translation id="6954936693361896459">Kunalokho sakaza le thebhu</translation>
 <translation id="6955446738988643816">Hlola okuzivelelayo</translation>
 <translation id="6955535239952325894">Lesi silungiselelo sikhutshaziwe ezipheqululini eziphathwayo</translation>
@@ -6919,6 +6954,7 @@
 <translation id="7075513071073410194">I-PKCS #1 MD5 ngokubethela kwe-RSA</translation>
 <translation id="7075625805486468288">Phatha izitifiketi ze-HTTPS/SSL nezilungiselelo</translation>
 <translation id="7076875098323397992">Finyelela kuma-app emiyalezo yefoni yakho</translation>
+<translation id="7077751457066325012">Buka futhi wenze ngendlela oyifisayo izinqamuleli zekhibhodi</translation>
 <translation id="7077829361966535409">Ikhasi lokungena ngemvume lihlulekile ukulayishwa kusetshenziswa izilungiselelo zamanje zommeleli. Sicela <ph name="GAIA_RELOAD_LINK_START" />uzame ukungena ngemvume futhi<ph name="GAIA_RELOAD_LINK_END" />, noma usebenzise <ph name="PROXY_SETTINGS_LINK_START" />izilungiselelo zommeleli<ph name="PROXY_SETTINGS_LINK_END" /> ezihlukile.</translation>
 <translation id="7078120482318506217">Wonke amanethiwekhi</translation>
 <translation id="708060913198414444">K&amp;opisha ikheli lomsindo</translation>
@@ -6948,6 +6984,7 @@
 <translation id="7108933416628942903">Khiya manje</translation>
 <translation id="7109543803214225826">Isinqamuleli sisusiwe</translation>
 <translation id="7110644433780444336">{NUM_TABS,plural, =1{Engeza Ithebhu Eqenjini}one{Engeza Amathebhu Eqenjini}other{Engeza Amathebhu Eqenjini}}</translation>
+<translation id="7110684627876015299">Iqembu elingaqanjiwe - <ph name="OPENED_STATE" /></translation>
 <translation id="7111822978084196600">Qamba leli windi</translation>
 <translation id="7113102733263608554">into <ph name="ITEM_COUNT_ONE" /></translation>
 <translation id="7113502843173351041">Yazi ikheli lakho le-imeyili</translation>
@@ -7162,6 +7199,7 @@
 <translation id="7328867076235380839">Inhlanganisela engavumelekile</translation>
 <translation id="7329154610228416156">Ukungena ngemvume kwehlulekile ngoba kwalungiswa ukusebenzisa i-URL engaphephile (<ph name="BLOCKED_URL" />). Sicela uxhumane nomlawuli wakho.</translation>
 <translation id="7332053360324989309">Isisebenzi Ezikhuthele: <ph name="SCRIPT_URL" /></translation>
+<translation id="7333669215417470379">Yenza isipele futhi ubuyisele ama-app akho namasethingi</translation>
 <translation id="7335974957018254119">Sebenzisela ukuhlola isipele ku-</translation>
 <translation id="7336799713063880535">Izaziso zivinjelwe.</translation>
 <translation id="7338630283264858612">Inombolo yomkhiqizo yedivayisi ayivumelekile.</translation>
@@ -7184,6 +7222,7 @@
 <translation id="7348093485538360975">Ikhibhodi kusikrini</translation>
 <translation id="7349010927677336670">Ubushelelezi bevidiyo</translation>
 <translation id="7352651011704765696">Okuthile akuhambanga kahle</translation>
+<translation id="7352664183151911163">Kuwo wonke ama-app akho nebrawuza ye-Chrome</translation>
 <translation id="7353261921908507769">Abathintwayo bakho bangabelana nawe lapho beseduze. Ukudlulisa ngeke kuqale kuze kube yilapho wamukela.</translation>
 <translation id="735361434055555355">Ifaka i-Linux...</translation>
 <translation id="7354120289251608189">Manje usunganikeza ibhrawuza yakho ukubukeka okusha noma nini.</translation>
@@ -7323,6 +7362,8 @@
 <translation id="7458168200501453431">Isebenzisa isihloli sokupela esifanayo esisetshenziswe kusesho lwe-Google. Umbhalo owuthayipha kusiphequluli uthunyelwe ku-Google.</translation>
 <translation id="7458715171471938198">Buyisela ama-app?</translation>
 <translation id="7458933488302148148">Hlola amaphasiwedi akho alondoloziwe ukuze uqinise ukuvikeleka kwakho futhi uhlale uphephile ku-inthanethi</translation>
+<translation id="745988141575685751"><ph name="BEGIN_PARAGRAPH1" />Ukuvumela amadivayisi e-ChromeOS ukuthi athumele imibiko ezenzakalelayo kusisiza sikubeke phambili lokho okufanele sikulungise futhi sikuthuthukise ku-ChromeOS. Le mibiko ingabandakanya izinto ezifana nokuthi i-ChromeOS ikhubazeka nini, yiziphi izakhi ozisebenzisayo nokuthi ingakanani inkumbulo oyisebenzisayo. Enye idatha yokuxilonga neyokusetshenziswa kwe-app, ebandakanya eye-Android nama-app ewebhu, izoqoqwa uma ukuvumelanisa ama-app nakho kuvuliwe.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Ungaqala noma uyeke ukuvumela le mibiko noma nini kumasethingi edivayisi yakho ye-Chrome. Uma ungumqondisi wesizinda, ungakwazi ukushintsha leli sethingi kukhonsoli yomphathi.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="7460045493116006516">Itimu yamanje oyifakile</translation>
 <translation id="7461924472993315131">Phina</translation>
 <translation id="746216226901520237">Ngesikhathi esilandelayo, ifoni yakho izovula i-<ph name="DEVICE_TYPE" />yakho. ungavala i-Smart Lock kuzilungiselelo.</translation>
@@ -7556,6 +7597,7 @@
 <translation id="7663719505383602579">Isamukeli: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7663774460282684730">Isinqamuleli sekhibhodi siyatholakala</translation>
 <translation id="7663859337051362114">Engeza iphrofayela le-eSIM</translation>
+<translation id="76641554187607347">Ayikho ikhibhodi exhunyiwe</translation>
 <translation id="7665082356120621510">Gcina usayizi</translation>
 <translation id="7665369617277396874">Engeza i-akhawunti</translation>
 <translation id="766560638707011986">Bonisa izizinda</translation>
@@ -7603,6 +7645,7 @@
 <translation id="769824636077131955">Le dokhumenti inkulu kakhulu ukuthi ingahlolelwa ezokuphepha. Ungaphrinta amadokhumenti afika kwangu-50 MB.</translation>
 <translation id="7698507637739331665">Ezinye izinto zivinjelwe</translation>
 <translation id="7701040980221191251">Lutho</translation>
+<translation id="7701265686005869308">Vala iphrofayela</translation>
 <translation id="7701869757853594372">Izibambi ZOMSEBENZISI</translation>
 <translation id="7702574632857388784">Susa i-<ph name="FILE_NAME" /> kusukela kuhlu</translation>
 <translation id="7702907602086592255">Isizinda</translation>
@@ -8023,6 +8066,7 @@
 <translation id="8050191834453426339">Qinisekisa futhi</translation>
 <translation id="8051193500142930381">Izici ezidinga ikhamera ngeke zisebenze</translation>
 <translation id="8051390370038326517">Vumela i-<ph name="HOST" /> njalo ukuba ibe nolawulo olugcwele lwamadivayisi e-MIDI</translation>
+<translation id="8052218774860457016">Phatha ukuvumelanisa ibhrawuza</translation>
 <translation id="8053278772142718589">Amafayela we-PKCS #12</translation>
 <translation id="8053390638574070785">Phinda ulayishe leli khasi</translation>
 <translation id="8054517699425078995">Lolu hlobo lefayela lungalimaza idivayisi yakho. Ingabe ufuna ukugcina i-<ph name="FILE_NAME" /> noma kunjalo?</translation>
@@ -8392,6 +8436,7 @@
 <translation id="8376137163494131156">Sitshele ukuthi kwenzakalani nge-Google Cast.</translation>
 <translation id="8376384591331888629">Kuhlanganise namakhukhi enkampani yangaphandle kule webhusayithi</translation>
 <translation id="8376451933628734023">Uma le app yewebhu izama ukukukhohlisa ukuze ucabange ukuthi i-app ehlukile, ikhiphe.</translation>
+<translation id="8376752431516546391">Iphaneli eseceleni ye-Google Search</translation>
 <translation id="8377625247046155446">Lo khiye wokudlula uzolondolozwa kule divayisi kuphela. Uzohlala ukule divayisi ngemva kokuvala wonke amawindi we-Incognito.</translation>
 <translation id="8378714024927312812">Kuphethwe inhlangano yakho</translation>
 <translation id="8379878387931047019">Le divayisi ayisekeli uhlobo lokhiye wokuphepha ocelwe yile webhusayithi</translation>
@@ -8459,6 +8504,11 @@
 <translation id="8428628598981198790">Ukhiye wakho wokuqinisekisa ubunikazi awukwazi ukusetshenziswa naleli sayithi</translation>
 <translation id="84297032718407999">Uzokhishwa ku-<ph name="LOGOUT_TIME_LEFT" /></translation>
 <translation id="8431190899827883166">Bonisa amathebhu</translation>
+<translation id="8431496281632382473">Le phrofayela iphethwe ngu-<ph name="DOMAIN" />. Ukuze uqhubeke usebenzisa le phrofayela ephethwe, inhlangano yakho idinga ukuthi wabelane ngamasignali edivayisi yakho.
+
+Amasignali edivayisi angabandakanya ulwazi mayelana nebhrawuza yakho, i-OS, idivayisi, isofthiwe efakiwe, namafayela.
+
+Uma ukhetha ukungabelani ngamasignali, le phrofayela izovalwa.</translation>
 <translation id="8434480141477525001">Imbobo yokulungisa iphutha ye-NaCl</translation>
 <translation id="8437209419043462667">I-US</translation>
 <translation id="8438328416656800239">Shintshela kusiphequluli esihlakaniphile</translation>
@@ -8543,6 +8593,8 @@
 <translation id="851263357009351303">Hlala uvumela i-<ph name="HOST" /> ukuthi ibonise izithombe</translation>
 <translation id="8513108775083588393">I-auto-rotate</translation>
 <translation id="8513357934662532537">Ukuze ungenise amaphasiwedi ku-<ph name="BRAND" /> ngo-<ph name="USER_EMAIL" />, khetha ifayela le-CSV.</translation>
+<translation id="8513683386591916542"><ph name="BEGIN_PARAGRAPH1" />Ukuvumela amadivayisi e-ChromeOS ukuthi athumele imibiko yokuzenzekelayo kusisiza sikubeke phambili lokho okufanele sikulungise futhi sikuthuthukise ku-ChromeOS. Le mibiko ingabandakanya izinto ezifana nokuthi i-ChromeOS ikhubazeka nini, yiziphi izakhi ezisetshenzisiwe, nokuthi ingakanani inkumbulo evame ukusetshenziswa. Enye idatha yokuxilonga neyokusetshenziswa kwe-app, ebandakanya eye-Android nama-app ewebhu, izoqoqwa uma ukuvumelanisa ama-app nakho kuvuliwe.<ph name="END_PARAGRAPH1" />
+    <ph name="BEGIN_PARAGRAPH2" />Ungaqala noma uyeke ukuvumela le mibiko noma kunini kumasethingi edivayisi ye-ChromeOS yengane yakho. Uma ungumqondisi wesizinda, ungakwazi ukushintsha leli sethingi kukhonsoli yomphathi.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="8514746246728959655">Zama ukhiye ohlukile wokuvikela</translation>
 <translation id="8514955299594277296">Ungavumeli amasayithi ukuthi alondoloze idatha kudivayisi yakho (akunconyiwe)</translation>
 <translation id="8517759303731677493">Hlela…</translation>
@@ -8904,6 +8956,7 @@
 <translation id="883062543841130884">Ukushintshaniswa</translation>
 <translation id="8830779999439981481">Iqala kabusha ukuze isebenzise izibuyekezo</translation>
 <translation id="8830796635868321089">Ukuhlola isibuyekezo kuhlulekile kusetshenziswa izilungiselelo zamanje zommeleli. Sicela ulungise <ph name="PROXY_SETTINGS_LINK_START" />izilungiselelo zommeleli<ph name="PROXY_SETTINGS_LINK_END" /> wakho.</translation>
+<translation id="8830863983385452402">Isayithi lizokwazi ukubona okuqukethwe kwale thebhu</translation>
 <translation id="8831769650322069887">Vula i-<ph name="FILE_NAME" /></translation>
 <translation id="8832781841902333794">Amaphrofayela wakho</translation>
 <translation id="8834039744648160717">Ukulungiswa kwenethiwekhi kulawula ngu-<ph name="USER_EMAIL" />.</translation>
@@ -9035,6 +9088,7 @@
 <translation id="8946359700442089734">Izici zokususa amaphutha azinikwanga amandla ngokuphelele kule divayisi ye-<ph name="IDS_SHORT_PRODUCT_NAME" />.</translation>
 <translation id="894763922177556086">Kuhle</translation>
 <translation id="8948939328578167195"><ph name="WEBSITE" /> ifuna ukubona ukwenziwa nemodeli yokhiye wakho wokuqinisekisa ubunikazi</translation>
+<translation id="8949304443659090542">Phatha ukuvumelanisa kwebhrawuza ye-Chrome</translation>
 <translation id="895054485242522631">Amasayithi angasebenzisa izinzwa zokunyakaza</translation>
 <translation id="8951256747718668828">Ukubuyisa akukwazanga ukuqedwa ngenxa yephutha</translation>
 <translation id="8951465597020890363">Phuma kumodi yesivakashi noma kunjalo?</translation>
@@ -9140,6 +9194,7 @@
 <translation id="9032097289595078011">Khubaza Ukuhlanganisa okusheshayo</translation>
 <translation id="9033765790910064284">Qhebeka kunjalo</translation>
 <translation id="9033857511263905942">Namathisela</translation>
+<translation id="9034408118624208974">Umusha ku-Chromebook? Vula ukuvumelanisa ukuze okuncanyelwayo kwakho kwenziwe isipele.</translation>
 <translation id="903480517321259405">Thayipha futhi Iphinikkhodi</translation>
 <translation id="9037054491984310631">Ixhunywe kudivayisi ye-Bluetooth eqanjwe ngokuthi <ph name="DEVICE" /></translation>
 <translation id="9037640663275993951">Idivayisi ayivumelekile</translation>
@@ -9183,6 +9238,7 @@
 <translation id="9068298336633421551">Vumela ama-app we-Android namasevisi ngemvume yendawo ukuze asebenzise indawo yale divayisi. I-Google ingaqoqa idatha yasendaweni ngezikhathi ezithile iphinde isebenzise le datha ngendlela engaziwa ukuze kuthuthukiswe ukunemba kwendawo namasevisi asuselwa endaweni.</translation>
 <translation id="9068598199622656904">Cindezela inkinobho eyodwa ngesikhathi ukuze uthole izinqamuleli zekhibhodi esikhundleni sokubamba izinkinobho phansi ngesikhathi esisodwa</translation>
 <translation id="9068878141610261315">Uhlobo lwefayela olungasekelwe</translation>
+<translation id="9069665781180028115">Izinto ezikhethiwe zizotholakala kule Chromebook. Uma umusha ku-Chromebook, vumelanisa zonke izinto ukuze okuncamelayo kwenziwe isipele. Yenza izinguquko noma nini Kumasethingi &gt; Ama-akhawunti.</translation>
 <translation id="9070342919388027491">Ithebhu ishone ngakwesobunxele</translation>
 <translation id="9074739597929991885">I-Bluetooth</translation>
 <translation id="9074836595010225693">Igundane le-USB lixhunyiwe</translation>
@@ -9356,6 +9412,7 @@
 <translation id="930268624053534560">Izitembu zesikhathi ezinemininingwane</translation>
 <translation id="930551443325541578">Phinda okhiye kanye nezimpawu zokugcizelela</translation>
 <translation id="930893132043726269">Okwamanje iyazula</translation>
+<translation id="930991362911221750">Vumela i-<ph name="APP_NAME" /> ibone le thebhu?</translation>
 <translation id="93140074055951850">Ama-app e-Android aye amiswa</translation>
 <translation id="932327136139879170">Ikhaya</translation>
 <translation id="932508678520956232">Ayikwazanga ukuqalisa ukuphrinta.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_da.xtb b/chrome/app/resources/google_chrome_strings_da.xtb
index 4ce7260a..d89e70d 100644
--- a/chrome/app/resources/google_chrome_strings_da.xtb
+++ b/chrome/app/resources/google_chrome_strings_da.xtb
@@ -147,7 +147,7 @@
 <translation id="3541482654983822893">Chrome kan ikke tjekke dine adgangskoder. Prøv igen efter 24 timer.</translation>
 <translation id="3576528680708590453">Din systemadministrator har konfigureret Google Chrome til at åbne en anden browser for at få adgang til <ph name="TARGET_URL_HOSTNAME" />.</translation>
 <translation id="3579965087968408543">Ryd altid websitedata fra din enhed, når du lukker Chrome</translation>
-<translation id="3582972582564653026">Synkroniser og tilpas Chrome på alle dine enheder</translation>
+<translation id="3582972582564653026">Synkroniser og personligt tilpas Chrome på alle dine enheder</translation>
 <translation id="3596080736082218006">{COUNT,plural, =0{Din administrator kræver, at du genstarter Chrome for at anvende en opdatering}=1{Din administrator kræver, at du genstarter Chrome for at anvende en opdatering. Dit inkognitovindue åbnes ikke igen.}one{Din administrator kræver, at du genstarter Chrome for at anvende en opdatering. # inkognitovindue åbnes ikke igen.}other{Din administrator kræver, at du genstarter Chrome for at anvende en opdatering. Dine # inkognitovinduer åbnes ikke igen.}}</translation>
 <translation id="3622797965165704966">Nu er det blevet nemmere at bruge Chrome med din Google-konto og på delte computere.</translation>
 <translation id="3673813398384385993">Chrome har registreret malware i "<ph name="EXTENSION_NAME" />"</translation>
@@ -183,7 +183,7 @@
 <translation id="4251615635259297716">Vil du linke dine Chrome-data til denne konto?</translation>
 <translation id="4262915912852657291"><ph name="BEGIN_BOLD" />Disse data bruges:<ph name="END_BOLD" /> Din browserhistorik, dvs. en oversigt over, hvilke websites du har besøgt i Chrome på denne enhed.</translation>
 <translation id="4281844954008187215">Servicevilkår</translation>
-<translation id="4293420128516039005">Log ind for at synkronisere og tilpasse Chrome på alle dine enheder</translation>
+<translation id="4293420128516039005">Log ind for at synkronisere og personligt tilpasse Chrome på alle dine enheder</translation>
 <translation id="430327780270213103">Tillad, at udvidelsen viser adgangsanmodninger på Chrome-værktøjslinjen</translation>
 <translation id="4328355335528187361">Udviklerversionen af Google Chrome (mDNS-In)</translation>
 <translation id="4334294535648607276">Download fuldført.</translation>
@@ -312,7 +312,7 @@
 De tilladelser, du har givet til websites og apps, gælder muligvis for denne konto. Du kan administrere dine Google-konti under <ph name="SETTINGS_LINK_BEGIN" />Indstillinger<ph name="SETTINGS_LINK_END" />.</translation>
 <translation id="7062128746136194023">Din forælder har deaktiveret "Tilladelser til websites, apps og udvidelser" for Chrome. Det er ikke tilladt at tilføje denne <ph name="EXTENSION_TYPE_PARAMETER" />.</translation>
 <translation id="7071827361006050863">Chrome sletter snart browserdataene</translation>
-<translation id="7085332316435785646">Vælg, om du vil inkludere Chrome-historikken for at få mere tilpassede oplevelser i Googles tjenester</translation>
+<translation id="7085332316435785646">Vælg, om du vil inkludere Chrome-historikken for at få mere personligt tilpassede oplevelser i Googles tjenester</translation>
 <translation id="7088681679121566888">Chrome er opdateret</translation>
 <translation id="7098166902387133879">Google Chrome bruger din mikrofon.</translation>
 <translation id="7099479769133613710">Genstart og opdater &amp;Chrome OS</translation>
@@ -379,7 +379,7 @@
 <translation id="8383226135083126309"><ph name="BEGIN_BOLD" />Sådan bruger vi disse data:<ph name="END_BOLD" /> Chrome kan estimere dine interesser. Senere kan et website, du besøger, anmode Chrome om at se dine interesser med henblik på at personligt tilpasse de annoncer, du ser.</translation>
 <translation id="8387459386171870978">Fortsæt med at bruge Chrome</translation>
 <translation id="8394720698884623075">Webadresser tjekkes i forhold til en liste over usikre websites, der er gemt i Chrome</translation>
-<translation id="8416347857511542594">Få flere oplysninger om personlig annoncetilpasning i Chrome</translation>
+<translation id="8416347857511542594">Få flere oplysninger om personlig tilpasning af annoncer i Chrome</translation>
 <translation id="8418845734693287262">ChromeOS kunne ikke synkronisere dine data, fordi loginoplysningerne til din konto er forældede.</translation>
 <translation id="8433638294851456451">Hvis du vil sende et nummer fra denne enhed til din Android-telefon, skal du logge ind på Chrome på begge enheder.</translation>
 <translation id="8451192282033883849">Din konto administreres af <ph name="MANAGER_NAME" />. Din administrator kan se og redigere denne Chrome-browserprofil og dens data som f.eks. bogmærker, historik og adgangskoder.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_lo.xtb b/chrome/app/resources/google_chrome_strings_lo.xtb
index 4672d20..a0ee5e00 100644
--- a/chrome/app/resources/google_chrome_strings_lo.xtb
+++ b/chrome/app/resources/google_chrome_strings_lo.xtb
@@ -259,6 +259,7 @@
 <translation id="5756509061973259733">ມີໂປຣໄຟລ໌ Chrome ກັບບັນຊີນີ້ຢູ່ອຸປະກອນນີ້ຢູ່ກ່ອນແລ້ວ</translation>
 <translation id="5795887333006832406"><ph name="PAGE_TITLE" /> - Google Chrome Canary</translation>
 <translation id="5804318322022881572">ບໍ່ສາມາດເປີດໃຊ້ Chrome. ກະລຸນາລອງອີກຄັ້ງ.</translation>
+<translation id="585620188971323280">ແກ້ໄຂການຕັ້ງຄ່າສຳລັບການຕື່ມວິທີການຈ່າຍເງິນ.</translation>
 <translation id="5895138241574237353">ເລີ່ມຕົ້ນໃໝ່</translation>
 <translation id="5903106910045431592"><ph name="PAGE_TITLE" /> - ການເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ</translation>
 <translation id="5924017743176219022">ກຳ​ລັງ​ເຊື່ອມ​ຕໍ່​ອິນ​ເຕີ​ເນັດ...</translation>
@@ -396,6 +397,7 @@
 <translation id="8516431725144212809">ຄວາມສົນໃຈຂອງທ່ານຕາມທີ່ Chrome ປະເມີນ</translation>
 <translation id="8521348052903287641">ກົດລະບຽບຂາເຂົ້າສໍາລັບ Google Chrome Dev ເພື່ອອະນຸຍາດການຮັບສົ່ງຂໍ້ມູນ mDNS.</translation>
 <translation id="8540666473246803645">Google Chrome</translation>
+<translation id="8544217240017914508">Google Chrome ກຳລັງພະຍາຍາມແກ້ໄຂການຕັ້ງຄ່າສຳລັບການຕື່ມຂໍ້ມູນວິທີການຈ່າຍເງິນ.</translation>
 <translation id="8550334526674375523">ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກນີ້ແຍກກັນຢ່າງສິ້ນເຊີງຈາກໂປຣໄຟລ໌ສ່ວນຕົວຂອງທ່ານ.</translation>
 <translation id="8556340503434111824">ມີ Google Chrome ລຸ້ນໃໝ່ຢູ່, ແລະມັນໄວກ່ວາຜ່ານມາ.</translation>
 <translation id="8571790202382503603">ດ້ວຍໂປຣໄຟລ໌ Chrome ທ່ານສາມາດແຍກເນື້ອຫາ Chrome ຂອງທ່ານທັງໝົດໄດ້. ນີ້ຈະເຮັດໃຫ້ແຍກລະຫວ່າງວຽກ ແລະ ຄວາມມ່ວນໄດ້ງ່າຍຂຶ້ນ.</translation>
diff --git a/chrome/app/theme/default_100_percent/common/autofill_mandatory_reauth_opt_in.png b/chrome/app/theme/default_100_percent/common/autofill_mandatory_reauth_opt_in.png
new file mode 100644
index 0000000..bd75daf
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/common/autofill_mandatory_reauth_opt_in.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/autofill_mandatory_reauth_opt_in.png b/chrome/app/theme/default_200_percent/common/autofill_mandatory_reauth_opt_in.png
new file mode 100644
index 0000000..66effeb
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/common/autofill_mandatory_reauth_opt_in.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 2e7110e..a54255a 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -275,6 +275,7 @@
         <structure type="chrome_scaled_image" name="IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54_DARK" file="common/migrate_address_avatar50_x135_y54_dark.png" />
         <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER" file="common/privacy_sandbox_confirmation_banner.png" />
         <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER_DARK" file="common/privacy_sandbox_confirmation_banner_dark.png" />
+        <structure type="chrome_scaled_image" name="IDR_AUTOFILL_MANDATORY_REAUTH_OPT_IN" file="common/autofill_mandatory_reauth_opt_in.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP" file="screen_capture_notification_grip.png" />
       <if expr="not is_android">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 877e075..f673aabf 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -7499,8 +7499,6 @@
       "supervised_user/supervised_user_browser_utils.h",
       "supervised_user/supervised_user_google_auth_navigation_throttle.cc",
       "supervised_user/supervised_user_google_auth_navigation_throttle.h",
-      "supervised_user/supervised_user_interstitial.cc",
-      "supervised_user/supervised_user_interstitial.h",
       "supervised_user/supervised_user_interstitial_tab_closer.cc",
       "supervised_user/supervised_user_interstitial_tab_closer.h",
       "supervised_user/supervised_user_metrics_service_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 23f5cd85..8475455 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5414,9 +5414,6 @@
      flag_descriptions::kArcSyncInstallPriorityName,
      flag_descriptions::kArcSyncInstallPriorityDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kSyncInstallPriority)},
-    {"arc-vmm-swap", flag_descriptions::kArcVmmSwapName,
-     flag_descriptions::kArcVmmSwapDesc, kOsCrOS,
-     PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootArcVmmSwap")},
     {"arc-vmm-swap-keyboard-shortcut",
      flag_descriptions::kArcVmmSwapKBShortcutName,
      flag_descriptions::kArcVmmSwapKBShortcutDesc, kOsCrOS,
@@ -6370,6 +6367,13 @@
                                     kNtpHistoryClustersModuleVariations,
                                     "DesktopNtpModules")},
 
+    {"ntp-journeys-module-model-ranking",
+     flag_descriptions::kNtpHistoryClustersModuleUseModelRankingName,
+     flag_descriptions::kNtpHistoryClustersModuleUseModelRankingDescription,
+     kOsDesktop,
+     FEATURE_VALUE_TYPE(
+         ntp_features::kNtpHistoryClustersModuleUseModelRanking)},
+
     {"ntp-modules-header-icon", flag_descriptions::kNtpModulesHeaderIconName,
      flag_descriptions::kNtpModulesHeaderIconDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(ntp_features::kNtpModulesHeaderIcon)},
@@ -6468,6 +6472,10 @@
      flag_descriptions::kNtpDesktopLensDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(ntp_features::kNtpRealboxLensSearch)},
 
+    {"price-insights", commerce::flag_descriptions::kPriceInsightsName,
+     commerce::flag_descriptions::kPriceInsightsDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(commerce::kPriceInsights)},
+
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION)
@@ -9794,20 +9802,6 @@
          policy::features::kSafeSitesFilterBehaviorPolicyAndroid)},
 #endif
 
-#if BUILDFLAG(ENABLE_NACL)
-    {"ppapi-shared-images-swapchain",
-     flag_descriptions::kPPAPISharedImagesSwapChainName,
-     flag_descriptions::kPPAPISharedImagesSwapChainDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kPPAPISharedImagesSwapChain)},
-#endif
-
-#if BUILDFLAG(ENABLE_NACL)
-    {"support-pepper-video-decoder-dev-api",
-     flag_descriptions::kSupportPepperVideoDecoderDevAPIName,
-     flag_descriptions::kSupportPepperVideoDecoderDevAPIDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kSupportPepperVideoDecoderDevAPI)},
-#endif
-
     {"cmd-decoder-always-get-size-from-source-texture",
      flag_descriptions::kCmdDecoderAlwaysGetSizeFromSourceTextureName,
      flag_descriptions::kCmdDecoderAlwaysGetSizeFromSourceTextureDescription,
diff --git a/chrome/browser/android/webapk/webapk_icon_hasher_browsertest.cc b/chrome/browser/android/webapk/webapk_icon_hasher_browsertest.cc
index d952cab..c5de126 100644
--- a/chrome/browser/android/webapk/webapk_icon_hasher_browsertest.cc
+++ b/chrome/browser/android/webapk/webapk_icon_hasher_browsertest.cc
@@ -118,7 +118,7 @@
     base::RunLoop run_loop;
     webapps::WebApkIconHasher::DownloadAndComputeMurmur2Hash(
         url_loader_factory.get(), web_contents->GetWeakPtr(),
-        url::Origin::Create(kIconUrl), {kIconUrl},
+        url::Origin::Create(kIconUrl), {webapps::WebappIcon(kIconUrl)},
         base::BindOnce(&OnGotMurmur2Hash, run_loop.QuitClosure()));
     run_loop.Run();
   }
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index a69959e..736bc67 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -572,7 +572,8 @@
   // We redownload the icon in order to take the Murmur2 hash. The redownload
   // should be fast because the icon should be in the HTTP cache.
 
-  std::set<GURL> icons = install_shortcut_info_->GetWebApkIcons();
+  std::vector<webapps::WebappIcon> icons =
+      install_shortcut_info_->GetWebApkIcons();
   webapps::WebApkIconHasher::DownloadAndComputeMurmur2Hash(
       GetURLLoaderFactory(browser_context_), web_contents_,
       url::Origin::Create(install_shortcut_info_->url), icons,
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index c573be0..973de80 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -18,6 +18,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/android/chrome_jni_headers/WebApkUpdateDataFetcher_jni.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/webapps/browser/android/webapp_icon.h"
 #include "components/webapps/browser/android/webapps_icon_utils.h"
 #include "components/webapps/browser/android/webapps_utils.h"
 #include "components/webapps/browser/features.h"
@@ -215,14 +216,7 @@
     is_splash_icon_maskable_ = data.has_maskable_splash_icon;
   }
 
-  std::set<GURL> urls{info_.best_primary_icon_url};
-  if (!info_.splash_image_url.is_empty())
-    urls.insert(info_.splash_image_url);
-
-  for (const auto& shortcut_url : info_.best_shortcut_icon_urls) {
-    if (shortcut_url.is_valid())
-      urls.insert(shortcut_url);
-  }
+  std::vector<webapps::WebappIcon> icons = info_.GetWebApkIcons();
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
@@ -232,7 +226,7 @@
           ->GetURLLoaderFactoryForBrowserProcess()
           .get(),
       web_contents()->GetWeakPtr(), url::Origin::Create(last_fetched_url_),
-      urls,
+      icons,
       base::BindOnce(&WebApkUpdateDataFetcher::OnGotIconMurmur2Hashes,
                      weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 8c988b9..80d53b3 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -134,6 +134,11 @@
 #include "ui/gfx/geometry/point.h"
 #include "url/url_constants.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"  // nogncheck
+#endif
+
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
 #include "ui/aura/env_observer.h"
@@ -2781,17 +2786,21 @@
   EXPECT_TRUE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
 }
 
-// This test executes the context menu command 'LanguageSettings' which will
-// load chrome://settings/languages in a browser window. This is a browser-
-// initiated operation and so we expect this to succeed if the embedder is
-// allowed to perform the operation.
+// This test executes the context menu command 'LanguageSettings'.
+// On Ash, this will open the language settings in the OS Settings app.
+// Elsewhere, it will load chrome://settings/languages in a browser window.
+// In either case, this is a browser-initiated operation and so we expect it
+// to succeed if the embedder is allowed to perform the operation.
 IN_PROC_BROWSER_TEST_F(WebViewTest, ContextMenuLanguageSettings) {
   LoadAppWithGuest("web_view/context_menus/basic");
-
   content::WebContents* embedder = GetEmbedderWebContents();
   ASSERT_TRUE(embedder);
 
-  // Create and build our test context menu.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  ash::SystemWebAppManager::Get(browser()->profile())
+      ->InstallSystemAppsForTesting();
+#endif
+
   content::WebContentsAddedObserver web_contents_added_observer;
 
   GURL page_url("http://www.google.com");
@@ -2800,14 +2809,20 @@
                                         GURL(), GURL()));
   menu->ExecuteCommand(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS, 0);
 
+  // Verify that a new WebContents has been created that is at the appropriate
+  // Language Settings page.
   content::WebContents* new_contents =
       web_contents_added_observer.GetWebContents();
-
-  // Verify that a new WebContents has been created that is at the Language
-  // Settings page.
-  EXPECT_EQ(GURL(std::string(chrome::kChromeUISettingsURL) +
-                 chrome::kLanguageOptionsSubPage),
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  EXPECT_EQ(
+      GURL(chrome::kChromeUIOSSettingsURL)
+          .Resolve(chromeos::settings::mojom::kLanguagesAndInputSectionPath),
+      new_contents->GetVisibleURL());
+#else
+  EXPECT_EQ(GURL(chrome::kChromeUISettingsURL)
+                .Resolve(chrome::kLanguageOptionsSubPage),
             new_contents->GetVisibleURL());
+#endif
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, ContextMenusAPI_Basic) {
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index bfef56f2..90d0c15 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -403,6 +403,8 @@
     "arc/input_overlay/ui/action_view.h",
     "arc/input_overlay/ui/action_view_list_item.cc",
     "arc/input_overlay/ui/action_view_list_item.h",
+    "arc/input_overlay/ui/button_options_menu.cc",
+    "arc/input_overlay/ui/button_options_menu.h",
     "arc/input_overlay/ui/edit_finish_view.cc",
     "arc/input_overlay/ui/edit_finish_view.h",
     "arc/input_overlay/ui/editing_list.cc",
@@ -656,8 +658,6 @@
     "audio/audio_survey_handler.h",
     "authpolicy/authpolicy_credentials_manager.cc",
     "authpolicy/authpolicy_credentials_manager.h",
-    "authpolicy/authpolicy_helper.cc",
-    "authpolicy/authpolicy_helper.h",
     "authpolicy/data_pipe_utils.cc",
     "authpolicy/data_pipe_utils.h",
     "authpolicy/kerberos_files_handler.cc",
@@ -1715,8 +1715,6 @@
     "login/saml/saml_profile_prefs.h",
     "login/screen_manager.cc",
     "login/screen_manager.h",
-    "login/screens/active_directory_password_change_screen.cc",
-    "login/screens/active_directory_password_change_screen.h",
     "login/screens/app_downloading_screen.cc",
     "login/screens/app_downloading_screen.h",
     "login/screens/arc_vm_data_migration_screen.cc",
@@ -3466,6 +3464,7 @@
     "//chromeos/ash/components/dbus/session_manager",
     "//chromeos/ash/components/dbus/session_manager:login_manager_proto",
     "//chromeos/ash/components/dbus/smbprovider",
+    "//chromeos/ash/components/dbus/swap_management",
     "//chromeos/ash/components/dbus/system_clock",
     "//chromeos/ash/components/dbus/system_proxy:system_proxy_proto",
     "//chromeos/ash/components/dbus/update_engine",
@@ -5004,7 +5003,6 @@
     "attestation/tpm_challenge_key_subtle_unittest.cc",
     "attestation/tpm_challenge_key_unittest.cc",
     "authpolicy/authpolicy_credentials_manager_unittest.cc",
-    "authpolicy/authpolicy_helper_unittest.cc",
     "bluetooth/debug_logs_manager_unittest.cc",
     "borealis/borealis_app_launcher_unittest.cc",
     "borealis/borealis_app_uninstaller_unittest.cc",
@@ -5284,7 +5282,6 @@
     "login/existing_user_controller_auto_login_unittest.cc",
     "login/existing_user_controller_base_test.cc",
     "login/existing_user_controller_base_test.h",
-    "login/existing_user_controller_forced_online_auth_unittest.cc",
     "login/hats_unlock_survey_trigger_unittest.cc",
     "login/hid_detection_revamp_field_trial_unittest.cc",
     "login/hwid_checker_unittest.cc",
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service.cc b/chrome/browser/ash/arc/auth/arc_auth_service.cc
index af859f9..eb767ed6 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service.cc
@@ -542,7 +542,7 @@
   ::GetAccountManagerFacade(profile_->GetPath().value())
       ->ShowReauthAccountDialog(
           account_manager::AccountManagerFacade::AccountAdditionSource::kArc,
-          email, base::OnceClosure());
+          email, base::DoNothing());
 }
 
 void ArcAuthService::OnRefreshTokenUpdatedForAccount(
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
index 6030bb4..4280003 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ash/arc/input_overlay/actions/action.h"
 #include "chrome/browser/ash/arc/input_overlay/touch_injector.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/action_edit_menu.h"
+#include "chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/edit_finish_view.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/editing_list.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/educational_view.h"
@@ -160,6 +161,18 @@
   touch_injector_->set_show_nudge(false);
 }
 
+bool DisplayOverlayController::HasButtonOptionsMenu() const {
+  return button_options_menu_ != nullptr;
+}
+
+void DisplayOverlayController::RemoveButtonOptionsMenu() {
+  if (!IsBeta() || !button_options_menu_) {
+    return;
+  }
+  button_options_menu_->parent()->RemoveChildViewT(button_options_menu_);
+  button_options_menu_ = nullptr;
+}
+
 void DisplayOverlayController::AddEditingList() {
   if (!IsBeta() || editing_list_) {
     return;
@@ -372,6 +385,7 @@
       RemoveInputMappingView();
       RemoveEducationalView();
       RemoveEditFinishView();
+      RemoveButtonOptionsMenu();
       RemoveNudgeView();
       break;
     case DisplayMode::kEducation:
@@ -388,6 +402,7 @@
       RemoveEditFinishView();
       RemoveEducationalView();
       RemoveNudgeView();
+      RemoveButtonOptionsMenu();
       AddInputMappingView(overlay_widget);
       AddMenuEntryView(overlay_widget);
       if (touch_injector_->show_nudge()) {
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
index 9b3bfef..414979ff 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
@@ -24,6 +24,7 @@
 class Action;
 class ActionEditMenu;
 class ActionView;
+class ButtonOptionsMenu;
 class EditFinishView;
 class EditingList;
 class EducationalView;
@@ -102,6 +103,7 @@
 
  private:
   friend class ArcInputOverlayManagerTest;
+  friend class ButtonOptionsMenu;
   friend class DisplayOverlayControllerTest;
   friend class EditingList;
   friend class EducationalView;
@@ -144,6 +146,9 @@
   void RemoveEducationalView();
   void OnEducationalViewDismissed();
 
+  bool HasButtonOptionsMenu() const;
+  void RemoveButtonOptionsMenu();
+
   void AddEditingList();
   void RemoveEditingList();
 
@@ -184,6 +189,7 @@
   // References to UI elements owned by the overlay widget.
   raw_ptr<InputMappingView> input_mapping_view_ = nullptr;
   raw_ptr<InputMenuView> input_menu_view_ = nullptr;
+  raw_ptr<ButtonOptionsMenu> button_options_menu_ = nullptr;
   raw_ptr<MenuEntryView> menu_entry_ = nullptr;
   raw_ptr<ActionEditMenu> action_edit_menu_ = nullptr;
   raw_ptr<EditFinishView> edit_finish_view_ = nullptr;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc
new file mode 100644
index 0000000..da53a602
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc
@@ -0,0 +1,367 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h"
+
+#include "ash/bubble/bubble_utils.h"
+#include "ash/components/arc/compat_mode/style/arc_color_provider.h"
+#include "ash/login/ui/views_utils.h"
+#include "ash/public/cpp/ash_view_ids.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
+#include "ash/style/icon_button.h"
+#include "ash/style/typography.h"
+#include "ash/system/unified/feature_tile.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/action.h"
+#include "chrome/browser/ash/arc/input_overlay/display_overlay_controller.h"
+#include "chrome/browser/ash/arc/input_overlay/ui/ui_utils.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/separator.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/layout_types.h"
+#include "ui/views/layout/table_layout.h"
+#include "ui/views/vector_icons.h"
+
+namespace arc::input_overlay {
+
+namespace {
+
+// Whole Menu measurements.
+constexpr int kMenuWidth = 316;
+
+// Triangle.
+constexpr int kTriangleLength = 20;
+constexpr int kTriangleHeight = 14;
+constexpr int kCornerRadius = 16;
+constexpr int kBorderThickness = 2;
+
+// Draws the dialog shape path with round corner. It starts after the corner
+// radius on line #0 and draws clockwise.
+//  _0>__________
+// |             |
+// |             |
+// |             |
+// |              >
+// |             |
+// |             |
+// |_____________|
+//
+SkPath BackgroundPath(int height) {
+  SkPath path;
+  auto short_length = kMenuWidth - kTriangleHeight - 2 * kCornerRadius;
+  auto short_height = height - 2 * kCornerRadius;
+  path.moveTo(kCornerRadius, 0);
+  // Top left after corner radius to top right corner radius.
+  path.rLineTo(short_length, 0);
+  path.rArcTo(kCornerRadius, kCornerRadius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, +kCornerRadius, +kCornerRadius);
+  // Top right after corner radius to midway point.
+  path.rLineTo(0, short_height / 2 - kTriangleLength / 2);
+  // Triangle shape.
+  path.rLineTo(kTriangleHeight, kTriangleLength / 2);
+  path.rLineTo(-kTriangleHeight, kTriangleLength / 2);
+  // After midway point to bottom right corner radius.
+  path.rLineTo(0, short_height / 2 - kTriangleLength / 2);
+  path.rArcTo(kCornerRadius, kCornerRadius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -kCornerRadius, +kCornerRadius);
+  // Bottom right after corner radius to bottom left corner radius.
+  path.rLineTo(-short_length, 0);
+  path.rArcTo(kCornerRadius, kCornerRadius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -kCornerRadius, -kCornerRadius);
+  // Bottom left after corner radius to top left corner radius.
+  path.rLineTo(0, -short_height);
+  path.rArcTo(kCornerRadius, kCornerRadius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, +kCornerRadius, -kCornerRadius);
+  // Path finish.
+  path.close();
+  return path;
+}
+
+}  // namespace
+
+// static
+ButtonOptionsMenu* ButtonOptionsMenu::Show(DisplayOverlayController* controller,
+                                           Action* action) {
+  // Ensure there is only one menu at any time.
+  if (controller->HasButtonOptionsMenu()) {
+    controller->RemoveButtonOptionsMenu();
+  }
+
+  auto* parent = controller->GetOverlayWidgetContentsView();
+  auto* button_options_menu = parent->AddChildView(
+      std::make_unique<ButtonOptionsMenu>(controller, action));
+  button_options_menu->Init();
+  return button_options_menu;
+}
+
+ButtonOptionsMenu::ButtonOptionsMenu(DisplayOverlayController* controller,
+                                     Action* action)
+    : display_overlay_controller_(controller), action_(action) {}
+
+ButtonOptionsMenu::~ButtonOptionsMenu() = default;
+
+void ButtonOptionsMenu::Init() {
+  SetUseDefaultFillLayout(true);
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+  SetBorder(views::CreateEmptyBorder(
+      gfx::Insets::TLBR(16, 16, 16, 16 + kTriangleHeight)));
+
+  AddHeader();
+  AddEditTitle();
+  AddActionSelection();
+  AddActionEdit();
+  AddActionNameLabel();
+
+  SizeToPreferredSize();
+  CalculatePosition();
+}
+
+void ButtonOptionsMenu::AddHeader() {
+  // ------------------------------------
+  // ||icon|  |"Button options"|  |icon||
+  // ------------------------------------
+  auto* container = AddChildView(std::make_unique<views::View>());
+  container->SetLayoutManager(std::make_unique<views::TableLayout>())
+      ->AddColumn(views::LayoutAlignment::kStart,
+                  views::LayoutAlignment::kCenter,
+                  /*horizontal_resize=*/1.0f,
+                  views::TableLayout::ColumnSize::kUsePreferred,
+                  /*fixed_width=*/0, /*min_width=*/0)
+      .AddColumn(views::LayoutAlignment::kCenter,
+                 views::LayoutAlignment::kCenter,
+                 /*horizontal_resize=*/2.0f,
+                 views::TableLayout::ColumnSize::kUsePreferred,
+                 /*fixed_width=*/0, /*min_width=*/0)
+      .AddColumn(views::LayoutAlignment::kEnd, views::LayoutAlignment::kCenter,
+                 /*horizontal_resize=*/1.0f,
+                 views::TableLayout::ColumnSize::kUsePreferred,
+                 /*fixed_width=*/0, /*min_width=*/0)
+      .AddRows(1, views::TableLayout::kFixedSize, 0);
+  container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 0, 16, 0));
+
+  container->AddChildView(std::make_unique<ash::IconButton>(
+      base::BindRepeating(&ButtonOptionsMenu::OnTrashButtonPressed,
+                          base::Unretained(this)),
+      ash::IconButton::Type::kMedium, &vector_icons::kCloseIcon,
+      IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+
+  container->AddChildView(ash::bubble_utils::CreateLabel(
+      // TODO(b/281753420): Replace placeholder text with localized strings.
+      ash::TypographyToken::kCrosTitle1, u"Button options",
+      cros_tokens::kCrosSysOnSurface));
+
+  container->AddChildView(std::make_unique<ash::IconButton>(
+      base::BindRepeating(&ButtonOptionsMenu::OnDoneButtonPressed,
+                          base::Unretained(this)),
+      ash::IconButton::Type::kMedium, &vector_icons::kCloseIcon,
+      // TODO(b/281753420): Replace placeholder names with a11y strings.
+      IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+}
+
+void ButtonOptionsMenu::AddEditTitle() {
+  // ------------------------------
+  // ||"Key assignment"|          |
+  // ------------------------------
+  auto* container = AddChildView(std::make_unique<views::View>());
+  container->SetLayoutManager(std::make_unique<views::FlexLayout>())
+      ->SetOrientation(views::LayoutOrientation::kHorizontal)
+      .SetMainAxisAlignment(views::LayoutAlignment::kStart);
+  container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 0, 12, 0));
+
+  container->AddChildView(ash::bubble_utils::CreateLabel(
+      // TODO(b/281753420): Replace placeholder text with localized strings.
+      ash::TypographyToken::kCrosBody2, u"Key assignment",
+      cros_tokens::kCrosSysOnSurface));
+}
+
+void ButtonOptionsMenu::AddActionSelection() {
+  // ----------------------------------
+  // | |feature_tile| |feature_title| |
+  // ----------------------------------
+  auto* container = AddChildView(std::make_unique<ash::RoundedContainer>(
+      ash::RoundedContainer::Behavior::kTopRounded));
+  // Create a 1x2 table with a column padding of 8.
+  container->SetLayoutManager(std::make_unique<views::TableLayout>())
+      ->AddColumn(views::LayoutAlignment::kStretch,
+                  views::LayoutAlignment::kStretch,
+                  /*horizontal_resize=*/1.0f,
+                  views::TableLayout::ColumnSize::kUsePreferred,
+                  /*fixed_width=*/0, /*min_width=*/0)
+      .AddPaddingColumn(/*horizontal_resize=*/views::TableLayout::kFixedSize,
+                        /*width=*/8)
+      .AddColumn(views::LayoutAlignment::kStretch,
+                 views::LayoutAlignment::kStretch,
+                 /*horizontal_resize=*/1.0f,
+                 views::TableLayout::ColumnSize::kUsePreferred,
+                 /*fixed_width=*/0, /*min_width=*/0)
+      .AddRows(1, views::TableLayout::kFixedSize, 0);
+  container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 0, 2, 0));
+
+  auto* tap_button = container->AddChildView(std::make_unique<ash::FeatureTile>(
+      base::BindRepeating(&ButtonOptionsMenu::OnTapButtonPressed,
+                          base::Unretained(this)),
+      /*is_togglable=*/true,
+      /*type=*/ash::FeatureTile::TileType::kCompact));
+  tap_button->SetID(ash::VIEW_ID_ACCESSIBILITY_FEATURE_TILE);
+  tap_button->SetAccessibleName(
+      // TODO(b/281753420): Replace placeholder names with a11y strings.
+      l10n_util::GetStringUTF16(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+  // TODO(b/281753420): Replace placeholder text with localized strings.
+  tap_button->SetLabel(u"Single button");
+  tap_button->SetVectorIcon(vector_icons::kCloseIcon);
+  tap_button->SetVisible(true);
+  tap_button->SetBackground(views::CreateSolidBackground(SK_ColorTRANSPARENT));
+
+  auto* move_button =
+      container->AddChildView(std::make_unique<ash::FeatureTile>(
+          base::BindRepeating(&ButtonOptionsMenu::OnMoveButtonPressed,
+                              base::Unretained(this)),
+          /*is_togglable=*/true,
+          /*type=*/ash::FeatureTile::TileType::kCompact));
+  move_button->SetID(ash::VIEW_ID_ACCESSIBILITY_FEATURE_TILE);
+  move_button->SetAccessibleName(
+      // TODO(b/281753420): Replace placeholder names with a11y strings.
+      l10n_util::GetStringUTF16(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+  // TODO(b/281753420): Replace placeholder text with localized strings.
+  move_button->SetLabel(u"Dpad");
+  move_button->SetVectorIcon(vector_icons::kCloseIcon);
+  move_button->SetVisible(true);
+  move_button->SetBackground(views::CreateSolidBackground(SK_ColorTRANSPARENT));
+}
+
+void ButtonOptionsMenu::AddActionEdit() {
+  // ------------------------------
+  // ||"Selected key" |key labels||
+  // ||"key"                      |
+  // ------------------------------
+  auto* container = AddChildView(std::make_unique<ash::RoundedContainer>(
+      ash::RoundedContainer::Behavior::kBottomRounded));
+  container->SetLayoutManager(std::make_unique<views::TableLayout>())
+      ->AddColumn(views::LayoutAlignment::kStart,
+                  views::LayoutAlignment::kCenter,
+                  /*horizontal_resize=*/1.0f,
+                  views::TableLayout::ColumnSize::kUsePreferred,
+                  /*fixed_width=*/0, /*min_width=*/0)
+      .AddColumn(views::LayoutAlignment::kEnd, views::LayoutAlignment::kCenter,
+                 /*horizontal_resize=*/1.0f,
+                 views::TableLayout::ColumnSize::kUsePreferred,
+                 /*fixed_width=*/0, /*min_width=*/0)
+      .AddRows(1, views::TableLayout::kFixedSize, 0);
+  container->SetBorderInsets(gfx::Insets::VH(14, 16));
+  container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 0, 8, 0));
+
+  // TODO(b/281753420): Replace placeholder text with localized strings.
+  container->AddChildView(CreateNameTag(u"Selected key", u"Key"));
+  auto* key_binding_button =
+      container->AddChildView(std::make_unique<views::LabelButton>(
+          views::Button::PressedCallback(), base::UTF8ToUTF16(action_->name()),
+          views::style::CONTEXT_BUTTON));
+  key_binding_button->SetBackground(views::CreateSolidBackground(SK_ColorGRAY));
+}
+
+void ButtonOptionsMenu::AddActionNameLabel() {
+  // ------------------------------
+  // ||"Button label"           > |
+  // ||"Unassigned"               |
+  //  -----------------------------
+  auto* container = AddChildView(std::make_unique<ash::RoundedContainer>());
+  container->SetUseDefaultFillLayout(true);
+  container->SetBorderInsets(gfx::Insets::VH(14, 16));
+
+  auto* action_name_feature_tile =
+      container->AddChildView(std::make_unique<ash::FeatureTile>(
+          base::BindRepeating(
+              &ButtonOptionsMenu::OnButtonLabelAssignmentPressed,
+              base::Unretained(this)),
+          /*is_togglable=*/false));
+  action_name_feature_tile->SetID(ash::VIEW_ID_ACCESSIBILITY_FEATURE_TILE);
+  action_name_feature_tile->SetAccessibleName(
+      // TODO(b/281753420): Replace placeholder names with a11y strings.
+      l10n_util::GetStringUTF16(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+  // TODO(b/281753420): Replace placeholder text with localized strings.
+  action_name_feature_tile->SetLabel(u"Button label");
+  action_name_feature_tile->SetSubLabel(u"Unassigned");
+  action_name_feature_tile->SetSubLabelVisibility(true);
+  action_name_feature_tile->CreateDecorativeDrillInArrow();
+  action_name_feature_tile->SetBackground(
+      views::CreateSolidBackground(SK_ColorTRANSPARENT));
+  action_name_feature_tile->SetVisible(true);
+}
+
+void ButtonOptionsMenu::CalculatePosition() {
+  auto position = action_->GetUICenterPosition();
+  auto x = position.x();
+  auto y = position.y();
+  auto parent_size =
+      display_overlay_controller_->GetOverlayWidgetContentsView()->size();
+
+  // Set the menu at the middle if there is not enough margin on the right
+  // or left side.
+  if (x + width() > parent_size.width() || x < 0) {
+    x = std::max(0, parent_size.width() - width());
+  }
+
+  // Set the menu at the bottom if there is not enough margin on the bottom
+  // side.
+  if (y + height() > parent_size.height()) {
+    y = std::max(0, parent_size.height() - height());
+  }
+
+  SetPosition(gfx::Point(x, y));
+}
+
+void ButtonOptionsMenu::OnTrashButtonPressed() {
+  // TODO(b/270969760): Implement close menu functionality.
+  display_overlay_controller_->RemoveButtonOptionsMenu();
+}
+
+void ButtonOptionsMenu::OnDoneButtonPressed() {
+  // TODO(b/270969760): Implement save menu functionality.
+  display_overlay_controller_->RemoveButtonOptionsMenu();
+}
+
+void ButtonOptionsMenu::OnTapButtonPressed() {
+  // TODO(b/270969760): Implement tap button functionality.
+}
+
+void ButtonOptionsMenu::OnMoveButtonPressed() {
+  // TODO(b/270969760): Implement move button functionality.
+}
+
+void ButtonOptionsMenu::OnButtonLabelAssignmentPressed() {
+  // TODO(b/270969760): Implement key binding change functionality.
+}
+
+void ButtonOptionsMenu::OnPaintBackground(gfx::Canvas* canvas) {
+  cc::PaintFlags flags;
+  // Draw the shape.
+  flags.setAntiAlias(true);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  ui::ColorProvider* color_provider = GetColorProvider();
+  flags.setColor(color_provider->GetColor(cros_tokens::kCrosSysBaseElevated));
+  int height = GetHeightForWidth(kMenuWidth);
+  canvas->DrawPath(BackgroundPath(height), flags);
+  // Draw the border.
+  flags.setStyle(cc::PaintFlags::kStroke_Style);
+  // TODO(b/270969760): Change to "sys.BorderHighlight1" when added.
+  flags.setColor(color_provider->GetColor(cros_tokens::kCrosSysSystemBorder1));
+  flags.setStrokeWidth(kBorderThickness);
+  canvas->DrawPath(BackgroundPath(height), flags);
+}
+
+gfx::Size ButtonOptionsMenu::CalculatePreferredSize() const {
+  // TODO(b/270969760): Dynamically calculate height based on action selection.
+  return gfx::Size(kMenuWidth, GetHeightForWidth(kMenuWidth));
+}
+
+}  // namespace arc::input_overlay
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h
new file mode 100644
index 0000000..5cd111c
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h
@@ -0,0 +1,62 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_BUTTON_OPTIONS_MENU_H_
+#define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_BUTTON_OPTIONS_MENU_H_
+
+#include "ash/constants/ash_features.h"
+#include "ash/style/rounded_container.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "ui/color/color_id.h"
+#include "ui/events/event.h"
+#include "ui/views/view.h"
+
+namespace arc::input_overlay {
+class Action;
+class DisplayOverlayController;
+class ButtonOptionsMenu : public views::View {
+ public:
+  static ButtonOptionsMenu* Show(
+      DisplayOverlayController* display_overlay_controller,
+      Action* action);
+
+  ButtonOptionsMenu(DisplayOverlayController* display_overlay_controller,
+                    Action* action);
+  ButtonOptionsMenu(const ButtonOptionsMenu&) = delete;
+  ButtonOptionsMenu& operator=(const ButtonOptionsMenu&) = delete;
+  ~ButtonOptionsMenu() override;
+
+ private:
+  void Init();
+
+  // Add UI components.
+  void AddHeader();
+  void AddEditTitle();
+  void AddActionEdit();
+  void AddActionSelection();
+  void AddActionNameLabel();
+
+  // Functions related to buttons.
+  void OnTrashButtonPressed();
+  void OnDoneButtonPressed();
+  void OnTapButtonPressed();
+  void OnMoveButtonPressed();
+  void OnButtonLabelAssignmentPressed();
+
+  // View position calculation.
+  void CalculatePosition();
+
+  // views::View:
+  void OnPaintBackground(gfx::Canvas* canvas) override;
+  gfx::Size CalculatePreferredSize() const override;
+
+  // DisplayOverlayController owns this class, no need to deallocate.
+  const raw_ptr<DisplayOverlayController> display_overlay_controller_ = nullptr;
+  const raw_ptr<Action> action_ = nullptr;
+};
+
+}  // namespace arc::input_overlay
+
+#endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_BUTTON_OPTIONS_MENU_H_
diff --git a/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc b/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
index 1b0f031..fcae721 100644
--- a/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
+++ b/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
@@ -17,6 +17,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/task/thread_pool.h"
+#include "base/time/time.h"
 #include "chrome/browser/ash/arc/vmm/arc_vmm_swap_scheduler.h"
 #include "chrome/browser/ash/arc/vmm/arcvm_working_set_trim_executor.h"
 #include "chromeos/ash/components/dbus/concierge/concierge_client.h"
@@ -44,6 +45,9 @@
   ~ArcVmmManagerFactory() override = default;
 };
 
+// The minimal time interval for two successful ARCVM memory shrink request.
+const base::TimeDelta kMinimalShrinkMemoryInterval = base::Minutes(10);
+
 }  // namespace
 
 // static
@@ -93,38 +97,46 @@
 ArcVmmManager::~ArcVmmManager() = default;
 
 void ArcVmmManager::SetSwapState(SwapState state) {
+  vm_tools::concierge::SwapOperation op;
   switch (state) {
     case SwapState::ENABLE:
-      // Trim ARCVM memory before enable vmm swap in order to squeeze the vm
-      // memory. Send enable operation if trim success.
-      DCHECK(!trim_call_.is_null());
-      trim_call_.Run(
-          base::BindOnce(
-              [](base::OnceClosure success_closure, bool success,
-                 const std::string& failure_reason) {
-                if (success) {
-                  std::move(success_closure).Run();
-                } else {
-                  LOG(ERROR) << "Failed to trim ARCVM memory when enable vmm "
-                                "swap, reason: "
-                             << failure_reason;
-                }
-              },
-              base::BindOnce(&ArcVmmManager::SendSwapRequest,
-                             weak_ptr_factory_.GetWeakPtr(),
-                             vm_tools::concierge::SwapOperation::ENABLE,
-                             base::DoNothing())),
-          arc::ArcVmReclaimType::kReclaimAll, arc::ArcSession::kNoPageLimit);
+      op = vm_tools::concierge::SwapOperation::ENABLE;
       break;
-    case SwapState::ENABLE_WITH_SWAPOUT:
-      SendSwapRequest(vm_tools::concierge::SwapOperation::FORCE_ENABLE,
-                      base::DoNothing());
+    case SwapState::FORCE_ENABLE:
+      op = vm_tools::concierge::SwapOperation::FORCE_ENABLE;
       break;
     case SwapState::DISABLE:
-      SendSwapRequest(vm_tools::concierge::SwapOperation::DISABLE,
-                      base::DoNothing());
+      op = vm_tools::concierge::SwapOperation::DISABLE;
       break;
   }
+
+  if (state == SwapState::DISABLE) {
+    SendSwapRequest(op, base::DoNothing());
+    return;
+  }
+
+  // Enable or ForceEnable need shrink ARCVM memory first.
+  if (!last_shrink_timestamp_ ||
+      base::Time::Now() - last_shrink_timestamp_.value() >
+          kMinimalShrinkMemoryInterval) {
+    last_shrink_timestamp_ = base::Time::Now();
+    last_shrink_result_ = false;
+    // Following attempts to enable vmm-swap will be ignored until
+    // `ShrinkArcVmMemoryAndEnableSwap()` finish. As a result, it will send an
+    // enable swap request as a coalesced request if it succeeds to shrink the
+    // ARCVM memory.
+    ShrinkArcVmMemoryAndEnableSwap(op);
+  } else {
+    if (last_shrink_result_.value_or(false)) {
+      // If recently the memory shrinking succeed, just send enable request
+      // rather than shrink memory again.
+      SendSwapRequest(op, base::DoNothing());
+    } else {
+      // If recently the memory failed to shrink, skip the request.
+      VLOG(0) << "Skip enable swap request due to last arcvm memory shrink "
+                 "failure";
+    }
+  }
 }
 
 void ArcVmmManager::SendSwapRequest(
@@ -156,11 +168,76 @@
           operation, std::move(success_callback)));
 }
 
+void ArcVmmManager::SendAggressiveBalloonRequest(
+    bool enable,
+    base::OnceClosure success_callback) {
+  auto* client = ash::ConciergeClient::Get();
+  if (!client) {
+    LOG(ERROR) << "Cannot find concierge client to swap ARCVM";
+    return;
+  }
+
+  vm_tools::concierge::AggressiveBalloonRequest request;
+  request.set_name(kArcVmName);
+  request.set_owner_id(user_id_hash_);
+  request.set_enable(enable);
+  client->AggressiveBalloon(
+      request,
+      base::BindOnce(
+          [](bool enabled, base::OnceClosure cb,
+             absl::optional<vm_tools::concierge::AggressiveBalloonResponse>
+                 response) {
+            if (!response->success()) {
+              LOG(ERROR) << "Failed to send aggressive balloon request: "
+                         << enabled
+                         << ". Reason: " << response->failure_reason();
+            } else {
+              std::move(cb).Run();
+            }
+          },
+          enable, std::move(success_callback)));
+}
+
 void ArcVmmManager::PostWithSwapDelay(base::OnceClosure callback) {
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
       FROM_HERE, std::move(callback), swap_out_delay_);
 }
 
+void ArcVmmManager::ShrinkArcVmMemoryAndEnableSwap(
+    vm_tools::concierge::SwapOperation requested_operation) {
+  // Trim ARCVM memory before enable vmm swap in order to squeeze the vm
+  // memory. Send enable operation if trim success.
+  DCHECK(!trim_call_.is_null());
+  trim_call_.Run(
+      base::BindOnce(
+          [](base::OnceClosure success_closure, bool success,
+             const std::string& failure_reason) {
+            if (success) {
+              std::move(success_closure).Run();
+            } else {
+              LOG(ERROR) << "Failed to trim ARCVM memory when enable vmm "
+                            "swap, reason: "
+                         << failure_reason;
+            }
+          },
+          // If successfully execute trim, request enable aggressive balloon.
+          base::BindOnce(&ArcVmmManager::SendAggressiveBalloonRequest,
+                         weak_ptr_factory_.GetWeakPtr(), true,
+                         // If enable aggressive balloon successful, set shrink
+                         // result and re-send enable swap request.
+                         base::BindOnce(&ArcVmmManager::SetShrinkResult,
+                                        weak_ptr_factory_.GetWeakPtr(), true)
+                             .Then(base::BindOnce(
+                                 &ArcVmmManager::SendSwapRequest,
+                                 weak_ptr_factory_.GetWeakPtr(),
+                                 requested_operation, base::DoNothing())))),
+      arc::ArcVmReclaimType::kReclaimAll, arc::ArcSession::kNoPageLimit);
+}
+
+void ArcVmmManager::SetShrinkResult(bool success) {
+  last_shrink_result_ = success;
+}
+
 // ArcVmmManager::AcceleratorTarget --------------------------------------------
 
 class ArcVmmManager::AcceleratorTarget : public ui::AcceleratorTarget {
@@ -180,7 +257,7 @@
   // ui::AcceleratorTarget:
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override {
     if (accelerator == vmm_swap_enabled_) {
-      manager_->SetSwapState(SwapState::ENABLE_WITH_SWAPOUT);
+      manager_->SetSwapState(SwapState::FORCE_ENABLE);
     } else if (accelerator == vmm_swap_disabled_) {
       manager_->SetSwapState(SwapState::DISABLE);
     } else {
diff --git a/chrome/browser/ash/arc/vmm/arc_vmm_manager.h b/chrome/browser/ash/arc/vmm/arc_vmm_manager.h
index a0bc1c0..da887cc2 100644
--- a/chrome/browser/ash/arc/vmm/arc_vmm_manager.h
+++ b/chrome/browser/ash/arc/vmm/arc_vmm_manager.h
@@ -22,7 +22,7 @@
 
 enum class SwapState {
   ENABLE,
-  ENABLE_WITH_SWAPOUT,
+  FORCE_ENABLE,
   DISABLE,
 };
 
@@ -62,8 +62,26 @@
   void SendSwapRequest(vm_tools::concierge::SwapOperation operation,
                        base::OnceClosure success_callback);
 
+  void SendAggressiveBalloonRequest(bool enable,
+                                    base::OnceClosure success_callback);
+
   void PostWithSwapDelay(base::OnceClosure callback);
 
+  // Called by `SendSwapRequest` and should not be called by other caller.
+  // Enable aggressive balloon and reclaim ARCVM guest memory.
+  // Shrink memory before enable swap. The function send enable swap request
+  // after shrink success.
+  void ShrinkArcVmMemoryAndEnableSwap(
+      vm_tools::concierge::SwapOperation requested_operation);
+
+  // Called by callback from `ShrinkArcVmMemoryAndEnableSwap` and should not be
+  // called by other caller. Update shrink result.
+  void SetShrinkResult(bool success);
+
+  // Log the time stamp and result of last shrink memory request.
+  absl::optional<base::Time> last_shrink_timestamp_;
+  absl::optional<bool> last_shrink_result_;
+
   // The default delay from swap enabled and swap out. Basically it's used for
   // keyboard swap. In finch, it will be replaced by the flag parameter.
   base::TimeDelta swap_out_delay_ = base::Seconds(3);
diff --git a/chrome/browser/ash/arc/vmm/arc_vmm_manager_unittest.cc b/chrome/browser/ash/arc/vmm/arc_vmm_manager_unittest.cc
index 0697317..19516bc 100644
--- a/chrome/browser/ash/arc/vmm/arc_vmm_manager_unittest.cc
+++ b/chrome/browser/ash/arc/vmm/arc_vmm_manager_unittest.cc
@@ -101,6 +101,12 @@
     manager_->set_user_id_hash("test_user_hash_id");
   }
 
+  void InitAggressiveBallonResponse() {
+    vm_tools::concierge::AggressiveBalloonResponse response;
+    response.set_success(true);
+    client()->set_aggressive_balloon_response(response);
+  }
+
   void SetTrimCall(bool trim_result) {
     manager()->trim_call_ = base::BindLambdaForTesting(
         [trim_result](ArcVmWorkingSetTrimExecutor::ResultCallback callback,
@@ -131,6 +137,7 @@
 TEST_F(ArcVmmManagerTest, EnableSwapWhenTrimSuccess) {
   InitVmmManager();
   SetTrimCall(true);
+  InitAggressiveBallonResponse();
 
   // Send "ENABLE".
   EXPECT_EQ(0, client()->enable_count());
@@ -145,6 +152,7 @@
 TEST_F(ArcVmmManagerTest, NotEnableSwapWhenTrimFail) {
   InitVmmManager();
   SetTrimCall(false);
+  InitAggressiveBallonResponse();
 
   // Send "ENABLE".
   EXPECT_EQ(0, client()->enable_count());
@@ -158,7 +166,10 @@
 
 TEST_F(ArcVmmManagerTest, ForceSwapSuccess) {
   InitVmmManager();
-  manager()->SetSwapState(SwapState::ENABLE_WITH_SWAPOUT);
+  SetTrimCall(true);
+  InitAggressiveBallonResponse();
+
+  manager()->SetSwapState(SwapState::FORCE_ENABLE);
   base::RunLoop().RunUntilIdle();
   // Send "FORCE_ENABLE".
   EXPECT_EQ(1, client()->force_enable_count());
diff --git a/chrome/browser/ash/attestation/platform_verification_flow.cc b/chrome/browser/ash/attestation/platform_verification_flow.cc
index c3a8ee5..ef255353 100644
--- a/chrome/browser/ash/attestation/platform_verification_flow.cc
+++ b/chrome/browser/ash/attestation/platform_verification_flow.cc
@@ -43,6 +43,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
+#include "media/base/media_switches.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 
@@ -83,7 +84,7 @@
   bool IsInSupportedMode() override {
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     return !command_line->HasSwitch(chromeos::switches::kSystemDevMode) ||
-           command_line->HasSwitch(switches::kAllowRAInDevMode);
+           command_line->HasSwitch(::switches::kAllowRAInDevMode);
   }
 };
 
diff --git a/chrome/browser/ash/authpolicy/authpolicy_helper.cc b/chrome/browser/ash/authpolicy/authpolicy_helper.cc
deleted file mode 100644
index 52a2027..0000000
--- a/chrome/browser/ash/authpolicy/authpolicy_helper.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/authpolicy/authpolicy_helper.h"
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/logging.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/task/thread_pool.h"
-#include "chrome/browser/ash/authpolicy/data_pipe_utils.h"
-#include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h"
-#include "chromeos/ash/components/dbus/dbus_thread_manager.h"
-#include "chromeos/ash/components/dbus/upstart/upstart_client.h"
-#include "chromeos/ash/components/install_attributes/install_attributes.h"
-#include "components/account_id/account_id.h"
-#include "crypto/encryptor.h"
-#include "crypto/hmac.h"
-#include "crypto/symmetric_key.h"
-
-namespace ash {
-
-namespace {
-
-constexpr char kDCPrefix[] = "DC=";
-constexpr char kOUPrefix[] = "OU=";
-
-bool ParseDomainAndOU(const std::string& distinguished_name,
-                      authpolicy::JoinDomainRequest* request) {
-  std::string machine_domain;
-  std::vector<std::string> split_dn =
-      base::SplitString(distinguished_name, ",", base::TRIM_WHITESPACE,
-                        base::SPLIT_WANT_NONEMPTY);
-  for (const std::string& str : split_dn) {
-    if (base::StartsWith(str, kOUPrefix,
-                         base::CompareCase::INSENSITIVE_ASCII)) {
-      *request->add_machine_ou() = str.substr(strlen(kOUPrefix));
-    } else if (base::StartsWith(str, kDCPrefix,
-                                base::CompareCase::INSENSITIVE_ASCII)) {
-      if (!machine_domain.empty())
-        machine_domain.append(".");
-      machine_domain.append(str.substr(strlen(kDCPrefix)));
-    } else {
-      return false;
-    }
-  }
-  if (!machine_domain.empty())
-    request->set_machine_domain(machine_domain);
-  return true;
-}
-
-std::string DoDecrypt(const std::string& encrypted_data,
-                      const std::string& password) {
-  constexpr char error_msg[] = "Failed to decrypt data";
-  const size_t kSaltSize = 32;
-  const size_t kSignatureSize = 32;
-  if (encrypted_data.size() <= kSaltSize + kSignatureSize) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-
-  const std::string salt = encrypted_data.substr(0, kSaltSize);
-  const std::string signature =
-      encrypted_data.substr(kSaltSize, kSignatureSize);
-  const std::string ciphertext =
-      encrypted_data.substr(kSaltSize + kSignatureSize);
-
-  // Derive AES key, AES IV and HMAC key from password.
-  const size_t kAesKeySize = 32;
-  const size_t kAesIvSize = 16;
-  const size_t kHmacKeySize = 32;
-  const size_t kKeySize = kAesKeySize + kAesIvSize + kHmacKeySize;
-  std::unique_ptr<crypto::SymmetricKey> key =
-      crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
-          crypto::SymmetricKey::HMAC_SHA1, password, salt, 10000, kKeySize * 8);
-  if (!key) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-  DCHECK(kAesKeySize + kAesIvSize + kHmacKeySize == key->key().size());
-  const char* key_data_chars = key->key().data();
-  std::string aes_key(key_data_chars, kAesKeySize);
-  std::string aes_iv(key_data_chars + kAesKeySize, kAesIvSize);
-  std::string hmac_key(key_data_chars + kAesKeySize + kAesIvSize, kHmacKeySize);
-
-  // Check signature.
-  crypto::HMAC hmac(crypto::HMAC::SHA256);
-  if (kSignatureSize != hmac.DigestLength()) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-  uint8_t recomputed_signature[kSignatureSize];
-  if (!hmac.Init(hmac_key) ||
-      !hmac.Sign(ciphertext, recomputed_signature, kSignatureSize)) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-  std::string recomputed_signature_str(
-      reinterpret_cast<char*>(recomputed_signature), kSignatureSize);
-  if (signature != recomputed_signature_str) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-
-  // Decrypt.
-  std::unique_ptr<crypto::SymmetricKey> aes_key_obj(
-      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, aes_key));
-  crypto::Encryptor encryptor;
-  if (!encryptor.Init(aes_key_obj.get(), crypto::Encryptor::CBC, aes_iv)) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-  std::string decrypted_data;
-  if (!encryptor.Decrypt(ciphertext, &decrypted_data)) {
-    LOG(ERROR) << error_msg;
-    return std::string();
-  }
-  return decrypted_data;
-}
-
-}  // namespace
-
-AuthPolicyHelper::AuthPolicyHelper() {
-  AuthPolicyClient::Get()->WaitForServiceToBeAvailable(base::BindOnce(
-      &AuthPolicyHelper::OnServiceAvailable, weak_factory_.GetWeakPtr()));
-}
-
-// static
-void AuthPolicyHelper::TryAuthenticateUser(const std::string& username,
-                                           const std::string& object_guid,
-                                           const std::string& password) {
-  authpolicy::AuthenticateUserRequest request;
-  request.set_user_principal_name(username);
-  request.set_account_id(object_guid);
-  AuthPolicyClient::Get()->AuthenticateUser(
-      request, data_pipe_utils::GetDataReadPipe(password).get(),
-      base::DoNothing());
-}
-
-// static
-void AuthPolicyHelper::Restart() {
-  UpstartClient::Get()->RestartAuthPolicyService();
-}
-
-// static
-void AuthPolicyHelper::DecryptConfiguration(const std::string& blob,
-                                            const std::string& password,
-                                            OnDecryptedCallback callback) {
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::BindOnce(&DoDecrypt, blob, password), std::move(callback));
-}
-
-void AuthPolicyHelper::JoinAdDomain(const std::string& machine_name,
-                                    const std::string& distinguished_name,
-                                    int encryption_types,
-                                    const std::string& username,
-                                    const std::string& password,
-                                    JoinCallback callback) {
-  DCHECK(service_is_available_);
-  DCHECK(!InstallAttributes::Get()->IsActiveDirectoryManaged());
-  DCHECK(!weak_factory_.HasWeakPtrs()) << "Another operation is in progress";
-  authpolicy::JoinDomainRequest request;
-  if (!ParseDomainAndOU(distinguished_name, &request)) {
-    DLOG(ERROR) << "Failed to parse computer distinguished name";
-    std::move(callback).Run(authpolicy::ERROR_INVALID_OU, std::string());
-    return;
-  }
-  if (!machine_name.empty())
-    request.set_machine_name(machine_name);
-  DCHECK(authpolicy::KerberosEncryptionTypes_IsValid(encryption_types));
-  request.set_kerberos_encryption_types(
-      static_cast<authpolicy::KerberosEncryptionTypes>(encryption_types));
-  if (!username.empty())
-    request.set_user_principal_name(username);
-  DCHECK(!dm_token_.empty());
-  request.set_dm_token(dm_token_);
-
-  AuthPolicyClient::Get()->JoinAdDomain(
-      request, data_pipe_utils::GetDataReadPipe(password).get(),
-      base::BindOnce(&AuthPolicyHelper::OnJoinCallback,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void AuthPolicyHelper::AuthenticateUser(const std::string& username,
-                                        const std::string& object_guid,
-                                        const std::string& password,
-                                        AuthCallback callback) {
-  DCHECK(service_is_available_);
-  DCHECK(!weak_factory_.HasWeakPtrs()) << "Another operation is in progress";
-  authpolicy::AuthenticateUserRequest request;
-  request.set_user_principal_name(username);
-  request.set_account_id(object_guid);
-  AuthPolicyClient::Get()->AuthenticateUser(
-      request, data_pipe_utils::GetDataReadPipe(password).get(),
-      base::BindOnce(&AuthPolicyHelper::OnAuthCallback,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void AuthPolicyHelper::RefreshDevicePolicy(RefreshPolicyCallback callback) {
-  if (service_is_available_) {
-    AuthPolicyClient::Get()->RefreshDevicePolicy(std::move(callback));
-    return;
-  }
-  DCHECK(!device_policy_callback_);
-  device_policy_callback_ = std::move(callback);
-}
-
-void AuthPolicyHelper::RefreshUserPolicy(const AccountId& account_id,
-                                         RefreshPolicyCallback callback) const {
-  DCHECK(service_is_available_);
-  AuthPolicyClient::Get()->RefreshUserPolicy(account_id, std::move(callback));
-}
-
-void AuthPolicyHelper::CancelRequestsAndRestart() {
-  weak_factory_.InvalidateWeakPtrs();
-  dm_token_.clear();
-  AuthPolicyHelper::Restart();
-  service_is_available_ = false;
-  AuthPolicyClient::Get()->WaitForServiceToBeAvailable(base::BindOnce(
-      &AuthPolicyHelper::OnServiceAvailable, weak_factory_.GetWeakPtr()));
-}
-
-void AuthPolicyHelper::OnServiceAvailable(bool service_is_available) {
-  DCHECK(service_is_available);
-  service_is_available_ = true;
-  if (device_policy_callback_) {
-    AuthPolicyClient::Get()->RefreshDevicePolicy(
-        std::move(device_policy_callback_));
-  }
-}
-
-void AuthPolicyHelper::OnJoinCallback(JoinCallback callback,
-                                      authpolicy::ErrorType error,
-                                      const std::string& machine_domain) {
-  DCHECK(!InstallAttributes::Get()->IsActiveDirectoryManaged());
-  if (error != authpolicy::ERROR_NONE) {
-    std::move(callback).Run(error, machine_domain);
-    return;
-  }
-  AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
-      &AuthPolicyHelper::OnFirstPolicyRefreshCallback,
-      weak_factory_.GetWeakPtr(), std::move(callback), machine_domain));
-}
-
-void AuthPolicyHelper::OnFirstPolicyRefreshCallback(
-    JoinCallback callback,
-    const std::string& machine_domain,
-    authpolicy::ErrorType error) {
-  DCHECK(!InstallAttributes::Get()->IsActiveDirectoryManaged());
-  // First policy refresh happens before device is locked. So policy store
-  // should not succeed. The error means that authpolicyd cached device policy
-  // and stores it in the next call to RefreshDevicePolicy in STEP_STORE_POLICY.
-  DCHECK(error != authpolicy::ERROR_NONE);
-  if (error == authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT)
-    error = authpolicy::ERROR_NONE;
-  std::move(callback).Run(error, machine_domain);
-}
-
-void AuthPolicyHelper::OnAuthCallback(
-    AuthCallback callback,
-    authpolicy::ErrorType error,
-    const authpolicy::ActiveDirectoryAccountInfo& account_info) {
-  DCHECK_NE(authpolicy::ERROR_DBUS_FAILURE, error);
-  std::move(callback).Run(error, account_info);
-}
-
-AuthPolicyHelper::~AuthPolicyHelper() = default;
-
-}  // namespace ash
diff --git a/chrome/browser/ash/authpolicy/authpolicy_helper.h b/chrome/browser/ash/authpolicy/authpolicy_helper.h
deleted file mode 100644
index da275b7..0000000
--- a/chrome/browser/ash/authpolicy/authpolicy_helper.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_AUTHPOLICY_AUTHPOLICY_HELPER_H_
-#define CHROME_BROWSER_ASH_AUTHPOLICY_AUTHPOLICY_HELPER_H_
-
-#include <string>
-
-#include "base/functional/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h"
-
-namespace ash {
-
-// Helper class to use AuthPolicyClient. For Active Directory domain join and
-// authenticate users this class should be used instead of AuthPolicyClient.
-// Allows canceling all pending calls and restarting AuthPolicy service. Used
-// for enrollment and login UI to proper cancel the flows.
-class AuthPolicyHelper {
- public:
-  using AuthCallback = AuthPolicyClient::AuthCallback;
-  using JoinCallback = AuthPolicyClient::JoinCallback;
-  using RefreshPolicyCallback = AuthPolicyClient::RefreshPolicyCallback;
-  using OnDecryptedCallback =
-      base::OnceCallback<void(std::string decrypted_data)>;
-
-  AuthPolicyHelper();
-
-  AuthPolicyHelper(const AuthPolicyHelper&) = delete;
-  AuthPolicyHelper& operator=(const AuthPolicyHelper&) = delete;
-
-  ~AuthPolicyHelper();
-
-  // Tries to get Kerberos TGT. To get TGT and password statuses one should use
-  // AuthPolicyClient::GetUserStatus afterwards.
-  static void TryAuthenticateUser(const std::string& username,
-                                  const std::string& object_guid,
-                                  const std::string& password);
-
-  // Restarts AuthPolicy service.
-  static void Restart();
-
-  // Decrypts |blob| with |password| on a separate thread. Calls |callback| on
-  // the orginal thread. If decryption failed |callback| called with an empty
-  // string.
-  static void DecryptConfiguration(const std::string& blob,
-                                   const std::string& password,
-                                   OnDecryptedCallback callback);
-
-  // Packs arguments and calls AuthPolicyClient::JoinAdDomain. Joins machine to
-  // Active directory domain. Then it calls RefreshDevicePolicy to cache the
-  // policy on the authpolicyd side. |machine_name| is a name for a local
-  // machine. If |distinguished_name| is not empty |machine| would be put into
-  // that domain or/and organizational unit structure. Otherwise |machine| would
-  // be joined to domain of the |username|. |username|, |password| are
-  // credentials of the Active directory account which has right to join the
-  // machine to the domain. |callback| is called after getting (or failing to
-  // get) D-BUS response.
-  void JoinAdDomain(const std::string& machine_name,
-                    const std::string& distinguished_name,
-                    int encryption_types,
-                    const std::string& username,
-                    const std::string& password,
-                    JoinCallback callback);
-
-  // Packs arguments and calls AuthPolicyClient::AuthenticateUser. Authenticates
-  // user against Active Directory server. |username|, |password| are
-  // credentials of the Active Directory account. |username| should be in the
-  // user@example.domain.com format. |object_guid| is the user's LDAP GUID. If
-  // specified, it is used instead of |username|. The GUID is guaranteed to be
-  // stable, the user's name can change on the server.
-  void AuthenticateUser(const std::string& username,
-                        const std::string& object_guid,
-                        const std::string& password,
-                        AuthCallback callback);
-
-  // Refreshes device policy. Waits for authpolicy D-Bus service to start if
-  // needed. When Chrome starts it tries to refresh device policy immediately.
-  // If authpolicy daemon being started at the same time - device policy fetch
-  // could fail. Could happen after reboot only on the login screen. So handle
-  // it for device policy only.
-  void RefreshDevicePolicy(RefreshPolicyCallback callback);
-  // Does not wait for authpolicyd D-Bus service. Added for symmetry.
-  void RefreshUserPolicy(const AccountId& account_id,
-                         RefreshPolicyCallback callback) const;
-
-  // Cancels pending requests and restarts AuthPolicy service.
-  void CancelRequestsAndRestart();
-
-  // Sets the DM token. Will be sent to authpolicy with the domain join call.
-  // Authpolicy would set it in the device policy.
-  void set_dm_token(const std::string& dm_token) { dm_token_ = dm_token; }
-
- private:
-  void OnServiceAvailable(bool service_is_available);
-
-  // Called from AuthPolicyClient::JoinAdDomain.
-  void OnJoinCallback(JoinCallback callback,
-                      authpolicy::ErrorType error,
-                      const std::string& machine_domain);
-
-  // Called from AuthPolicyClient::RefreshDevicePolicy. This is used only once
-  // during device enrollment with the first device policy refresh.
-  void OnFirstPolicyRefreshCallback(JoinCallback callback,
-                                    const std::string& machine_domain,
-                                    authpolicy::ErrorType error);
-
-  // Called from AuthPolicyClient::AuthenticateUser.
-  void OnAuthCallback(
-      AuthCallback callback,
-      authpolicy::ErrorType error,
-      const authpolicy::ActiveDirectoryAccountInfo& account_info);
-
-  std::string dm_token_;
-
-  bool service_is_available_ = false;
-  RefreshPolicyCallback device_policy_callback_;
-
-  base::WeakPtrFactory<AuthPolicyHelper> weak_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_AUTHPOLICY_AUTHPOLICY_HELPER_H_
diff --git a/chrome/browser/ash/authpolicy/authpolicy_helper_unittest.cc b/chrome/browser/ash/authpolicy/authpolicy_helper_unittest.cc
deleted file mode 100644
index ffd5c1e..0000000
--- a/chrome/browser/ash/authpolicy/authpolicy_helper_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/authpolicy/authpolicy_helper.h"
-
-#include "base/functional/bind.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
-#include "chromeos/ash/components/dbus/dbus_thread_manager.h"
-#include "chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h"
-#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-namespace {
-
-constexpr char kDMToken[] = "dm_token";
-
-class MockAuthPolicyClient : public FakeAuthPolicyClient {
- public:
-  MockAuthPolicyClient() { SetStarted(true); }
-
-  MockAuthPolicyClient(const MockAuthPolicyClient&) = delete;
-  MockAuthPolicyClient& operator=(const MockAuthPolicyClient&) = delete;
-
-  ~MockAuthPolicyClient() override = default;
-
-  void JoinAdDomain(const authpolicy::JoinDomainRequest& request,
-                    int password_fd,
-                    JoinCallback callback) override {
-    EXPECT_FALSE(join_ad_domain_called_);
-    EXPECT_FALSE(refresh_device_policy_called_);
-    join_ad_domain_called_ = true;
-    dm_token_ = request.dm_token();
-    std::move(callback).Run(authpolicy::ERROR_NONE, std::string());
-  }
-
-  void RefreshDevicePolicy(RefreshPolicyCallback callback) override {
-    EXPECT_TRUE(join_ad_domain_called_);
-    EXPECT_FALSE(refresh_device_policy_called_);
-    refresh_device_policy_called_ = true;
-    std::move(callback).Run(
-        authpolicy::ERROR_DEVICE_POLICY_CACHED_BUT_NOT_SENT);
-  }
-
-  void CheckExpectations() {
-    EXPECT_TRUE(join_ad_domain_called_);
-    EXPECT_TRUE(refresh_device_policy_called_);
-    EXPECT_EQ(dm_token_, kDMToken);
-  }
-
- private:
-  bool join_ad_domain_called_ = false;
-  bool refresh_device_policy_called_ = false;
-  std::string dm_token_;
-};
-
-}  // namespace
-
-// Check that helper calls RefreshDevicePolicy after JoinAdDomain.
-TEST(AuthPolicyHelper, JoinFollowedByRefreshDevicePolicy) {
-  ScopedStubInstallAttributes scoped_stub_install_attributes;
-
-  auto* mock_client = new MockAuthPolicyClient;
-  InstallAttributesClient::InitializeFake();
-
-  AuthPolicyHelper helper;
-  helper.set_dm_token(kDMToken);
-  helper.JoinAdDomain(std::string(), std::string(),
-                      authpolicy::KerberosEncryptionTypes(), std::string(),
-                      std::string(),
-                      base::BindOnce([](authpolicy::ErrorType error,
-                                        const std::string& domain) {
-                        EXPECT_EQ(authpolicy::ERROR_NONE, error);
-                        EXPECT_TRUE(domain.empty());
-                      }));
-  mock_client->CheckExpectations();
-
-  InstallAttributesClient::Shutdown();
-  AuthPolicyClient::Shutdown();
-}
-
-}  // namespace ash
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index 7b1a851..07b0749 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -295,8 +295,9 @@
 
 // Creates an instance of the NetworkPortalDetector implementation or a stub.
 void InitializeNetworkPortalDetector() {
-  if (network_portal_detector::SetForTesting())
+  if (network_portal_detector::SetForTesting()) {
     return;
+  }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           ::switches::kTestType)) {
     network_portal_detector::SetNetworkPortalDetector(
@@ -868,8 +869,9 @@
     g_browser_process->metrics_service()->InitPerUserMetrics();
   }
 
-  if (base::FeatureList::IsEnabled(::features::kWilcoDtc))
+  if (base::FeatureList::IsEnabled(::features::kWilcoDtc)) {
     wilco_dtc_supportd_manager_ = std::make_unique<WilcoDtcSupportdManager>();
+  }
 
   ScreenLocker::InitClass();
 
@@ -1115,8 +1117,9 @@
   // The previous one must be "locale default layout".
   // First, enable all hardware input methods.
   input_methods = manager->GetInputMethodUtil()->GetHardwareInputMethodIds();
-  for (size_t i = 0; i < input_methods.size(); ++i)
+  for (size_t i = 0; i < input_methods.size(); ++i) {
     ime_state->EnableInputMethod(input_methods[i]);
+  }
 
   // Second, enable locale based input methods.
   const std::string locale_default_input_method =
@@ -1233,8 +1236,9 @@
 
     // Guest user profile is never initialized with locale settings,
     // so we need special handling for Guest session.
-    if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
+    if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
       SetGuestLocale(profile);
+    }
 
     renderer_freezer_ = std::make_unique<RendererFreezer>(
         std::make_unique<FreezerCgroupProcessManager>());
@@ -1317,8 +1321,9 @@
       accessibility_event_rewriter_delegate_.get());
 
   // Enable the KeyboardDrivenEventRewriter if the OEM manifest flag is on.
-  if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation())
+  if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
     event_rewriter_controller->SetKeyboardDrivenEventRewriterEnabled(true);
+  }
 
   // Add MagnificationManager as a pretarget handler after `Shell` is
   // initialized.
@@ -1437,20 +1442,23 @@
 
   BootTimesRecorder::Get()->AddLogoutTimeMarker("UIMessageLoopEnded", true);
 
-  if (base::FeatureList::IsEnabled(features::kEnableHostnameSetting))
+  if (base::FeatureList::IsEnabled(features::kEnableHostnameSetting)) {
     DeviceNameStore::Shutdown();
+  }
 
   // This needs to be called before the
   // ChromeBrowserMainPartsLinux::PostMainMessageLoopRun, because the
   // SessionControllerClientImpl is destroyed there.
   browser_manager_->RemoveObserver(SessionControllerClientImpl::Get());
 
-  if (lock_screen_apps_state_controller_)
+  if (lock_screen_apps_state_controller_) {
     lock_screen_apps_state_controller_->Shutdown();
+  }
 
   // This must be shut down before |arc_service_launcher_|.
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     NoteTakingHelper::Shutdown();
+  }
 
   arc_service_launcher_->Shutdown();
 
@@ -1460,15 +1468,17 @@
 
   assistant_state_client_.reset();
 
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     Shell::Get()->RemovePreTargetHandler(MagnificationManager::Get());
+  }
 
   // Unregister CrosSettings observers before CrosSettings is destroyed.
   shutdown_policy_forwarder_.reset();
 
   // Destroy the application name notifier for Kiosk mode.
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     KioskModeIdleAppNameNotification::Shutdown();
+  }
 
   // Tell DeviceSettingsService to stop talking to session_manager. Do not
   // shutdown DeviceSettingsService yet, it might still be accessed by
@@ -1486,8 +1496,9 @@
   renderer_freezer_.reset();
   fast_transition_observer_.reset();
   network_throttling_observer_.reset();
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     ScreenLocker::ShutDownClass();
+  }
   low_disk_notification_.reset();
   demo_mode_resources_remover_.reset();
   smart_charging_manager_.reset();
@@ -1500,16 +1511,19 @@
   login_screen_extensions_storage_cleaner_.reset();
   debugd_notification_handler_.reset();
   shortcut_mapping_pref_service_.reset();
-  if (features::IsTrafficCountersEnabled())
+  if (features::IsTrafficCountersEnabled()) {
     traffic_counters_handler_.reset();
+  }
   bluetooth_pref_state_observer_.reset();
   auth_events_recorder_.reset();
 
   // Detach D-Bus clients before DBusThreadManager is shut down.
   idle_action_warning_observer_.reset();
 
-  if (chromeos::login_screen_extension_ui::UiHandler::Get(false /*can_create*/))
+  if (chromeos::login_screen_extension_ui::UiHandler::Get(
+          false /*can_create*/)) {
     chromeos::login_screen_extension_ui::UiHandler::Shutdown();
+  }
 
   if (pre_profile_init_called_) {
     MagnificationManager::Shutdown();
@@ -1522,8 +1536,9 @@
   // Inform |NetworkCertLoader| that it should not notify observers anymore.
   // TODO(https://crbug.com/894867): Remove this when the root cause of the
   // crash is found.
-  if (NetworkCertLoader::IsInitialized())
+  if (NetworkCertLoader::IsInitialized()) {
     NetworkCertLoader::Get()->set_is_shutting_down();
+  }
 
   // Tear down BulkPrintersCalculators while we still have threads.
   bulk_printers_calculator_factory_.reset();
@@ -1534,8 +1549,9 @@
   // Let the UserManager unregister itself as an observer of the CrosSettings
   // singleton before it is destroyed. This also ensures that the UserManager
   // has no URLRequest pending (see http://crbug.com/276659).
-  if (g_browser_process->platform_part()->user_manager())
+  if (g_browser_process->platform_part()->user_manager()) {
     g_browser_process->platform_part()->user_manager()->Shutdown();
+  }
 
   // Let the DeviceDisablingManager unregister itself as an observer of the
   // CrosSettings singleton before it is destroyed.
@@ -1549,8 +1565,9 @@
   kiosk_app_manager_.reset();
 
   // Make sure that there is no pending URLRequests.
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     UserSessionManager::GetInstance()->Shutdown();
+  }
 
   // Give BrowserPolicyConnectorAsh a chance to unregister any observers
   // on services that are going to be deleted later but before its Shutdown()
@@ -1561,8 +1578,9 @@
 
   // Shutdown the virtual keyboard UI before destroying `Shell` or the primary
   // profile.
-  if (chrome_keyboard_controller_client_)
+  if (chrome_keyboard_controller_client_) {
     chrome_keyboard_controller_client_->Shutdown();
+  }
 
   // Must occur before BrowserProcessImpl::StartTearDown() destroys the
   // ProfileManager.
@@ -1647,8 +1665,9 @@
   // Called after ChromeBrowserMainPartsLinux::PostMainMessageLoopRun() (which
   // calls chrome::CloseAsh()) because some parts of WebUI depend on
   // NetworkPortalDetector.
-  if (pre_profile_init_called_)
+  if (pre_profile_init_called_) {
     network_portal_detector::Shutdown();
+  }
 
   g_browser_process->platform_part()->ShutdownSessionManager();
   // Ash needs to be closed before UserManager is destroyed.
@@ -1693,8 +1712,9 @@
 void ChromeBrowserMainPartsAsh::StartDeviceActivityController() {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Terminate immediately if feature is turned off.
-  if (!base::FeatureList::IsEnabled(features::kDeviceActiveClient))
+  if (!base::FeatureList::IsEnabled(features::kDeviceActiveClient)) {
     return;
+  }
 
   CrosSettingsProvider::TrustedStatus status =
       CrosSettings::Get()->PrepareTrustedValues(base::BindOnce(
diff --git a/chrome/browser/ash/crosapi/ash_requires_lacros_browsertestbase.cc b/chrome/browser/ash/crosapi/ash_requires_lacros_browsertestbase.cc
index a8139ef..7805da8 100644
--- a/chrome/browser/ash/crosapi/ash_requires_lacros_browsertestbase.cc
+++ b/chrome/browser/ash/crosapi/ash_requires_lacros_browsertestbase.cc
@@ -7,7 +7,7 @@
 #include "ash/constants/ash_features.h"
 #include "base/location.h"
 #include "base/one_shot_event.h"
-#include "base/run_loop.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/common/chrome_features.h"
@@ -40,10 +40,10 @@
 
   ash_starter_.StartLacros(this);
 
-  base::RunLoop run_loop;
+  base::test::TestFuture<void> waiter;
   test_controller_ash_->on_standalone_browser_test_controller_bound().Post(
-      FROM_HERE, run_loop.QuitClosure());
-  run_loop.Run();
+      FROM_HERE, waiter.GetCallback());
+  EXPECT_TRUE(waiter.Wait());
 }
 
 mojom::StandaloneBrowserTestController*
diff --git a/chrome/browser/ash/crosapi/ash_requires_lacros_extension_apitest.cc b/chrome/browser/ash/crosapi/ash_requires_lacros_extension_apitest.cc
index 9e8c4f6..84f0528 100644
--- a/chrome/browser/ash/crosapi/ash_requires_lacros_extension_apitest.cc
+++ b/chrome/browser/ash/crosapi/ash_requires_lacros_extension_apitest.cc
@@ -7,7 +7,7 @@
 #include "ash/constants/ash_features.h"
 #include "base/location.h"
 #include "base/one_shot_event.h"
-#include "base/run_loop.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -44,10 +44,10 @@
   ash_starter_.StartLacros(this);
 
   // Wait until StandaloneBrowserTestController binds with test_controller_ash_.
-  base::RunLoop run_loop;
+  base::test::TestFuture<void> waiter;
   test_controller_ash_->on_standalone_browser_test_controller_bound().Post(
-      FROM_HERE, run_loop.QuitClosure());
-  run_loop.Run();
+      FROM_HERE, waiter.GetCallback());
+  EXPECT_TRUE(waiter.Wait());
 }
 
 mojom::StandaloneBrowserTestController*
diff --git a/chrome/browser/ash/crosapi/audio_service_ash_unittest.cc b/chrome/browser/ash/crosapi/audio_service_ash_unittest.cc
index 98161ccb..264f18e 100644
--- a/chrome/browser/ash/crosapi/audio_service_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/audio_service_ash_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/crosapi/audio_service_ash.h"
 
+#include "base/test/test_future.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/ash/components/audio/cras_audio_handler.h"
 #include "content/public/test/browser_task_environment.h"
@@ -49,15 +50,15 @@
   MOCK_METHOD(void, OnLevelChangedMock, (const std::string& id, int32_t level));
   MOCK_METHOD(void, OnMuteChangedMock, (bool is_input, bool is_muted));
 
-  void Wait() { run_loop_.Run(); }
+  void Wait() { EXPECT_TRUE(waiter.Wait()); }
 
   auto GetRemote() { return receiver_.BindNewPipeAndPassRemote(); }
 
-  void Quit() { run_loop_.Quit(); }
+  void Quit() { waiter.SetValue(); }
 
  private:
   mojo::Receiver<crosapi::mojom::AudioChangeObserver> receiver_{this};
-  base::RunLoop run_loop_;
+  base::test::TestFuture<void> waiter;
 };
 
 class AudioServiceAshTest : public ::testing::Test {
diff --git a/chrome/browser/ash/crosapi/browser_data_back_migrator_browsertest.cc b/chrome/browser/ash/crosapi/browser_data_back_migrator_browsertest.cc
index b23d014..0f40ffc6 100644
--- a/chrome/browser/ash/crosapi/browser_data_back_migrator_browsertest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_back_migrator_browsertest.cc
@@ -6,8 +6,8 @@
 
 #include "ash/constants/ash_features.h"
 #include "base/files/file_util.h"
-#include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
@@ -105,12 +105,12 @@
 IN_PROC_BROWSER_TEST_F(BrowserDataBackMigratorOnSignIn, BackMigrateOnSignIn) {
   CreateLacrosDirectoryForProfile(regular_user_.account_id);
 
-  base::RunLoop run_loop;
+  base::test::TestFuture<void> waiter;
   ScopedBackMigratorRestartAttemptForTesting
       scoped_back_migrator_restart_attempt(
-          base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
+          base::BindLambdaForTesting([&]() { waiter.SetValue(); }));
   ASSERT_TRUE(Login());
-  run_loop.Run();
+  EXPECT_TRUE(waiter.Wait());
   EXPECT_TRUE(FakeSessionManagerClient::Get()
                   ->request_browser_data_backward_migration_called());
 }
@@ -161,13 +161,13 @@
   CHECK(KioskAppManager::Get()->GetApp(test_app_id(), &app));
   CreateLacrosDirectoryForProfile(app.account_id);
 
-  base::RunLoop run_loop;
+  base::test::TestFuture<void> waiter;
   ScopedBackMigratorRestartAttemptForTesting
       scoped_back_migrator_restart_attempt(
-          base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
+          base::BindLambdaForTesting([&]() { waiter.SetValue(); }));
   StartAppLaunchFromLoginScreen(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
-  run_loop.Run();
+  EXPECT_TRUE(waiter.Wait());
   EXPECT_TRUE(FakeSessionManagerClient::Get()
                   ->request_browser_data_backward_migration_called());
 }
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index 3ff1252..97a80904 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -80,6 +80,7 @@
 #include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "chromeos/crosapi/cpp/lacros_startup_state.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom-shared.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/startup/startup_switches.h"
 #include "components/crash/core/app/crashpad.h"
 #include "components/nacl/common/buildflags.h"
@@ -96,6 +97,7 @@
 #include "components/user_manager/user_type.h"
 #include "components/version_info/version_info.h"
 #include "content/public/common/content_switches.h"
+#include "media/base/media_switches.h"
 #include "media/capture/capture_switches.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
@@ -968,13 +970,14 @@
                      is_initial_lacros_launch_after_reboot_,
                      launching_at_login_screen),
       base::BindOnce(&BrowserManager::StartWithLogFile,
-                     weak_factory_.GetWeakPtr()));
+                     weak_factory_.GetWeakPtr(), launching_at_login_screen));
 
   // Set false to prepare for the next Lacros launch.
   is_initial_lacros_launch_after_reboot_ = false;
 }
 
-void BrowserManager::StartWithLogFile(LaunchParamsFromBackground params) {
+void BrowserManager::StartWithLogFile(bool launching_at_login_screen,
+                                      LaunchParamsFromBackground params) {
   DCHECK_EQ(state_, State::CREATING_LOG_FILE);
 
   // Shutdown() might have been called after Start() posted the StartWithLogFile
@@ -1072,6 +1075,16 @@
     argv.push_back("--use-cras");
   }
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kSystemDevMode)) {
+    argv.push_back("--system-developer-mode");
+  }
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAllowRAInDevMode)) {
+    argv.push_back("--allow-ra-in-dev-mode");
+  }
+
 #if BUILDFLAG(ENABLE_NACL)
   // This switch is forwarded to nacl_helper and is needed before zygote fork.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -1119,7 +1132,7 @@
     argv.push_back(
         "--vmodule=command_storage_backend=1,session_service_commands=1");
 
-    if (launch_at_login_screen_ &&
+    if (launching_at_login_screen &&
         !command_line->HasSwitch(switches::kDisableLoggingRedirect)) {
       // Redirect logs to cryptohome after login on non-test images.
       argv.push_back(base::StringPrintf(
@@ -1139,16 +1152,12 @@
   // startup if we're not launching at login screen.
   // Vice versa, if we're launching at login screen, we want to split
   // the parameters in pre-login and post-login.
-  bool pass_post_login_params =
-      launch_at_login_screen_ &&
-      !user_manager::UserManager::Get()->IsUserLoggedIn();
-
   base::ScopedFD startup_fd = browser_util::CreateStartupData(
       environment_provider_.get(),
       browser_util::InitialBrowserAction(
           mojom::InitialBrowserAction::kDoNotOpenWindow),
       !keep_alive_features_.empty(), lacros_selection_,
-      !pass_post_login_params);
+      !launching_at_login_screen);
   if (startup_fd.is_valid()) {
     // Hardcoded to use FD 3 to make the ash-chrome's behavior more predictable.
     // Lacros-chrome should not depend on the hardcoded value though. Instead
@@ -1162,7 +1171,7 @@
   // If at login screen, open an anonymous pipe to pass post-login parameters to
   // Lacros later on.
   base::ScopedFD read_pipe_fd;
-  if (pass_post_login_params) {
+  if (launching_at_login_screen) {
     bool success = base::CreatePipe(&read_pipe_fd, &postlogin_pipe_fd_);
     DCHECK(success);
 
@@ -1222,7 +1231,7 @@
     SetState(State::UNAVAILABLE);
     return;
   }
-  SetState(pass_post_login_params ? State::PRE_LAUNCHED : State::STARTING);
+  SetState(launching_at_login_screen ? State::PRE_LAUNCHED : State::STARTING);
   LOG(WARNING) << "Launched lacros-chrome with pid " << lacros_process_.Pid();
   channel.RemoteProcessLaunchAttempted();
 }
@@ -1381,7 +1390,7 @@
     return;
   }
 
-  if (launch_at_login_screen_ && postlogin_pipe_fd_.is_valid()) {
+  if (state_ == State::PRE_LAUNCHED) {
     // Resume Lacros launch after login, if it was pre-launched.
     ResumeLaunch();
   } else {
diff --git a/chrome/browser/ash/crosapi/browser_manager.h b/chrome/browser/ash/crosapi/browser_manager.h
index e7e6a0c..a378257 100644
--- a/chrome/browser/ash/crosapi/browser_manager.h
+++ b/chrome/browser/ash/crosapi/browser_manager.h
@@ -569,7 +569,8 @@
 
   // Starts the lacros-chrome process and redirects stdout/err to file pointed
   // by |params.logfd|.
-  void StartWithLogFile(LaunchParamsFromBackground params);
+  void StartWithLogFile(bool launching_at_login_screen,
+                        LaunchParamsFromBackground params);
 
   // ash::SessionManagerClient::Observer:
   void EmitLoginPromptVisibleCalled() override;
diff --git a/chrome/browser/ash/crosapi/device_oauth2_token_service_ash_unittest.cc b/chrome/browser/ash/crosapi/device_oauth2_token_service_ash_unittest.cc
index 5e81ecd..2b7b5ce 100644
--- a/chrome/browser/ash/crosapi/device_oauth2_token_service_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/device_oauth2_token_service_ash_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/crosapi/device_oauth2_token_service_ash.h"
 
 #include "base/test/mock_callback.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
@@ -49,20 +50,17 @@
 };
 
 TEST_F(DeviceOAuth2TokenServiceAshTest, SingleRequest) {
-  base::RunLoop run_loop;
+  base::test::TestFuture<crosapi::mojom::AccessTokenResultPtr> waiter;
   std::unique_ptr<crosapi::DeviceOAuth2TokenServiceAsh> service =
       std::make_unique<crosapi::DeviceOAuth2TokenServiceAsh>();
-  base::MockCallback<FetchAccessTokenForDeviceAccountCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_)).WillOnce(testing::Invoke([&run_loop] {
-    run_loop.Quit();
-  }));
-  service->FetchAccessTokenForDeviceAccount(/*scopes=*/{}, callback.Get());
-  run_loop.Run();
+
+  service->FetchAccessTokenForDeviceAccount(/*scopes=*/{},
+                                            waiter.GetCallback());
+  EXPECT_TRUE(waiter.Wait());
 }
 
 // Tests that passing an empty callback does not crash.
 TEST_F(DeviceOAuth2TokenServiceAshTest, EmptyCallback) {
-  base::RunLoop run_loop;
   std::unique_ptr<crosapi::DeviceOAuth2TokenServiceAsh> service =
       std::make_unique<crosapi::DeviceOAuth2TokenServiceAsh>();
   service->FetchAccessTokenForDeviceAccount(
@@ -72,24 +70,15 @@
 
 TEST_F(DeviceOAuth2TokenServiceAshTest, MultipleRequests) {
   constexpr int kRequestCount = 4;
-  base::RunLoop run_loop;
   std::unique_ptr<crosapi::DeviceOAuth2TokenServiceAsh> service =
       std::make_unique<crosapi::DeviceOAuth2TokenServiceAsh>();
-  std::array<base::MockCallback<FetchAccessTokenForDeviceAccountCallback>,
-             kRequestCount>
-      callbacks;
-  int call_count = 0;
-  for (auto& callback : callbacks) {
-    EXPECT_CALL(callback, Run(testing::_))
-        .WillOnce(testing::Invoke([&run_loop, &call_count] {
-          if (++call_count == kRequestCount)
-            run_loop.Quit();
-        }));
+
+  for (int call_count = 0; call_count < kRequestCount; call_count++) {
+    base::test::TestFuture<crosapi::mojom::AccessTokenResultPtr> waiter;
+    service->FetchAccessTokenForDeviceAccount(/*scopes=*/{},
+                                              waiter.GetCallback());
+    EXPECT_TRUE(waiter.Wait());
   }
-  for (auto& callback : callbacks)
-    service->FetchAccessTokenForDeviceAccount(/*scopes=*/{}, callback.Get());
-  run_loop.Run();
-  EXPECT_EQ(call_count, kRequestCount);
 }
 
 TEST_F(DeviceOAuth2TokenServiceAshTest, Cancel) {
diff --git a/chrome/browser/ash/crosapi/device_settings_ash_unittest.cc b/chrome/browser/ash/crosapi/device_settings_ash_unittest.cc
index 0c7d498..e99bcc8 100644
--- a/chrome/browser/ash/crosapi/device_settings_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/device_settings_ash_unittest.cc
@@ -42,10 +42,10 @@
     session_manager_client_.set_device_policy(device_policy_.GetBlob());
 
     auto* const device_settings_service = ::ash::DeviceSettingsService::Get();
-    base::RunLoop run_loop;
+    base::test::TestFuture<void> waiter;
     device_settings_service->Store(device_policy_.GetCopy(),
-                                   run_loop.QuitClosure());
-    run_loop.Run();
+                                   waiter.GetCallback());
+    EXPECT_TRUE(waiter.Wait());
     ASSERT_EQ(device_settings_service->status(),
               ::ash::DeviceSettingsService::STORE_SUCCESS);
   }
diff --git a/chrome/browser/ash/crosapi/extension_info_private_ash.cc b/chrome/browser/ash/crosapi/extension_info_private_ash.cc
index 0675219a..988386f4 100644
--- a/chrome/browser/ash/crosapi/extension_info_private_ash.cc
+++ b/chrome/browser/ash/crosapi/extension_info_private_ash.cc
@@ -245,10 +245,10 @@
 }
 
 const char* GetBoolPrefNameForApiProperty(const char* api_name) {
-  for (size_t i = 0; i < (sizeof(kPreferencesMap) / sizeof(*kPreferencesMap));
-       i++) {
-    if (strcmp(kPreferencesMap[i].api_name, api_name) == 0)
-      return kPreferencesMap[i].preference_name;
+  for (const auto& item : kPreferencesMap) {
+    if (strcmp(item.api_name, api_name) == 0) {
+      return item.preference_name;
+    }
   }
 
   return nullptr;
@@ -417,16 +417,17 @@
 void ExtensionInfoPrivateAsh::GetSystemProperties(
     const std::vector<std::string>& property_names,
     GetSystemPropertiesCallback callback) {
-  base::Value result(base::Value::Type::DICT);
+  base::Value::Dict result;
   for (const std::string& property_name : property_names) {
     std::unique_ptr<base::Value> value = GetValue(property_name);
     if (value) {
-      result.SetKey(property_name,
-                    base::Value::FromUniquePtrValue(std::move(value)));
+      result.Set(property_name,
+                 base::Value::FromUniquePtrValue(std::move(value)));
     }
   }
   base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
+      FROM_HERE,
+      base::BindOnce(std::move(callback), base::Value(std::move(result))));
 }
 
 void ExtensionInfoPrivateAsh::SetTimezone(const std::string& value) {
diff --git a/chrome/browser/ash/crosapi/media_ui_ash.cc b/chrome/browser/ash/crosapi/media_ui_ash.cc
index 30388ca..12945b8 100644
--- a/chrome/browser/ash/crosapi/media_ui_ash.cc
+++ b/chrome/browser/ash/crosapi/media_ui_ash.cc
@@ -30,6 +30,9 @@
       std::move(pending_device_service)};
   device_service.set_disconnect_handler(base::BindOnce(
       &MediaUIAsh::RemoveDeviceService, base::Unretained(this), id));
+  for (Observer& observer : observers_) {
+    observer.OnDeviceServiceRegistered(device_service.get());
+  }
   device_services_.emplace(id, std::move(device_service));
 }
 
@@ -46,6 +49,14 @@
                                               : service_it->second.get();
 }
 
+void MediaUIAsh::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MediaUIAsh::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void MediaUIAsh::RemoveDeviceService(const base::UnguessableToken& id) {
   device_services_.erase(id);
 }
diff --git a/chrome/browser/ash/crosapi/media_ui_ash.h b/chrome/browser/ash/crosapi/media_ui_ash.h
index 90bc0d7f..b754663 100644
--- a/chrome/browser/ash/crosapi/media_ui_ash.h
+++ b/chrome/browser/ash/crosapi/media_ui_ash.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_ASH_CROSAPI_MEDIA_UI_ASH_H_
 #define CHROME_BROWSER_ASH_CROSAPI_MEDIA_UI_ASH_H_
 
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/unguessable_token.h"
 #include "chromeos/crosapi/mojom/media_ui.mojom.h"
 #include "components/global_media_controls/public/mojom/device_service.mojom.h"
@@ -16,6 +18,14 @@
 
 class MediaUIAsh : public mojom::MediaUI {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // The pointer to `device_service` may be invalidated after this call exits,
+    // so it should not be stored.
+    virtual void OnDeviceServiceRegistered(
+        global_media_controls::mojom::DeviceService* device_service) = 0;
+  };
+
   MediaUIAsh();
   MediaUIAsh(const MediaUIAsh&) = delete;
   MediaUIAsh& operator=(const MediaUIAsh&) = delete;
@@ -33,6 +43,14 @@
   // Returns the DeviceService associated with `id`, if it exists.
   global_media_controls::mojom::DeviceService* GetDeviceService(
       const base::UnguessableToken& id);
+  const std::map<base::UnguessableToken,
+                 mojo::Remote<global_media_controls::mojom::DeviceService>>&
+  device_services() const {
+    return device_services_;
+  }
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
 
  private:
   void RemoveDeviceService(const base::UnguessableToken& id);
@@ -41,6 +59,7 @@
   std::map<base::UnguessableToken,
            mojo::Remote<global_media_controls::mojom::DeviceService>>
       device_services_;
+  base::ObserverList<Observer> observers_;
 };
 
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/media_ui_ash_browsertest.cc b/chrome/browser/ash/crosapi/media_ui_ash_browsertest.cc
index 054b5e12..cb6071d0 100644
--- a/chrome/browser/ash/crosapi/media_ui_ash_browsertest.cc
+++ b/chrome/browser/ash/crosapi/media_ui_ash_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/crosapi/mojom/media_ui.mojom.h"
 #include "components/global_media_controls/public/mojom/device_service.mojom-forward.h"
+#include "components/global_media_controls/public/test/mock_device_service.h"
 #include "content/public/test/browser_test.h"
 
 using testing::_;
@@ -32,31 +33,11 @@
               (std::vector<global_media_controls::mojom::DevicePtr> devices));
 };
 
-class MockDeviceService : public ::mojom::DeviceService {
+class MockObserver : public MediaUIAsh::Observer {
  public:
-  mojo::PendingRemote<::mojom::DeviceService> TakeRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void ResetReceiver() { receiver_.reset(); }
-
   MOCK_METHOD(void,
-              GetDeviceListHostForSession,
-              (const std::string& session_id,
-               mojo::PendingReceiver<::mojom::DeviceListHost> host_receiver,
-               mojo::PendingRemote<::mojom::DeviceListClient> client_remote));
-  MOCK_METHOD(void,
-              GetDeviceListHostForPresentation,
-              (mojo::PendingReceiver<::mojom::DeviceListHost> host_receiver,
-               mojo::PendingRemote<::mojom::DeviceListClient> client_remote));
-
-  MOCK_METHOD(
-      void,
-      SetDevicePickerProvider,
-      (mojo::PendingRemote<::mojom::DevicePickerProvider> provider_remote));
-
- private:
-  mojo::Receiver<::mojom::DeviceService> receiver_{this};
+              OnDeviceServiceRegistered,
+              (global_media_controls::mojom::DeviceService * device_service));
 };
 
 }  // namespace
@@ -71,7 +52,7 @@
   // Returns the ID of the registered DeviceService.
   base::UnguessableToken RegisterDeviceService() {
     auto id = base::UnguessableToken::Create();
-    media_ui_remote_->RegisterDeviceService(id, device_service_.TakeRemote());
+    media_ui_remote_->RegisterDeviceService(id, device_service_.PassRemote());
     media_ui_remote_.FlushForTesting();
     return id;
   }
@@ -82,7 +63,7 @@
 
  protected:
   mojo::Remote<mojom::MediaUI> media_ui_remote_;
-  MockDeviceService device_service_;
+  global_media_controls::test::MockDeviceService device_service_;
   mojo::Remote<::mojom::DeviceListHost> device_list_host_remote_;
   MockDeviceListClient device_list_client_;
   mojo::Receiver<::mojom::DeviceListClient> device_list_client_receiver_{
@@ -120,4 +101,14 @@
   EXPECT_EQ(nullptr, device_service_ptr);
 }
 
+IN_PROC_BROWSER_TEST_F(MediaUIAshBrowserTest, AddObserver) {
+  MockObserver observer;
+  media_ui_ash()->AddObserver(&observer);
+  EXPECT_CALL(observer, OnDeviceServiceRegistered);
+  RegisterDeviceService();
+
+  testing::Mock::VerifyAndClearExpectations(&observer);
+  media_ui_ash()->RemoveObserver(&observer);
+}
+
 }  // namespace crosapi
diff --git a/chrome/browser/ash/dbus/ash_dbus_helper.cc b/chrome/browser/ash/dbus/ash_dbus_helper.cc
index 6d72bfa..a14029d7 100644
--- a/chrome/browser/ash/dbus/ash_dbus_helper.cc
+++ b/chrome/browser/ash/dbus/ash_dbus_helper.cc
@@ -66,6 +66,7 @@
 #include "chromeos/ash/components/dbus/shill/shill_clients.h"
 #include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
 #include "chromeos/ash/components/dbus/spaced/spaced_client.h"
+#include "chromeos/ash/components/dbus/swap_management/swap_management_client.h"
 #include "chromeos/ash/components/dbus/system_clock/system_clock_client.h"
 #include "chromeos/ash/components/dbus/system_proxy/system_proxy_client.h"
 #include "chromeos/ash/components/dbus/typecd/typecd_client.h"
@@ -188,6 +189,7 @@
   InitializeDBusClient<SessionManagerClient>(bus);
   InitializeDBusClient<SmbProviderClient>(bus);
   InitializeDBusClient<SpacedClient>(bus);
+  InitializeDBusClient<SwapManagementClient>(bus);
   InitializeDBusClient<SystemClockClient>(bus);
   InitializeDBusClient<SystemProxyClient>(bus);
   InitializeDBusClient<chromeos::TpmManagerClient>(bus);
@@ -277,6 +279,7 @@
   chromeos::TpmManagerClient::Shutdown();
   SystemProxyClient::Shutdown();
   SystemClockClient::Shutdown();
+  SwapManagementClient::Shutdown();
   SpacedClient::Shutdown();
   SmbProviderClient::Shutdown();
   SessionManagerClient::Shutdown();
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc b/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
index 0ecafcc..2a305d8 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
@@ -62,7 +62,10 @@
 #include "chrome/browser/ash/fileapi/file_system_backend.h"
 #include "chrome/browser/ash/fileapi/recent_disk_source.h"
 #include "chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h"
+#include "chrome/browser/ash/policy/dlp/files_policy_notification_manager.h"
+#include "chrome/browser/ash/policy/dlp/files_policy_notification_manager_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
@@ -276,6 +279,20 @@
   return {};
 }
 
+policy::FilesDialogType ApiPolicyDialogTypeToChromeEnum(
+    api::file_manager_private::PolicyDialogType type) {
+  switch (type) {
+    case api::file_manager_private::POLICY_DIALOG_TYPE_NONE:
+      return policy::FilesDialogType::kUnknown;
+    case api::file_manager_private::POLICY_DIALOG_TYPE_WARNING:
+      return policy::FilesDialogType::kWarning;
+    case api::file_manager_private::POLICY_DIALOG_TYPE_ERROR:
+      return policy::FilesDialogType::kError;
+  }
+  NOTREACHED() << "Unknown policy dialog type " << type;
+  return policy::FilesDialogType::kUnknown;
+}
+
 }  // namespace
 
 ExtensionFunction::ResponseAction
@@ -1701,7 +1718,22 @@
     return RespondNow(Error("Invalid task id"));
   }
 
-  // TODO(b/279436140): Call FilesPolicyNotificationManager.
+  policy::FilesDialogType type = ApiPolicyDialogTypeToChromeEnum(params->type);
+  if (type == policy::FilesDialogType::kUnknown) {
+    return RespondNow(Error("No dialog type passed for task_id *",
+                            base::NumberToString(params->task_id)));
+  }
+
+  policy::FilesPolicyNotificationManager* manager =
+      policy::FilesPolicyNotificationManagerFactory::GetForBrowserContext(
+          browser_context());
+  if (!manager) {
+    LOG(ERROR) << "No FilesPolicyNotificationManager instantiated,"
+                  "can't show policy dialog for task_id "
+               << params->task_id;
+    Respond(NoArguments());
+  }
+  manager->ShowDialog(params->task_id, type);
 
   return RespondNow(NoArguments());
 }
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc b/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
index e1cacb1d..be6ab6fa 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
@@ -23,6 +23,9 @@
 #include "chrome/browser/ash/file_manager/io_task.h"
 #include "chrome/browser/ash/file_manager/io_task_controller.h"
 #include "chrome/browser/ash/file_manager/path_util.h"
+#include "chrome/browser/ash/policy/dlp/files_policy_notification_manager.h"
+#include "chrome/browser/ash/policy/dlp/files_policy_notification_manager_factory.h"
+#include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
@@ -172,7 +175,7 @@
 // TODO(b/279435843): Replace with translation strings.
 std::u16string GetPolicyNotificationCancelButton(const ProgressStatus& status) {
   if (status.HasWarning()) {
-    return u"Cancel";
+    return l10n_util::GetStringUTF16(IDS_FILE_BROWSER_CANCEL_LABEL);
   } else {
     return u"Dismiss";
   }
@@ -358,13 +361,12 @@
   std::vector<message_center::ButtonInfo> notification_buttons;
 
   // Add "Cancel" button.
-  notification_buttons.emplace_back(message_center::ButtonInfo(
-      l10n_util::GetStringUTF16(IDS_FILE_BROWSER_CANCEL_LABEL)));
+  notification_buttons.emplace_back(
+      l10n_util::GetStringUTF16(IDS_FILE_BROWSER_CANCEL_LABEL));
 
   if (paused) {  // For paused tasks, add "Open Files app" button.
-    notification_buttons.emplace_back(
-        message_center::ButtonInfo(l10n_util::GetStringUTF16(
-            IDS_REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL)));
+    notification_buttons.emplace_back(l10n_util::GetStringUTF16(
+        IDS_REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL));
   }
 
   notification->set_buttons(notification_buttons);
@@ -736,11 +738,20 @@
   // notification.
   if (status.HasWarning() || status.HasPolicyError()) {
     Dismiss(id);
-    // TODO(aidazolic): Pass a real continue callback.
     std::unique_ptr<message_center::Notification> notification =
-        MakeDataProtectionPolicyNotification(
-            id, status,
-            /*continue_callback=*/base::DoNothing());
+        MakeDataProtectionPolicyNotification(id, status);
+    GetNotificationDisplayService()->Display(
+        NotificationHandler::Type::TRANSIENT, *notification,
+        /*metadata=*/nullptr);
+    return;
+  }
+
+  // If the task is currently in the scanning state, show a data protection
+  // progress notification.
+  if (status.IsScanning()) {
+    Dismiss(id);
+    std::unique_ptr<message_center::Notification> notification =
+        MakeDataProtectionPolicyProgressNotification(id, status);
     GetNotificationDisplayService()->Display(
         NotificationHandler::Type::TRANSIENT, *notification,
         /*metadata=*/nullptr);
@@ -813,21 +824,19 @@
 }
 
 void SystemNotificationManager::HandleDataProtectionPolicyNotificationClick(
-    file_manager::io_task::IOTaskId task_id,
-    const std::string& notification_id,
-    DataProtectionWarningContinueCallback callback,
+    base::RepeatingClosure proceed_callback,
+    base::RepeatingClosure cancel_callback,
     absl::optional<int> button_index) {
   if (!button_index.has_value()) {
     return;
   }
 
   if (button_index.value() == 0) {
-    CancelTask(task_id);
+    proceed_callback.Run();
   }
 
-  if (button_index.value() == 1) {
-    Dismiss(notification_id);
-    callback.Run();
+  if (button_index.value() == 1 && cancel_callback) {
+    cancel_callback.Run();
   }
 }
 
@@ -1055,8 +1064,7 @@
 std::unique_ptr<message_center::Notification>
 SystemNotificationManager::MakeDataProtectionPolicyNotification(
     const std::string& notification_id,
-    const file_manager::io_task::ProgressStatus& status,
-    DataProtectionWarningContinueCallback continue_callback) {
+    const file_manager::io_task::ProgressStatus& status) {
   std::u16string title = GetPolicyNotificationTitle(status);
   std::u16string message = GetPolicyNotificationMessage(status);
   std::u16string cancel_button = GetPolicyNotificationCancelButton(status);
@@ -1064,41 +1072,52 @@
   std::vector<message_center::ButtonInfo> notification_buttons;
   notification_buttons.emplace_back(cancel_button);
 
-  DataProtectionWarningContinueCallback callback;
+  base::RepeatingClosure proceed_callback;
+  base::RepeatingClosure cancel_callback;
   if (status.HasWarning()) {
     notification_buttons.emplace_back(
         GetPolicyNotificationProceedButton(status));
     if (status.sources.size() == 1) {
-      // If there's only one file, the user can continue the action directly
-      // from the notification.
-      callback = continue_callback;
+      // Single file: the user can continue the action directly from the
+      // notification.
+      proceed_callback =
+          base::BindRepeating(&SystemNotificationManager::ResumeTask,
+                              weak_ptr_factory_.GetWeakPtr(), status.task_id);
     } else {
-      // If there's more than one file, add the "Review" button. The user can
-      // continue the action from the dialog.
-      callback = base::BindRepeating(
-          &SystemNotificationManager::ShowPolicyWarningDialog,
-          weak_ptr_factory_.GetWeakPtr(), std::move(continue_callback));
+      // Multiple files: add the "Review" button. The user can continue the
+      // action from the dialog.
+      proceed_callback = base::BindRepeating(
+          &SystemNotificationManager::ShowDataProtectionPolicyDialog,
+          weak_ptr_factory_.GetWeakPtr(), status.task_id,
+          policy::FilesDialogType::kWarning);
     }
+    cancel_callback =
+        base::BindRepeating(&SystemNotificationManager::CancelTask,
+                            weak_ptr_factory_.GetWeakPtr(), status.task_id);
   } else {  // Error - some files couldn't be transferred.
-    DCHECK(status.policy_error.has_value());
+    DCHECK(status.HasPolicyError());
     if (status.policy_error !=
             file_manager::io_task::PolicyErrorType::kDlpWarningTimeout &&
         status.sources.size() > 1) {
       // If more than one file was blocked, add the "Review" button.
       notification_buttons.emplace_back(
           GetPolicyNotificationProceedButton(status));
-      callback =
-          base::BindRepeating(&SystemNotificationManager::ShowPolicyErrorDialog,
-                              weak_ptr_factory_.GetWeakPtr());
+      proceed_callback = base::BindRepeating(
+          &SystemNotificationManager::ShowDataProtectionPolicyDialog,
+          weak_ptr_factory_.GetWeakPtr(), status.task_id,
+          policy::FilesDialogType::kError);
     }
+    cancel_callback =
+        base::BindRepeating(&SystemNotificationManager::Dismiss,
+                            weak_ptr_factory_.GetWeakPtr(), notification_id);
   }
 
   scoped_refptr<message_center::NotificationDelegate> delegate =
       base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
           base::BindRepeating(&SystemNotificationManager::
                                   HandleDataProtectionPolicyNotificationClick,
-                              weak_ptr_factory_.GetWeakPtr(), status.task_id,
-                              notification_id, callback));
+                              weak_ptr_factory_.GetWeakPtr(), proceed_callback,
+                              cancel_callback));
   std::unique_ptr<message_center::Notification> notification =
       CreateSystemNotification(notification_id, title, message, delegate);
 
@@ -1107,13 +1126,32 @@
   return notification;
 }
 
-void SystemNotificationManager::ShowPolicyWarningDialog(
-    DataProtectionWarningContinueCallback callback) {
-  // TODO(b/279436140): Create a dialog.
+std::unique_ptr<message_center::Notification>
+SystemNotificationManager::MakeDataProtectionPolicyProgressNotification(
+    const std::string& notification_id,
+    const file_manager::io_task::ProgressStatus& status) {
+  // TODO(b/279435843): Replace with translation strings.
+  std::u16string message =
+      u"Checking files with your organization's security policies.";
+  // TODO(b/282130948): Set progress value.
+  return CreateIOTaskProgressNotification(status.task_id, notification_id,
+                                          app_name_, message, /*paused=*/false,
+                                          /*progress=*/0);
 }
 
-void SystemNotificationManager::ShowPolicyErrorDialog() {
-  // TODO(b/279436140): Create a dialog.
+void SystemNotificationManager::ShowDataProtectionPolicyDialog(
+    file_manager::io_task::IOTaskId task_id,
+    policy::FilesDialogType type) {
+  policy::FilesPolicyNotificationManager* manager =
+      policy::FilesPolicyNotificationManagerFactory::GetForBrowserContext(
+          profile_);
+  if (!manager) {
+    LOG(ERROR) << "No FilesPolicyNotificationManager instantiated,"
+                  "can't show policy dialog for task_id "
+               << task_id;
+    return;
+  }
+  manager->ShowDialog(task_id, type);
 }
 
 void SystemNotificationManager::CancelTask(
@@ -1125,6 +1163,16 @@
   }
 }
 
+void SystemNotificationManager::ResumeTask(
+    file_manager::io_task::IOTaskId task_id) {
+  if (io_task_controller_) {
+    // TODO(b/281973963): Pass resume reason.
+    io_task_controller_->Resume(task_id, {});
+  } else {
+    LOG(ERROR) << "No TaskController, can't resume task_id: " << task_id;
+  }
+}
+
 void SystemNotificationManager::HandleMountCompletedEvent(
     file_manager_private::MountCompletedEvent& event,
     const Volume& volume) {
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager.h b/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
index 384b9b3..c9638a4 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/ash/file_manager/io_task.h"
 #include "chrome/browser/ash/file_manager/io_task_controller.h"
 #include "chrome/browser/ash/file_manager/volume_manager.h"
+#include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/browser/notifications/system_notification_helper.h"
@@ -258,16 +259,13 @@
           uma_types_for_buttons,
       absl::optional<int> button_index);
 
-  using DataProtectionWarningContinueCallback = base::RepeatingClosure;
-
   /**
    * Click handler for Data Leak Prevention or Enterprise Connectors policy
    * notifications.
    */
   void HandleDataProtectionPolicyNotificationClick(
-      file_manager::io_task::IOTaskId task_id,
-      const std::string& notification_id,
-      DataProtectionWarningContinueCallback callback,
+      base::RepeatingClosure proceed_callback,
+      base::RepeatingClosure cancel_callback,
       absl::optional<int> button_index);
 
   /**
@@ -291,25 +289,26 @@
       const Volume& volume);
 
   /**
-   * Makes a notification instance Data Leak Prevention or Enterprise Connectors
-   * errors and warnings. For warnings, |continue_callback| should be passed in
-   * order to resume the task in case the user chooses to.
+   * Makes a notification instance Data Protection errors and warnings.
    */
   std::unique_ptr<message_center::Notification>
   MakeDataProtectionPolicyNotification(
       const std::string& notification_id,
-      const file_manager::io_task::ProgressStatus& status,
-      DataProtectionWarningContinueCallback continue_callback);
+      const file_manager::io_task::ProgressStatus& status);
 
   /**
-   * Helper function to show a policy warning dialog.
+   * Makes a notification instance for Data Protection progress notifications.
    */
-  void ShowPolicyWarningDialog(DataProtectionWarningContinueCallback callback);
+  std::unique_ptr<message_center::Notification>
+  MakeDataProtectionPolicyProgressNotification(
+      const std::string& notification_id,
+      const file_manager::io_task::ProgressStatus& status);
 
   /**
-   * Helper function to show a policy error dialog.
+   * Helper function to show a data protection policy dialog.
    */
-  void ShowPolicyErrorDialog();
+  void ShowDataProtectionPolicyDialog(file_manager::io_task::IOTaskId task_id,
+                                      policy::FilesDialogType type);
 
   /**
    * Helper function bound to notification instances that hides notifications.
@@ -322,6 +321,11 @@
   void CancelTask(file_manager::io_task::IOTaskId task_id);
 
   /**
+   * Helper function to resume a task.
+   */
+  void ResumeTask(file_manager::io_task::IOTaskId task_id);
+
+  /**
    * Maps device paths to their mount status.
    * This is used for removable devices with single/multiple partitions.
    * e.g. the same device path could have 2 partitions that each generate a
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc b/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
index b3723b4..ac907d27 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
@@ -1305,6 +1305,43 @@
   ASSERT_EQ(0u, GetNotificationCount());
 }
 
+TEST_F(SystemNotificationManagerTest, HandleIOTaskProgressPolicyScanning) {
+  // The system notification only sees the IOTask ProgressStatus.
+  file_manager::io_task::ProgressStatus status;
+  status.task_id = 1;
+  status.state = file_manager::io_task::State::kScanning;
+  status.type = file_manager::io_task::OperationType::kCopy;
+  status.total_bytes = 100;
+  status.bytes_transferred = 0;
+  status.sources.emplace_back(CreateTestFile("volume/src_file.txt"),
+                              absl::nullopt);
+  status.SetDestinationFolder(CreateTestFile("volume/dest_dir/"));
+
+  // Send the scanning progress.
+  auto* notification_manager = GetSystemNotificationManager();
+  notification_manager->HandleIOTaskProgress(status);
+
+  // Check: We have the 1 notification.
+  ASSERT_EQ(1u, GetNotificationCount());
+
+  TestNotificationStrings notification_strings =
+      notification_platform_bridge->GetNotificationStringsById(
+          "swa-file-operation-1");
+
+  // Check: the expected strings match.
+  EXPECT_EQ(notification_strings.title, u"Files");
+  EXPECT_EQ(notification_strings.message,
+            u"Checking files with your organization's security policies.");
+
+  // Send the success progress status.
+  status.bytes_transferred = 100;
+  status.state = file_manager::io_task::State::kSuccess;
+  notification_manager->HandleIOTaskProgress(status);
+
+  // Notification should disappear.
+  ASSERT_EQ(0u, GetNotificationCount());
+}
+
 std::u16string kGoogleDrive = u"Google Drive";
 
 // Tests all the various error notifications.
diff --git a/chrome/browser/ash/extensions/users_private/users_private_apitest.cc b/chrome/browser/ash/extensions/users_private/users_private_apitest.cc
index fe39641..6638bac 100644
--- a/chrome/browser/ash/extensions/users_private/users_private_apitest.cc
+++ b/chrome/browser/ash/extensions/users_private/users_private_apitest.cc
@@ -125,7 +125,7 @@
     scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util =
         new ownership::MockOwnerKeyUtil();
     owner_key_util->ImportPrivateKeyAndSetPublicKey(
-        crypto::RSAPrivateKey::Create(512));
+        crypto::RSAPrivateKey::Create(2048));
 
     ash::OwnerSettingsServiceAshFactory::GetInstance()
         ->SetOwnerKeyUtilForTesting(owner_key_util);
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.cc b/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.cc
index 1c696f0d..827da25 100644
--- a/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.cc
+++ b/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.cc
@@ -18,6 +18,8 @@
 #include "chrome/browser/ash/file_manager/file_manager_copy_or_move_hook_delegate.h"
 #include "chrome/browser/ash/file_manager/file_manager_copy_or_move_hook_file_check_delegate.h"
 #include "chrome/browser/ash/file_manager/io_task.h"
+#include "chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
 #include "chrome/browser/enterprise/connectors/analysis/file_transfer_analysis_delegate.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/common/task_util.h"
@@ -103,6 +105,14 @@
                        std::move(outputs), profile, file_system_context);
 }
 
+// Returns DlpFilesControllerAsh* if exists.
+policy::DlpFilesControllerAsh* GetDlpFilesController() {
+  policy::DlpRulesManager* rules_manager =
+      policy::DlpRulesManagerFactory::GetForPrimaryProfile();
+  return static_cast<policy::DlpFilesControllerAsh*>(
+      rules_manager ? rules_manager->GetDlpFilesController() : nullptr);
+}
+
 }  // namespace
 
 CopyOrMoveIOTaskPolicyImpl::CopyOrMoveIOTaskPolicyImpl(
@@ -157,17 +167,23 @@
 }
 
 void CopyOrMoveIOTaskPolicyImpl::VerifyTransfer() {
-  if (report_only_scans_) {
-    // Don't do any scans. Instead, the scans are performed after the copy/move
-    // is completed.
-    StartTransfer();
+  auto on_check_transfer_cb =
+      base::BindOnce(&CopyOrMoveIOTaskPolicyImpl::OnCheckIfTransferAllowed,
+                     weak_ptr_factory_.GetWeakPtr());
+
+  if (auto* files_controller = GetDlpFilesController();
+      policy::DlpFilesController::kCopyTaskFlowEnabled && files_controller) {
+    std::vector<storage::FileSystemURL> transferred_urls;
+    for (const auto& entry : progress_->sources) {
+      transferred_urls.push_back(entry.url);
+    }
+    files_controller->CheckIfTransferAllowed(
+        progress_->task_id, std::move(transferred_urls),
+        progress_->GetDestinationFolder(), std::move(on_check_transfer_cb));
     return;
   }
 
-  // Allocate one unique_ptr for each source. If it is not set, scanning is not
-  // enabled for this source.
-  file_transfer_analysis_delegates_.resize(progress_->sources.size());
-  MaybeScanForDisallowedFiles(0);
+  std::move(on_check_transfer_cb).Run(/*blocked_entries=*/{});
 }
 
 void CopyOrMoveIOTaskPolicyImpl::MaybeScanForDisallowedFiles(size_t idx) {
@@ -280,4 +296,23 @@
       file_system_context_, progress_callback, file_check_callback);
 }
 
+void CopyOrMoveIOTaskPolicyImpl::OnCheckIfTransferAllowed(
+    std::set<storage::FileSystemURL> blocked_entries) {
+  // TODO(b/279029167): This function shouldn't be reached if the user cancelled
+  // the DLP warning or the DLP warning timed out. If there's any file blocked
+  // by DLP, skip Enterprise Connectors scanning for them.
+
+  if (report_only_scans_) {
+    // Don't do any scans. Instead, the scans are performed after the copy/move
+    // is completed.
+    StartTransfer();
+    return;
+  }
+
+  // Allocate one unique_ptr for each source. If it is not set, scanning is not
+  // enabled for this source.
+  file_transfer_analysis_delegates_.resize(progress_->sources.size());
+  MaybeScanForDisallowedFiles(0);
+}
+
 }  // namespace file_manager::io_task
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.h b/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.h
index b229b1c..22f5bfb 100644
--- a/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.h
+++ b/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.h
@@ -100,6 +100,10 @@
   std::unique_ptr<storage::CopyOrMoveHookDelegate> GetHookDelegate(
       size_t idx) override;
 
+  // Continues executing the IO task after DLP checks are done.
+  void OnCheckIfTransferAllowed(
+      std::set<storage::FileSystemURL> blocked_entries);
+
   raw_ptr<Profile, ExperimentalAsh> profile_;
   scoped_refptr<storage::FileSystemContext> file_system_context_;
 
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 856192f..61fd427 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -2170,7 +2170,8 @@
         TestCase("searchHierarchy").EnableSearchV2(),
         TestCase("hideSearchInTrash").EnableSearchV2(),
         TestCase("searchTrashedFiles").EnableSearchV2(),
-        TestCase("matchDriveFilesByName").EnableSearchV2()
+        TestCase("matchDriveFilesByName").EnableSearchV2(),
+        TestCase("searchSharedWithMe").EnableSearchV2()
         // TODO(b/189173190): Enable
         // TestCase("searchQueryLaunchParam")
         ));
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index e906ce7a..f641adf 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -261,8 +261,22 @@
   // Represents the different types of entries (e.g. file, folder).
   enum EntryType { FILE, DIRECTORY, LINK, TEAM_DRIVE, COMPUTER };
 
-  // Represents whether an entry appears in 'Share with Me' or not.
-  enum SharedOption { NONE, SHARED, SHARED_WITH_ME, NESTED_SHARED_WITH_ME };
+  // Enumeration that determines the shared status of entries.
+  enum SharedOption {
+    // Not shared.
+    NONE,
+
+    // Shared but not visible in the 'Shared with me' view.
+    SHARED,
+
+    // Shared and appears in the 'Shared With Me' view.
+    SHARED_WITH_ME,
+
+    // Not directly shared, but belongs to a folder that is shared with me.
+    // Entries marked as indirectly shared do not have the 'shared' metadata
+    // field, and thus cannot be located via search for shared items.
+    INDIRECTLY_SHARED_WITH_ME,
+  };
 
   // The actual AddEntriesMessage contents.
 
@@ -545,8 +559,8 @@
         *option = SHARED;
       } else if (value == "sharedWithMe") {
         *option = SHARED_WITH_ME;
-      } else if (value == "nestedSharedWithMe") {
-        *option = NESTED_SHARED_WITH_ME;
+      } else if (value == "indirectlySharedWithMe") {
+        *option = INDIRECTLY_SHARED_WITH_ME;
       } else if (value == "none") {
         *option = NONE;
       } else {
@@ -1516,7 +1530,7 @@
   base::FilePath GetTargetBasePathForTestEntry(
       const AddEntriesMessage::TestEntryInfo& entry) {
     if (entry.shared_option == AddEntriesMessage::SHARED_WITH_ME ||
-        entry.shared_option == AddEntriesMessage::NESTED_SHARED_WITH_ME) {
+        entry.shared_option == AddEntriesMessage::INDIRECTLY_SHARED_WITH_ME) {
       return GetSharedWithMePath();
     }
     if (!entry.team_drive_name.empty()) {
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index 740656637..471a715b 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -353,6 +353,8 @@
   SET_STRING("BULK_PINNING_ERROR", IDS_FILE_BROWSER_BULK_PINNING_ERROR);
   SET_STRING("BULK_PINNING_EXPLANATION",
              IDS_FILE_BROWSER_BULK_PINNING_EXPLANATION);
+  SET_STRING("BULK_PINNING_GET_STARTED",
+             IDS_FILE_BROWSER_BULK_PINNING_GET_STARTED);
   SET_STRING("BULK_PINNING_LISTING", IDS_FILE_BROWSER_BULK_PINNING_LISTING);
   SET_STRING("BULK_PINNING_NOT_ENOUGH_SPACE",
              IDS_FILE_BROWSER_BULK_PINNING_NOT_ENOUGH_SPACE);
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index a24526f..cb79f9f 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -438,9 +438,19 @@
                                const TaskDescriptor& task,
                                const std::vector<FileSystemURL>& file_urls,
                                gfx::NativeWindow modal_parent) {
+  drive::DriveIntegrationService* integration_service =
+      drive::DriveIntegrationServiceFactory::FindForProfile(profile);
   bool offline = drive::util::GetDriveConnectionStatus(profile) !=
                  drive::util::DRIVE_CONNECTED;
-  if (offline) {
+  if (!integration_service || !integration_service->IsMounted() ||
+      !integration_service->GetDriveFsInterface()) {
+    UMA_HISTOGRAM_ENUMERATION(kDriveErrorMetricName,
+                              OfficeDriveErrors::DRIVEFS_INTERFACE);
+
+    return GetUserFallbackChoice(
+        profile, task, file_urls, modal_parent,
+        ash::office_fallback::FallbackReason::kDriveUnavailable);
+  } else if (offline) {
     UMA_HISTOGRAM_ENUMERATION(kDriveErrorMetricName,
                               OfficeDriveErrors::OFFLINE);
     // TODO(petermarshall): Quick Office vs. other default handler.
@@ -449,21 +459,9 @@
         ash::office_fallback::FallbackReason::kOffline);
   }
 
-  drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(profile);
-  if (integration_service && integration_service->IsMounted() &&
-      integration_service->GetDriveFsInterface()) {
-    return ash::cloud_upload::CloudOpenTask::Execute(
-        profile, file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive,
-        modal_parent);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION(kDriveErrorMetricName,
-                              OfficeDriveErrors::DRIVEFS_INTERFACE);
-
-    return GetUserFallbackChoice(
-        profile, task, file_urls, modal_parent,
-        ash::office_fallback::FallbackReason::kDriveUnavailable);
-  }
+  return ash::cloud_upload::CloudOpenTask::Execute(
+      profile, file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive,
+      modal_parent);
 }
 
 using ash::file_system_provider::ProvidedFileSystemInfo;
@@ -493,9 +491,6 @@
 
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterDictionaryPref(prefs::kDefaultHandlersForFileExtensions);
-  registry->RegisterBooleanPref(
-      prefs::kOfficeSetupComplete, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(prefs::kOfficeFilesAlwaysMoveToDrive, false);
   registry->RegisterBooleanPref(prefs::kOfficeFilesAlwaysMoveToOneDrive, false);
   registry->RegisterBooleanPref(prefs::kOfficeMoveConfirmationShownForDrive,
@@ -1158,11 +1153,15 @@
 }
 
 bool IsOfficeFile(const base::FilePath& path) {
-  constexpr const char* kOfficeExtensions[] = {".doc",  ".docx", ".xls",
-                                               ".xlsx", ".ppt",  ".pptx"};
-  for (const char* extension : kOfficeExtensions) {
-    if (path.MatchesExtension(extension)) {
-      return true;
+  std::vector<std::set<std::string>> groups = {WordGroupExtensions(),
+                                               ExcelGroupExtensions(),
+                                               PowerPointGroupExtensions()};
+
+  for (const std::set<std::string>& group : groups) {
+    for (const std::string& extension : group) {
+      if (path.MatchesExtension(extension)) {
+        return true;
+      }
     }
   }
   return false;
@@ -1183,6 +1182,15 @@
   return *extensions;
 }
 
+std::set<std::string> WordGroupMimeTypes() {
+  static const base::NoDestructor<std::set<std::string>> mime_types(
+      std::initializer_list<std::string>(
+          {"application/msword",
+           "application/"
+           "vnd.openxmlformats-officedocument.wordprocessingml.document"}));
+  return *mime_types;
+}
+
 bool HasExplicitDefaultFileHandler(Profile* profile,
                                    const std::string& extension) {
   std::string lower_extension = base::ToLowerASCII(extension);
@@ -1192,11 +1200,7 @@
 }
 
 void SetWordFileHandler(Profile* profile, const TaskDescriptor& task) {
-  UpdateDefaultTask(
-      profile, task, WordGroupExtensions(),
-      {"application/msword",
-       "application/"
-       "vnd.openxmlformats-officedocument.wordprocessingml.document"});
+  UpdateDefaultTask(profile, task, WordGroupExtensions(), WordGroupMimeTypes());
 }
 
 void SetWordFileHandlerToFilesSWA(Profile* profile,
@@ -1208,15 +1212,23 @@
 
 std::set<std::string> ExcelGroupExtensions() {
   static const base::NoDestructor<std::set<std::string>> extensions(
-      std::initializer_list<std::string>({".xls", ".xlsx"}));
+      std::initializer_list<std::string>({".xls", ".xlsm", ".xlsx"}));
   return *extensions;
 }
 
+std::set<std::string> ExcelGroupMimeTypes() {
+  static const base::NoDestructor<std::set<std::string>> mime_types(
+      std::initializer_list<std::string>(
+          {"application/vnd.ms-excel",
+           "application/vnd.ms-excel.sheet.macroEnabled.12",
+           "application/"
+           "vnd.openxmlformats-officedocument.spreadsheetml.sheet"}));
+  return *mime_types;
+}
+
 void SetExcelFileHandler(Profile* profile, const TaskDescriptor& task) {
-  UpdateDefaultTask(
-      profile, task, ExcelGroupExtensions(),
-      {"application/vnd.ms-excel",
-       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
+  UpdateDefaultTask(profile, task, ExcelGroupExtensions(),
+                    ExcelGroupMimeTypes());
 }
 
 void SetExcelFileHandlerToFilesSWA(Profile* profile,
@@ -1232,12 +1244,18 @@
   return *extensions;
 }
 
+std::set<std::string> PowerPointGroupMimeTypes() {
+  static const base::NoDestructor<std::set<std::string>> mime_types(
+      std::initializer_list<std::string>(
+          {"application/vnd.ms-powerpoint",
+           "application/"
+           "vnd.openxmlformats-officedocument.presentationml.presentation"}));
+  return *mime_types;
+}
+
 void SetPowerPointFileHandler(Profile* profile, const TaskDescriptor& task) {
-  UpdateDefaultTask(
-      profile, task, PowerPointGroupExtensions(),
-      {"application/vnd.ms-powerpoint",
-       "application/"
-       "vnd.openxmlformats-officedocument.presentationml.presentation"});
+  UpdateDefaultTask(profile, task, PowerPointGroupExtensions(),
+                    PowerPointGroupMimeTypes());
 }
 
 void SetPowerPointFileHandlerToFilesSWA(Profile* profile,
@@ -1247,14 +1265,6 @@
   SetPowerPointFileHandler(profile, task);
 }
 
-void SetOfficeSetupComplete(Profile* profile, bool complete) {
-  profile->GetPrefs()->SetBoolean(prefs::kOfficeSetupComplete, complete);
-}
-
-bool OfficeSetupComplete(Profile* profile) {
-  return profile->GetPrefs()->GetBoolean(prefs::kOfficeSetupComplete);
-}
-
 void SetAlwaysMoveOfficeFilesToDrive(Profile* profile, bool always_move) {
   profile->GetPrefs()->SetBoolean(prefs::kOfficeFilesAlwaysMoveToDrive,
                                   always_move);
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index c6c1797..4d01749 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -417,6 +417,11 @@
 std::set<std::string> ExcelGroupExtensions();
 std::set<std::string> PowerPointGroupExtensions();
 
+// The same as above but MIME types.
+std::set<std::string> WordGroupMimeTypes();
+std::set<std::string> ExcelGroupMimeTypes();
+std::set<std::string> PowerPointGroupMimeTypes();
+
 // Updates the default task for each of the office file types.
 void SetWordFileHandler(Profile* profile, const TaskDescriptor& task);
 void SetExcelFileHandler(Profile* profile, const TaskDescriptor& task);
@@ -439,12 +444,6 @@
                                         const std::string& action_id);
 
 // TODO(petermarshall): Move these to a new file office_file_tasks.cc/h
-// Sets the user preference storing whether the setup flow for office files has
-// ever been completed.
-void SetOfficeSetupComplete(Profile* profile, bool complete = true);
-// Whether or not the setup flow for office files has ever been completed.
-bool OfficeSetupComplete(Profile* profile);
-
 // Sets the user preference storing whether we should always move office files
 // to Google Drive without first asking the user.
 void SetAlwaysMoveOfficeFilesToDrive(Profile* profile, bool complete = true);
diff --git a/chrome/browser/ash/file_manager/io_task.cc b/chrome/browser/ash/file_manager/io_task.cc
index 67bf3d1..08899711 100644
--- a/chrome/browser/ash/file_manager/io_task.cc
+++ b/chrome/browser/ash/file_manager/io_task.cc
@@ -50,6 +50,10 @@
   return state == State::kError && policy_error.has_value();
 }
 
+bool ProgressStatus::IsScanning() const {
+  return state == State::kScanning;
+}
+
 std::string ProgressStatus::GetSourceName(Profile* profile) const {
   if (!source_name.empty()) {
     return source_name;
diff --git a/chrome/browser/ash/file_manager/io_task.h b/chrome/browser/ash/file_manager/io_task.h
index 58aa32c..9778b1d 100644
--- a/chrome/browser/ash/file_manager/io_task.h
+++ b/chrome/browser/ash/file_manager/io_task.h
@@ -149,6 +149,9 @@
   // or Enterprise Connectors policies.
   bool HasPolicyError() const;
 
+  // True if the task is in scanning state.
+  bool IsScanning() const;
+
   // Returns a default method for obtaining the source name.
   std::string GetSourceName(Profile* profile) const;
 
diff --git a/chrome/browser/ash/input_method/assistive_suggester.cc b/chrome/browser/ash/input_method/assistive_suggester.cc
index bffc96c0..780845e 100644
--- a/chrome/browser/ash/input_method/assistive_suggester.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester.cc
@@ -41,6 +41,7 @@
 using ime::AssistiveSuggestion;
 using ime::AssistiveSuggestionMode;
 using ime::AssistiveSuggestionType;
+using ime::SuggestionsTextContext;
 
 constexpr int kModifierKeysMask = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
                                   ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN |
@@ -492,18 +493,20 @@
 }
 
 void AssistiveSuggester::OnExternalSuggestionsUpdated(
-    const std::vector<AssistiveSuggestion>& suggestions) {
+    const std::vector<AssistiveSuggestion>& suggestions,
+    const absl::optional<SuggestionsTextContext>& context) {
   if (!IsMultiWordSuggestEnabled())
     return;
 
   suggester_switch_->FetchEnabledSuggestionsThen(
       base::BindOnce(&AssistiveSuggester::ProcessExternalSuggestions,
-                     weak_ptr_factory_.GetWeakPtr(), suggestions),
+                     weak_ptr_factory_.GetWeakPtr(), suggestions, context),
       context_);
 }
 
 void AssistiveSuggester::ProcessExternalSuggestions(
     const std::vector<AssistiveSuggestion>& suggestions,
+    const absl::optional<SuggestionsTextContext>& context,
     const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions) {
   RecordSuggestionsMatch(suggestions);
 
@@ -516,13 +519,13 @@
   }
 
   if (current_suggester_) {
-    current_suggester_->OnExternalSuggestionsUpdated(suggestions);
+    current_suggester_->OnExternalSuggestionsUpdated(suggestions, context);
     return;
   }
 
   if (IsTopResultMultiWord(suggestions)) {
     current_suggester_ = &multi_word_suggester_;
-    current_suggester_->OnExternalSuggestionsUpdated(suggestions);
+    current_suggester_->OnExternalSuggestionsUpdated(suggestions, context);
     RecordAssistiveCoverage(current_suggester_->GetProposeActionType());
   }
 }
diff --git a/chrome/browser/ash/input_method/assistive_suggester.h b/chrome/browser/ash/input_method/assistive_suggester.h
index 3e8a5ac9..6587433 100644
--- a/chrome/browser/ash/input_method/assistive_suggester.h
+++ b/chrome/browser/ash/input_method/assistive_suggester.h
@@ -88,7 +88,8 @@
 
   // Called when suggestions are generated outside of the assistive framework.
   void OnExternalSuggestionsUpdated(
-      const std::vector<ime::AssistiveSuggestion>& suggestions);
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context);
 
   // Accepts the suggestion at a given index if a suggester is currently
   // active.
@@ -163,6 +164,7 @@
 
   void ProcessExternalSuggestions(
       const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context,
       const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
 
   // This records any text input state metrics for each relevant assistive
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
index 9032517..dbcb883a 100644
--- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -45,12 +45,14 @@
 using ime::AssistiveSuggestion;
 using ime::AssistiveSuggestionMode;
 using ime::AssistiveSuggestionType;
+using ime::SuggestionsTextContext;
 using EnabledSuggestions = AssistiveSuggesterSwitch::EnabledSuggestions;
 
 const char kUsEnglishEngineId[] = "xkb:us::eng";
 const char kSpainSpanishEngineId[] = "xkb:es::spa";
 const char kEmojiData[] = "arrow,←;↑;→";
 const TextInputMethod::InputContext empty_context(ui::TEXT_INPUT_TYPE_NONE);
+constexpr size_t kTakeLastNChars = 100;
 
 ui::KeyEvent GenerateKeyEvent(const ui::DomCode& code,
                               const ui::EventType& event_type,
@@ -100,6 +102,15 @@
                           base::Value(diacritics_on_longpress_enabled));
 }
 
+SuggestionsTextContext TextContext(const std::string& surrounding_text) {
+  const size_t text_length = surrounding_text.length();
+  const size_t trim_from =
+      text_length > kTakeLastNChars ? text_length - kTakeLastNChars : 0;
+  return SuggestionsTextContext{
+      .last_n_chars = surrounding_text.substr(trim_from),
+      .surrounding_text_length = text_length};
+}
+
 }  // namespace
 
 class FakeSuggesterSwitch : public AssistiveSuggesterSwitch {
@@ -944,7 +955,7 @@
 
 TEST_F(AssistiveSuggesterMultiWordTest,
        MatchMetricNotRecordedWhenZeroSuggestions) {
-  assistive_suggester_->OnExternalSuggestionsUpdated({});
+  assistive_suggester_->OnExternalSuggestionsUpdated({}, TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Match", 0);
 }
@@ -958,7 +969,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_TRUE(suggestion_handler_->GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"hello there");
@@ -977,7 +989,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_FALSE(suggestion_handler_->GetShowingSuggestion());
 }
@@ -997,7 +1010,8 @@
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
 
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_FALSE(suggestion_handler_->GetShowingSuggestion());
 }
@@ -1012,7 +1026,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Match", 1);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Match",
@@ -1033,7 +1048,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Match", 0);
 }
@@ -1048,7 +1064,7 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated({});
+  assistive_suggester_->OnExternalSuggestionsUpdated({}, TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Disabled.MultiWord",
                                      0);
@@ -1068,7 +1084,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Disabled.MultiWord",
                                      1);
@@ -1082,7 +1099,7 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated({});
+  assistive_suggester_->OnExternalSuggestionsUpdated({}, TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 0);
 }
@@ -1097,7 +1114,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 1);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Coverage",
@@ -1114,13 +1132,17 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"hel", gfx::Range(3));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 1);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Coverage",
@@ -1141,13 +1163,17 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
-  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions,
+                                                     TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"he ", gfx::Range(3));
-  assistive_suggester_->OnExternalSuggestionsUpdated(second_suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(second_suggestions,
+                                                     TextContext(""));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 2);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Coverage",
@@ -1163,7 +1189,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_EQ(assistive_suggester_->OnKeyEvent(PressKey(ui::DomCode::TAB)),
             AssistiveSuggesterKeyResult::kHandled);
@@ -1178,7 +1205,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_EQ(assistive_suggester_->OnKeyEvent(PressKeyWithAlt(ui::DomCode::TAB)),
             AssistiveSuggesterKeyResult::kNotHandled);
@@ -1193,7 +1221,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_EQ(
       assistive_suggester_->OnKeyEvent(PressKeyWithCtrl(ui::DomCode::TAB)),
@@ -1209,7 +1238,8 @@
   assistive_suggester_->OnActivate(kUsEnglishEngineId);
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                                     TextContext(""));
 
   EXPECT_EQ(
       assistive_suggester_->OnKeyEvent(PressKeyWithShift(ui::DomCode::TAB)),
diff --git a/chrome/browser/ash/input_method/emoji_suggester.cc b/chrome/browser/ash/input_method/emoji_suggester.cc
index 4a3cc7c..aaf866c 100644
--- a/chrome/browser/ash/input_method/emoji_suggester.cc
+++ b/chrome/browser/ash/input_method/emoji_suggester.cc
@@ -36,6 +36,7 @@
 using AssistiveSuggestion = ime::AssistiveSuggestion;
 using AssistiveSuggestionMode = ime::AssistiveSuggestionMode;
 using AssistiveSuggestionType = ime::AssistiveSuggestionType;
+using SuggestionsTextContext = ime::SuggestionsTextContext;
 
 constexpr char kEmojiSuggesterShowSettingCount[] =
     "emoji_suggester.show_setting_count";
@@ -163,7 +164,8 @@
 }
 
 void EmojiSuggester::OnExternalSuggestionsUpdated(
-    const std::vector<AssistiveSuggestion>& suggestions) {
+    const std::vector<AssistiveSuggestion>& suggestions,
+    const absl::optional<SuggestionsTextContext>& context) {
   // EmojiSuggester doesn't utilize any suggestions produced externally, so
   // ignore this call.
 }
diff --git a/chrome/browser/ash/input_method/emoji_suggester.h b/chrome/browser/ash/input_method/emoji_suggester.h
index c4897a3..3024b6a 100644
--- a/chrome/browser/ash/input_method/emoji_suggester.h
+++ b/chrome/browser/ash/input_method/emoji_suggester.h
@@ -35,7 +35,8 @@
   void OnFocus(int context_id) override;
   void OnBlur() override;
   void OnExternalSuggestionsUpdated(
-      const std::vector<ime::AssistiveSuggestion>& suggestions) override;
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context) override;
   SuggestionStatus HandleKeyEvent(const ui::KeyEvent& event) override;
   bool TrySuggestWithSurroundingText(const std::u16string& text,
                                      gfx::Range selection_range) override;
diff --git a/chrome/browser/ash/input_method/longpress_suggester.cc b/chrome/browser/ash/input_method/longpress_suggester.cc
index 215e77a..7191d02c 100644
--- a/chrome/browser/ash/input_method/longpress_suggester.cc
+++ b/chrome/browser/ash/input_method/longpress_suggester.cc
@@ -26,7 +26,8 @@
 }
 
 void LongpressSuggester::OnExternalSuggestionsUpdated(
-    const std::vector<ime::AssistiveSuggestion>& suggestions) {
+    const std::vector<ime::AssistiveSuggestion>& suggestions,
+    const absl::optional<ime::SuggestionsTextContext>& context) {
   // Clipboard history updates are handled elsewhere, and diacritics suggestions
   // are not updated externally.
   return;
diff --git a/chrome/browser/ash/input_method/longpress_suggester.h b/chrome/browser/ash/input_method/longpress_suggester.h
index e091dfe..b212be6 100644
--- a/chrome/browser/ash/input_method/longpress_suggester.h
+++ b/chrome/browser/ash/input_method/longpress_suggester.h
@@ -25,7 +25,8 @@
   void OnFocus(int context_id) override;
   void OnBlur() override;
   void OnExternalSuggestionsUpdated(
-      const std::vector<ime::AssistiveSuggestion>& suggestions) override;
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context) override;
   bool HasSuggestions() override;
   std::vector<ime::AssistiveSuggestion> GetSuggestions() override;
 
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.cc b/chrome/browser/ash/input_method/multi_word_suggester.cc
index 3aef39f..1a9e99d 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester.cc
@@ -27,6 +27,7 @@
 using ime::AssistiveSuggestion;
 using ime::AssistiveSuggestionMode;
 using ime::AssistiveSuggestionType;
+using ime::SuggestionsTextContext;
 
 // Used for UmaHistogramExactLinear, should remain <= 101.
 constexpr size_t kMaxSuggestionLength = 101;
@@ -211,7 +212,8 @@
 }
 
 void MultiWordSuggester::OnExternalSuggestionsUpdated(
-    const std::vector<AssistiveSuggestion>& suggestions) {
+    const std::vector<AssistiveSuggestion>& suggestions,
+    const absl::optional<SuggestionsTextContext>& context) {
   if (state_.IsSuggestionShowing() || !state_.IsCursorAtEndOfText())
     return;
 
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.h b/chrome/browser/ash/input_method/multi_word_suggester.h
index 2adf091..8b13612a 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.h
+++ b/chrome/browser/ash/input_method/multi_word_suggester.h
@@ -31,7 +31,8 @@
   void OnFocus(int context_id) override;
   void OnBlur() override;
   void OnExternalSuggestionsUpdated(
-      const std::vector<ime::AssistiveSuggestion>& suggestions) override;
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context) override;
   SuggestionStatus HandleKeyEvent(const ui::KeyEvent& event) override;
   bool TrySuggestWithSurroundingText(const std::u16string& text,
                                      gfx::Range selection_range) override;
diff --git a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
index be89130..62213a3 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
@@ -27,8 +27,10 @@
 using ime::AssistiveSuggestion;
 using ime::AssistiveSuggestionMode;
 using ime::AssistiveSuggestionType;
+using ime::SuggestionsTextContext;
 
 constexpr int kFocusedContextId = 5;
+constexpr size_t kTakeLastNChars = 100;
 
 void SendKeyEvent(MultiWordSuggester* suggester, const ui::DomCode& code) {
   suggester->HandleKeyEvent(ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
@@ -50,6 +52,15 @@
   return update->FindInt("multi_word_first_accept");
 }
 
+SuggestionsTextContext TextContext(const std::string& surrounding_text) {
+  const size_t text_length = surrounding_text.length();
+  const size_t trim_from =
+      text_length > kTakeLastNChars ? text_length - kTakeLastNChars : 0;
+  return SuggestionsTextContext{
+      .last_n_chars = surrounding_text.substr(trim_from),
+      .surrounding_text_length = text_length};
+}
+
 }  // namespace
 
 class MultiWordSuggesterTest : public testing::Test {
@@ -76,7 +87,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_NE(suggestion_handler_.GetContextId(), kFocusedContextId);
@@ -86,7 +97,7 @@
 TEST_F(MultiWordSuggesterTest, IgnoresEmpyExternalSuggestions) {
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated({});
+  suggester_->OnExternalSuggestionsUpdated({}, TextContext(""));
 
   EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_NE(suggestion_handler_.GetContextId(), kFocusedContextId);
@@ -101,7 +112,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetContextId(), kFocusedContextId);
@@ -118,7 +129,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
   suggester_->OnBlur();
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_NE(suggestion_handler_.GetContextId(), kFocusedContextId);
@@ -133,7 +144,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
   EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
@@ -151,7 +162,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   suggester_->OnBlur();
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
@@ -167,7 +178,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_UP);
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
@@ -184,7 +195,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
@@ -201,7 +212,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ENTER);
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
@@ -218,7 +229,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
   SendKeyEvent(suggester_.get(), ui::DomCode::ENTER);
 
@@ -237,7 +248,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   suggester_->OnBlur();
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
 
@@ -253,7 +264,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
 
   EXPECT_TRUE(suggestion_handler_.GetHighlightedSuggestion());
@@ -268,7 +279,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
@@ -285,7 +296,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_DOWN);
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_UP);
 
@@ -301,7 +312,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_UP);
 
   EXPECT_FALSE(suggestion_handler_.GetHighlightedSuggestion());
@@ -316,7 +327,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_UP);
   SendKeyEvent(suggester_.get(), ui::DomCode::ARROW_UP);
 
@@ -332,7 +343,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   auto suggestion_details = suggestion_handler_.GetLastSuggestionDetails();
   EXPECT_TRUE(suggestion_details.show_quick_accept_annotation);
@@ -350,7 +361,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   auto suggestion_details = suggestion_handler_.GetLastSuggestionDetails();
   EXPECT_TRUE(suggestion_details.show_quick_accept_annotation);
@@ -368,7 +379,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
 
   auto suggestion_details = suggestion_handler_.GetLastSuggestionDetails();
   EXPECT_FALSE(suggestion_details.show_quick_accept_annotation);
@@ -384,12 +395,12 @@
   auto pref_before_accept = GetFirstAcceptTime(profile_.get());
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
   auto pref_after_first_accept = GetFirstAcceptTime(profile_.get());
 
   suggester_->OnSurroundingTextChanged(u"", gfx::Range(0));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext(""));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
   auto pref_after_second_accept = GetFirstAcceptTime(profile_.get());
 
@@ -408,7 +419,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"ho", gfx::Range(2));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("ho"));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetSuggestionText(), u"how are you going");
@@ -424,7 +435,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"hey there sam whe", gfx::Range(17));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("hey there sam whe"));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetSuggestionText(), u"where are you going");
@@ -441,7 +453,8 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"merry christmas hohoho",
                                        gfx::Range(22));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(
+      suggestions, TextContext("merry christmas hohoho"));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetSuggestionText(), u"hohohohoho");
@@ -457,7 +470,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"this ", gfx::Range(5));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("this "));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetSuggestionText(), u"is the next task");
@@ -473,7 +486,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"\nh", gfx::Range(2));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("\nh"));
 
   EXPECT_TRUE(suggestion_handler_.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler_.GetSuggestionText(), u"how are you");
@@ -490,7 +503,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
   suggester_->TrySuggestWithSurroundingText(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"hh", gfx::Range(2));
 
   EXPECT_FALSE(suggester_->TrySuggestWithSurroundingText(u"hh", gfx::Range(2)));
@@ -506,7 +519,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"hello h", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"hello h", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hello h"));
   suggester_->OnSurroundingTextChanged(u"hello h", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"hello h", gfx::Range(7));
   suggester_->OnSurroundingTextChanged(u"hello h", gfx::Range(7));
@@ -524,7 +537,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"hey there sam whe", gfx::Range(17));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("hey there sam whe"));
   suggester_->OnSurroundingTextChanged(u"hey there sam wher", gfx::Range(18));
   suggester_->TrySuggestWithSurroundingText(u"hey there sam wher",
                                             gfx::Range(18));
@@ -562,7 +576,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"ho", gfx::Range(2));
   suggester_->TrySuggestWithSurroundingText(u"ho", gfx::Range(2));
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
@@ -583,7 +597,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->TrySuggestWithSurroundingText(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are yo", gfx::Range(10));
@@ -603,7 +617,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"ho", gfx::Range(2));
   suggester_->TrySuggestWithSurroundingText(u"ho", gfx::Range(2));
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
@@ -624,7 +638,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"ho", gfx::Range(2));
   suggester_->TrySuggestWithSurroundingText(u"ho", gfx::Range(2));
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
@@ -646,7 +660,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("h"));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->TrySuggestWithSurroundingText(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how yo", gfx::Range(6));
@@ -666,7 +680,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"this is some text", gfx::Range(17));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("this is some text"));
   suggester_->OnSurroundingTextChanged(u"this is some text ", gfx::Range(18));
   suggester_->TrySuggestWithSurroundingText(u"this is some text ",
                                             gfx::Range(18));
@@ -697,7 +712,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"this is some text fo", gfx::Range(20));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("this is some text fo"));
   suggester_->OnSurroundingTextChanged(u"this is some text for",
                                        gfx::Range(21));
   suggester_->TrySuggestWithSurroundingText(u"this is some text for",
@@ -723,7 +739,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"this is some text fo", gfx::Range(20));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("this is some text fo"));
   suggester_->OnSurroundingTextChanged(u"this is some text for",
                                        gfx::Range(21));
   suggester_->TrySuggestWithSurroundingText(u"this is some text for",
@@ -744,7 +761,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
   suggester_->TrySuggestWithSurroundingText(u"how ", gfx::Range(4));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
@@ -774,7 +791,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how ar"));
 
   EXPECT_EQ(suggester_->GetProposeActionType(),
             AssistiveType::kMultiWordCompletion);
@@ -790,7 +807,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
 
   EXPECT_EQ(suggester_->GetProposeActionType(),
             AssistiveType::kMultiWordPrediction);
@@ -807,7 +824,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
   suggester_->TrySuggestWithSurroundingText(u"why", gfx::Range(6));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why ar"));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
   ASSERT_EQ(suggester_->GetProposeActionType(),
@@ -825,7 +842,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why", gfx::Range(3));
   suggester_->TrySuggestWithSurroundingText(u"why", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why"));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
   ASSERT_EQ(suggester_->GetProposeActionType(),
@@ -845,7 +862,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
   EXPECT_TRUE(suggestion_handler_.GetAcceptedSuggestion());
@@ -866,7 +883,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
   suggester_->DismissSuggestion();
 
   histogram_tester.ExpectTotalCount(
@@ -886,7 +903,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
 
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.MultiWord.SuggestionLength", 1);
@@ -909,7 +926,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how"));
 
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.MultiWord.SuggestionLength", 0);
@@ -1037,7 +1054,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1068,7 +1085,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1092,7 +1109,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1118,7 +1135,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
@@ -1140,7 +1157,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1171,7 +1188,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"ho", gfx::Range(2));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("ho"));
   suggester_->OnSurroundingTextChanged(u"how", gfx::Range(3));
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
@@ -1204,7 +1221,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1242,7 +1259,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
 
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.MultiWord.ImplicitRejection", 0);
@@ -1262,7 +1279,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how a"));
 
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.MultiWord.ImplicitRejection", 0);
@@ -1282,7 +1299,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
@@ -1304,7 +1321,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1327,7 +1344,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
@@ -1351,7 +1368,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnBlur();
 
@@ -1373,7 +1390,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1398,7 +1415,8 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how are you ", gfx::Range(12));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions,
+                                           TextContext("how are you "));
   suggester_->OnSurroundingTextChanged(u"how are you f", gfx::Range(13));
 
   histogram_tester.ExpectTotalCount(
@@ -1418,7 +1436,7 @@
 
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"how ", gfx::Range(4));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("how "));
   suggester_->OnSurroundingTextChanged(u"how a", gfx::Range(5));
   suggester_->OnSurroundingTextChanged(u"how ar", gfx::Range(6));
   suggester_->OnSurroundingTextChanged(u"how are", gfx::Range(7));
@@ -1456,7 +1474,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
 
   ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 1u);
   EXPECT_EQ(suggestion_handler_.GetAnnouncements().back(),
@@ -1475,7 +1493,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
   suggester_->OnSurroundingTextChanged(u"why aren", gfx::Range(8));
   suggester_->TrySuggestWithSurroundingText(u"why aren", gfx::Range(8));
   suggester_->OnSurroundingTextChanged(u"why aren'", gfx::Range(9));
@@ -1499,7 +1517,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
 
   ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u);
@@ -1518,7 +1536,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
   SendKeyEvent(suggester_.get(), ui::DomCode::TAB);
   suggester_->OnSurroundingTextChanged(u"why aren", gfx::Range(8));
   suggester_->TrySuggestWithSurroundingText(u"why aren", gfx::Range(8));
@@ -1536,7 +1554,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
   suggester_->DismissSuggestion();
 
   ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u);
@@ -1555,7 +1573,7 @@
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
   suggester_->TrySuggestWithSurroundingText(u"why are", gfx::Range(7));
-  suggester_->OnExternalSuggestionsUpdated(suggestions);
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("why are"));
   suggester_->DismissSuggestion();
   suggester_->OnSurroundingTextChanged(u"why aren", gfx::Range(8));
   suggester_->TrySuggestWithSurroundingText(u"why aren", gfx::Range(8));
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
index 7e49b79..b89f6874 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -1380,10 +1380,11 @@
 }
 
 void NativeInputMethodEngineObserver::DisplaySuggestions(
-    const std::vector<ime::AssistiveSuggestion>& suggestions) {
+    const std::vector<ime::AssistiveSuggestion>& suggestions,
+    const absl::optional<ime::SuggestionsTextContext>& context) {
   if (!IsTextClientActive())
     return;
-  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
+  assistive_suggester_->OnExternalSuggestionsUpdated(suggestions, context);
 }
 
 void NativeInputMethodEngineObserver::UpdateCandidatesWindow(
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.h b/chrome/browser/ash/input_method/native_input_method_engine_observer.h
index 2af8a87..cb4ee52 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.h
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.h
@@ -106,7 +106,8 @@
   void RequestSuggestions(ime::mojom::SuggestionsRequestPtr request,
                           RequestSuggestionsCallback callback) override;
   void DisplaySuggestions(
-      const std::vector<ime::AssistiveSuggestion>& suggestions) override;
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context) override;
   void UpdateCandidatesWindow(ime::mojom::CandidatesWindowPtr window) override;
   void RecordUkm(ime::mojom::UkmEntryPtr entry) override;
   void ReportKoreanAction(ime::mojom::KoreanAction action) override;
diff --git a/chrome/browser/ash/input_method/suggester.h b/chrome/browser/ash/input_method/suggester.h
index cb84e19..6638a4f 100644
--- a/chrome/browser/ash/input_method/suggester.h
+++ b/chrome/browser/ash/input_method/suggester.h
@@ -26,7 +26,8 @@
 
   // Called when suggestions are generated outside of the assisitve framework.
   virtual void OnExternalSuggestionsUpdated(
-      const std::vector<ime::AssistiveSuggestion>& suggestions) = 0;
+      const std::vector<ime::AssistiveSuggestion>& suggestions,
+      const absl::optional<ime::SuggestionsTextContext>& context) = 0;
 
   // Called when suggestion is being shown.
   // Returns SuggestionStatus as suggester handles the event.
diff --git a/chrome/browser/ash/login/debug_overlay_browsertest.cc b/chrome/browser/ash/login/debug_overlay_browsertest.cc
index 9d8d7272..552b1b2 100644
--- a/chrome/browser/ash/login/debug_overlay_browsertest.cc
+++ b/chrome/browser/ash/login/debug_overlay_browsertest.cc
@@ -22,7 +22,7 @@
 constexpr char kScreensPanel[] = "DebuggerPanelScreens";
 
 constexpr int kOobeScreensCount = 47;
-constexpr int kLoginScreensCount = 45;
+constexpr int kLoginScreensCount = 44;
 constexpr int kOsInstallScreensCount = 2;
 
 std::string ElementsInPanel(const std::string& panel) {
diff --git a/chrome/browser/ash/login/enterprise_enrollment_browsertest.cc b/chrome/browser/ash/login/enterprise_enrollment_browsertest.cc
index 3489fa6..97bdfab 100644
--- a/chrome/browser/ash/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/ash/login/enterprise_enrollment_browsertest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ash/login/wizard_controller.h"
 #include "chrome/browser/ash/policy/enrollment/enrollment_status.h"
 #include "chrome/browser/browser_process.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
 #include "chromeos/ash/components/dbus/dbus_thread_manager.h"
 #include "chromeos/ash/components/dbus/upstart/upstart_client.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
@@ -42,31 +41,6 @@
 
 const test::UIPath kWebview = {kEnrollmentUI, "step-signin", "signin-frame"};
 
-class MockAuthPolicyClient : public FakeAuthPolicyClient {
- public:
-  MockAuthPolicyClient() = default;
-  ~MockAuthPolicyClient() override = default;
-  void JoinAdDomain(const authpolicy::JoinDomainRequest& request,
-                    int password_fd,
-                    JoinCallback callback) override {
-    if (expected_request_) {
-      ASSERT_EQ(expected_request_->SerializeAsString(),
-                request.SerializeAsString());
-      expected_request_.reset();
-    }
-    FakeAuthPolicyClient::JoinAdDomain(request, password_fd,
-                                       std::move(callback));
-  }
-
-  void set_expected_request(
-      std::unique_ptr<authpolicy::JoinDomainRequest> expected_request) {
-    expected_request_ = std::move(expected_request);
-  }
-
- private:
-  std::unique_ptr<authpolicy::JoinDomainRequest> expected_request_;
-};
-
 }  // namespace
 
 class EnterpriseEnrollmentTestBase : public OobeBaseTest {
diff --git a/chrome/browser/ash/login/existing_user_controller.cc b/chrome/browser/ash/login/existing_user_controller.cc
index dfa8a3a..23718da 100644
--- a/chrome/browser/ash/login/existing_user_controller.cc
+++ b/chrome/browser/ash/login/existing_user_controller.cc
@@ -301,18 +301,6 @@
   return regular_users_counter;
 }
 
-user_manager::UserList ExtractSamlLoginUsers(
-    const user_manager::UserList& users) {
-  user_manager::UserList saml_users_for_password_sync;
-  for (auto* user : users) {
-    if (user->using_saml() && user->HasGaiaAccount() &&
-        user_manager::UserManager::Get()->IsGaiaUserAllowed(*user)) {
-      saml_users_for_password_sync.push_back(user);
-    }
-  }
-  return saml_users_for_password_sync;
-}
-
 }  // namespace
 
 // Utility class used to wait for a Public Session policy to be available if
@@ -440,19 +428,6 @@
   base::UmaHistogramCounts100("Login.NumberOfUsersOnLoginScreen",
                               regular_users_counter);
   AuthEventsRecorder::Get()->OnUserCount(regular_users_counter);
-  const auto saml_users_for_password_sync = ExtractSamlLoginUsers(users);
-
-  // ExistingUserController owns PasswordSyncTokenLoginCheckers only if user
-  // pods are hidden.
-  if (!show_users_on_signin && !saml_users_for_password_sync.empty()) {
-    sync_token_checkers_ =
-        std::make_unique<PasswordSyncTokenCheckersCollection>();
-    sync_token_checkers_->StartPasswordSyncCheckers(
-        saml_users_for_password_sync,
-        /*observer*/ nullptr);
-  } else {
-    sync_token_checkers_.reset();
-  }
 
   if (LoginScreen::Get()) {
     LoginScreen::Get()->SetAllowLoginAsGuest(
diff --git a/chrome/browser/ash/login/existing_user_controller.h b/chrome/browser/ash/login/existing_user_controller.h
index 1dd466f1..cef2a20 100644
--- a/chrome/browser/ash/login/existing_user_controller.h
+++ b/chrome/browser/ash/login/existing_user_controller.h
@@ -377,10 +377,6 @@
   // Timer for the interval to wait for the reboot after TPM error UI was shown.
   base::OneShotTimer reboot_timer_;
 
-  // Collection of verifiers that check validity of password sync token for SAML
-  // users.
-  std::unique_ptr<PasswordSyncTokenCheckersCollection> sync_token_checkers_;
-
   std::unique_ptr<login::NetworkStateHelper> network_state_helper_;
 
   base::CallbackListSubscription show_user_names_subscription_;
diff --git a/chrome/browser/ash/login/existing_user_controller_browsertest.cc b/chrome/browser/ash/login/existing_user_controller_browsertest.cc
index c33906f..d37461f7 100644
--- a/chrome/browser/ash/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/ash/login/existing_user_controller_browsertest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/arc/session/arc_session_manager.h"
-#include "chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h"
 #include "chrome/browser/ash/login/existing_user_controller.h"
 #include "chrome/browser/ash/login/help_app_launcher.h"
 #include "chrome/browser/ash/login/helper.h"
@@ -64,7 +63,6 @@
 #include "chrome/test/base/fake_gaia_mixin.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h"
 #include "chromeos/ash/components/login/auth/public/key.h"
diff --git a/chrome/browser/ash/login/existing_user_controller_forced_online_auth_unittest.cc b/chrome/browser/ash/login/existing_user_controller_forced_online_auth_unittest.cc
deleted file mode 100644
index 4ada266e..0000000
--- a/chrome/browser/ash/login/existing_user_controller_forced_online_auth_unittest.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string>
-#include <utility>
-
-#include "base/time/clock.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h"
-#include "chrome/browser/ash/login/existing_user_controller.h"
-#include "chrome/browser/ash/login/existing_user_controller_base_test.h"
-#include "chrome/browser/ash/login/saml/password_sync_token_checkers_collection.h"
-#include "chrome/browser/ash/login/saml/password_sync_token_fetcher.h"
-#include "chrome/browser/ash/login/saml/password_sync_token_login_checker.h"
-#include "chrome/browser/ash/login/ui/mock_login_display_host.h"
-#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
-#include "chrome/browser/browser_process.h"
-#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
-#include "components/user_manager/known_user.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-namespace {
-
-using ::testing::Return;
-
-const char kSamlToken1[] = "saml-token-1";
-const char kSamlToken2[] = "saml-token-2";
-
-constexpr base::TimeDelta kLoginOnlineShortDelay = base::Seconds(10);
-
-}  // namespace
-
-class ExistingUserControllerForcedOnlineAuthTest
-    : public ExistingUserControllerBaseTest {
- public:
-  ExistingUserControllerForcedOnlineAuthTest() {
-    mock_login_display_host_ = std::make_unique<MockLoginDisplayHost>();
-    settings_helper_.ReplaceDeviceSettingsProviderWithStub();
-    existing_user_controller_ = std::make_unique<ExistingUserController>();
-
-    ON_CALL(*mock_login_display_host_, GetExistingUserController())
-        .WillByDefault(Return(existing_user_controller_.get()));
-  }
-
-  ExistingUserController* existing_user_controller() const {
-    return ExistingUserController::current_controller();
-  }
-
-  int password_sync_token_checkers_size() {
-    if (!existing_user_controller()->sync_token_checkers_)
-      return 0;
-    return existing_user_controller()
-        ->sync_token_checkers_->sync_token_checkers_.size();
-  }
-
-  PasswordSyncTokenLoginChecker* get_password_sync_token_checker(
-      std::string token) {
-    return existing_user_controller()
-        ->sync_token_checkers_->sync_token_checkers_[token]
-        .get();
-  }
-
-  void set_hide_user_names_on_signin() {
-    settings_helper_.SetBoolean(kAccountsPrefShowUserNamesOnSignIn, false);
-  }
-
- private:
-  std::unique_ptr<MockLoginDisplayHost> mock_login_display_host_;
-
-  // Required by ExistingUserController:
-  ScopedCrosSettingsTestHelper settings_helper_;
-  ArcKioskAppManager arc_kiosk_app_manager_;
-
-  std::unique_ptr<ExistingUserController> existing_user_controller_;
-};
-
-// Tests creation of password sync token checker for 2 SAML users. Only one of
-// them has local copy of password sync token.
-TEST_F(ExistingUserControllerForcedOnlineAuthTest,
-       SyncTokenCheckersCreationWithOneToken) {
-  user_manager::KnownUser known_user(g_browser_process->local_state());
-  known_user.SetPasswordSyncToken(saml_login_account1_id_, kSamlToken1);
-  set_hide_user_names_on_signin();
-  auto* user_manager = GetFakeUserManager();
-  user_manager->AddSamlUser(saml_login_account1_id_);
-  user_manager->AddSamlUser(saml_login_account2_id_);
-  existing_user_controller()->Init(user_manager->GetUsers());
-  EXPECT_EQ(password_sync_token_checkers_size(), 1);
-  get_password_sync_token_checker(kSamlToken1)->OnTokenVerified(true);
-  task_environment_.FastForwardBy(kLoginOnlineShortDelay);
-  EXPECT_TRUE(get_password_sync_token_checker(kSamlToken1)->IsCheckPending());
-}
-
-// Tests creation of password sync token checker for 2 SAML users with password
-// sync tokens.
-TEST_F(ExistingUserControllerForcedOnlineAuthTest,
-       SyncTokenCheckersCreationWithTwoTokens) {
-  user_manager::KnownUser known_user(g_browser_process->local_state());
-  known_user.SetPasswordSyncToken(saml_login_account1_id_, kSamlToken1);
-  known_user.SetPasswordSyncToken(saml_login_account2_id_, kSamlToken2);
-
-  set_hide_user_names_on_signin();
-  auto* user_manager = GetFakeUserManager();
-  user_manager->AddSamlUser(saml_login_account1_id_);
-  user_manager->AddSamlUser(saml_login_account2_id_);
-  existing_user_controller()->Init(user_manager->GetUsers());
-  EXPECT_EQ(password_sync_token_checkers_size(), 2);
-  get_password_sync_token_checker(kSamlToken1)
-      ->OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType::kServerError);
-  task_environment_.FastForwardBy(kLoginOnlineShortDelay);
-  EXPECT_TRUE(get_password_sync_token_checker(kSamlToken1)->IsCheckPending());
-}
-
-// Tests sync token checkers removal in case of failed token validation.
-TEST_F(ExistingUserControllerForcedOnlineAuthTest,
-       SyncTokenCheckersInvalidPasswordForTwoUsers) {
-  user_manager::KnownUser known_user(g_browser_process->local_state());
-  known_user.SetPasswordSyncToken(saml_login_account1_id_, kSamlToken1);
-  known_user.SetPasswordSyncToken(saml_login_account2_id_, kSamlToken2);
-
-  set_hide_user_names_on_signin();
-  auto* user_manager = GetFakeUserManager();
-  user_manager->AddSamlUser(saml_login_account1_id_);
-  user_manager->AddSamlUser(saml_login_account2_id_);
-  existing_user_controller()->Init(user_manager->GetUsers());
-  EXPECT_EQ(password_sync_token_checkers_size(), 2);
-  get_password_sync_token_checker(kSamlToken1)->OnTokenVerified(false);
-  get_password_sync_token_checker(kSamlToken2)->OnTokenVerified(false);
-  EXPECT_EQ(password_sync_token_checkers_size(), 0);
-}
-
-// Sync token checkers are not owned by ExistingUserController if user pods are
-// visible.
-TEST_F(ExistingUserControllerForcedOnlineAuthTest,
-       NoSyncTokenCheckersWhenPodsVisible) {
-  user_manager::KnownUser known_user(g_browser_process->local_state());
-  known_user.SetPasswordSyncToken(saml_login_account1_id_, kSamlToken1);
-  known_user.SetPasswordSyncToken(saml_login_account2_id_, kSamlToken2);
-
-  auto* user_manager = GetFakeUserManager();
-  user_manager->AddSamlUser(saml_login_account1_id_);
-  user_manager->AddSamlUser(saml_login_account2_id_);
-  existing_user_controller()->Init(user_manager->GetUsers());
-  EXPECT_EQ(password_sync_token_checkers_size(), 0);
-}
-
-}  // namespace ash
diff --git a/chrome/browser/ash/login/screens/active_directory_password_change_screen.cc b/chrome/browser/ash/login/screens/active_directory_password_change_screen.cc
deleted file mode 100644
index 2603e30..0000000
--- a/chrome/browser/ash/login/screens/active_directory_password_change_screen.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/login/screens/active_directory_password_change_screen.h"
-
-#include <memory>
-
-#include "base/check_op.h"
-#include "base/functional/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ash/login/ui/login_display_host.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h"
-#include "chrome/grit/generated_resources.h"
-#include "chromeos/ash/components/login/auth/public/cryptohome_key_constants.h"
-#include "chromeos/ash/components/login/auth/public/key.h"
-#include "components/user_manager/known_user.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace ash {
-namespace {
-
-constexpr char kUserActionCancel[] = "cancel";
-
-// Possible error states of the Active Directory password change screen. Must be
-// in the same order as ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE enum
-// values.
-enum class ActiveDirectoryPasswordChangeErrorState {
-  NO_ERROR = 0,
-  WRONG_OLD_PASSWORD = 1,
-  NEW_PASSWORD_REJECTED = 2,
-};
-
-}  // namespace
-
-ActiveDirectoryPasswordChangeScreen::ActiveDirectoryPasswordChangeScreen(
-    base::WeakPtr<TView> view,
-    const base::RepeatingClosure& exit_callback)
-    : BaseScreen(TView::kScreenId, OobeScreenPriority::DEFAULT),
-      authpolicy_login_helper_(std::make_unique<AuthPolicyHelper>()),
-      view_(std::move(view)),
-      exit_callback_(exit_callback) {}
-
-ActiveDirectoryPasswordChangeScreen::~ActiveDirectoryPasswordChangeScreen() =
-    default;
-
-void ActiveDirectoryPasswordChangeScreen::SetUsername(
-    const std::string& username) {
-  username_ = username;
-}
-
-void ActiveDirectoryPasswordChangeScreen::ShowImpl() {
-  if (!view_)
-    return;
-  view_->Show(
-      username_,
-      static_cast<int>(ActiveDirectoryPasswordChangeErrorState::NO_ERROR));
-}
-
-void ActiveDirectoryPasswordChangeScreen::HideImpl() {
-  username_.clear();
-}
-
-void ActiveDirectoryPasswordChangeScreen::OnUserAction(
-    const base::Value::List& args) {
-  const std::string& action_id = args[0].GetString();
-  if (action_id == kUserActionCancel) {
-    HandleCancel();
-    return;
-  }
-  if (action_id == "changePassword") {
-    CHECK_EQ(3u, args.size());
-    const std::string& old_password = args[1].GetString();
-    const std::string& new_password = args[2].GetString();
-    HandleChangePassword(old_password, new_password);
-    return;
-  }
-  BaseScreen::OnUserAction(args);
-}
-
-void ActiveDirectoryPasswordChangeScreen::HandleCancel() {
-  authpolicy_login_helper_->CancelRequestsAndRestart();
-  exit_callback_.Run();
-}
-
-void ActiveDirectoryPasswordChangeScreen::HandleChangePassword(
-    const std::string& old_password,
-    const std::string& new_password) {
-  DCHECK(!old_password.empty() && !new_password.empty())
-      << "Empty passwords should have been blocked in the UI";
-
-  // The Cryptohome key label is required when changing the password of an
-  // ephemeral user or a new user. Without this label, the login will fail
-  // with a Cryptohome mount error. For historical reasons, Active Directory
-  // users have the same label as GAIA users.
-  Key key(new_password);
-  key.SetLabel(kCryptohomeGaiaKeyLabel);
-
-  DCHECK(authpolicy_login_helper_);
-  authpolicy_login_helper_->AuthenticateUser(
-      username_, std::string() /* object_guid */,
-      old_password + "\n" + new_password + "\n" + new_password,
-      base::BindOnce(&ActiveDirectoryPasswordChangeScreen::OnAuthFinished,
-                     weak_factory_.GetWeakPtr(), username_, key));
-}
-
-void ActiveDirectoryPasswordChangeScreen::OnAuthFinished(
-    const std::string& username,
-    const Key& key,
-    authpolicy::ErrorType error,
-    const authpolicy::ActiveDirectoryAccountInfo& account_info) {
-  switch (error) {
-    case authpolicy::ERROR_NONE: {
-      DCHECK(account_info.has_account_id() &&
-             !account_info.account_id().empty());
-      user_manager::KnownUser known_user(g_browser_process->local_state());
-      const AccountId account_id = known_user.GetAccountId(
-          username, account_info.account_id(), AccountType::ACTIVE_DIRECTORY);
-      DCHECK(LoginDisplayHost::default_host());
-      LoginDisplayHost::default_host()->SetDisplayAndGivenName(
-          account_info.display_name(), account_info.given_name());
-      UserContext user_context(
-          user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY, account_id);
-      user_context.SetKey(key);
-      user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
-      user_context.SetIsUsingOAuth(false);
-      LoginDisplayHost::default_host()->CompleteLogin(user_context);
-      break;
-    }
-    case authpolicy::ERROR_BAD_PASSWORD:
-      if (view_) {
-        view_->Show(
-            username_,
-            static_cast<int>(
-                ActiveDirectoryPasswordChangeErrorState::WRONG_OLD_PASSWORD));
-      }
-      break;
-    case authpolicy::ERROR_PASSWORD_REJECTED:
-      if (view_) {
-        view_->Show(username_,
-                    static_cast<int>(ActiveDirectoryPasswordChangeErrorState::
-                                         NEW_PASSWORD_REJECTED));
-        view_->ShowSignInError(l10n_util::GetStringUTF8(
-            IDS_AD_PASSWORD_CHANGE_NEW_PASSWORD_REJECTED_LONG_ERROR));
-      }
-      break;
-    default:
-      NOTREACHED() << "Unhandled error: " << error;
-      if (view_) {
-        view_->Show(username_,
-                    static_cast<int>(
-                        ActiveDirectoryPasswordChangeErrorState::NO_ERROR));
-        view_->ShowSignInError(
-            l10n_util::GetStringUTF8(IDS_AD_AUTH_UNKNOWN_ERROR));
-      }
-  }
-}
-
-}  // namespace ash
diff --git a/chrome/browser/ash/login/screens/active_directory_password_change_screen.h b/chrome/browser/ash/login/screens/active_directory_password_change_screen.h
deleted file mode 100644
index 7786ad7..0000000
--- a/chrome/browser/ash/login/screens/active_directory_password_change_screen.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_LOGIN_SCREENS_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_H_
-#define CHROME_BROWSER_ASH_LOGIN_SCREENS_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ash/authpolicy/authpolicy_helper.h"
-#include "chrome/browser/ash/login/screen_manager.h"
-#include "chrome/browser/ash/login/screens/base_screen.h"
-
-namespace authpolicy {
-class ActiveDirectoryAccountInfo;
-}
-
-namespace ash {
-
-class ActiveDirectoryPasswordChangeView;
-class Key;
-
-// Controller for the active directory password change screen.
-class ActiveDirectoryPasswordChangeScreen : public BaseScreen {
- public:
-  using TView = ActiveDirectoryPasswordChangeView;
-
-  ActiveDirectoryPasswordChangeScreen(
-      base::WeakPtr<TView> view,
-      const base::RepeatingClosure& exit_callback);
-  ActiveDirectoryPasswordChangeScreen(
-      const ActiveDirectoryPasswordChangeScreen&) = delete;
-  ActiveDirectoryPasswordChangeScreen& operator=(
-      const ActiveDirectoryPasswordChangeScreen&) = delete;
-  ~ActiveDirectoryPasswordChangeScreen() override;
-
-  // Set username.
-  void SetUsername(const std::string& username);
-
- private:
-  // BaseScreen:
-  void ShowImpl() override;
-  void HideImpl() override;
-  void OnUserAction(const base::Value::List& args) override;
-
-  // Handles cancel password change request.
-  void HandleCancel();
-
-  // Handles password change request.
-  void HandleChangePassword(const std::string& old_password,
-                            const std::string& new_password);
-
-  // Callback called by AuthPolicyHelper::AuthenticateUser with results and
-  // error code. (see AuthPolicyHelper::AuthenticateUser)
-  void OnAuthFinished(
-      const std::string& username,
-      const Key& key,
-      authpolicy::ErrorType error,
-      const authpolicy::ActiveDirectoryAccountInfo& account_info);
-
-  std::string username_;
-
-  // Helper to call AuthPolicyClient and cancel calls if needed. Used to change
-  // password on the Active Directory server.
-  std::unique_ptr<AuthPolicyHelper> authpolicy_login_helper_;
-
-  base::WeakPtr<TView> view_;
-
-  base::RepeatingClosure exit_callback_;
-
-  base::WeakPtrFactory<ActiveDirectoryPasswordChangeScreen> weak_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_LOGIN_SCREENS_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_H_
diff --git a/chrome/browser/ash/login/session/user_session_initializer.cc b/chrome/browser/ash/login/session/user_session_initializer.cc
index 167db5ca..cd2b14a 100644
--- a/chrome/browser/ash/login/session/user_session_initializer.cc
+++ b/chrome/browser/ash/login/session/user_session_initializer.cc
@@ -6,7 +6,8 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
-#include "base/feature_list.h"
+#include "ash/shell.h"
+#include "ash/system/media/media_notification_provider.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/system/sys_info.h"
@@ -300,6 +301,8 @@
         settings::PeripheralDataAccessHandler::GetPrefState());
 
     CrasAudioHandler::Get()->RefreshNoiseCancellationState();
+
+    Shell::Get()->media_notification_provider()->OnPrimaryUserSessionStarted();
   }
 }
 
diff --git a/chrome/browser/ash/login/test/session_flags_manager.cc b/chrome/browser/ash/login/test/session_flags_manager.cc
index d2cfb52..b9affe9 100644
--- a/chrome/browser/ash/login/test/session_flags_manager.cc
+++ b/chrome/browser/ash/login/test/session_flags_manager.cc
@@ -18,15 +18,13 @@
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
-#include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "components/user_manager/user_names.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 
-namespace ash {
-namespace test {
+namespace ash::test {
 namespace {
 
 // Keys for values in dictionary used to preserve session manager state.
@@ -74,8 +72,9 @@
     DCHECK_EQ(mode_, Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE);
     for (const auto& item : *restart_job_) {
       // Do not override flags added to test command line by default.
-      if (command_line->HasSwitch(item.first))
+      if (command_line->HasSwitch(item.first)) {
         continue;
+      }
       command_line->AppendSwitchASCII(item.first, item.second);
     }
   }
@@ -104,8 +103,9 @@
 }
 
 void SessionFlagsManager::Finalize() {
-  if (finalized_ || mode_ != Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE)
+  if (finalized_ || mode_ != Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE) {
     return;
+  }
 
   finalized_ = true;
   StoreStateToBackingFile();
@@ -119,8 +119,9 @@
   int error_code = 0;
   std::unique_ptr<base::Value> value =
       deserializer.Deserialize(&error_code, nullptr);
-  if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR)
+  if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR) {
     return;
+  }
 
   base::Value::Dict& value_dict = value->GetDict();
   const std::string* user_id = value_dict.FindString(kUserIdKey);
@@ -188,14 +189,14 @@
     user_profile = it->second;
   }
 
-  base::Value cached_state(base::Value::Type::DICT);
+  base::Value::Dict cached_state;
 
   // Restart job command line should already contain login user and profile
   // switches, no reason to store it separately.
   if (!has_restart_job && !user_id.empty()) {
     DCHECK(!user_profile.empty());
-    cached_state.SetKey(kUserIdKey, base::Value(user_id));
-    cached_state.SetKey(kUserHashKey, base::Value(user_profile));
+    cached_state.Set(kUserIdKey, user_id);
+    cached_state.Set(kUserHashKey, user_profile);
   }
 
   std::vector<Switch> user_flag_args;
@@ -207,7 +208,7 @@
   if (has_user_flags) {
     std::vector<std::string> argv = {"" /* Empty program */};
     argv.insert(argv.end(), raw_flags.begin(), raw_flags.end());
-    cached_state.SetKey(kUserFlagsKey, GetSwitchesValueFromArgv(argv));
+    cached_state.Set(kUserFlagsKey, GetSwitchesValueFromArgv(argv));
   }
 
   if (has_restart_job) {
@@ -219,14 +220,14 @@
     DCHECK(base::Contains(
         argv, base::StringPrintf("--%s=%s", switches::kLoginProfile, "user")));
 
-    cached_state.SetKey(kRestartJobKey, GetSwitchesValueFromArgv(argv));
+    cached_state.Set(kRestartJobKey, GetSwitchesValueFromArgv(argv));
   }
 
   JSONFileValueSerializer serializer(backing_file_);
   serializer.Serialize(cached_state);
 }
 
-base::Value SessionFlagsManager::GetSwitchesValueFromArgv(
+base::Value::List SessionFlagsManager::GetSwitchesValueFromArgv(
     const std::vector<std::string>& argv) {
   // Parse flag name-value pairs using command line initialization.
   base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
@@ -234,14 +235,12 @@
 
   base::Value::List flag_list;
   for (const auto& flag : cmd_line.GetSwitches()) {
-    base::Value::Dict flag_value;
-    flag_value.Set(kFlagNameKey, flag.first);
-    flag_value.Set(kFlagValueKey, flag.second);
-
+    auto flag_value = base::Value::Dict()
+                          .Set(kFlagNameKey, flag.first)
+                          .Set(kFlagValueKey, flag.second);
     flag_list.Append(std::move(flag_value));
   }
-  return base::Value(std::move(flag_list));
+  return flag_list;
 }
 
-}  // namespace test
-}  // namespace ash
+}  // namespace ash::test
diff --git a/chrome/browser/ash/login/test/session_flags_manager.h b/chrome/browser/ash/login/test/session_flags_manager.h
index eed28bf..f47c33e 100644
--- a/chrome/browser/ash/login/test/session_flags_manager.h
+++ b/chrome/browser/ash/login/test/session_flags_manager.h
@@ -10,15 +10,14 @@
 #include <vector>
 
 #include "base/files/file_path.h"
+#include "base/values.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 class CommandLine;
-class Value;
 }  // namespace base
 
-namespace ash {
-namespace test {
+namespace ash::test {
 
 // Test helper that sets up command line for login tests. By default, it
 // initializes the command line so tests start on the login manager.
@@ -86,7 +85,8 @@
 
   void LoadStateFromBackingFile();
   void StoreStateToBackingFile();
-  base::Value GetSwitchesValueFromArgv(const std::vector<std::string>& argv);
+  base::Value::List GetSwitchesValueFromArgv(
+      const std::vector<std::string>& argv);
 
   // The mode this manager is running in.
   Mode mode_ = Mode::LOGIN_SCREEN;
@@ -112,7 +112,6 @@
   base::FilePath backing_file_;
 };
 
-}  // namespace test
-}  // namespace ash
+}  // namespace ash::test
 
 #endif  // CHROME_BROWSER_ASH_LOGIN_TEST_SESSION_FLAGS_MANAGER_H_
diff --git a/chrome/browser/ash/login/ui/login_display_host_webui.cc b/chrome/browser/ash/login/ui/login_display_host_webui.cc
index 2e1719fe..a4bd2012 100644
--- a/chrome/browser/ash/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/ash/login/ui/login_display_host_webui.cc
@@ -565,9 +565,9 @@
     }
     ash::Shell::Get()
         ->booting_animation_controller()
-        ->ShowAnimationWithEndCallback(
-            base::BindOnce(&LoginDisplayHostWebUI::BootingAnimationFinished,
-                           weak_factory_.GetWeakPtr()));
+        ->ShowAnimationWithEndCallback(base::BindOnce(
+            &LoginDisplayHostWebUI::OnViewsBootingAnimationPlayed,
+            weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -705,13 +705,22 @@
   ShowWebUI();
 }
 
-void LoginDisplayHostWebUI::BootingAnimationFinished() {
+void LoginDisplayHostWebUI::OnViewsBootingAnimationPlayed() {
+  booting_animation_finished_playing_ = true;
+  if (webui_ready_to_take_over_) {
+    // This function is called by the AnimationObserver which can't destroy the
+    // animation on its own so we need to post a task to do so.
+    content::GetUIThreadTaskRunner({})->PostTask(
+        FROM_HERE,
+        base::BindOnce(&LoginDisplayHostWebUI::FinishBootingAnimation,
+                       weak_factory_.GetWeakPtr()));
+  }
+}
+
+void LoginDisplayHostWebUI::FinishBootingAnimation() {
   CHECK(features::IsOobeSimonEnabled());
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &BootingAnimationController::Finish,
-          ash::Shell::Get()->booting_animation_controller()->GetWeakPtr()));
+  ash::Shell::Get()->booting_animation_controller()->Finish();
+  GetOobeUI()->GetCoreOobeView()->TriggerDown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -770,6 +779,13 @@
   }
 }
 
+void LoginDisplayHostWebUI::OnBackdropLoaded() {
+  webui_ready_to_take_over_ = true;
+  if (booting_animation_finished_playing_) {
+    FinishBootingAnimation();
+  }
+}
+
 void LoginDisplayHostWebUI::OnDestroyingOobeUI() {
   GetOobeUI()->RemoveObserver(this);
 }
diff --git a/chrome/browser/ash/login/ui/login_display_host_webui.h b/chrome/browser/ash/login/ui/login_display_host_webui.h
index 40a8821..81d38ec3 100644
--- a/chrome/browser/ash/login/ui/login_display_host_webui.h
+++ b/chrome/browser/ash/login/ui/login_display_host_webui.h
@@ -153,6 +153,7 @@
   // OobeUI::Observer:
   void OnCurrentScreenChanged(OobeScreenId current_screen,
                               OobeScreenId new_screen) override;
+  void OnBackdropLoaded() override;
   void OnDestroyingOobeUI() override;
 
   // LoginDisplayHostCommon:
@@ -208,9 +209,12 @@
   // Show OOBE WebUI if signal from javascript side never came.
   void OnShowWebUITimeout();
 
-  // Callback that is called once booting animation has finished running, but
-  // the last frame is still shown.
-  void BootingAnimationFinished();
+  // Callback that is called once booting animation in views has finished
+  // running, but the last frame is still shown.
+  void OnViewsBootingAnimationPlayed();
+
+  // Finishes booting animation in views and triggers the WebUI part.
+  void FinishBootingAnimation();
 
   // Sign in screen controller.
   std::unique_ptr<ExistingUserController> existing_user_controller_;
@@ -260,6 +264,13 @@
   // True if we need to play startup sound when audio device becomes available.
   bool need_to_play_startup_sound_ = false;
 
+  // True if WebUI has loaded the minimum UI that can be shown. It is used to
+  // synchronize the booting animation between views and WebUI.
+  bool webui_ready_to_take_over_ = false;
+
+  // True if booting animation has finished playing.
+  bool booting_animation_finished_playing_ = false;
+
   // Measures OOBE WebUI load time.
   absl::optional<base::ElapsedTimer> oobe_load_timer_;
 
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index 59b8b518..58ffa16 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -51,7 +51,6 @@
 #include "chrome/browser/ash/login/login_wizard.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
-#include "chrome/browser/ash/login/screens/active_directory_password_change_screen.h"
 #include "chrome/browser/ash/login/screens/app_downloading_screen.h"
 #include "chrome/browser/ash/login/screens/arc_vm_data_migration_screen.h"
 #include "chrome/browser/ash/login/screens/assistant_optin_flow_screen.h"
@@ -131,7 +130,6 @@
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/app_downloading_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/app_launch_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/arc_vm_data_migration_screen_handler.h"
@@ -789,13 +787,6 @@
     append(std::move(gaia_password_change_screen));
   }
 
-  append(std::make_unique<ActiveDirectoryPasswordChangeScreen>(
-      oobe_ui->GetView<ActiveDirectoryPasswordChangeScreenHandler>()
-          ->AsWeakPtr(),
-      base::BindRepeating(
-          &WizardController::OnActiveDirectoryPasswordChangeScreenExit,
-          weak_factory_.GetWeakPtr())));
-
   append(std::make_unique<FamilyLinkNoticeScreen>(
       oobe_ui->GetView<FamilyLinkNoticeScreenHandler>()->AsWeakPtr(),
       base::BindRepeating(&WizardController::OnFamilyLinkNoticeScreenExit,
@@ -1170,12 +1161,6 @@
   }
 }
 
-void WizardController::ShowActiveDirectoryPasswordChangeScreen(
-    const std::string& username) {
-  GetScreen<ActiveDirectoryPasswordChangeScreen>()->SetUsername(username);
-  AdvanceToScreen(ActiveDirectoryPasswordChangeView::kScreenId);
-}
-
 void WizardController::ShowLacrosDataMigrationScreen() {
   SetCurrentScreen(GetScreen(LacrosDataMigrationScreenView::kScreenId));
 }
@@ -1199,12 +1184,6 @@
   SetCurrentScreen(GetScreen(CryptohomeRecoveryScreenView::kScreenId));
 }
 
-void WizardController::OnActiveDirectoryPasswordChangeScreenExit() {
-  OnScreenExit(ActiveDirectoryPasswordChangeView::kScreenId,
-               kDefaultExitReason);
-  ShowLoginScreen();
-}
-
 void WizardController::OnUserCreationScreenExit(
     UserCreationScreen::Result result) {
   OnScreenExit(UserCreationView::kScreenId,
@@ -2480,7 +2459,6 @@
     ShowGaiaInfoScreen();
   } else if (screen_id == TpmErrorView::kScreenId ||
              screen_id == GaiaPasswordChangedView::kScreenId ||
-             screen_id == ActiveDirectoryPasswordChangeView::kScreenId ||
              screen_id == FamilyLinkNoticeView::kScreenId ||
              screen_id == GaiaView::kScreenId ||
              screen_id == UserCreationView::kScreenId ||
diff --git a/chrome/browser/ash/login/wizard_controller.h b/chrome/browser/ash/login/wizard_controller.h
index fd6b939..59f48c6 100644
--- a/chrome/browser/ash/login/wizard_controller.h
+++ b/chrome/browser/ash/login/wizard_controller.h
@@ -237,9 +237,6 @@
   void ShowGaiaPasswordChangedScreenLegacy(const AccountId& account_id,
                                            bool has_error);
 
-  // Configure and show active directory password change screen.
-  void ShowActiveDirectoryPasswordChangeScreen(const std::string& username);
-
   // Configure and show the signin fatal error screen.
   void ShowSignInFatalErrorScreen(SignInFatalErrorScreen::Error error,
                                   base::Value::Dict params);
@@ -349,8 +346,7 @@
   // `exit_reason` is the screen specific exit reason reported by the screen.
   void OnScreenExit(OobeScreenId screen, const std::string& exit_reason);
 
-  // Advances either to Gaia screen or Active Directory login screen, depending
-  // on the device state.
+  // Advances to Gaia login screen.
   void AdvanceToSigninScreen();
 
   // Exit handlers:
@@ -390,7 +386,6 @@
   void OnUpdateRequiredScreenExit();
   void OnOobeFlowFinished();
   void OnPackagedLicenseScreenExit(PackagedLicenseScreen::Result result);
-  void OnActiveDirectoryPasswordChangeScreenExit();
   void OnFamilyLinkNoticeScreenExit(FamilyLinkNoticeScreen::Result result);
   void OnUserCreationScreenExit(UserCreationScreen::Result result);
   void OnGaiaScreenExit(GaiaScreen::Result result);
diff --git a/chrome/browser/ash/policy/affiliation/affiliation_mixin.cc b/chrome/browser/ash/policy/affiliation/affiliation_mixin.cc
index 7a1172f..faf0ac0 100644
--- a/chrome/browser/ash/policy/affiliation/affiliation_mixin.cc
+++ b/chrome/browser/ash/policy/affiliation/affiliation_mixin.cc
@@ -10,8 +10,6 @@
 #include "base/strings/string_piece.h"
 #include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h"
 #include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
-#include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
@@ -33,8 +31,6 @@
 
 constexpr char kAffiliatedUserEmail[] = "affiliateduser@example.com";
 constexpr char kAffiliatedUserGaiaId[] = "1029384756";
-constexpr char kAffiliatedUserObjGuid[] =
-    "{11111111-1111-1111-1111-111111111111}";
 
 }  // namespace
 
@@ -61,29 +57,9 @@
       std::array{affiliated_ ? kAffiliationID : kAnotherAffiliationID}));
 }
 
-void AffiliationMixin::SetIsForActiveDirectory(bool is_for_active_directory) {
-  if (is_for_active_directory == is_for_active_directory_)
-    return;
-
-  is_for_active_directory_ = is_for_active_directory;
-  if (is_for_active_directory) {
-    account_id_ = AccountId::AdFromUserEmailObjGuid(kAffiliatedUserEmail,
-                                                    kAffiliatedUserObjGuid);
-  } else {
-    account_id_ = AccountId::FromUserEmailGaiaId(kAffiliatedUserEmail,
-                                                 kAffiliatedUserGaiaId);
-  }
-}
-
 AffiliationTestHelper AffiliationMixin::GetAffiliationTestHelper() const {
   auto* session_manager_client = ash::FakeSessionManagerClient::Get();
   CHECK(session_manager_client);
-  if (is_for_active_directory_) {
-    auto* fake_auth_policy_client = ash::FakeAuthPolicyClient::Get();
-    CHECK(fake_auth_policy_client);
-    return AffiliationTestHelper::CreateForActiveDirectory(
-        session_manager_client, fake_auth_policy_client);
-  }
   return AffiliationTestHelper::CreateForCloud(session_manager_client);
 }
 
diff --git a/chrome/browser/ash/policy/affiliation/affiliation_mixin.h b/chrome/browser/ash/policy/affiliation/affiliation_mixin.h
index ae05a767..b9ff429 100644
--- a/chrome/browser/ash/policy/affiliation/affiliation_mixin.h
+++ b/chrome/browser/ash/policy/affiliation/affiliation_mixin.h
@@ -39,11 +39,6 @@
   // Returns the account id of the user.
   AccountId account_id() const { return account_id_; }
 
-  // Sets if the user is an Active Directory user. False by default. Needs to be
-  // called before SetUp to have an effect (e.g., directly after mixin
-  // construction).
-  void SetIsForActiveDirectory(bool is_for_active_directory);
-
   // Sets if the user is affiliated with the device. True by default. Needs to
   // be called before SetUp to have an effect (e.g., directly after mixin
   // construction).
@@ -61,7 +56,6 @@
   const raw_ptr<DevicePolicyCrosTestHelper, ExperimentalAsh>
       policy_test_helper_;
   bool affiliated_ = true;
-  bool is_for_active_directory_ = false;
   AccountId account_id_;
   std::unique_ptr<UserPolicyBuilder> user_policy_;
 };
diff --git a/chrome/browser/ash/policy/affiliation/affiliation_test_helper.cc b/chrome/browser/ash/policy/affiliation/affiliation_test_helper.cc
index 9d61e14..26f4494 100644
--- a/chrome/browser/ash/policy/affiliation/affiliation_test_helper.cc
+++ b/chrome/browser/ash/policy/affiliation/affiliation_test_helper.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
@@ -80,37 +79,20 @@
 // static
 AffiliationTestHelper AffiliationTestHelper::CreateForCloud(
     ash::FakeSessionManagerClient* fake_session_manager_client) {
-  return AffiliationTestHelper(ManagementType::kCloud,
-                               fake_session_manager_client,
-                               nullptr /* fake_authpolicy_client */);
-}
-
-// static
-AffiliationTestHelper AffiliationTestHelper::CreateForActiveDirectory(
-    ash::FakeSessionManagerClient* fake_session_manager_client,
-    ash::FakeAuthPolicyClient* fake_authpolicy_client) {
-  return AffiliationTestHelper(ManagementType::kActiveDirectory,
-                               fake_session_manager_client,
-                               fake_authpolicy_client);
+  return AffiliationTestHelper(fake_session_manager_client);
 }
 
 AffiliationTestHelper::AffiliationTestHelper(AffiliationTestHelper&& other) =
     default;
 
 AffiliationTestHelper::AffiliationTestHelper(
-    ManagementType management_type,
-    ash::FakeSessionManagerClient* fake_session_manager_client,
-    ash::FakeAuthPolicyClient* fake_authpolicy_client)
-    : management_type_(management_type),
-      fake_session_manager_client_(fake_session_manager_client),
-      fake_authpolicy_client_(fake_authpolicy_client) {
+    ash::FakeSessionManagerClient* fake_session_manager_client)
+    : fake_session_manager_client_(fake_session_manager_client) {
   DCHECK(fake_session_manager_client);
 }
 
 void AffiliationTestHelper::CheckPreconditions() {
   ASSERT_TRUE(fake_session_manager_client_);
-  ASSERT_TRUE(management_type_ != ManagementType::kActiveDirectory ||
-              fake_authpolicy_client_);
 }
 
 void AffiliationTestHelper::SetDeviceAffiliationIDs(
@@ -123,18 +105,12 @@
     device_policy->policy_data().add_device_affiliation_ids(
         std::string(device_affiliation_id));
   }
-  if (management_type_ != ManagementType::kActiveDirectory) {
-    // Create keys and sign policy. Note that Active Directory policy is
-    // unsigned.
-    device_policy->SetDefaultSigningKey();
-  }
+  // Create keys and sign policy.
+  device_policy->SetDefaultSigningKey();
   device_policy->Build();
 
   fake_session_manager_client_->set_device_policy(device_policy->GetBlob());
   fake_session_manager_client_->OnPropertyChangeComplete(true);
-
-  if (management_type_ == ManagementType::kActiveDirectory)
-    fake_authpolicy_client_->set_device_affiliation_ids(device_affiliation_ids);
 }
 
 void AffiliationTestHelper::SetUserAffiliationIDs(
@@ -142,15 +118,10 @@
     const AccountId& user_account_id,
     const base::span<const base::StringPiece>& user_affiliation_ids) {
   ASSERT_NO_FATAL_FAILURE(CheckPreconditions());
-  ASSERT_TRUE(management_type_ != ManagementType::kActiveDirectory ||
-              user_account_id.GetAccountType() ==
-                  AccountType::ACTIVE_DIRECTORY);
 
   user_policy->policy_data().set_username(user_account_id.GetUserEmail());
-  if (management_type_ != ManagementType::kActiveDirectory) {
-    user_policy->policy_data().set_gaia_id(user_account_id.GetGaiaId());
-    ASSERT_NO_FATAL_FAILURE(SetUserKeys(*user_policy));
-  }
+  user_policy->policy_data().set_gaia_id(user_account_id.GetGaiaId());
+  ASSERT_NO_FATAL_FAILURE(SetUserKeys(*user_policy));
   for (const auto& user_affiliation_id : user_affiliation_ids) {
     user_policy->policy_data().add_user_affiliation_ids(
         std::string(user_affiliation_id));
@@ -160,9 +131,6 @@
   fake_session_manager_client_->set_user_policy(
       cryptohome::CreateAccountIdentifierFromAccountId(user_account_id),
       user_policy->GetBlob());
-
-  if (management_type_ == ManagementType::kActiveDirectory)
-    fake_authpolicy_client_->set_user_affiliation_ids(user_affiliation_ids);
 }
 
 // static
diff --git a/chrome/browser/ash/policy/affiliation/affiliation_test_helper.h b/chrome/browser/ash/policy/affiliation/affiliation_test_helper.h
index f05cc093..ca3372b 100644
--- a/chrome/browser/ash/policy/affiliation/affiliation_test_helper.h
+++ b/chrome/browser/ash/policy/affiliation/affiliation_test_helper.h
@@ -13,7 +13,6 @@
 class AccountId;
 
 namespace ash {
-class FakeAuthPolicyClient;
 class FakeSessionManagerClient;
 }  // namespace ash
 
@@ -33,12 +32,6 @@
   static AffiliationTestHelper CreateForCloud(
       ash::FakeSessionManagerClient* fake_session_manager_client);
 
-  // Creates an |AffiliationTestHelper| for Active Directory management (Active
-  // Directory accounts). The pointers must outlive this object.
-  static AffiliationTestHelper CreateForActiveDirectory(
-      ash::FakeSessionManagerClient* fake_session_manager_client,
-      ash::FakeAuthPolicyClient* fake_authpolicy_client);
-
   // Allow move construction, so the static constructors can be used despite
   // deleted constructors.
   AffiliationTestHelper(AffiliationTestHelper&& other);
@@ -83,21 +76,14 @@
   static const char kEnterpriseUserGaiaId[];
 
  private:
-  enum class ManagementType { kCloud, kActiveDirectory };
-
-  AffiliationTestHelper(
-      ManagementType management_type,
-      ash::FakeSessionManagerClient* fake_session_manager_client,
-      ash::FakeAuthPolicyClient* fake_authpolicy_client);
+  explicit AffiliationTestHelper(
+      ash::FakeSessionManagerClient* fake_session_manager_client);
 
   // ASSERTs on pointer validity.
   void CheckPreconditions();
 
-  ManagementType management_type_;
   raw_ptr<ash::FakeSessionManagerClient, ExperimentalAsh>
       fake_session_manager_client_;  // Not owned.
-  raw_ptr<ash::FakeAuthPolicyClient, ExperimentalAsh>
-      fake_authpolicy_client_;  // Not owned.
 };
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc b/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
index 94d872b8..af39d714 100644
--- a/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
+++ b/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
-#include "chromeos/ash/components/dbus/authpolicy/fake_authpolicy_client.h"
 #include "chromeos/ash/components/dbus/dbus_thread_manager.h"
 #include "chromeos/ash/components/dbus/upstart/upstart_client.h"
 #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
@@ -47,22 +46,17 @@
 namespace {
 
 struct Params {
-  Params(bool affiliated, bool active_directory)
-      : affiliated(affiliated), active_directory(active_directory) {}
+  explicit Params(bool affiliated) : affiliated(affiliated) {}
 
   // Whether the user is expected to be affiliated.
   bool affiliated;
-
-  // Whether the user account is an Active Directory account.
-  bool active_directory;
 };
 
 // Must be a valid test name (no spaces etc.). Makes the test show up as e.g.
-// AffiliationCheck/U.A.B.T.Affiliated/NotAffiliated_NotActiveDirectory
+// AffiliationCheck/U.A.B.T.Affiliated/NotAffiliated
 std::string PrintParam(testing::TestParamInfo<Params> param_info) {
-  return base::StringPrintf("%sAffiliated_%sActiveDirectory",
-                            param_info.param.affiliated ? "" : "Not",
-                            param_info.param.active_directory ? "" : "Not");
+  return base::StringPrintf("%sAffiliated",
+                            param_info.param.affiliated ? "" : "Not");
 }
 
 void CheckIsSystemSlotAvailableOnIOThreadWithCertDb(
@@ -116,7 +110,6 @@
  public:
   UserAffiliationBrowserTest() {
     set_exit_when_last_browser_closes(false);
-    affiliation_mixin_.SetIsForActiveDirectory(GetParam().active_directory);
     affiliation_mixin_.set_affiliated(GetParam().affiliated);
   }
 
@@ -150,11 +143,6 @@
     // shutdown in ChromeBrowserMain.
     ash::SessionManagerClient::InitializeFakeInMemory();
     ash::UpstartClient::InitializeFake();
-    if (GetParam().active_directory) {
-      ash::AuthPolicyClient::InitializeFake();
-      ash::FakeAuthPolicyClient::Get()->DisableOperationDelayForTesting();
-    }
-
     // Set retry delay to prevent timeouts.
     DeviceManagementService::SetRetryDelayForTesting(0);
   }
@@ -245,10 +233,7 @@
 
   ash::DeviceStateMixin device_state_{
       &mixin_host_,
-      GetParam().active_directory
-          ? ash::DeviceStateMixin::State::
-                OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED
-          : ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
 };
 
 IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_PRE_TestAffiliation) {
@@ -274,14 +259,7 @@
 // TODO(https://crbug.com/946024): PRE_ test is flakily timing out.
 INSTANTIATE_TEST_SUITE_P(DISABLED_AffiliationCheck,
                          UserAffiliationBrowserTest,
-                         //         affiliated            active_directory
-                         //              |                         |
-                         //              +----------+      ______  +---------+
-                         //                         |     /      \______     |
-                         ::testing::Values(Params(true, true),     //   \   /
-                                           Params(false, true),    //    \ /
-                                           Params(true, false),    //     X
-                                           Params(false, false)),  //    / \<--!
-                         PrintParam);                              //    \_/
+                         ::testing::Values(Params(true), Params(false)),
+                         PrintParam);
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
index d9dc652..2ada382 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
@@ -623,6 +623,15 @@
                      base::Unretained(roots_recursion_delegate)));
 }
 
+void DlpFilesControllerAsh::CheckIfTransferAllowed(
+    file_manager::io_task::IOTaskId task_id,
+    const std::vector<storage::FileSystemURL>& transferred_urls,
+    storage::FileSystemURL destination,
+    CheckIfTransferAllowedCallback result_callback) {
+  // TODO(b/281043020): Add Implementation.
+  std::move(result_callback).Run(/*blocked_entries=*/{});
+}
+
 void DlpFilesControllerAsh::RequestCopyAccess(
     const storage::FileSystemURL& source_file,
     const storage::FileSystemURL& destination,
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
index 8c6dd6ac..15f43829 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
@@ -12,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ash/file_manager/io_task.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_files_controller.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
@@ -115,6 +116,8 @@
 
   using GetDisallowedTransfersCallback =
       base::OnceCallback<void(std::vector<storage::FileSystemURL>)>;
+  using CheckIfTransferAllowedCallback =
+      base::OnceCallback<void(std::set<storage::FileSystemURL>)>;
   using GetFilesRestrictedByAnyRuleCallback = GetDisallowedTransfersCallback;
   using FilterDisallowedUploadsCallback =
       base::OnceCallback<void(std::vector<ui::SelectedFileInfo>)>;
@@ -139,6 +142,15 @@
       bool is_move,
       GetDisallowedTransfersCallback result_callback);
 
+  // Checks whether transferring `transferred_urls` to `destination` is
+  // allowed. Runs `result_callback` with false if the user cancelled the
+  // warning. Otherwise, it'll return the blocked entries.
+  void CheckIfTransferAllowed(
+      file_manager::io_task::IOTaskId task_id,
+      const std::vector<storage::FileSystemURL>& transferred_urls,
+      storage::FileSystemURL destination,
+      CheckIfTransferAllowedCallback result_callback);
+
   // Retrieves metadata for each entry in |files| and returns it as a list in
   // |result_callback|. If |destination| is passed, marks the files that are not
   // allowed to be uploaded to that particular destination.
diff --git a/chrome/browser/ash/policy/dlp/files_policy_notification_manager.cc b/chrome/browser/ash/policy/dlp/files_policy_notification_manager.cc
index 3de7a6a..549a435 100644
--- a/chrome/browser/ash/policy/dlp/files_policy_notification_manager.cc
+++ b/chrome/browser/ash/policy/dlp/files_policy_notification_manager.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ash/policy/dlp/files_policy_notification_manager.h"
 
 #include "base/check.h"
+#include "chrome/browser/ash/file_manager/io_task.h"
+#include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h"
 
 namespace policy {
 
@@ -15,4 +17,9 @@
 
 FilesPolicyNotificationManager::~FilesPolicyNotificationManager() = default;
 
+// TODO(b/281047025): Add implementation.
+void FilesPolicyNotificationManager::ShowDialog(
+    file_manager::io_task::IOTaskId task_id,
+    FilesDialogType type) {}
+
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/dlp/files_policy_notification_manager.h b/chrome/browser/ash/policy/dlp/files_policy_notification_manager.h
index ad14b26..31c83b61 100644
--- a/chrome/browser/ash/policy/dlp/files_policy_notification_manager.h
+++ b/chrome/browser/ash/policy/dlp/files_policy_notification_manager.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_ASH_POLICY_DLP_FILES_POLICY_NOTIFICATION_MANAGER_H_
 #define CHROME_BROWSER_ASH_POLICY_DLP_FILES_POLICY_NOTIFICATION_MANAGER_H_
 
+#include "chrome/browser/ash/file_manager/io_task.h"
+#include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
@@ -26,6 +28,11 @@
       const FilesPolicyNotificationManager&) = delete;
 
   ~FilesPolicyNotificationManager() override;
+
+  // Shows a policy dialog of type `type` for task identified by `task_id`. Used
+  // for copy and move operations.
+  void ShowDialog(file_manager::io_task::IOTaskId task_id,
+                  FilesDialogType type);
 };
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
index b08dc25..ccedbc22 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
@@ -31,7 +31,6 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/attestation/attestation_features.h"
 #include "chromeos/ash/components/attestation/attestation_flow.h"
-#include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h"
 #include "chromeos/ash/components/dbus/constants/attestation_constants.h"
 #include "chromeos/ash/components/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/ash/components/dbus/dbus_thread_manager.h"
@@ -691,33 +690,7 @@
 void EnrollmentHandler::OnDeviceAccountTokenStored() {
   DCHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_);
   SetStep(STEP_STORE_POLICY);
-  if (device_mode_ == DEVICE_MODE_ENTERPRISE_AD) {
-    CHECK(install_attributes_->IsActiveDirectoryManaged());
-    // Update device settings so that in case of Active Directory unsigned
-    // policy is accepted.
-    ash::DeviceSettingsService::Get()->SetDeviceMode(
-        install_attributes_->GetMode());
-    ash::AuthPolicyClient::Get()->RefreshDevicePolicy(
-        base::BindOnce(&EnrollmentHandler::HandleActiveDirectoryPolicyRefreshed,
-                       weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    store_->InstallInitialPolicy(*policy_);
-  }
-}
-
-void EnrollmentHandler::HandleActiveDirectoryPolicyRefreshed(
-    authpolicy::ErrorType error) {
-  DCHECK_EQ(STEP_STORE_POLICY, enrollment_step_);
-
-  if (error != authpolicy::ERROR_NONE) {
-    LOG(ERROR) << "Failed to load Active Directory policy.";
-    ReportResult(EnrollmentStatus::ForStatus(
-        EnrollmentStatus::ACTIVE_DIRECTORY_POLICY_FETCH_FAILED));
-    return;
-  }
-
-  // After that, the enrollment flow continues in one of the OnStore* observers.
-  store_->Load();
+  store_->InstallInitialPolicy(*policy_);
 }
 
 void EnrollmentHandler::Stop() {
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_handler.h b/chrome/browser/ash/policy/enrollment/enrollment_handler.h
index c692c41..0387b8d 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_handler.h
+++ b/chrome/browser/ash/policy/enrollment/enrollment_handler.h
@@ -17,7 +17,6 @@
 #include "chrome/browser/ash/policy/enrollment/enrollment_config.h"
 #include "chrome/browser/policy/device_account_initializer.h"
 #include "chromeos/ash/components/attestation/attestation_flow.h"
-#include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h"
 #include "chromeos/ash/components/dbus/constants/attestation_constants.h"
 #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
 #include "chromeos/ash/components/install_attributes/install_attributes.h"
@@ -143,8 +142,7 @@
     STEP_LOCK_DEVICE = 10,       // Writing installation-time attributes.
     STEP_STORE_TOKEN = 11,       // Encrypting and storing DM token.
     STEP_STORE_ROBOT_AUTH = 12,  // Encrypting & writing robot refresh token.
-    STEP_STORE_POLICY = 13,      // Storing policy and API refresh token. For
-                                 // AD, includes policy fetch via authpolicyd.
+    STEP_STORE_POLICY = 13,      // Storing policy and API refresh token.
     STEP_FINISHED = 14,          // Enrollment process done, no further action.
   };
 
@@ -192,9 +190,6 @@
   // Initiates storing of robot auth token.
   void StartStoreRobotAuth();
 
-  // Handles result from device policy refresh via authpolicyd.
-  void HandleActiveDirectoryPolicyRefreshed(authpolicy::ErrorType error);
-
   std::unique_ptr<DeviceCloudPolicyValidator> CreateValidator(
       std::unique_ptr<enterprise_management::PolicyFetchResponse> policy,
       const std::string& domain);
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc b/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc
new file mode 100644
index 0000000..974d7fc2
--- /dev/null
+++ b/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc
@@ -0,0 +1,167 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+#include "chrome/browser/ash/login/app_mode/test/kiosk_apps_mixin.h"
+#include "chrome/browser/ash/login/login_manager_test.h"
+#include "chrome/browser/ash/login/test/device_state_mixin.h"
+#include "chrome/browser/ash/login/test/login_manager_mixin.h"
+#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h"
+#include "chrome/browser/ash/policy/core/device_policy_cros_test_helper.h"
+#include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_ash.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/ash/components/login/login_state/login_state.h"
+#include "chromeos/dbus/power/fake_power_manager_client.h"
+#include "components/policy/core/common/remote_commands/remote_commands_service.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+#include "components/policy/test_support/embedded_policy_test_server.h"
+#include "components/policy/test_support/remote_commands_result_waiter.h"
+#include "content/public/test/browser_test.h"
+
+namespace em = enterprise_management;
+
+namespace policy {
+namespace {
+
+constexpr int kFakePolicyPublicKeyVersion = 1;
+constexpr int kUniqueCommandId = 123456789;
+
+class DeviceCommandRebootJobBaseTest : public ash::LoginManagerTest {
+ public:
+  DeviceCommandRebootJobBaseTest(const DeviceCommandRebootJobBaseTest&) =
+      delete;
+  DeviceCommandRebootJobBaseTest& operator=(
+      const DeviceCommandRebootJobBaseTest&) = delete;
+
+ protected:
+  DeviceCommandRebootJobBaseTest() = default;
+  ~DeviceCommandRebootJobBaseTest() override = default;
+
+  DevicePolicyCrosTestHelper* policy_helper() { return &policy_helper_; }
+
+  DevicePolicyBuilder* device_policy() {
+    return policy_helper()->device_policy();
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    LoginManagerTest::SetUpInProcessBrowserTestFixture();
+
+    device_policy()->policy_data().set_public_key_version(
+        kFakePolicyPublicKeyVersion);
+    device_policy()->Build();
+    ash::FakeSessionManagerClient::Get()->set_device_policy(
+        device_policy()->GetBlob());
+  }
+
+  void AddPendingRemoteCommand(const em::RemoteCommand& command) {
+    policy_test_server_mixin_.server()
+        ->remote_commands_state()
+        ->AddPendingRemoteCommand(command);
+  }
+
+  void SendDeviceRemoteCommandsRequest() {
+    g_browser_process->browser_policy_connector()
+        ->ScheduleServiceInitialization(0);
+
+    DeviceCloudPolicyManagerAsh* policy_manager =
+        g_browser_process->platform_part()
+            ->browser_policy_connector_ash()
+            ->GetDeviceCloudPolicyManager();
+
+    ASSERT_TRUE(policy_manager);
+    ASSERT_TRUE(policy_manager->core()->client());
+
+    RemoteCommandsService* remote_commands_service =
+        policy_manager->core()->remote_commands_service();
+    remote_commands_service->FetchRemoteCommands();
+  }
+
+  em::RemoteCommandResult WaitForResult(int command_id) {
+    return RemoteCommandsResultWaiter(
+               policy_test_server_mixin_.server()->remote_commands_state(),
+               command_id)
+        .WaitAndGetResult();
+  }
+
+ private:
+  DevicePolicyCrosTestHelper policy_helper_;
+  ash::EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_};
+  ash::DeviceStateMixin device_state_{
+      &mixin_host_,
+      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+};
+
+}  // namespace
+
+class DeviceCommandRebootJobKioskBrowserTest
+    : public DeviceCommandRebootJobBaseTest {
+ protected:
+  void SetUpInProcessBrowserTestFixture() override {
+    DeviceCommandRebootJobBaseTest::SetUpInProcessBrowserTestFixture();
+
+    // Set up kiosk auto-launch mode.
+    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+    ash::KioskAppsMixin::AppendAutoLaunchKioskAccount(&proto);
+    policy_helper()->RefreshDevicePolicy();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobKioskBrowserTest,
+                       RebootsKioskInstantly) {
+  ASSERT_TRUE(ash::LoginState::Get()->IsKioskSession());
+  ASSERT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
+
+  em::RemoteCommand command;
+  command.set_type(em::RemoteCommand_Type_DEVICE_REBOOT);
+  command.set_command_id(kUniqueCommandId);
+  command.set_age_of_command(base::TimeDelta().InMilliseconds());
+  AddPendingRemoteCommand(command);
+
+  SendDeviceRemoteCommandsRequest();
+
+  em::RemoteCommandResult result = WaitForResult(kUniqueCommandId);
+  EXPECT_EQ(result.result(), em::RemoteCommandResult_ResultType_RESULT_SUCCESS);
+  EXPECT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
+}
+
+// TODO(b/225913691) Add test case for manually launched kiosk.
+
+class DeviceCommandRebootJobUserBrowserTest
+    : public DeviceCommandRebootJobBaseTest {
+ protected:
+  void LoginManagedUser() { login_manager_mixin_.LoginAsNewRegularUser(); }
+
+ private:
+  ash::LoginManagerMixin login_manager_mixin_{&mixin_host_};
+};
+
+IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobUserBrowserTest,
+                       RebootsLoginScreenInstantly) {
+  ASSERT_FALSE(ash::LoginState::Get()->IsUserLoggedIn());
+  ASSERT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
+
+  em::RemoteCommand command;
+  command.set_type(em::RemoteCommand_Type_DEVICE_REBOOT);
+  command.set_command_id(kUniqueCommandId);
+  command.set_age_of_command(base::TimeDelta().InMilliseconds());
+  AddPendingRemoteCommand(command);
+
+  SendDeviceRemoteCommandsRequest();
+
+  em::RemoteCommandResult result = WaitForResult(kUniqueCommandId);
+  EXPECT_EQ(result.result(), em::RemoteCommandResult_ResultType_RESULT_SUCCESS);
+  EXPECT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
+}
+
+// TODO(b/225913691) Add user session test case.
+
+}  // namespace policy
diff --git a/chrome/browser/ash/printing/print_management/printing_manager_factory.cc b/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
index f71c89e7..27c1503e 100644
--- a/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
+++ b/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/printing/print_management/printing_manager_factory.h"
 
+#include "ash/webui/print_management/print_management_ui.h"
 #include "chrome/browser/ash/printing/cups_print_job_manager_factory.h"
 #include "chrome/browser/ash/printing/history/print_job_history_service_factory.h"
 #include "chrome/browser/ash/printing/print_management/printing_manager.h"
@@ -59,6 +60,28 @@
       profile->GetPrefs());
 }
 
+// static
+void PrintingManagerFactory::MaybeBindPrintManagementForWebUI(
+    Profile* profile,
+    mojo::PendingReceiver<
+        chromeos::printing::printing_manager::mojom::PrintingMetadataProvider>
+        receiver) {
+  PrintingManager* handler = GetForProfile(profile);
+  if (handler) {
+    handler->BindInterface(std::move(receiver));
+  }
+}
+
+// static
+std::unique_ptr<content::WebUIController>
+PrintingManagerFactory::CreatePrintManagementUIController(
+    content::WebUI* web_ui,
+    const GURL& url) {
+  return std::make_unique<printing_manager::PrintManagementUI>(
+      web_ui, base::BindRepeating(&MaybeBindPrintManagementForWebUI,
+                                  Profile::FromWebUI(web_ui)));
+}
+
 KeyedService* PrintingManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   return BuildInstanceFor(context);
diff --git a/chrome/browser/ash/printing/print_management/printing_manager_factory.h b/chrome/browser/ash/printing/print_management/printing_manager_factory.h
index 19a4434..bd1f75d3 100644
--- a/chrome/browser/ash/printing/print_management/printing_manager_factory.h
+++ b/chrome/browser/ash/printing/print_management/printing_manager_factory.h
@@ -6,12 +6,20 @@
 #define CHROME_BROWSER_ASH_PRINTING_PRINT_MANAGEMENT_PRINTING_MANAGER_FACTORY_H_
 
 #include "base/memory/singleton.h"
+#include "chrome/browser/ash/printing/print_management/printing_manager.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+
+namespace content {
+class WebUI;
+class WebUIController;
+}  // namespace content
 
 namespace user_prefs {
 class PrefRegistrySyncable;
 }  // namespace user_prefs
 
+class GURL;
 class Profile;
 
 namespace ash {
@@ -26,6 +34,13 @@
   static PrintingManager* GetForProfile(Profile* profile);
   static PrintingManagerFactory* GetInstance();
   static KeyedService* BuildInstanceFor(content::BrowserContext* profile);
+  static void MaybeBindPrintManagementForWebUI(
+      Profile* profile,
+      mojo::PendingReceiver<
+          chromeos::printing::printing_manager::mojom::PrintingMetadataProvider>
+          receiver);
+  static std::unique_ptr<content::WebUIController>
+  CreatePrintManagementUIController(content::WebUI* web_ui, const GURL& url);
 
  private:
   friend struct base::DefaultSingletonTraits<PrintingManagerFactory>;
diff --git a/chrome/browser/ash/settings/cros_settings.cc b/chrome/browser/ash/settings/cros_settings.cc
index 116eb72..343db0c 100644
--- a/chrome/browser/ash/settings/cros_settings.cc
+++ b/chrome/browser/ash/settings/cros_settings.cc
@@ -100,12 +100,12 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-bool CrosSettings::IsCrosSettings(const std::string& path) {
+bool CrosSettings::IsCrosSettings(base::StringPiece path) {
   return base::StartsWith(path, kCrosSettingsPrefix,
                           base::CompareCase::SENSITIVE);
 }
 
-const base::Value* CrosSettings::GetPref(const std::string& path) const {
+const base::Value* CrosSettings::GetPref(base::StringPiece path) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CrosSettingsProvider* provider = GetProvider(path);
   if (provider)
@@ -126,8 +126,7 @@
   return CrosSettingsProvider::TRUSTED;
 }
 
-bool CrosSettings::GetBoolean(const std::string& path,
-                              bool* bool_value) const {
+bool CrosSettings::GetBoolean(base::StringPiece path, bool* bool_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const base::Value* value = GetPref(path);
   if (value && value->is_bool()) {
@@ -137,8 +136,7 @@
   return false;
 }
 
-bool CrosSettings::GetInteger(const std::string& path,
-                              int* out_value) const {
+bool CrosSettings::GetInteger(base::StringPiece path, int* out_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const base::Value* value = GetPref(path);
   if (value && value->is_int()) {
@@ -148,8 +146,7 @@
   return false;
 }
 
-bool CrosSettings::GetDouble(const std::string& path,
-                             double* out_value) const {
+bool CrosSettings::GetDouble(base::StringPiece path, double* out_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // `GetIfDouble` incapsulates type check.
   absl::optional<double> maybe_value = GetPref(path)->GetIfDouble();
@@ -160,7 +157,7 @@
   return false;
 }
 
-bool CrosSettings::GetString(const std::string& path,
+bool CrosSettings::GetString(base::StringPiece path,
                              std::string* out_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const base::Value* value = GetPref(path);
@@ -171,7 +168,7 @@
   return false;
 }
 
-bool CrosSettings::GetList(const std::string& path,
+bool CrosSettings::GetList(base::StringPiece path,
                            const base::Value::List** out_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const base::Value* value = GetPref(path);
@@ -182,7 +179,7 @@
   return false;
 }
 
-bool CrosSettings::GetDictionary(const std::string& path,
+bool CrosSettings::GetDictionary(base::StringPiece path,
                                  const base::Value::Dict** out_value) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const base::Value* value = GetPref(path);
@@ -322,11 +319,11 @@
   return registry->Add(std::move(callback));
 }
 
-CrosSettingsProvider* CrosSettings::GetProvider(
-    const std::string& path) const {
-  for (size_t i = 0; i < providers_.size(); ++i) {
-    if (providers_[i]->HandlesSetting(path))
-      return providers_[i].get();
+CrosSettingsProvider* CrosSettings::GetProvider(base::StringPiece path) const {
+  for (const auto& provider : providers_) {
+    if (provider->HandlesSetting(path)) {
+      return provider.get();
+    }
   }
   return nullptr;
 }
diff --git a/chrome/browser/ash/settings/cros_settings.h b/chrome/browser/ash/settings/cros_settings.h
index d4ea979..197ae45 100644
--- a/chrome/browser/ash/settings/cros_settings.h
+++ b/chrome/browser/ash/settings/cros_settings.h
@@ -14,6 +14,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "build/chromeos_buildflags.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
@@ -60,10 +61,10 @@
   virtual ~CrosSettings();
 
   // Helper function to test if the given |path| is a valid cros setting.
-  static bool IsCrosSettings(const std::string& path);
+  static bool IsCrosSettings(base::StringPiece path);
 
   // Returns setting value for the given |path|.
-  const base::Value* GetPref(const std::string& path) const;
+  const base::Value* GetPref(base::StringPiece path) const;
 
   // Requests that all providers ensure the values they are serving were read
   // from a trusted store:
@@ -84,13 +85,13 @@
   // These are convenience forms of Get().  The value will be retrieved
   // 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.
-  bool GetBoolean(const std::string& path, bool* out_value) const;
-  bool GetInteger(const std::string& path, int* out_value) const;
-  bool GetDouble(const std::string& path, double* out_value) const;
-  bool GetString(const std::string& path, std::string* out_value) const;
-  bool GetList(const std::string& path,
+  bool GetBoolean(base::StringPiece path, bool* out_value) const;
+  bool GetInteger(base::StringPiece path, int* out_value) const;
+  bool GetDouble(base::StringPiece path, double* out_value) const;
+  bool GetString(base::StringPiece path, std::string* out_value) const;
+  bool GetList(base::StringPiece path,
                const base::Value::List** out_value) const;
-  bool GetDictionary(const std::string& path,
+  bool GetDictionary(base::StringPiece path,
                      const base::Value::Dict** out_value) const;
 
   // Checks if the given username is on the list of users allowed to sign-in to
@@ -127,7 +128,7 @@
       base::RepeatingClosure callback);
 
   // Returns the provider that handles settings with the |path| or prefix.
-  CrosSettingsProvider* GetProvider(const std::string& path) const;
+  CrosSettingsProvider* GetProvider(base::StringPiece path) const;
 
   const SupervisedUserCrosSettingsProvider*
   supervised_user_cros_settings_provider() const {
diff --git a/chrome/browser/ash/settings/device_settings_provider.cc b/chrome/browser/ash/settings/device_settings_provider.cc
index e3506f5d..492de1cf 100644
--- a/chrome/browser/ash/settings/device_settings_provider.cc
+++ b/chrome/browser/ash/settings/device_settings_provider.cc
@@ -1351,7 +1351,7 @@
 }
 
 // static
-bool DeviceSettingsProvider::IsDeviceSetting(const std::string& name) {
+bool DeviceSettingsProvider::IsDeviceSetting(base::StringPiece name) {
   return base::Contains(kKnownSettings, name);
 }
 
@@ -1582,7 +1582,7 @@
   return true;
 }
 
-const base::Value* DeviceSettingsProvider::Get(const std::string& path) const {
+const base::Value* DeviceSettingsProvider::Get(base::StringPiece path) const {
   if (IsDeviceSetting(path)) {
     const base::Value* value;
     if (values_cache_.GetValue(path, &value))
@@ -1602,7 +1602,7 @@
   return status;
 }
 
-bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const {
+bool DeviceSettingsProvider::HandlesSetting(base::StringPiece path) const {
   return IsDeviceSetting(path);
 }
 
diff --git a/chrome/browser/ash/settings/device_settings_provider.h b/chrome/browser/ash/settings/device_settings_provider.h
index a396c622..2e106bb 100644
--- a/chrome/browser/ash/settings/device_settings_provider.h
+++ b/chrome/browser/ash/settings/device_settings_provider.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
 #include "components/ownership/owner_settings_service.h"
@@ -55,12 +56,12 @@
   ~DeviceSettingsProvider() override;
 
   // Returns true if |path| is handled by this provider.
-  static bool IsDeviceSetting(const std::string& name);
+  static bool IsDeviceSetting(base::StringPiece name);
 
   // CrosSettingsProvider implementation.
-  const base::Value* Get(const std::string& path) const override;
+  const base::Value* Get(base::StringPiece path) const override;
   TrustedStatus PrepareTrustedValues(base::OnceClosure* callback) override;
-  bool HandlesSetting(const std::string& path) const override;
+  bool HandlesSetting(base::StringPiece path) const override;
 
   // Helper function that decodes policies from provided proto into the pref
   // map.
diff --git a/chrome/browser/ash/settings/stub_cros_settings_provider.cc b/chrome/browser/ash/settings/stub_cros_settings_provider.cc
index b70310a..ef452ae 100644
--- a/chrome/browser/ash/settings/stub_cros_settings_provider.cc
+++ b/chrome/browser/ash/settings/stub_cros_settings_provider.cc
@@ -27,8 +27,7 @@
 StubCrosSettingsProvider::~StubCrosSettingsProvider() {
 }
 
-const base::Value* StubCrosSettingsProvider::Get(
-    const std::string& path) const {
+const base::Value* StubCrosSettingsProvider::Get(base::StringPiece path) const {
   DCHECK(HandlesSetting(path));
   const base::Value* value;
   if (values_.GetValue(path, &value))
@@ -43,7 +42,7 @@
   return trusted_status_;
 }
 
-bool StubCrosSettingsProvider::HandlesSetting(const std::string& path) const {
+bool StubCrosSettingsProvider::HandlesSetting(base::StringPiece path) const {
   return DeviceSettingsProvider::IsDeviceSetting(path);
 }
 
diff --git a/chrome/browser/ash/settings/stub_cros_settings_provider.h b/chrome/browser/ash/settings/stub_cros_settings_provider.h
index d12a4aa..7e11c74 100644
--- a/chrome/browser/ash/settings/stub_cros_settings_provider.h
+++ b/chrome/browser/ash/settings/stub_cros_settings_provider.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/functional/callback.h"
+#include "base/strings/string_piece.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
 #include "components/prefs/pref_value_map.h"
 
@@ -26,9 +27,9 @@
   ~StubCrosSettingsProvider() override;
 
   // CrosSettingsProvider implementation.
-  const base::Value* Get(const std::string& path) const override;
+  const base::Value* Get(base::StringPiece path) const override;
   TrustedStatus PrepareTrustedValues(base::OnceClosure* callback) override;
-  bool HandlesSetting(const std::string& path) const override;
+  bool HandlesSetting(base::StringPiece path) const override;
 
   void SetTrustedStatus(TrustedStatus status);
   void SetCurrentUserIsOwner(bool owner);
diff --git a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
index 75f2d3f9..dcb7182a 100644
--- a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
+++ b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
@@ -6,6 +6,7 @@
 
 #include "base/check.h"
 #include "base/containers/contains.h"
+#include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
 #include "components/account_id/account_id.h"
@@ -16,17 +17,19 @@
 SupervisedUserCrosSettingsProvider::SupervisedUserCrosSettingsProvider(
     const CrosSettingsProvider::NotifyObserversCallback& notify_cb)
     : CrosSettingsProvider(notify_cb) {
-  child_user_restrictions_[kAccountsPrefAllowGuest] = base::Value(false);
-  child_user_restrictions_[kAccountsPrefShowUserNamesOnSignIn] =
-      base::Value(true);
-  child_user_restrictions_[kAccountsPrefAllowNewUser] = base::Value(true);
+  child_user_restrictions_.insert_or_assign(kAccountsPrefAllowGuest,
+                                            base::Value(false));
+  child_user_restrictions_.insert_or_assign(kAccountsPrefShowUserNamesOnSignIn,
+                                            base::Value(true));
+  child_user_restrictions_.insert_or_assign(kAccountsPrefAllowNewUser,
+                                            base::Value(true));
 }
 
 SupervisedUserCrosSettingsProvider::~SupervisedUserCrosSettingsProvider() =
     default;
 
 const base::Value* SupervisedUserCrosSettingsProvider::Get(
-    const std::string& path) const {
+    base::StringPiece path) const {
   DCHECK(HandlesSetting(path));
   auto iter = child_user_restrictions_.find(path);
   return &(iter->second);
@@ -39,7 +42,7 @@
 }
 
 bool SupervisedUserCrosSettingsProvider::HandlesSetting(
-    const std::string& path) const {
+    base::StringPiece path) const {
   if (!user_manager::UserManager::IsInitialized())
     return false;
   auto* user_manager = user_manager::UserManager::Get();
diff --git a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
index 6ad21a6..9d09f5b 100644
--- a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
+++ b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
@@ -5,15 +5,13 @@
 #ifndef CHROME_BROWSER_ASH_SETTINGS_SUPERVISED_USER_CROS_SETTINGS_PROVIDER_H_
 #define CHROME_BROWSER_ASH_SETTINGS_SUPERVISED_USER_CROS_SETTINGS_PROVIDER_H_
 
-#include <map>
 #include <string>
 
+#include "base/containers/flat_map.h"
+#include "base/strings/string_piece_forward.h"
+#include "base/values.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
 
-namespace base {
-class Value;
-}
-
 namespace ash {
 
 class SupervisedUserCrosSettingsProvider : public CrosSettingsProvider {
@@ -29,13 +27,13 @@
   ~SupervisedUserCrosSettingsProvider() override;
 
   // CrosSettingsProvider:
-  const base::Value* Get(const std::string& path) const override;
+  const base::Value* Get(base::StringPiece path) const override;
   TrustedStatus PrepareTrustedValues(base::OnceClosure* callback) override;
-  bool HandlesSetting(const std::string& path) const override;
+  bool HandlesSetting(base::StringPiece path) const override;
 
  private:
   // Cros pref name to pref value.
-  std::map<std::string, base::Value> child_user_restrictions_;
+  base::flat_map<std::string, base::Value> child_user_restrictions_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/startup_settings_cache.cc b/chrome/browser/ash/startup_settings_cache.cc
index b6cb4cf..8a8f26cf 100644
--- a/chrome/browser/ash/startup_settings_cache.cc
+++ b/chrome/browser/ash/startup_settings_cache.cc
@@ -14,8 +14,7 @@
 #include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 
-namespace ash {
-namespace startup_settings_cache {
+namespace ash::startup_settings_cache {
 namespace {
 
 // Name of the cache file on disk.
@@ -26,8 +25,9 @@
 
 bool GetCacheFilePath(base::FilePath* path) {
   base::FilePath user_data_dir;
-  if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
+  if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
     return false;
+  }
 
   *path = user_data_dir.Append(kCacheFilename);
   return true;
@@ -37,16 +37,19 @@
 
 std::string ReadAppLocale() {
   base::FilePath cache_file;
-  if (!GetCacheFilePath(&cache_file))
+  if (!GetCacheFilePath(&cache_file)) {
     return std::string();
+  }
 
   std::string input;
-  if (!base::ReadFileToString(cache_file, &input))
+  if (!base::ReadFileToString(cache_file, &input)) {
     return std::string();
+  }
 
   absl::optional<base::Value> settings = base::JSONReader::Read(input);
-  if (!settings.has_value())
+  if (!settings.has_value()) {
     return std::string();
+  }
 
   const std::string* app_locale_setting =
       settings->GetDict().FindString(kAppLocaleKey);
@@ -55,21 +58,20 @@
   return app_locale_setting ? *app_locale_setting : std::string();
 }
 
-void WriteAppLocale(std::string app_locale) {
+void WriteAppLocale(const std::string& app_locale) {
   base::FilePath cache_file;
-  if (!GetCacheFilePath(&cache_file))
+  if (!GetCacheFilePath(&cache_file)) {
     return;
+  }
 
-  base::Value settings(base::Value::Type::DICT);
-  settings.SetKey(kAppLocaleKey, base::Value(app_locale));
-
+  auto settings = base::Value::Dict().Set(kAppLocaleKey, app_locale);
   std::string output;
-  if (!base::JSONWriter::Write(settings, &output))
+  if (!base::JSONWriter::Write(settings, &output)) {
     return;
+  }
 
   // Ignore errors because we're shutting down and we can't recover.
   base::WriteFile(cache_file, output);
 }
 
-}  // namespace startup_settings_cache
-}  // namespace ash
+}  // namespace ash::startup_settings_cache
diff --git a/chrome/browser/ash/startup_settings_cache.h b/chrome/browser/ash/startup_settings_cache.h
index 51845d9..0bbfdc7 100644
--- a/chrome/browser/ash/startup_settings_cache.h
+++ b/chrome/browser/ash/startup_settings_cache.h
@@ -7,8 +7,7 @@
 
 #include <string>
 
-namespace ash {
-namespace startup_settings_cache {
+namespace ash::startup_settings_cache {
 
 // On Chrome OS, the application locale is stored in local state prefs. The
 // zygote needs the locale so it can load the correct resource bundle and
@@ -24,9 +23,8 @@
 std::string ReadAppLocale();
 
 // Writes the locale string to a JSON file on disk. See above.
-void WriteAppLocale(std::string app_locale);
+void WriteAppLocale(const std::string& app_locale);
 
-}  // namespace startup_settings_cache
-}  // namespace ash
+}  // namespace ash::startup_settings_cache
 
 #endif  // CHROME_BROWSER_ASH_STARTUP_SETTINGS_CACHE_H_
diff --git a/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc b/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
index 3ae7626..83280afe 100644
--- a/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
+++ b/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/gtest_tags.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
 #include "chrome/browser/browser_process.h"
@@ -418,6 +419,9 @@
 
 IN_PROC_BROWSER_TEST_P(VideoConferenceIntegrationTest,
                        MicWithoutPermissionShouldNotShow) {
+  base::AddFeatureIdTagToTestResult(
+      "screenplay-92ebd14e-9017-4734-ae47-e9dc6afc6e87");
+
   // Open a tab.
   content::WebContents* web_contents =
       NavigateTo("/video_conference_demo.html");
@@ -440,6 +444,9 @@
 
 IN_PROC_BROWSER_TEST_P(VideoConferenceIntegrationTest,
                        CameraWithoutPermissionShouldNotShow) {
+  base::AddFeatureIdTagToTestResult(
+      "screenplay-2d9bddf4-8d96-4304-a605-1140f9a0b45e");
+
   // Open a tab.
   content::WebContents* web_contents =
       NavigateTo("/video_conference_demo.html");
@@ -484,6 +491,9 @@
 
 IN_PROC_BROWSER_TEST_P(VideoConferenceIntegrationTest,
                        ClickOnTheMicOrCameraIconsShouldMute) {
+  base::AddFeatureIdTagToTestResult(
+      "screenplay-cc18f9a3-e46f-4192-b505-876975c5ef4b");
+
   // Trigger the VcTray with microphone.
   TriggeringTray(/*use_camera=*/false,
                  /*use_microphone=*/true,
@@ -614,6 +624,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(VideoConferenceIntegrationTest, UseWhileDisabled) {
+  base::AddFeatureIdTagToTestResult(
+      "screenplay-f583c1ff-db6f-460e-b1f2-ddec173359a6");
+  base::AddFeatureIdTagToTestResult(
+      "screenplay-3042cdd9-978d-432c-8488-77684b09a9e4");
+
   // Trigger the VcTray with microphone.
   content::WebContents* web_contents =
       TriggeringTray(/*use_camera=*/false,
diff --git a/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc b/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc
index eb095c3..14b8b2d3 100644
--- a/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc
+++ b/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc
@@ -1028,9 +1028,9 @@
   // photos with the given attributes exist. We return an empty list of photos
   // to communicate this back to the caller.
   if (error_code == net::HTTP_NOT_FOUND) {
-    absl::optional<base::Value> empty_list(base::Value::Type::DICT);
-    empty_list->SetKey("item", base::Value(base::Value::Type::LIST));
-    return empty_list;
+    auto empty_list_response =
+        base::Value::Dict().Set("item", base::Value::List());
+    return base::Value(std::move(empty_list_response));
   }
   return absl::nullopt;
 }
diff --git a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
index 9820a82..910a39cd 100644
--- a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
@@ -124,7 +124,7 @@
                     {"doc", "docx"});
   AppendFileHandler(*info,
                     ::file_manager::file_tasks::kActionIdWebDriveOfficeExcel,
-                    {"xls", "xlsx"});
+                    {"xls", "xlsm", "xlsx"});
   AppendFileHandler(
       *info, ::file_manager::file_tasks::kActionIdWebDriveOfficePowerPoint,
       {"ppt", "pptx"});
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
index c7022f4..3cd6a1af 100644
--- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
+++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
@@ -14,7 +14,9 @@
 #include "chrome/browser/ash/fusebox/fusebox_server.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
+#include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 
 ChromeFilesInternalsUIDelegate::ChromeFilesInternalsUIDelegate(
     content::WebUI* web_ui)
@@ -49,31 +51,83 @@
   }
 }
 
-bool ChromeFilesInternalsUIDelegate::GetOfficeSetupComplete() const {
+std::string ChromeFilesInternalsUIDelegate::GetOfficeFileHandlers() const {
   Profile* profile = Profile::FromWebUI(web_ui_);
-  return profile && file_manager::file_tasks::OfficeSetupComplete(profile);
+  const base::Value::Dict& extension_task_prefs =
+      profile->GetPrefs()->GetDict(prefs::kDefaultTasksBySuffix);
+  base::Value::Dict filtered_prefs;
+
+  for (const std::string& extension :
+       file_manager::file_tasks::WordGroupExtensions()) {
+    if (extension_task_prefs.contains(extension)) {
+      filtered_prefs.Set(extension,
+                         *extension_task_prefs.FindString(extension));
+    }
+  }
+  for (const std::string& extension :
+       file_manager::file_tasks::ExcelGroupExtensions()) {
+    if (extension_task_prefs.contains(extension)) {
+      filtered_prefs.Set(extension,
+                         *extension_task_prefs.FindString(extension));
+    }
+  }
+  for (const std::string& extension :
+       file_manager::file_tasks::PowerPointGroupExtensions()) {
+    if (extension_task_prefs.contains(extension)) {
+      filtered_prefs.Set(extension,
+                         *extension_task_prefs.FindString(extension));
+    }
+  }
+  return filtered_prefs.DebugString();
 }
 
-void ChromeFilesInternalsUIDelegate::SetOfficeSetupComplete(bool complete) {
+void ChromeFilesInternalsUIDelegate::ClearOfficeFileHandlers() {
   Profile* profile = Profile::FromWebUI(web_ui_);
   if (profile) {
-    file_manager::file_tasks::SetOfficeSetupComplete(profile, complete);
-    // If setup complete is set to false, also update the preferences to signal
-    // that the move confirmation dialog has never been shown.
-    if (!complete) {
-      file_manager::file_tasks::SetOfficeMoveConfirmationShownForDrive(profile,
-                                                                       false);
-      file_manager::file_tasks::SetOfficeMoveConfirmationShownForOneDrive(
-          profile, false);
-      file_manager::file_tasks::SetOfficeMoveConfirmationShownForLocalToDrive(
-          profile, false);
-      file_manager::file_tasks::
-          SetOfficeMoveConfirmationShownForLocalToOneDrive(profile, false);
-      file_manager::file_tasks::SetOfficeMoveConfirmationShownForCloudToDrive(
-          profile, false);
-      file_manager::file_tasks::
-          SetOfficeMoveConfirmationShownForCloudToOneDrive(profile, false);
+    ScopedDictPrefUpdate mime_type_pref(profile->GetPrefs(),
+                                        prefs::kDefaultTasksByMimeType);
+    for (const std::string& mime_type :
+         file_manager::file_tasks::WordGroupMimeTypes()) {
+      mime_type_pref->Remove(mime_type);
     }
+    for (const std::string& mime_type :
+         file_manager::file_tasks::ExcelGroupMimeTypes()) {
+      mime_type_pref->Remove(mime_type);
+    }
+    for (const std::string& mime_type :
+         file_manager::file_tasks::PowerPointGroupMimeTypes()) {
+      mime_type_pref->Remove(mime_type);
+    }
+
+    ScopedDictPrefUpdate extension_pref(profile->GetPrefs(),
+                                        prefs::kDefaultTasksBySuffix);
+    for (const std::string& extension :
+         file_manager::file_tasks::WordGroupExtensions()) {
+      extension_pref->Remove(extension);
+    }
+    for (const std::string& extension :
+         file_manager::file_tasks::ExcelGroupExtensions()) {
+      extension_pref->Remove(extension);
+    }
+    for (const std::string& extension :
+         file_manager::file_tasks::PowerPointGroupExtensions()) {
+      extension_pref->Remove(extension);
+    }
+
+    // Also update the preferences to signal that the move confirmation dialog
+    // has never been shown.
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForDrive(profile,
+                                                                     false);
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForOneDrive(profile,
+                                                                        false);
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForLocalToDrive(
+        profile, false);
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForLocalToOneDrive(
+        profile, false);
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForCloudToDrive(
+        profile, false);
+    file_manager::file_tasks::SetOfficeMoveConfirmationShownForCloudToOneDrive(
+        profile, false);
   }
 }
 
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
index c584446..1ee44bdf 100644
--- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
+++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
@@ -27,8 +27,8 @@
   bool GetSmbfsEnableVerboseLogging() const override;
   void SetSmbfsEnableVerboseLogging(bool enabled) override;
 
-  bool GetOfficeSetupComplete() const override;
-  void SetOfficeSetupComplete(bool complete) override;
+  std::string GetOfficeFileHandlers() const override;
+  void ClearOfficeFileHandlers() override;
 
   bool GetMoveConfirmationShownForDrive() const override;
   bool GetMoveConfirmationShownForOneDrive() const override;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 9c5f8632..6d864a0 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1579,10 +1579,6 @@
       prefs::kThrottleNonVisibleCrossOriginIframesAllowed, true);
   registry->RegisterBooleanPref(prefs::kNewBaseUrlInheritanceBehaviorAllowed,
                                 true);
-  registry->RegisterBooleanPref(
-      policy::policy_prefs::kPPAPISharedImagesSwapChainAllowed, true);
-  registry->RegisterBooleanPref(
-      policy::policy_prefs::kForceEnablePepperVideoDecoderDevAPI, false);
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
   registry->RegisterBooleanPref(prefs::kOutOfProcessSystemDnsResolutionEnabled,
                                 true);
@@ -3001,21 +2997,6 @@
                                     switches::kChangeStackGuardOnForkEnabled);
   }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  if (process_type != switches::kZygoteProcess) {
-    DCHECK(g_browser_process);
-    PrefService* local_state = g_browser_process->local_state();
-    DCHECK(local_state);
-    if (!local_state->GetBoolean(
-            policy::policy_prefs::kPPAPISharedImagesSwapChainAllowed)) {
-      command_line->AppendSwitch(
-          ::switches::kDisablePPAPISharedImagesSwapChain);
-    }
-    if (local_state->GetBoolean(
-            policy::policy_prefs::kForceEnablePepperVideoDecoderDevAPI)) {
-      command_line->AppendSwitch(
-          ::switches::kForceEnablePepperVideoDecoderDevAPI);
-    }
-  }
 }
 
 std::string
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
index 2a20743..c30b92d1 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/base64.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/task/bind_post_task.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h"
@@ -46,15 +47,6 @@
 
 namespace {
 
-std::string KeyTypeToStr(KeyType key_type) {
-  switch (key_type) {
-    case KeyType::kRsa:
-      return "kRsa";
-    case KeyType::kEcc:
-      return "kEcc";
-  }
-}
-
 constexpr char kPublicKeyBase64[] =
     "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArURIGgAq8joyzjFdUpzmOeDa5VgTC8"
     "n77sMCQsm01mwk+6NwHhCSyCfXoB9EuMcKynj9SZbCgArnsHcZiqBsKpU/VnBO/"
@@ -64,6 +56,15 @@
     "eoy7MtXwSchI0e2Q8QdUneNp529Ee+pUQ5Uki1L2pE4Pnyj+j2i2x4wGFGdJgiBMSvtpvdPdF+"
     "NMfjdbVaDzTF3rcL3lNCxRb4xk3TMFXV7dQIDAQAB";
 
+std::string KeyTypeToStr(KeyType key_type) {
+  switch (key_type) {
+    case KeyType::kRsa:
+      return "kRsa";
+    case KeyType::kEcc:
+      return "kEcc";
+  }
+}
+
 std::vector<uint8_t> StrToBytes(const std::string& val) {
   return std::vector<uint8_t>(val.begin(), val.end());
 }
@@ -72,6 +73,74 @@
   return content::GetIOThreadTaskRunner({});
 }
 
+std::string ToString(const std::vector<SigningScheme>& vec) {
+  std::stringstream res;
+  res << "[";
+  for (const SigningScheme& s : vec) {
+    res << static_cast<int>(s) << ", ";
+  }
+  res << "]";
+  return res.str();
+}
+
+std::string ToString(const absl::optional<chaps::KeyPermissions>& val) {
+  if (!val.has_value()) {
+    return "<empty>";
+  }
+  // Should be updated if `KeyPermissions` struct is changed.
+  return base::StringPrintf("[arc:%d corp:%d]", val->key_usages().arc(),
+                            val->key_usages().corporate());
+}
+
+bool operator==(const absl::optional<chaps::KeyPermissions>& a,
+                const absl::optional<chaps::KeyPermissions>& b) {
+  if (!a.has_value() || !b.has_value()) {
+    return (a.has_value() == b.has_value());
+  }
+  return (a->SerializeAsString() == b->SerializeAsString());
+}
+
+bool KeyInfoEquals(const KeyInfo& expected, const KeyInfo& actual) {
+  if (expected.is_hardware_backed != actual.is_hardware_backed) {
+    LOG(ERROR) << "ERROR: is_hardware_backed: expected: "
+               << expected.is_hardware_backed
+               << ", actual: " << actual.is_hardware_backed;
+    return false;
+  }
+  if (expected.key_type != actual.key_type) {
+    LOG(ERROR) << "ERROR: key_type: expected: " << int(expected.key_type)
+               << ", actual: " << int(actual.key_type);
+    return false;
+  }
+  if (expected.supported_signing_schemes != actual.supported_signing_schemes) {
+    LOG(ERROR) << "ERROR: supported_signing_schemes: expected: "
+               << ToString(expected.supported_signing_schemes)
+               << ", actual: " << ToString(actual.supported_signing_schemes);
+    return false;
+  }
+  if (expected.nickname != actual.nickname) {
+    LOG(ERROR) << "ERROR: nickname: expected: "
+               << expected.nickname.value_or("<empty>")
+               << ", actual: " << actual.nickname.value_or("<empty>");
+    return false;
+  }
+  if (expected.key_permissions != actual.key_permissions) {
+    LOG(ERROR) << "ERROR: key_permissions: expected: "
+               << ToString(expected.key_permissions)
+               << ", actual: " << ToString(actual.key_permissions);
+    return false;
+  }
+  if (expected.cert_provisioning_profile_id !=
+      actual.cert_provisioning_profile_id) {
+    LOG(ERROR) << "ERROR: cert_provisioning_profile_id: expected: "
+               << expected.cert_provisioning_profile_id.value_or("<empty>")
+               << ", actual: "
+               << actual.cert_provisioning_profile_id.value_or("<empty>");
+    return false;
+  }
+  return true;
+}
+
 // Reads a file in the PEM format, decodes it, returns the content of the first
 // PEM block in the DER format. Currently supports CERTIFICATE and PRIVATE KEY
 // block types.
@@ -95,6 +164,7 @@
  public:
   explicit TokenHolder(Token token) {
     io_token_ = std::make_unique<internal::KcerTokenImplNss>(token);
+    io_token_->SetAttributeTranslationForTesting(/*is_enabled=*/true);
     weak_ptr_ = io_token_->GetWeakPtr();
     // After this point `io_token_` should only be used on the IO thread.
   }
@@ -289,12 +359,23 @@
   base::test::TestFuture<base::expected<bool, Error>> does_key_exist_waiter;
   kcer->DoesPrivateKeyExist(PrivateKeyHandle(PublicKeySpki()),
                             does_key_exist_waiter.GetCallback());
+  base::test::TestFuture<base::expected<TokenInfo, Error>>
+      get_token_info_waiter;
+  kcer->GetTokenInfo(Token::kUser, get_token_info_waiter.GetCallback());
   base::test::TestFuture<base::expected<KeyInfo, Error>> get_key_info_waiter;
   kcer->GetKeyInfo(PrivateKeyHandle(PublicKeySpki()),
                    get_key_info_waiter.GetCallback());
   base::test::TestFuture<base::expected<void, Error>> set_nickname_waiter;
   kcer->SetKeyNickname(PrivateKeyHandle(PublicKeySpki()), "new_nickname",
                        set_nickname_waiter.GetCallback());
+  base::test::TestFuture<base::expected<void, Error>> set_permissions_waiter;
+  kcer->SetKeyPermissions(PrivateKeyHandle(PublicKeySpki()),
+                          chaps::KeyPermissions(),
+                          set_permissions_waiter.GetCallback());
+  base::test::TestFuture<base::expected<void, Error>> set_cert_prov_waiter;
+  kcer->SetCertProvisioningProfileId(PrivateKeyHandle(PublicKeySpki()),
+                                     "cert_prov_id",
+                                     set_cert_prov_waiter.GetCallback());
   // Close the list with one more GenerateRsaKey, so all methods are tested
   // with other methods before and after them.
   base::test::TestFuture<base::expected<PublicKey, Error>>
@@ -329,17 +410,49 @@
   ASSERT_FALSE(does_key_exist_waiter.Get().has_value());
   EXPECT_EQ(does_key_exist_waiter.Get().error(),
             Error::kTokenInitializationFailed);
+  ASSERT_FALSE(get_token_info_waiter.Get().has_value());
+  EXPECT_EQ(get_token_info_waiter.Get().error(),
+            Error::kTokenInitializationFailed);
   ASSERT_FALSE(get_key_info_waiter.Get().has_value());
   EXPECT_EQ(get_key_info_waiter.Get().error(),
             Error::kTokenInitializationFailed);
   ASSERT_FALSE(set_nickname_waiter.Get().has_value());
   EXPECT_EQ(set_nickname_waiter.Get().error(),
             Error::kTokenInitializationFailed);
+  ASSERT_FALSE(set_permissions_waiter.Get().has_value());
+  EXPECT_EQ(set_permissions_waiter.Get().error(),
+            Error::kTokenInitializationFailed);
+  ASSERT_FALSE(set_cert_prov_waiter.Get().has_value());
+  EXPECT_EQ(set_cert_prov_waiter.Get().error(),
+            Error::kTokenInitializationFailed);
   ASSERT_FALSE(generate_rsa_waiter_2.Get().has_value());
   EXPECT_EQ(generate_rsa_waiter_2.Get().error(),
             Error::kTokenInitializationFailed);
 }
 
+// Test that Kcer::GetTokenInfo() method returns meaningful values.
+TEST_F(KcerNssTest, GetTokenInfo) {
+  TokenHolder user_token(Token::kUser);
+  user_token.Initialize();
+
+  std::unique_ptr<Kcer> kcer = internal::CreateKcer(
+      IOTaskRunner(), user_token.GetWeakPtr(), /*device_token=*/nullptr);
+
+  base::test::TestFuture<base::expected<TokenInfo, Error>>
+      get_token_info_waiter;
+  kcer->GetTokenInfo(Token::kUser, get_token_info_waiter.GetCallback());
+  ASSERT_TRUE(get_token_info_waiter.Get().has_value());
+  const TokenInfo& token_info = get_token_info_waiter.Get().value();
+
+  // These values don't have to be exactly like this, they are what a software
+  // NSS slot returns in tests. Still useful to test that they are not
+  // completely off.
+  EXPECT_THAT(token_info.pkcs11_id, testing::Lt(1000u));
+  EXPECT_THAT(token_info.token_name,
+              testing::StartsWith("NSS Application Slot"));
+  EXPECT_EQ(token_info.module_name, "NSS Internal PKCS #11 Module");
+}
+
 // Test RSA specific fields from GetKeyInfo's result.
 TEST_F(KcerNssTest, GetKeyInfoForRsaKey) {
   TokenHolder user_token(Token::kUser);
@@ -411,28 +524,17 @@
   ASSERT_TRUE(generate_waiter.Get().has_value());
   const PublicKey& public_key = generate_waiter.Get().value();
 
-  {
-    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
-    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
-                     key_info_waiter.GetCallback());
-    ASSERT_TRUE(key_info_waiter.Get().has_value());
-    const KeyInfo& key_info = key_info_waiter.Get().value();
-    // Hardware- vs software-backed indicators on real devices are provided by
-    // Chaps and are wrong in unit tests.
-    EXPECT_EQ(key_info.is_hardware_backed, true);
-    // NSS sets an empty nickname by default, doesn't have to be like this in
-    // general.
-    ASSERT_TRUE(key_info.nickname.has_value());
-    EXPECT_EQ(key_info.nickname.value(), "");
-    EXPECT_FALSE(key_info.key_permissions.has_value());
-    EXPECT_FALSE(key_info.cert_provisioning_profile_id.has_value());
-  }
-
-  constexpr char kNickname[] = "new_nickname";
-  base::test::TestFuture<base::expected<void, Error>> set_nickname_waiter;
-  kcer->SetKeyNickname(PrivateKeyHandle(public_key), kNickname,
-                       set_nickname_waiter.GetCallback());
-  ASSERT_TRUE(set_nickname_waiter.Get().has_value());
+  KeyInfo expected_key_info;
+  // Hardware- vs software-backed indicators on real devices are provided by
+  // Chaps and are wrong in unit tests.
+  expected_key_info.is_hardware_backed = true;
+  // NSS sets an empty nickname by default, this doesn't have to be like this in
+  // general.
+  expected_key_info.nickname = "";
+  // Custom attributes are stored differently in tests and have empty values by
+  // default.
+  expected_key_info.key_permissions = chaps::KeyPermissions();
+  expected_key_info.cert_provisioning_profile_id = "";
 
   {
     base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
@@ -440,17 +542,75 @@
                      key_info_waiter.GetCallback());
     ASSERT_TRUE(key_info_waiter.Get().has_value());
     const KeyInfo& key_info = key_info_waiter.Get().value();
-    // Hardware- vs software-backed indicators on real devices are provided by
-    // Chaps and are wrong in unit tests.
-    EXPECT_EQ(key_info.is_hardware_backed, true);
-    ASSERT_TRUE(key_info.nickname.has_value());
-    EXPECT_EQ(key_info.nickname.value(), kNickname);
-    EXPECT_FALSE(key_info.key_permissions.has_value());
-    EXPECT_FALSE(key_info.cert_provisioning_profile_id.has_value());
+
+    // Copy some fields, their values are covered by dedicated tests, this test
+    // only checks that they don't change when they shouldn't.
+    expected_key_info.key_type = key_info.key_type;
+    expected_key_info.supported_signing_schemes =
+        key_info.supported_signing_schemes;
+
+    EXPECT_TRUE(KeyInfoEquals(expected_key_info, key_info));
   }
 
-  // TODO(244408716): Test setting and reading other key attributes when that's
-  // implemented.
+  {
+    expected_key_info.nickname = "new_nickname";
+
+    base::test::TestFuture<base::expected<void, Error>> set_nickname_waiter;
+    kcer->SetKeyNickname(PrivateKeyHandle(public_key),
+                         expected_key_info.nickname.value(),
+                         set_nickname_waiter.GetCallback());
+    ASSERT_TRUE(set_nickname_waiter.Get().has_value());
+  }
+
+  {
+    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
+                     key_info_waiter.GetCallback());
+    ASSERT_TRUE(key_info_waiter.Get().has_value());
+    EXPECT_TRUE(
+        KeyInfoEquals(expected_key_info, key_info_waiter.Get().value()));
+  }
+
+  {
+    expected_key_info.key_permissions->mutable_key_usages()->set_corporate(
+        true);
+    expected_key_info.key_permissions->mutable_key_usages()->set_arc(true);
+
+    base::test::TestFuture<base::expected<void, Error>> set_permissions_waiter;
+    kcer->SetKeyPermissions(PrivateKeyHandle(public_key),
+                            expected_key_info.key_permissions.value(),
+                            set_permissions_waiter.GetCallback());
+    ASSERT_TRUE(set_permissions_waiter.Get().has_value());
+  }
+
+  {
+    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
+                     key_info_waiter.GetCallback());
+    ASSERT_TRUE(key_info_waiter.Get().has_value());
+    EXPECT_TRUE(
+        KeyInfoEquals(expected_key_info, key_info_waiter.Get().value()));
+  }
+
+  {
+    expected_key_info.cert_provisioning_profile_id = "cert_prov_id_123";
+
+    base::test::TestFuture<base::expected<void, Error>> set_permissions_waiter;
+    kcer->SetCertProvisioningProfileId(
+        PrivateKeyHandle(public_key),
+        expected_key_info.cert_provisioning_profile_id.value(),
+        set_permissions_waiter.GetCallback());
+    ASSERT_TRUE(set_permissions_waiter.Get().has_value());
+  }
+
+  {
+    base::test::TestFuture<base::expected<KeyInfo, Error>> key_info_waiter;
+    kcer->GetKeyInfo(PrivateKeyHandle(public_key),
+                     key_info_waiter.GetCallback());
+    ASSERT_TRUE(key_info_waiter.Get().has_value());
+    EXPECT_TRUE(
+        KeyInfoEquals(expected_key_info, key_info_waiter.Get().value()));
+  }
 }
 
 // Test different ways to call DoesPrivateKeyExist() method and that it returns
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
index 80e52b6..a5e51de 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
@@ -13,6 +13,7 @@
 #include <string>
 #include <vector>
 
+#include "base/check_is_test.h"
 #include "base/compiler_specific.h"
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
@@ -56,8 +57,8 @@
   unblocker.RunAndReset();
 }
 
-// Returns a vector containing bytes from `value` or an empty vector if `value`
-// is nullptr.
+// Returns a vector containing bytes from `value` or an empty vector if
+// `value` is nullptr.
 std::vector<uint8_t> SECItemToBytes(crypto::ScopedSECItem value) {
   return value ? std::vector<uint8_t>(value->data, value->data + value->len)
                : std::vector<uint8_t>();
@@ -175,7 +176,8 @@
         slot.get(), SEC_OID_ANSIX962_EC_PRIME256V1, /*permanent=*/true,
         &public_key, &private_key);
   } else {
-    // Shouldn't be needed yet, will be implemented in non-NSS version of Kcer.
+    // Shouldn't be needed yet, will be implemented in non-NSS version of
+    // Kcer.
     return std::move(callback).Run(base::unexpected(Error::kNotImplemented));
   }
 
@@ -293,9 +295,9 @@
         base::unexpected(Error::kFailedToRemoveCertificate));
   }
   // TODO(miersh): Currently the method returns "success" even when
-  // SEC_DeletePermCertificate doesn't find the certificate. This is acceptable
-  // for a "remove" method, but it might be useful to change it after NSS is not
-  // used for Kcer.
+  // SEC_DeletePermCertificate doesn't find the certificate. This is
+  // acceptable for a "remove" method, but it might be useful to change it
+  // after NSS is not used for Kcer.
   std::move(callback).Run({});
 }
 
@@ -337,6 +339,7 @@
 
 base::expected<absl::optional<chaps::KeyPermissions>, Error>
 GetKeyPermissionsOnWorkerThread(
+    KeyPermissionsAttributeId key_permissions_attribute_id,
     const crypto::ScopedSECKEYPrivateKey& sec_private_key) {
   crypto::ScopedSECItem key_permissions_attribute(
       SECITEM_AllocItem(/*arena=*/nullptr,
@@ -345,8 +348,7 @@
 
   SECStatus status = PK11_ReadRawAttribute(
       /*objType=*/PK11_TypePrivKey, sec_private_key.get(),
-      pkcs11_custom_attributes::kCkaChromeOsKeyPermissions,
-      key_permissions_attribute.get());
+      key_permissions_attribute_id.value(), key_permissions_attribute.get());
 
   if (status != SECSuccess) {
     // CKR_ATTRIBUTE_TYPE_INVALID is a cryptoki function return value which is
@@ -372,6 +374,7 @@
 
 base::expected<absl::optional<std::string>, Error>
 GetCertProvisioningIdOnWorkerThread(
+    CertProvisioningIdAttributeId cert_prov_attribute_id,
     const crypto::ScopedSECKEYPrivateKey& sec_private_key) {
   crypto::ScopedSECItem cert_prov_attribute(SECITEM_AllocItem(/*arena=*/nullptr,
                                                               /*item=*/nullptr,
@@ -379,8 +382,7 @@
 
   SECStatus status = PK11_ReadRawAttribute(
       /*objType=*/PK11_TypePrivKey, sec_private_key.get(),
-      pkcs11_custom_attributes::kCkaChromeOsBuiltinProvisioningProfileId,
-      cert_prov_attribute.get());
+      cert_prov_attribute_id.value(), cert_prov_attribute.get());
 
   if (status != SECSuccess) {
     // CKR_ATTRIBUTE_TYPE_INVALID is a cryptoki function return value which is
@@ -400,9 +402,21 @@
                      cert_prov_attribute->data + cert_prov_attribute->len);
 }
 
-void GetKeyInfoOnWorkerThread(crypto::ScopedPK11Slot slot,
-                              PrivateKeyHandle key,
-                              Kcer::GetKeyInfoCallback callback) {
+void GetTokenInfoOnWorkerThread(crypto::ScopedPK11Slot slot,
+                                Kcer::GetTokenInfoCallback callback) {
+  TokenInfo token_info;
+  token_info.pkcs11_id = PK11_GetSlotID(slot.get());
+  token_info.token_name = PK11_GetSlotName(slot.get());
+  token_info.module_name = PK11_GetModule(slot.get())->commonName;
+  return std::move(callback).Run(std::move(token_info));
+}
+
+void GetKeyInfoOnWorkerThread(
+    KeyPermissionsAttributeId key_permissions_attribute_id,
+    CertProvisioningIdAttributeId cert_prov_attribute_id,
+    crypto::ScopedPK11Slot slot,
+    PrivateKeyHandle key,
+    Kcer::GetKeyInfoCallback callback) {
   KeyInfo key_info;
 
   base::expected<crypto::ScopedSECKEYPrivateKey, Error> private_key =
@@ -438,28 +452,21 @@
     PORT_Free(nickname);
   }
 
-  // TODO(miersh): Temporary disable the code because on some builds unit tests
-  // fail to read custom attributes. This will be re-enabled in a following CL
-  // when custom attributes are mapped into unused normal attributes in tests.
-#if 0
   base::expected<absl::optional<chaps::KeyPermissions>, Error> key_permissions =
-      GetKeyPermissionsOnWorkerThread(sec_private_key);
+      GetKeyPermissionsOnWorkerThread(key_permissions_attribute_id,
+                                      sec_private_key);
   if (!key_permissions.has_value()) {
     return std::move(callback).Run(base::unexpected(key_permissions.error()));
   }
   key_info.key_permissions = std::move(key_permissions).value();
 
   base::expected<absl::optional<std::string>, Error> cert_prov_id =
-      GetCertProvisioningIdOnWorkerThread(sec_private_key);
+      GetCertProvisioningIdOnWorkerThread(cert_prov_attribute_id,
+                                          sec_private_key);
   if (!cert_prov_id.has_value()) {
     return std::move(callback).Run(base::unexpected(cert_prov_id.error()));
   }
   key_info.cert_provisioning_profile_id = std::move(cert_prov_id).value();
-#endif
-  // TODO(miersh): Temporary suppress "unused method" warnings. This should be
-  // removed together with the "#if 0" above.
-  (void)GetKeyPermissionsOnWorkerThread;
-  (void)GetCertProvisioningIdOnWorkerThread;
 
   return std::move(callback).Run(std::move(key_info));
 }
@@ -482,6 +489,62 @@
   return std::move(callback).Run({});
 }
 
+void SetKeyPermissionsOnWorkerThread(KeyPermissionsAttributeId attribute_id,
+                                     crypto::ScopedPK11Slot slot,
+                                     PrivateKeyHandle key,
+                                     chaps::KeyPermissions key_permissions,
+                                     Kcer::StatusCallback callback) {
+  base::expected<crypto::ScopedSECKEYPrivateKey, Error> private_key =
+      GetSECKEYPrivateKey(slot, key);
+  if (!private_key.has_value()) {
+    return std::move(callback).Run(base::unexpected(private_key.error()));
+  }
+
+  std::vector<uint8_t> serialized_permissions;
+  serialized_permissions.resize(key_permissions.ByteSizeLong());
+  key_permissions.SerializeToArray(serialized_permissions.data(),
+                                   serialized_permissions.size());
+
+  SECItem attribute_value;
+  attribute_value.data = serialized_permissions.data();
+  attribute_value.len = serialized_permissions.size();
+
+  if (SECStatus res = PK11_WriteRawAttribute(
+          /*objType=*/PK11_TypePrivKey, private_key.value().get(),
+          attribute_id.value(), &attribute_value);
+      res != SECSuccess) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kFailedToWriteAttribute));
+  }
+  return std::move(callback).Run({});
+}
+
+void SetCertProvisioningProfileIdOnWorkerThread(
+    CertProvisioningIdAttributeId attribute_id,
+    crypto::ScopedPK11Slot slot,
+    PrivateKeyHandle key,
+    std::string cert_prov_id,
+    Kcer::StatusCallback callback) {
+  base::expected<crypto::ScopedSECKEYPrivateKey, Error> private_key =
+      GetSECKEYPrivateKey(slot, key);
+  if (!private_key.has_value()) {
+    return std::move(callback).Run(base::unexpected(private_key.error()));
+  }
+
+  SECItem attribute_value;
+  attribute_value.data = reinterpret_cast<uint8_t*>(cert_prov_id.data());
+  attribute_value.len = cert_prov_id.size();
+
+  if (SECStatus res = PK11_WriteRawAttribute(
+          /*objType=*/PK11_TypePrivKey, private_key.value().get(),
+          attribute_id.value(), &attribute_value);
+      res != SECSuccess) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kFailedToWriteAttribute));
+  }
+  return std::move(callback).Run({});
+}
+
 scoped_refptr<const Cert> BuildKcerCert(
     Token token,
     const net::ScopedCERTCertificate& nss_cert) {
@@ -512,8 +575,8 @@
     state_ = State::kInitializationFailed;
   }
 
-  // This is supposed to be the first time the task queue is unblocked, no other
-  // tasks should be already running.
+  // This is supposed to be the first time the task queue is unblocked, no
+  // other tasks should be already running.
   UnblockQueueProcessNextTask();
 }
 
@@ -744,7 +807,25 @@
 
 void KcerTokenImplNss::GetTokenInfo(Kcer::GetTokenInfoCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  // TODO(244408716): Implement.
+
+  if (UNLIKELY(state_ == State::kInitializationFailed)) {
+    return HandleInitializationFailed(std::move(callback));
+  }
+  if (is_blocked_) {
+    return task_queue_.push(base::BindOnce(&KcerTokenImplNss::GetTokenInfo,
+                                           weak_factory_.GetWeakPtr(),
+                                           std::move(callback)));
+  }
+
+  // Block task queue, attach unblocking task to the callback.
+  auto unblocking_callback = std::move(callback).Then(BlockQueueGetUnblocker());
+
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&GetTokenInfoOnWorkerThread,
+                     crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
+                     std::move(unblocking_callback)));
 }
 
 void KcerTokenImplNss::GetKeyInfo(PrivateKeyHandle key,
@@ -765,7 +846,8 @@
   base::ThreadPool::PostTask(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&GetKeyInfoOnWorkerThread,
+      base::BindOnce(&GetKeyInfoOnWorkerThread, GetKeyPermissionsAttributeId(),
+                     GetCertProvisioningIdAttributeId(),
                      crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
                      std::move(key), std::move(unblocking_callback)));
 }
@@ -799,7 +881,26 @@
                                          chaps::KeyPermissions key_permissions,
                                          Kcer::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  // TODO(244408716): Implement.
+
+  if (UNLIKELY(state_ == State::kInitializationFailed)) {
+    return HandleInitializationFailed(std::move(callback));
+  } else if (is_blocked_) {
+    return task_queue_.push(base::BindOnce(
+        &KcerTokenImplNss::SetKeyPermissions, weak_factory_.GetWeakPtr(),
+        std::move(key), std::move(key_permissions), std::move(callback)));
+  }
+
+  // Block task queue, attach unblocking task to the callback.
+  auto unblocking_callback = std::move(callback).Then(BlockQueueGetUnblocker());
+
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&SetKeyPermissionsOnWorkerThread,
+                     GetKeyPermissionsAttributeId(),
+                     crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
+                     std::move(key), std::move(key_permissions),
+                     std::move(unblocking_callback)));
 }
 
 void KcerTokenImplNss::SetCertProvisioningProfileId(
@@ -807,7 +908,27 @@
     std::string profile_id,
     Kcer::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  // TODO(244408716): Implement.
+
+  if (UNLIKELY(state_ == State::kInitializationFailed)) {
+    return HandleInitializationFailed(std::move(callback));
+  } else if (is_blocked_) {
+    return task_queue_.push(
+        base::BindOnce(&KcerTokenImplNss::SetCertProvisioningProfileId,
+                       weak_factory_.GetWeakPtr(), std::move(key),
+                       std::move(profile_id), std::move(callback)));
+  }
+
+  // Block task queue, attach unblocking task to the callback.
+  auto unblocking_callback = std::move(callback).Then(BlockQueueGetUnblocker());
+
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&SetCertProvisioningProfileIdOnWorkerThread,
+                     GetCertProvisioningIdAttributeId(),
+                     crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
+                     std::move(key), std::move(profile_id),
+                     std::move(unblocking_callback)));
 }
 
 void KcerTokenImplNss::OnCertsModified(Kcer::StatusCallback callback,
@@ -836,8 +957,8 @@
   base::ScopedClosureRunner unblocker(
       base::BindOnce(&KcerTokenImplNss::UnblockQueueProcessNextTask,
                      weak_factory_.GetWeakPtr()));
-  // Pack `unblocker` into an IO thread bound closure, so it can be attached to
-  // a callback.
+  // Pack `unblocker` into an IO thread bound closure, so it can be attached
+  // to a callback.
   return base::BindPostTask(
       content::GetIOThreadTaskRunner({}),
       base::BindOnce(&RunUnblocker, std::move(unblocker)));
@@ -886,9 +1007,9 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   if (state_ == State::kCacheOutdated) {
-    // If the status switched from kUpdating, then new update happened since the
-    // cache started to update, `new_certs` might already be outdated. Skip
-    // re-building the cache and try again.
+    // If the status switched from kUpdating, then new update happened since
+    // the cache started to update, `new_certs` might already be outdated.
+    // Skip re-building the cache and try again.
     return;
   }
 
@@ -905,8 +1026,8 @@
   }
 
   // Rebuilding the cache implicitly removes all the certs that are not in the
-  // permanent storage anymore. The certs themself will be fully destroyed when
-  // the last ref-counting reference to them is destroyed.
+  // permanent storage anymore. The certs themself will be fully destroyed
+  // when the last ref-counting reference to them is destroyed.
   cert_cache_ = CertCacheNss(new_cache);
   state_ = State::kCacheUpToDate;
 }
@@ -916,11 +1037,36 @@
     base::OnceCallback<void(base::expected<T, Error>)> callback) {
   std::move(callback).Run(base::unexpected(Error::kTokenInitializationFailed));
   // Multiple tasks might be handled in a row, schedule the next task
-  // asynchronously to not overload the stack and not occupy the thread for too
-  // long.
+  // asynchronously to not overload the stack and not occupy the thread for
+  // too long.
   content::GetIOThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&KcerTokenImplNss::UnblockQueueProcessNextTask,
                                 weak_factory_.GetWeakPtr()));
 }
 
+void KcerTokenImplNss::SetAttributeTranslationForTesting(bool is_enabled) {
+  CHECK_IS_TEST();
+  translate_attributes_for_testing_ = is_enabled;
+}
+
+KeyPermissionsAttributeId KcerTokenImplNss::GetKeyPermissionsAttributeId()
+    const {
+  if (UNLIKELY(translate_attributes_for_testing_)) {
+    CHECK_IS_TEST();
+    return KeyPermissionsAttributeId(CKA_END_DATE);
+  }
+  return KeyPermissionsAttributeId(
+      pkcs11_custom_attributes::kCkaChromeOsKeyPermissions);
+}
+
+CertProvisioningIdAttributeId
+KcerTokenImplNss::GetCertProvisioningIdAttributeId() const {
+  if (UNLIKELY(translate_attributes_for_testing_)) {
+    CHECK_IS_TEST();
+    return CertProvisioningIdAttributeId(CKA_START_DATE);
+  }
+  return CertProvisioningIdAttributeId(
+      pkcs11_custom_attributes::kCkaChromeOsBuiltinProvisioningProfileId);
+}
+
 }  // namespace kcer::internal
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
index 321ed14..348a153 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
+++ b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
@@ -12,15 +12,24 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
+#include "base/types/strong_alias.h"
 #include "chrome/browser/chromeos/kcer_nss/cert_cache_nss.h"
 #include "chromeos/components/kcer/kcer_token.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/cert_database.h"
 #include "net/cert/scoped_nss_types.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/cros_system_api/constants/pkcs11_custom_attributes.h"
 
 namespace kcer::internal {
 
+using KeyPermissionsAttributeId =
+    base::StrongAlias<class TagKcerToken0,
+                      pkcs11_custom_attributes::CkAttributeType>;
+using CertProvisioningIdAttributeId =
+    base::StrongAlias<class TagKcerToken1,
+                      pkcs11_custom_attributes::CkAttributeType>;
+
 // Implementation of KcerToken that uses NSS as a permanent storage.
 class KcerTokenImplNss : public KcerToken, public net::CertDatabase::Observer {
  public:
@@ -101,6 +110,12 @@
                                     std::string profile_id,
                                     Kcer::StatusCallback callback) override;
 
+  // NSS software database (softoken) doesn't support custom attributes. If
+  // attribute translation is enabled, KcerToken will store the attributes in
+  // some standard attributes, which is wrong in general, but good enough for
+  // tests.
+  void SetAttributeTranslationForTesting(bool is_enabled);
+
  private:
   // Immediately blocks the queue and returns a closure that unblocks it when
   // called or destroyed.
@@ -123,6 +138,13 @@
   void OnCertsModified(Kcer::StatusCallback callback,
                        base::expected<void, Error> result);
 
+  // These methods return PKCS#11 attribute IDs that should be passed to NSS,
+  // respecting SetAttribtueTranslationForTesting.
+  KeyPermissionsAttributeId GetKeyPermissionsAttributeId() const;
+  CertProvisioningIdAttributeId GetCertProvisioningIdAttributeId() const;
+
+  // Indicates whether fake attribute ids should be used (for testing).
+  bool translate_attributes_for_testing_ = false;
   // Indicates whether the task queue is blocked. Task queue should be blocked
   // until NSS is initialized, during the processing of most requests and
   // during updating the cache.
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h b/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h
index 0a83aeb..abe095b 100644
--- a/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h
+++ b/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h
@@ -15,6 +15,13 @@
 
 namespace policy {
 
+// Dialog type (warning or error).
+enum class FilesDialogType {
+  kUnknown,  // Not a valid type - no dialog will be created.
+  kWarning,  // Warning dialog - user can select to proceed or not.
+  kError,    // Error dialog - overview of blocked files.
+};
+
 // FilesPolicyDialog is a window modal dialog used to show detailed overview of
 // warnings and files blocked by data protection policies.
 class FilesPolicyDialog : public PolicyDialogBase {
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_files_controller.h b/chrome/browser/chromeos/policy/dlp/dlp_files_controller.h
index da93340..e66afa4 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_files_controller.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_files_controller.h
@@ -35,6 +35,8 @@
 
   virtual ~DlpFilesController();
 
+  static constexpr bool kCopyTaskFlowEnabled = false;
+
  protected:
   explicit DlpFilesController(const DlpRulesManager& rules_manager);
 
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index 591ae08b..056aa90 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -297,6 +298,8 @@
       prefs->GetString(prefs::kDemoModeCountry);
   demo_app_installer_attributes["is_cloud_gaming_device"] =
       chromeos::features::IsCloudGamingDeviceEnabled() ? "true" : "false";
+  demo_app_installer_attributes["is_feature_aware_device"] =
+      ash::features::IsFeatureAwareDeviceDemoModeEnabled() ? "true" : "false";
   return demo_app_installer_attributes;
 }
 
diff --git a/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc b/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
index 4732141..40da6f7 100644
--- a/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
@@ -177,16 +177,16 @@
   std::unique_ptr<content_settings::RuleIterator> rule_iterator(
       map.GetRuleIterator(ContentSettingsType::COOKIES));
   ASSERT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(sub_pattern, rule.primary_pattern);
-  EXPECT_EQ(2, content_settings::ValueToContentSetting(rule.value));
-  EXPECT_EQ(t2, rule.metadata.last_modified);
+  std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+  EXPECT_EQ(sub_pattern, rule->primary_pattern);
+  EXPECT_EQ(2, content_settings::ValueToContentSetting(rule->value()));
+  EXPECT_EQ(t2, rule->metadata.last_modified);
 
   ASSERT_TRUE(rule_iterator->HasNext());
   rule = rule_iterator->Next();
-  EXPECT_EQ(pattern, rule.primary_pattern);
-  EXPECT_EQ(1, content_settings::ValueToContentSetting(rule.value));
-  EXPECT_EQ(t1, rule.metadata.last_modified);
+  EXPECT_EQ(pattern, rule->primary_pattern);
+  EXPECT_EQ(1, content_settings::ValueToContentSetting(rule->value()));
+  EXPECT_EQ(t1, rule->metadata.last_modified);
 }
 
 TEST(OriginIdentifierValueMapTest, UpdateLastModified) {
@@ -216,21 +216,21 @@
     std::unique_ptr<content_settings::RuleIterator> rule_iterator(
         map.GetRuleIterator(ContentSettingsType::COOKIES));
     ASSERT_TRUE(rule_iterator->HasNext());
-    content_settings::Rule rule = rule_iterator->Next();
-    EXPECT_EQ(sub_pattern, rule.primary_pattern);
-    EXPECT_EQ(2, content_settings::ValueToContentSetting(rule.value));
-    EXPECT_EQ(t1, rule.metadata.last_modified);
-    ASSERT_FALSE(rule.metadata.expiration.is_null());
-    EXPECT_GT(rule.metadata.expiration, base::Time::Now());
-    EXPECT_EQ(rule.metadata.session_model,
+    std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+    EXPECT_EQ(sub_pattern, rule->primary_pattern);
+    EXPECT_EQ(2, content_settings::ValueToContentSetting(rule->value()));
+    EXPECT_EQ(t1, rule->metadata.last_modified);
+    ASSERT_FALSE(rule->metadata.expiration.is_null());
+    EXPECT_GT(rule->metadata.expiration, base::Time::Now());
+    EXPECT_EQ(rule->metadata.session_model,
               content_settings::SessionModel::UserSession);
 
     rule = rule_iterator->Next();
-    EXPECT_EQ(pattern, rule.primary_pattern);
-    EXPECT_EQ(1, content_settings::ValueToContentSetting(rule.value));
-    EXPECT_EQ(t1, rule.metadata.last_modified);
-    ASSERT_TRUE(rule.metadata.expiration.is_null());
-    EXPECT_EQ(rule.metadata.session_model,
+    EXPECT_EQ(pattern, rule->primary_pattern);
+    EXPECT_EQ(1, content_settings::ValueToContentSetting(rule->value()));
+    EXPECT_EQ(t1, rule->metadata.last_modified);
+    ASSERT_TRUE(rule->metadata.expiration.is_null());
+    EXPECT_EQ(rule->metadata.session_model,
               content_settings::SessionModel::Durable);
     ASSERT_FALSE(rule_iterator->HasNext());
   }
@@ -244,14 +244,14 @@
     std::unique_ptr<content_settings::RuleIterator> rule_iterator =
         map.GetRuleIterator(ContentSettingsType::COOKIES);
     ASSERT_TRUE(rule_iterator->HasNext());
-    content_settings::Rule rule = rule_iterator->Next();
-    EXPECT_EQ(sub_pattern, rule.primary_pattern);
-    EXPECT_EQ(2, content_settings::ValueToContentSetting(rule.value));
-    EXPECT_EQ(t1, rule.metadata.last_modified);
+    std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+    EXPECT_EQ(sub_pattern, rule->primary_pattern);
+    EXPECT_EQ(2, content_settings::ValueToContentSetting(rule->value()));
+    EXPECT_EQ(t1, rule->metadata.last_modified);
     rule = rule_iterator->Next();
-    EXPECT_EQ(pattern, rule.primary_pattern);
-    EXPECT_EQ(3, content_settings::ValueToContentSetting(rule.value));
-    EXPECT_EQ(t2, rule.metadata.last_modified);
+    EXPECT_EQ(pattern, rule->primary_pattern);
+    EXPECT_EQ(3, content_settings::ValueToContentSetting(rule->value()));
+    EXPECT_EQ(t2, rule->metadata.last_modified);
     ASSERT_FALSE(rule_iterator->HasNext());
   }
 }
diff --git a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
index 372cda9..4b56d3a5 100644
--- a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
@@ -54,12 +54,12 @@
       provider.GetRuleIterator(ContentSettingsType::GEOLOCATION, false);
   ASSERT_TRUE(rule_iterator);
   EXPECT_TRUE(rule_iterator->HasNext());
-  Rule rule = rule_iterator->Next();
+  std::unique_ptr<Rule> rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule->value()));
 
   provider.ShutdownOnUIThread();
 }
@@ -76,12 +76,12 @@
   std::unique_ptr<RuleIterator> rule_iterator(
       provider.GetRuleIterator(ContentSettingsType::COOKIES, false));
   EXPECT_TRUE(rule_iterator->HasNext());
-  Rule rule = rule_iterator->Next();
+  std::unique_ptr<Rule> rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule->value()));
 
   provider.ShutdownOnUIThread();
 }
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index 7520bf47..ea1a9d6 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -448,13 +448,13 @@
     std::unique_ptr<RuleIterator> it(
         normal_provider.GetRuleIterator(ContentSettingsType::COOKIES, false));
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_5, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_5, it->Next()->primary_pattern);
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_3, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_3, it->Next()->primary_pattern);
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_4, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_4, it->Next()->primary_pattern);
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_1, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_1, it->Next()->primary_pattern);
     EXPECT_FALSE(it->HasNext());
   }
 
@@ -479,11 +479,11 @@
     std::unique_ptr<RuleIterator> it(incognito_provider.GetRuleIterator(
         ContentSettingsType::COOKIES, false));
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_3, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_3, it->Next()->primary_pattern);
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_4, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_4, it->Next()->primary_pattern);
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_1, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_1, it->Next()->primary_pattern);
     EXPECT_FALSE(it->HasNext());
   }
 
@@ -492,7 +492,7 @@
     std::unique_ptr<RuleIterator> it(
         incognito_provider.GetRuleIterator(ContentSettingsType::COOKIES, true));
     EXPECT_TRUE(it->HasNext());
-    EXPECT_EQ(pattern_2, it->Next().primary_pattern);
+    EXPECT_EQ(pattern_2, it->Next()->primary_pattern);
     EXPECT_FALSE(it->HasNext());
   }
 
diff --git a/chrome/browser/content_settings/content_settings_supervised_provider_unittest.cc b/chrome/browser/content_settings/content_settings_supervised_provider_unittest.cc
index 8119978..b78d52f 100644
--- a/chrome/browser/content_settings/content_settings_supervised_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_supervised_provider_unittest.cc
@@ -63,12 +63,12 @@
   rule_iterator =
       provider_->GetRuleIterator(ContentSettingsType::GEOLOCATION, false);
   ASSERT_TRUE(rule_iterator->HasNext());
-  Rule rule = rule_iterator->Next();
+  std::unique_ptr<Rule> rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule->value()));
 
   // Re-enable the default geolocation setting.
   EXPECT_CALL(mock_observer_,
@@ -86,12 +86,12 @@
       provider_->GetRuleIterator(ContentSettingsType::COOKIES, false);
 
   ASSERT_TRUE(rule_iterator->HasNext());
-  Rule rule = rule_iterator->Next();
+  std::unique_ptr<Rule> rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_ALLOW, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, ValueToContentSetting(rule->value()));
 
   // Re-enable the default cookie setting.
   EXPECT_CALL(mock_observer_,
@@ -124,12 +124,12 @@
   rule_iterator = provider_->GetRuleIterator(
       ContentSettingsType::MEDIASTREAM_CAMERA, false);
   ASSERT_TRUE(rule_iterator->HasNext());
-  Rule rule = rule_iterator->Next();
+  std::unique_ptr<Rule> rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule->value()));
 
   rule_iterator =
       provider_->GetRuleIterator(ContentSettingsType::MEDIASTREAM_MIC, false);
@@ -137,9 +137,9 @@
   rule = rule_iterator->Next();
   EXPECT_FALSE(rule_iterator->HasNext());
 
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule.value));
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, ValueToContentSetting(rule->value()));
 
   // Re-enable the default camera and microphone setting.
   EXPECT_CALL(
diff --git a/chrome/browser/content_settings/one_time_permission_provider.cc b/chrome/browser/content_settings/one_time_permission_provider.cc
index ea3ea62..9434bc6 100644
--- a/chrome/browser/content_settings/one_time_permission_provider.cc
+++ b/chrome/browser/content_settings/one_time_permission_provider.cc
@@ -172,10 +172,11 @@
 
   while (rule_iterator && rule_iterator->HasNext()) {
     auto rule = rule_iterator->Next();
-    if (rule.primary_pattern.Matches(origin_gurl) &&
-        rule.secondary_pattern.Matches(origin_gurl)) {
-      patterns_to_delete.insert({rule.primary_pattern, rule.secondary_pattern});
-      if (rule.metadata.expiration >= clock_->Now()) {
+    if (rule->primary_pattern.Matches(origin_gurl) &&
+        rule->secondary_pattern.Matches(origin_gurl)) {
+      patterns_to_delete.insert(
+          {rule->primary_pattern, rule->secondary_pattern});
+      if (rule->metadata.expiration >= clock_->Now()) {
         permissions::PermissionUmaUtil::RecordOneTimePermissionEvent(
             content_setting_type, trigger_event);
       }
diff --git a/chrome/browser/dev_ui_browser_resources.grd b/chrome/browser/dev_ui_browser_resources.grd
index cac60b9..2f58d2bb 100644
--- a/chrome/browser/dev_ui_browser_resources.grd
+++ b/chrome/browser/dev_ui_browser_resources.grd
@@ -23,8 +23,8 @@
       <include name="IDR_ACCESSIBILITY_JS" file="${root_gen_dir}\chrome\browser\resources\accessibility\tsc\accessibility.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_COMPONENTS_COMPONENTS_HTML" file="resources\components\components.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_COMPONENTS_COMPONENTS_JS" file="${root_gen_dir}\chrome\browser\resources\components\tsc\components.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_DEVICE_LOG_UI_HTML" file="resources\device_log_ui\device_log_ui.html" type="BINDATA" />
-      <include name="IDR_DEVICE_LOG_UI_JS" file="resources\device_log_ui\device_log_ui.js" type="BINDATA" />
+      <include name="IDR_DEVICE_LOG_UI_HTML" file="resources\device_log_ui\device_log_ui.html" preprocess="true" type="BINDATA" />
+      <include name="IDR_DEVICE_LOG_UI_JS" file="resources\device_log_ui\device_log_ui.js" preprocess="true" type="BINDATA" />
       <include name="IDR_DEVICE_LOG_UI_CSS" file="resources\device_log_ui\device_log_ui.css" type="BINDATA" />
       <include name="IDR_MEMORY_INTERNALS_HTML" file="resources\memory_internals\memory_internals.html" type="BINDATA" />
       <include name="IDR_MEMORY_INTERNALS_JS" file="${root_gen_dir}\chrome\browser\resources\memory_internals\tsc\memory_internals.js" use_base_dir="false" type="BINDATA" />
diff --git a/chrome/browser/devtools/protocol/autofill_handler.cc b/chrome/browser/devtools/protocol/autofill_handler.cc
index c446cef..ad3815d 100644
--- a/chrome/browser/devtools/protocol/autofill_handler.cc
+++ b/chrome/browser/devtools/protocol/autofill_handler.cc
@@ -17,6 +17,7 @@
 #include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
 #include "components/autofill/core/common/unique_ids.h"
 #include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/render_frame_host.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 using autofill::AutofillTriggerSource;
@@ -55,6 +56,7 @@
 
 void AutofillHandler::Trigger(
     int field_id,
+    Maybe<String> frame_id,
     std::unique_ptr<protocol::Autofill::CreditCard> card,
     std::unique_ptr<TriggerCallback> callback) {
   auto host = content::DevToolsAgentHost::GetForId(target_id_);
@@ -63,12 +65,14 @@
     return;
   }
   host->GetUniqueFormControlId(
-      field_id, base::BindOnce(&AutofillHandler::FinishTrigger,
-                               weak_ptr_factory_.GetWeakPtr(), std::move(card),
-                               std::move(callback)));
+      field_id,
+      base::BindOnce(&AutofillHandler::FinishTrigger,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(frame_id),
+                     std::move(card), std::move(callback)));
 }
 
 void AutofillHandler::FinishTrigger(
+    Maybe<String> frame_id,
     std::unique_ptr<protocol::Autofill::CreditCard> card,
     std::unique_ptr<TriggerCallback> callback,
     uint64_t field_id) {
@@ -81,6 +85,26 @@
   content::RenderFrameHost* outermost_primary_rfh =
       host->GetWebContents()->GetOutermostWebContents()->GetPrimaryMainFrame();
 
+  autofill::LocalFrameToken frame_token(
+      outermost_primary_rfh->GetFrameToken().value());
+  if (frame_id.isJust()) {
+    bool found = false;
+    outermost_primary_rfh->ForEachRenderFrameHost(
+        [&frame_token, &frame_id, &found](content::RenderFrameHost* rfh) {
+          if (rfh->GetDevToolsFrameToken().ToString() == frame_id.fromJust()) {
+            frame_token =
+                autofill::LocalFrameToken(rfh->GetFrameToken().value());
+            found = true;
+          }
+        });
+
+    if (!found) {
+      std::move(callback)->sendFailure(
+          Response::ServerError("Frame not found"));
+      return;
+    }
+  }
+
   autofill::ContentAutofillDriver* autofill_driver =
       autofill::ContentAutofillDriver::GetForRenderFrameHost(
           outermost_primary_rfh);
@@ -90,8 +114,6 @@
     return;
   }
 
-  autofill::LocalFrameToken frame_token(
-      outermost_primary_rfh->GetFrameToken().value());
   autofill::FieldGlobalId global_field_id = {
       frame_token, autofill::FieldRendererId(field_id)};
 
diff --git a/chrome/browser/devtools/protocol/autofill_handler.h b/chrome/browser/devtools/protocol/autofill_handler.h
index 898cde2..0ac894c 100644
--- a/chrome/browser/devtools/protocol/autofill_handler.h
+++ b/chrome/browser/devtools/protocol/autofill_handler.h
@@ -24,9 +24,11 @@
 
  private:
   void Trigger(int field_id,
+               Maybe<String> frame_id,
                std::unique_ptr<protocol::Autofill::CreditCard> card,
                std::unique_ptr<TriggerCallback> callback) override;
-  void FinishTrigger(std::unique_ptr<protocol::Autofill::CreditCard> card,
+  void FinishTrigger(Maybe<String> frame_id,
+                     std::unique_ptr<protocol::Autofill::CreditCard> card,
                      std::unique_ptr<TriggerCallback> callback,
                      uint64_t field_id);
 
diff --git a/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc b/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
index b5a9fa0f6..a1c71010 100644
--- a/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/strcat.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -45,10 +47,83 @@
   content::RenderFrameHost* main_frame() {
     return web_contents()->GetPrimaryMainFrame();
   }
+
   TestAutofillManager* main_autofill_manager() {
     return TestAutofillManager::GetForRenderFrameHost(main_frame());
   }
 
+  std::string EvaluateAndGetValue(const std::string& expression,
+                                  const std::string& unique_context_id) {
+    base::Value::Dict params;
+    params.Set("expression", expression);
+    if (!unique_context_id.empty()) {
+      params.Set("uniqueContextId", unique_context_id);
+    }
+    const base::Value::Dict* result =
+        SendCommand("Runtime.evaluate", std::move(params));
+    return *result->FindStringByDottedPath("result.value");
+  }
+
+  int GetBackendNodeIdByIdAttribute(const std::string& expression) {
+    return GetBackendNodeIdByIdAttribute(expression, "");
+  }
+
+  int GetBackendNodeIdByIdAttribute(const std::string& id_attribute,
+                                    const std::string& unique_context_id) {
+    std::string object_id;
+    {
+      base::Value::Dict params;
+      params.Set("expression", base::StrCat({"document.getElementById('",
+                                             id_attribute, "')"}));
+      if (!unique_context_id.empty()) {
+        params.Set("uniqueContextId", unique_context_id);
+      }
+      const base::Value::Dict* result =
+          SendCommand("Runtime.evaluate", std::move(params));
+      object_id = *result->FindStringByDottedPath("result.objectId");
+    }
+
+    base::Value::Dict params;
+    params.Set("objectId", object_id);
+    const base::Value::Dict* result =
+        SendCommand("DOM.describeNode", std::move(params));
+    return *result->FindIntByDottedPath("node.backendNodeId");
+  }
+
+  base::Value::Dict GetTestCreditCard() {
+    base::Value::Dict card;
+    card.Set("number", "4444444444444444");
+    card.Set("name", "John Smith");
+    card.Set("expiryMonth", "01");
+    card.Set("expiryYear", "2030");
+    card.Set("cvc", "123");
+    return card;
+  }
+
+  base::Value::Dict GetFilledOutForm(const std::string& unique_context_id) {
+    base::Value::Dict card;
+    card.Set("number",
+             EvaluateAndGetValue(
+                 "document.getElementById('CREDIT_CARD_NUMBER').value",
+                 unique_context_id));
+    card.Set("name",
+             EvaluateAndGetValue(
+                 "document.getElementById('CREDIT_CARD_NAME_FULL').value",
+                 unique_context_id));
+    card.Set("expiryMonth",
+             EvaluateAndGetValue(
+                 "document.getElementById('CREDIT_CARD_EXP_MONTH').value",
+                 unique_context_id));
+    card.Set(
+        "expiryYear",
+        EvaluateAndGetValue(
+            "document.getElementById('CREDIT_CARD_EXP_4_DIGIT_YEAR').value",
+            unique_context_id));
+    // CVC is not filled out in the form.
+    card.Set("cvc", "123");
+    return card;
+  }
+
  private:
   autofill::TestAutofillManagerInjector<TestAutofillManager>
       autofill_manager_injector_;
@@ -64,65 +139,86 @@
   ASSERT_TRUE(content::WaitForLoadStop(web_contents()));
   Attach();
 
-  content::SimulateMouseClickOrTapElementWithId(
-      browser()->tab_strip_model()->GetActiveWebContents(),
-      "CREDIT_CARD_NUMBER");
-
   EXPECT_TRUE(main_autofill_manager()->WaitForFormsSeen(1));
 
-  content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
-
-  std::string object_id;
-  {
-    base::Value::Dict params;
-    params.Set("expression", "document.getElementById('CREDIT_CARD_NUMBER')");
-    const base::Value::Dict* result =
-        SendCommand("Runtime.evaluate", std::move(params));
-    object_id = *result->FindStringByDottedPath("result.objectId");
-  }
-
-  int backend_node_id = 0;
-  {
-    base::Value::Dict params;
-    params.Set("objectId", object_id);
-    const base::Value::Dict* result =
-        SendCommand("DOM.describeNode", std::move(params));
-    backend_node_id = *result->FindIntByDottedPath("node.backendNodeId");
-  }
+  int backend_node_id = GetBackendNodeIdByIdAttribute("CREDIT_CARD_NUMBER");
 
   base::Value::Dict params;
   params.Set("fieldId", backend_node_id);
+  params.Set("card", GetTestCreditCard());
 
-  base::Value::Dict card;
-  card.Set("number", "4444444444444444");
-  card.Set("name", "John Smith");
-  card.Set("expiryMonth", "01");
-  card.Set("expiryYear", "2030");
-  card.Set("cvc", "123");
-  params.Set("card", std::move(card));
+  SendCommandSync("Autofill.trigger", std::move(params));
+  EXPECT_EQ(*result(), base::Value::Dict());
+  EXPECT_EQ(GetFilledOutForm(""), GetTestCreditCard());
+}
 
-  const base::Value::Dict* result =
-      SendCommandSync("Autofill.trigger", std::move(params));
+// TODO(crbug.com/1416789): The test currently fails on chromeos probably
+// because of a difference in behaviour between the chrome-branded and not
+// chrome-branded patterns in Autofill.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_TriggerCreditCardInIframe DISABLED_TriggerCreditCardInIframe
+#else
+#define MAYBE_TriggerCreditCardInIframe TriggerCreditCardInIframe
+#endif
+IN_PROC_BROWSER_TEST_F(DevToolsAutofillTest, MAYBE_TriggerCreditCardInIframe) {
+  embedded_test_server()->ServeFilesFromSourceDirectory(
+      "chrome/test/data/autofill");
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL url(embedded_test_server()->GetURL(
+      "/autofill_creditcard_form_in_iframe.html"));
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  ASSERT_TRUE(content::WaitForLoadStop(web_contents()));
+  Attach();
 
-  EXPECT_EQ(*result, base::Value::Dict());
+  EXPECT_TRUE(main_autofill_manager()->WaitForFormsSeen(1));
 
-  std::string ccNameResult =
-      EvalJs(rfh, "document.getElementById('CREDIT_CARD_NAME_FULL').value")
-          .ExtractString();
-  std::string ccNumberResult =
-      EvalJs(rfh, "document.getElementById('CREDIT_CARD_NUMBER').value")
-          .ExtractString();
-  std::string ccExpiryMonthResult =
-      EvalJs(rfh, "document.getElementById('CREDIT_CARD_EXP_MONTH').value")
-          .ExtractString();
-  std::string ccExpiryYearResult =
-      EvalJs(rfh,
-             "document.getElementById('CREDIT_CARD_EXP_4_DIGIT_YEAR').value")
-          .ExtractString();
-  EXPECT_EQ(ccNameResult, "John Smith");
-  EXPECT_EQ(ccNumberResult, "4444444444444444");
-  EXPECT_EQ(ccExpiryMonthResult, "01");
-  EXPECT_EQ(ccExpiryYearResult, "2030");
+  std::string frame_id;
+  {
+    const base::Value::Dict* result = SendCommandSync("Page.getFrameTree");
+    const base::Value::List* frames =
+        result->FindListByDottedPath("frameTree.childFrames");
+    const base::Value::Dict* frame_dict = frames->front().GetIfDict();
+    frame_id = *frame_dict->FindStringByDottedPath("frame.id");
+  }
+
+  std::string unique_context_id;
+  {
+    base::Value::Dict command_params;
+    SendCommandSync("Runtime.enable");
+    base::Value::Dict params;
+    for (int context_count = 1; true; context_count++) {
+      params = WaitForNotification("Runtime.executionContextCreated", true);
+      if (*params.FindStringByDottedPath("context.auxData.frameId") ==
+          frame_id) {
+        unique_context_id = *params.FindStringByDottedPath("context.uniqueId");
+        break;
+      }
+      ASSERT_LT(context_count, 2);
+    }
+  }
+
+  int backend_node_id =
+      GetBackendNodeIdByIdAttribute("CREDIT_CARD_NUMBER", unique_context_id);
+
+  {
+    base::Value::Dict params;
+    params.Set("fieldId", backend_node_id);
+    params.Set("card", GetTestCreditCard());
+    params.Set("frameId", "wrong");
+    SendCommandSync("Autofill.trigger", std::move(params));
+    EXPECT_EQ(*error()->FindString("message"), "Frame not found");
+  }
+
+  {
+    base::Value::Dict params;
+    params.Set("fieldId", backend_node_id);
+    params.Set("card", GetTestCreditCard());
+    params.Set("frameId", frame_id);
+    SendCommandSync("Autofill.trigger", std::move(params));
+    EXPECT_EQ(*result(), base::Value::Dict());
+  }
+
+  EXPECT_EQ(GetFilledOutForm(unique_context_id), GetTestCreditCard());
 }
 
 }  // namespace
diff --git a/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc b/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc
index 615afc9..1151ece 100644
--- a/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc
+++ b/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc
@@ -14,6 +14,8 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 
+// TODO(crbug.com/1399414): Refactor tests when we start emitting issues in
+// bulk, via checkFormsIssues command and FormIssuesAdded event.
 namespace autofill {
 
 namespace {
@@ -57,6 +59,15 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(AutofillFormDevtoolsProtocolTest,
+                       checkFormIssuesCommandReturnsIssuesList) {
+  NavigateToFormPageAndEnableAudits();
+  const base::Value::Dict* res = SendCommandSync("Audits.checkFormsIssues");
+  const base::Value::List* issues = res->FindListByDottedPath("formIssues");
+  ASSERT_NE(issues, nullptr);
+  ASSERT_EQ(issues->size(), 0ul);
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillFormDevtoolsProtocolTest,
                        FormHasLabelAssociatedToNameAttribute) {
   NavigateToFormPageAndEnableAudits();
   base::Value::Dict notification =
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 5661ffa2..62eff20 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -957,13 +957,12 @@
                          ui::kColorAlertMediumSeverityIcon)
         .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
         .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-        .AddSubpageButton(l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                          DownloadCommands::Command::DISCARD,
-                          /*is_prominent=*/true)
-        .AddSubpageButton(
+        .AddPrimarySubpageButton(
+            l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
+            DownloadCommands::Command::DISCARD)
+        .AddSecondarySubpageButton(
             l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
-            DownloadCommands::Command::KEEP,
-            /*is_prominent=*/false);
+            DownloadCommands::Command::KEEP, ui::kColorAlertMediumSeverityText);
   }
 
   // Cookie theft
@@ -991,10 +990,9 @@
             .AddIconAndColor(vector_icons::kDangerousIcon,
                              ui::kColorAlertHighSeverity)
             .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-            .AddSubpageButton(
+            .AddPrimarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                DownloadCommands::Command::DISCARD,
-                /*is_prominent=*/true);
+                DownloadCommands::Command::DISCARD);
       }
     }
     return DownloadUIModel::BubbleUIInfo(
@@ -1003,9 +1001,9 @@
         .AddIconAndColor(vector_icons::kDangerousIcon,
                          ui::kColorAlertHighSeverity)
         .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-        .AddSubpageButton(l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                          DownloadCommands::Command::DISCARD,
-                          /*is_prominent=*/true);
+        .AddPrimarySubpageButton(
+            l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
+            DownloadCommands::Command::DISCARD);
   }
 
   NOTREACHED();
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index de91b8d..fc4ea9e6 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -740,6 +740,10 @@
        {}},
   };
   for (const auto& test_case : kDangerTypeTestCases) {
+    SCOPED_TRACE(testing::Message()
+                 << "Failed for danger type "
+                 << download::GetDownloadDangerTypeString(test_case.danger_type)
+                 << std::endl);
     SetupDownloadItemDefaults();
     ON_CALL(item(), GetDangerType())
         .WillByDefault(Return(test_case.danger_type));
@@ -804,6 +808,10 @@
        {}},
   };
   for (const auto& test_case : kDangerTypeTestCases) {
+    SCOPED_TRACE(testing::Message()
+                 << "Failed for danger type "
+                 << download::GetDownloadDangerTypeString(test_case.danger_type)
+                 << std::endl);
     SetupDownloadItemDefaults();
     ON_CALL(item(), GetDangerType())
         .WillByDefault(Return(test_case.danger_type));
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc
index b194875..f9c9a79 100644
--- a/chrome/browser/download/download_ui_model.cc
+++ b/chrome/browser/download/download_ui_model.cc
@@ -727,8 +727,12 @@
 DownloadUIModel::BubbleUIInfo::SubpageButton::SubpageButton(
     DownloadCommands::Command command,
     std::u16string label,
-    bool is_prominent)
-    : command(command), label(label), is_prominent(is_prominent) {}
+    bool is_prominent,
+    absl::optional<ui::ColorId> color)
+    : command(command),
+      label(label),
+      is_prominent(is_prominent),
+      color(color) {}
 DownloadUIModel::BubbleUIInfo::QuickAction::QuickAction(
     DownloadCommands::Command command,
     const std::u16string& hover_text,
@@ -760,13 +764,25 @@
   checkbox_label = label;
   return *this;
 }
-DownloadUIModel::BubbleUIInfo& DownloadUIModel::BubbleUIInfo::AddSubpageButton(
+DownloadUIModel::BubbleUIInfo&
+DownloadUIModel::BubbleUIInfo::AddPrimarySubpageButton(
+    const std::u16string& label,
+    DownloadCommands::Command command) {
+  // The subpage of the bubble supports at most 2 buttons. The primary one must
+  // come first, then the secondary.
+  CHECK(subpage_buttons.empty());
+  subpage_buttons.emplace_back(command, label, /*is_prominent=*/true);
+  return *this;
+}
+DownloadUIModel::BubbleUIInfo&
+DownloadUIModel::BubbleUIInfo::AddSecondarySubpageButton(
     const std::u16string& label,
     DownloadCommands::Command command,
-    bool is_prominent) {
-  // The subpage of the bubble supports at most 2 buttons.
-  DCHECK(subpage_buttons.size() <= 1);
-  subpage_buttons.emplace_back(command, label, is_prominent);
+    ui::ColorId color) {
+  // The subpage of the bubble supports at most 2 buttons. The primary one must
+  // come first, then the secondary.
+  CHECK(subpage_buttons.size() == 1);
+  subpage_buttons.emplace_back(command, label, /*is_prominent=*/false, color);
   return *this;
 }
 
@@ -930,13 +946,13 @@
           .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                            ui::kColorAlertMediumSeverityIcon)
           .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
-          .AddSubpageButton(
+          .AddPrimarySubpageButton(
               l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-              DownloadCommands::Command::DISCARD,
-              /*is_prominent=*/true)
-          .AddSubpageButton(
+              DownloadCommands::Command::DISCARD)
+          .AddSecondarySubpageButton(
               l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
-              DownloadCommands::Command::KEEP, /*is_prominent=*/false);
+              DownloadCommands::Command::KEEP,
+              ui::kColorAlertMediumSeverityText);
     case download::DownloadItem::InsecureDownloadStatus::UNKNOWN:
     case download::DownloadItem::InsecureDownloadStatus::SAFE:
     case download::DownloadItem::InsecureDownloadStatus::VALIDATED:
@@ -985,14 +1001,13 @@
             .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                              ui::kColorAlertMediumSeverityIcon)
             .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
-            .AddSubpageButton(
+            .AddPrimarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                DownloadCommands::Command::DISCARD,
-                /*is_prominent=*/true)
-            .AddSubpageButton(
+                DownloadCommands::Command::DISCARD)
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
                 DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                ui::kColorAlertMediumSeverityText);
       } else {
         return DownloadUIModel::BubbleUIInfo(
                    l10n_util::GetStringUTF16(
@@ -1000,14 +1015,12 @@
             .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                              ui::kColorSecondaryForeground)
             .AddPrimaryButton(DownloadCommands::Command::KEEP)
-            .AddSubpageButton(
+            .AddPrimarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                DownloadCommands::Command::DISCARD,
-                /*is_prominent=*/false)
-            .AddSubpageButton(
+                DownloadCommands::Command::DISCARD)
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
-                DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                DownloadCommands::Command::KEEP, ui::kColorSecondaryForeground);
       }
     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
@@ -1018,18 +1031,16 @@
                     .AddIconAndColor(vector_icons::kDangerousIcon,
                                      ui::kColorAlertHighSeverity)
                     .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-                    .AddSubpageButton(
+                    .AddPrimarySubpageButton(
                         l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                        DownloadCommands::Command::DISCARD,
-                        /*is_prominent=*/true);
+                        DownloadCommands::Command::DISCARD);
       if (!is_download_bubble_v2) {
         ui_info
             .AddCheckbox(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CHECKBOX_BYPASS))
-            .AddSubpageButton(
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
-                DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                DownloadCommands::Command::KEEP, ui::kColorAlertHighSeverity);
       }
       return ui_info;
 
@@ -1041,18 +1052,17 @@
                                      ui::kColorAlertMediumSeverityIcon)
                     .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
                     .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-                    .AddSubpageButton(
+                    .AddPrimarySubpageButton(
                         l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                        DownloadCommands::Command::DISCARD,
-                        /*is_prominent=*/true);
+                        DownloadCommands::Command::DISCARD);
       if (!is_download_bubble_v2) {
         ui_info
             .AddCheckbox(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CHECKBOX_BYPASS))
-            .AddSubpageButton(
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
                 DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                ui::kColorAlertMediumSeverityText);
       }
       return ui_info;
 
@@ -1063,18 +1073,16 @@
                     .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                                      ui::kColorAlertHighSeverity)
                     .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-                    .AddSubpageButton(
+                    .AddPrimarySubpageButton(
                         l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                        DownloadCommands::Command::DISCARD,
-                        /*is_prominent=*/true);
+                        DownloadCommands::Command::DISCARD);
       if (!is_download_bubble_v2) {
         ui_info
             .AddCheckbox(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CHECKBOX_BYPASS))
-            .AddSubpageButton(
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
-                DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                DownloadCommands::Command::KEEP, ui::kColorAlertHighSeverity);
       }
       return ui_info;
     case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
@@ -1092,14 +1100,13 @@
             .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                              ui::kColorAlertMediumSeverityIcon)
             .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
-            .AddSubpageButton(
+            .AddPrimarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                DownloadCommands::Command::DISCARD,
-                /*is_prominent=*/true)
-            .AddSubpageButton(
+                DownloadCommands::Command::DISCARD)
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
                 DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                ui::kColorAlertMediumSeverityText);
       } else {
         return DownloadUIModel::BubbleUIInfo(
                    l10n_util::GetStringUTF16(
@@ -1108,14 +1115,13 @@
                              ui::kColorAlertMediumSeverityIcon)
             .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
             .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-            .AddSubpageButton(
+            .AddPrimarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-                DownloadCommands::Command::DISCARD,
-                /*is_prominent=*/true)
-            .AddSubpageButton(
+                DownloadCommands::Command::DISCARD)
+            .AddSecondarySubpageButton(
                 l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
                 DownloadCommands::Command::KEEP,
-                /*is_prominent=*/false);
+                ui::kColorAlertMediumSeverityText);
       }
     }
     case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
@@ -1125,14 +1131,13 @@
           .AddIconAndColor(views::kInfoIcon, ui::kColorAlertMediumSeverityIcon)
           .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
           .AddPrimaryButton(DownloadCommands::Command::DISCARD)
-          .AddSubpageButton(
+          .AddPrimarySubpageButton(
               l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_DELETE),
-              DownloadCommands::Command::DISCARD,
-              /*is_prominent=*/true)
-          .AddSubpageButton(
+              DownloadCommands::Command::DISCARD)
+          .AddSecondarySubpageButton(
               l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_CONTINUE),
               DownloadCommands::Command::KEEP,
-              /*is_prominent=*/false);
+              ui::kColorAlertMediumSeverityText);
     case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
       return DownloadUIModel::BubbleUIInfo(
                  l10n_util::GetStringUTF16(
@@ -1140,12 +1145,13 @@
           .AddIconAndColor(vector_icons::kNotSecureWarningIcon,
                            ui::kColorAlertMediumSeverityIcon)
           .AddSecondaryTextColor(ui::kColorAlertMediumSeverityText)
-          .AddSubpageButton(l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_SCAN),
-                            DownloadCommands::Command::DEEP_SCAN,
-                            /*is_prominent=*/true)
-          .AddSubpageButton(l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_OPEN),
-                            DownloadCommands::Command::BYPASS_DEEP_SCANNING,
-                            /*is_prominent=*/false);
+          .AddPrimarySubpageButton(
+              l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_SCAN),
+              DownloadCommands::Command::DEEP_SCAN)
+          .AddSecondarySubpageButton(
+              l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_OPEN),
+              DownloadCommands::Command::BYPASS_DEEP_SCANNING,
+              ui::kColorButtonForeground);
     case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING: {
       BubbleUIInfo bubble_ui_info =
           DownloadUIModel::BubbleUIInfo(/*has_progress_bar=*/true)
diff --git a/chrome/browser/download/download_ui_model.h b/chrome/browser/download/download_ui_model.h
index 9d3362a..52f3ca49 100644
--- a/chrome/browser/download/download_ui_model.h
+++ b/chrome/browser/download/download_ui_model.h
@@ -116,9 +116,14 @@
       std::u16string label;
       bool is_prominent = false;
 
+      // Controls the text color of the button. Only applied for secondary
+      // buttons.
+      absl::optional<ui::ColorId> color;
+
       SubpageButton(DownloadCommands::Command command,
                     std::u16string label,
-                    bool is_prominent);
+                    bool is_prominent,
+                    absl::optional<ui::ColorId> color = absl::nullopt);
     };
 
     struct QuickAction {
@@ -176,9 +181,11 @@
     // Add button to the subpage. Only two buttons are supported.
     // The first one added is the primary, and the second one the secondary.
     // The checkbox, if present, controls the secondary.
-    BubbleUIInfo& AddSubpageButton(const std::u16string& label,
-                                   DownloadCommands::Command command,
-                                   bool is_prominent);
+    BubbleUIInfo& AddPrimarySubpageButton(const std::u16string& label,
+                                          DownloadCommands::Command command);
+    BubbleUIInfo& AddSecondarySubpageButton(const std::u16string& label,
+                                            DownloadCommands::Command command,
+                                            ui::ColorId color);
     BubbleUIInfo& SetProgressBarLooping();
     BubbleUIInfo& AddQuickAction(DownloadCommands::Command command,
                                  const std::u16string& label,
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index 9db7531..ebd5e6e 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -663,7 +663,13 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, Debugger) {
+// TODO(crbug/1434257): Flaky on Lacros and Linux.
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
+#define MAYBE_Debugger DISABLED_Debugger
+#else
+#define MAYBE_Debugger Debugger
+#endif
+IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, MAYBE_Debugger) {
   ASSERT_TRUE(RunExtensionTest("debugger")) << message_;
 }
 
@@ -742,8 +748,8 @@
   }
 };
 
-// TODO(crbug/1444625): Flaky on Lacros.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// TODO(crbug/1440919): Flaky on Lacros and Linux.
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
 #define MAYBE_Debugger DISABLED_Debugger
 #else
 #define MAYBE_Debugger Debugger
diff --git a/chrome/browser/extensions/api/desktop_capture/OWNERS b/chrome/browser/extensions/api/desktop_capture/OWNERS
index da4c285..a11c158 100644
--- a/chrome/browser/extensions/api/desktop_capture/OWNERS
+++ b/chrome/browser/extensions/api/desktop_capture/OWNERS
@@ -1,3 +1,2 @@
 sergeyu@chromium.org
-wez@chromium.org
 eladalon@chromium.org
diff --git a/chrome/browser/extensions/external_pref_loader_unittest.cc b/chrome/browser/extensions/external_pref_loader_unittest.cc
index 07313f3..f1e4f30 100644
--- a/chrome/browser/extensions/external_pref_loader_unittest.cc
+++ b/chrome/browser/extensions/external_pref_loader_unittest.cc
@@ -135,8 +135,7 @@
 
   // Initially CanSyncFeatureStart() returns true, returning false will let
   // |loader| proceed.
-  sync_service()->SetDisableReasons(
-      {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
+  sync_service()->SetHasSyncConsent(false);
   ASSERT_FALSE(sync_service()->CanSyncFeatureStart());
   sync_service()->FireOnStateChanged();
   run_loop.Run();
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a66f492..18b45f8 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -348,11 +348,6 @@
     "expiry_milestone": 110
   },
   {
-    "name": "arc-vmm-swap",
-    "owners": [ "sstan" ],
-    "expiry_milestone": 120
-  },
-  {
     "name": "arc-vmm-swap-keyboard-shortcut",
     "owners": [ "sstan"],
     "expiry_milestone": 120
@@ -1914,7 +1909,7 @@
   },
   {
     "name": "enable-baseline-gm3-surface-colors",
-    "owners": ["nemco", "skavuluru"],
+    "owners": ["nemco@google.com", "skavuluru@google.com"],
     "expiry_milestone": 120
   },
   {
@@ -2230,7 +2225,7 @@
   },
   {
     "name": "enable-delay-temp-strip-removal",
-    "owners": [ "skavuluru", "nemco", "clank-app-team@google.com" ],
+    "owners": [ "skavuluru@google.com", "nemco@google.com", "clank-app-team@google.com" ],
     "expiry_milestone": 120
   },
   {
@@ -2375,7 +2370,7 @@
   },
   {
     "name": "enable-empty-states",
-    "owners": [ "zheliooo", "skavuluru", "nemco", "clank-app-team@google.com" ],
+    "owners": [ "zheliooo@google.com", "skavuluru@google.com", "nemco@google.com", "clank-app-team@google.com" ],
     "expiry_milestone": 120
   },
   {
@@ -3338,12 +3333,12 @@
   },
   {
     "name": "enable-tab-strip-redesign",
-    "owners": [ "zheliooo", "skavuluru", "nemco", "clank-app-team@google.com" ],
+    "owners": [ "zheliooo@google.com", "skavuluru@google.com", "nemco@google.com", "clank-app-team@google.com" ],
     "expiry_milestone": 120
   },
   {
     "name": "enable-tab-strip-startup-refactoring",
-    "owners": [ "skavuluru", "nemco", "clank-large-form-factors@google.com" ],
+    "owners": [ "skavuluru@google.com", "nemco@google.com", "clank-large-form-factors@google.com" ],
     "expiry_milestone": 120
   },
   {
@@ -4282,7 +4277,7 @@
   },
   {
     "name": "grid-tab-switcher-for-tablets",
-    "owners": [ "nemco", "clank-app-team@google.com" ],
+    "owners": [ "nemco@google.com", "clank-app-team@google.com" ],
     "expiry_milestone": 114
   },
   {
@@ -5285,6 +5280,11 @@
     "expiry_milestone": 118
   },
   {
+    "name": "ntp-journeys-module-model-ranking",
+    "owners": [ "sophiechang", "tiborg" ],
+    "expiry_milestone": 118
+  },
+  {
     "name": "ntp-middle-slot-promo-dismissal",
     "owners": [ "pauladedeji", "tiborg" ],
     "expiry_milestone": 111
@@ -6164,11 +6164,6 @@
     "expiry_milestone": 118
   },
   {
-    "name": "ppapi-shared-images-swapchain",
-    "owners": [ "vasilyt" ],
-    "expiry_milestone": 128
-  },
-  {
     "name": "prefer-constant-frame-rate",
     "owners": [ "chromeos-camera-eng@google.com" ],
     "expiry_milestone": 130
@@ -6186,6 +6181,11 @@
     "expiry_milestone": 123
   },
   {
+    "name": "price-insights",
+    "owners": [ "zhiyuancai", "chrome-shopping-eng@google.com" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "print-management-jelly",
     "owners": [
       "//ash/webui/print_management/OWNERS"
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ca6c9d4..cb0871c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -215,17 +215,6 @@
     "after 3 restarts. On the third restart, the flag will appear to be off "
     "but the effect is still active.";
 
-extern const char kPPAPISharedImagesSwapChainName[] =
-    "Use SharedImages for PPAPI swapchain";
-extern const char kPPAPISharedImagesSwapChainDescription[] =
-    "Switches legacy swap chain code to SharedImages";
-
-extern const char kSupportPepperVideoDecoderDevAPIName[] =
-    "Controls whether the Pepper PPB_VideoDecoder(Dev) API is supported";
-extern const char kSupportPepperVideoDecoderDevAPIDescription[] =
-    "When disabled, Chrome will return 0 if asked to create the "
-    "PPB_VideoDecoder(Dev) API by in-process callers";
-
 extern const char kCmdDecoderAlwaysGetSizeFromSourceTextureName[] =
     "Controls whether the GLES2 validating decoder always gets size from the "
     "source texture when copying textures";
@@ -4568,6 +4557,12 @@
 const char kNtpHistoryClustersModuleDescription[] =
     "Shows the Journeys module on the New Tab Page.";
 
+const char kNtpHistoryClustersModuleUseModelRankingName[] =
+    "NTP Journeys Module Model Ranking";
+const char kNtpHistoryClustersModuleUseModelRankingDescription[] =
+    "Leverages a machine learning model to rank clusters for the Journeys "
+    "module on the New Tab Page.";
+
 const char kNtpChromeCartInHistoryClustersModuleName[] =
     "NTP ChromeCart in Journeys Module";
 const char kNtpChromeCartInHistoryClustersModuleDescription[] =
@@ -5124,10 +5119,6 @@
     "priority to Play instead of using default install priority specified "
     "in Play";
 
-const char kArcVmmSwapName[] = "Vmm swap support for ARCVM";
-const char kArcVmmSwapDesc[] =
-    "When enabled, the ARCVM will be launched with vmm swap feature.";
-
 const char kArcVmmSwapKBShortcutName[] =
     "Keyboard shortcut trigger for ARCVM"
     " vmm swap feature";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 996ca50..aa2aa20e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -158,12 +158,6 @@
 extern const char kPasspointSettingsName[];
 extern const char kPasspointSettingsDescription[];
 
-extern const char kPPAPISharedImagesSwapChainName[];
-extern const char kPPAPISharedImagesSwapChainDescription[];
-
-extern const char kSupportPepperVideoDecoderDevAPIName[];
-extern const char kSupportPepperVideoDecoderDevAPIDescription[];
-
 extern const char kCmdDecoderAlwaysGetSizeFromSourceTextureName[];
 extern const char kCmdDecoderAlwaysGetSizeFromSourceTextureDescription[];
 
@@ -2614,6 +2608,9 @@
 extern const char kNtpHistoryClustersModuleName[];
 extern const char kNtpHistoryClustersModuleDescription[];
 
+extern const char kNtpHistoryClustersModuleUseModelRankingName[];
+extern const char kNtpHistoryClustersModuleUseModelRankingDescription[];
+
 extern const char kNtpChromeCartInHistoryClustersModuleName[];
 extern const char kNtpChromeCartInHistoryClustersModuleDescription[];
 
@@ -2935,9 +2932,6 @@
 extern const char kArcSyncInstallPriorityName[];
 extern const char kArcSyncInstallPriorityDescription[];
 
-extern const char kArcVmmSwapName[];
-extern const char kArcVmmSwapDesc[];
-
 extern const char kArcVmmSwapKBShortcutName[];
 extern const char kArcVmmSwapKBShortcutDesc[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 2a1b2800..41b4d379 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -613,7 +613,7 @@
 
 BASE_FEATURE(kCCTTextFragmentLookupApiEnabled,
              "CCTTextFragmentLookupApiEnabled",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kCCTToolbarCustomizations,
              "CCTToolbarCustomizations",
diff --git a/chrome/browser/installable/installed_webapp_provider.cc b/chrome/browser/installable/installed_webapp_provider.cc
index 8a4bb548..420e0d9 100644
--- a/chrome/browser/installable/installed_webapp_provider.cc
+++ b/chrome/browser/installable/installed_webapp_provider.cc
@@ -30,15 +30,16 @@
 
   bool HasNext() const override { return index_ < rules_.size(); }
 
-  content_settings::Rule Next() override {
+  std::unique_ptr<content_settings::Rule> Next() override {
     DCHECK(HasNext());
     const GURL& origin = rules_[index_].first;
     ContentSetting setting = rules_[index_].second;
     index_++;
 
-    return content_settings::Rule(
+    return std::make_unique<content_settings::OwnedRule>(
         ContentSettingsPattern::FromURLNoWildcard(origin),
-        ContentSettingsPattern::Wildcard(), base::Value(setting), {});
+        ContentSettingsPattern::Wildcard(), base::Value(setting),
+        content_settings::RuleMetaData{});
   }
 
  private:
diff --git a/chrome/browser/lacros/account_manager/profile_account_manager.cc b/chrome/browser/lacros/account_manager/profile_account_manager.cc
index c4fee97..ad2f30ee 100644
--- a/chrome/browser/lacros/account_manager/profile_account_manager.cc
+++ b/chrome/browser/lacros/account_manager/profile_account_manager.cc
@@ -92,7 +92,8 @@
 void ProfileAccountManager::ShowReauthAccountDialog(
     AccountAdditionSource source,
     const std::string& email,
-    base::OnceClosure callback) {
+    base::OnceCallback<
+        void(const account_manager::AccountUpsertionResult& result)> callback) {
   NOTREACHED();
 }
 
diff --git a/chrome/browser/lacros/account_manager/profile_account_manager.h b/chrome/browser/lacros/account_manager/profile_account_manager.h
index aa8252e..c98c794c 100644
--- a/chrome/browser/lacros/account_manager/profile_account_manager.h
+++ b/chrome/browser/lacros/account_manager/profile_account_manager.h
@@ -73,9 +73,11 @@
       AccountAdditionSource source,
       base::OnceCallback<void(const account_manager::AccountUpsertionResult&
                                   result)> callback) override;
-  void ShowReauthAccountDialog(AccountAdditionSource source,
-                               const std::string& email,
-                               base::OnceClosure callback) override;
+  void ShowReauthAccountDialog(
+      AccountAdditionSource source,
+      const std::string& email,
+      base::OnceCallback<void(const account_manager::AccountUpsertionResult&
+                                  result)> callback) override;
   void ShowManageAccountsSettings() override;
   std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
       const account_manager::AccountKey& account,
diff --git a/chrome/browser/lacros/input_method_lacros_browsertest.cc b/chrome/browser/lacros/input_method_lacros_browsertest.cc
index 9b96c58..597ab1e 100644
--- a/chrome/browser/lacros/input_method_lacros_browsertest.cc
+++ b/chrome/browser/lacros/input_method_lacros_browsertest.cc
@@ -682,6 +682,10 @@
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextReplacesSelection) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
@@ -1049,6 +1053,10 @@
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendLeftArrowKeyWithSelectionCollapsesSelectionLeft) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
@@ -1079,6 +1087,10 @@
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendRightArrowKeyWithSelectionCollapsesSelectionRight) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
@@ -1109,6 +1121,10 @@
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendKeyEventShortcutsModifiesSelection) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
@@ -1545,6 +1561,10 @@
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        ConfirmCompositionWithSelectionAndNoComposition) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
@@ -1623,6 +1643,10 @@
 // See b/267944900 for more information.
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        EscapeAfterResetKeepsSelection) {
+  if (!GetParam().fix_265853952) {
+    GTEST_SKIP() << "Temporarily disabled for crbug.com/1445055";
+  }
+
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
           GetParam(),
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index 2ead6e0..859f3e8 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -24,6 +24,10 @@
 #include "net/base/url_util.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 
+#if BUILDFLAG(IS_CHROMEOS)
+#include "chromeos/dbus/constants/dbus_switches.h"  // nogncheck
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include <utility>
 
@@ -31,7 +35,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
-#include "chromeos/dbus/constants/dbus_switches.h"  // nogncheck
 #include "components/permissions/permission_request.h"
 #include "components/permissions/permission_uma_util.h"
 #include "components/permissions/request_type.h"
@@ -126,7 +129,7 @@
 // across platforms.
 bool ProtectedMediaIdentifierPermissionContext::
     IsProtectedMediaIdentifierEnabled() const {
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
   Profile* profile = Profile::FromBrowserContext(browser_context());
   // Identifier is not allowed in incognito or guest mode.
   if (profile->IsOffTheRecord() || profile->IsGuestSession()) {
@@ -135,14 +138,15 @@
     return false;
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(chromeos::switches::kSystemDevMode) &&
-      !command_line->HasSwitch(ash::switches::kAllowRAInDevMode)) {
+      !command_line->HasSwitch(switches::kAllowRAInDevMode)) {
     DVLOG(1) << "Protected media identifier disabled in dev mode.";
     return false;
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // This could be disabled by the device policy or by a switch in content
   // settings.
   bool enabled_for_device = false;
@@ -154,7 +158,8 @@
     return false;
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
+#endif  // BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
 
   return true;
 }
diff --git a/chrome/browser/metrics/chromeos_system_profile_provider.cc b/chrome/browser/metrics/chromeos_system_profile_provider.cc
index 7adc680..76aeb9c 100644
--- a/chrome/browser/metrics/chromeos_system_profile_provider.cc
+++ b/chrome/browser/metrics/chromeos_system_profile_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/metrics/chromeos_system_profile_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "base/barrier_closure.h"
 #include "base/files/file_util.h"
@@ -175,6 +176,11 @@
         metrics::
             SystemProfileProto_DemoModeDimensions_CustomizationFacet_CLOUD_GAMING_DEVICE);
   }
+  if (ash::features::IsFeatureAwareDeviceDemoModeEnabled()) {
+    demo_mode_dimensions->add_customization_facet(
+        metrics::
+            SystemProfileProto_DemoModeDimensions_CustomizationFacet_FEATURE_AWARE_DEVICE);
+  }
 }
 
 void ChromeOSSystemProfileProvider::InitTaskGetFullHardwareClass(
diff --git a/chrome/browser/metrics/chromeos_system_profile_provider_unittest.cc b/chrome/browser/metrics/chromeos_system_profile_provider_unittest.cc
index 79c9aca..6cb4b73 100644
--- a/chrome/browser/metrics/chromeos_system_profile_provider_unittest.cc
+++ b/chrome/browser/metrics/chromeos_system_profile_provider_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -262,8 +263,10 @@
   const std::string expected_country = "CA";
   const std::string expected_retailer_id = "ABC";
   const std::string expected_store_id = "12345";
-  scoped_feature_list_.InitAndEnableFeature(
-      chromeos::features::kCloudGamingDevice);
+  scoped_feature_list_.InitWithFeatures(
+      {chromeos::features::kCloudGamingDevice,
+       ash::features::kFeatureManagementFeatureAwareDeviceDemoMode},
+      {});
   g_browser_process->local_state()->SetString("demo_mode.country",
                                               expected_country);
   g_browser_process->local_state()->SetString("demo_mode.retailer_id",
@@ -283,11 +286,15 @@
       system_profile.demo_mode_dimensions().retailer().has_retailer_id());
   ASSERT_TRUE(system_profile.demo_mode_dimensions().retailer().has_store_id());
   EXPECT_EQ(system_profile.demo_mode_dimensions().customization_facet_size(),
-            1);
+            2);
   ASSERT_EQ(
       system_profile.demo_mode_dimensions().customization_facet().at(0),
       metrics::
           SystemProfileProto_DemoModeDimensions_CustomizationFacet_CLOUD_GAMING_DEVICE);
+  ASSERT_EQ(
+      system_profile.demo_mode_dimensions().customization_facet().at(1),
+      metrics::
+          SystemProfileProto_DemoModeDimensions_CustomizationFacet_FEATURE_AWARE_DEVICE);
   std::string country = system_profile.demo_mode_dimensions().country();
   std::string retailer_id =
       system_profile.demo_mode_dimensions().retailer().retailer_id();
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc
index 5a3ac45..552d340 100644
--- a/chrome/browser/notifications/notification_channels_provider_android.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/notifications/notification_channels_provider_android.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/android/build_info.h"
 #include "base/android/jni_android.h"
@@ -25,7 +26,6 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_constraints.h"
-#include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_utils.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/search_engines/template_url.h"
@@ -126,15 +126,16 @@
 
   bool HasNext() const override { return index_ < channels_.size(); }
 
-  content_settings::Rule Next() override {
+  std::unique_ptr<content_settings::Rule> Next() override {
     DCHECK(HasNext());
     auto& channel = channels_[index_];
     DCHECK_NE(channels_[index_].status, NotificationChannelStatus::UNAVAILABLE);
-    content_settings::Rule rule = content_settings::Rule(
-        ContentSettingsPattern::FromURLNoWildcard(GURL(channel.origin)),
-        ContentSettingsPattern::Wildcard(),
-        base::Value(ChannelStatusToContentSetting(channel.status)),
-        {.last_modified = channel.timestamp});
+    std::unique_ptr<content_settings::Rule> rule =
+        std::make_unique<content_settings::OwnedRule>(
+            ContentSettingsPattern::FromURLNoWildcard(GURL(channel.origin)),
+            ContentSettingsPattern::Wildcard(),
+            base::Value(ChannelStatusToContentSetting(channel.status)),
+            content_settings::RuleMetaData{.last_modified = channel.timestamp});
     index_++;
     return rule;
   }
@@ -207,7 +208,8 @@
   }
   InitCachedChannels();
 
-  std::vector<content_settings::Rule> rules;
+  std::vector<std::pair<ContentSettingsPattern, ContentSettingsPattern>>
+      patterns;
 
   // Collect the existing rules and create channels for them.
   {
@@ -216,17 +218,18 @@
                                        false /* incognito */));
 
     while (it && it->HasNext()) {
-      content_settings::Rule rule = it->Next();
-      CreateChannelForRule(rule);
-      rules.push_back(std::move(rule));
+      std::unique_ptr<content_settings::Rule> rule = it->Next();
+      CreateChannelForRule(*rule);
+      patterns.emplace_back(std::move(rule->primary_pattern),
+                            std::move(rule->secondary_pattern));
     }
   }
 
   // Remove the existing |rules| from the preference provider.
-  for (const auto& rule : rules) {
-    pref_provider->SetWebsiteSetting(
-        rule.primary_pattern, rule.secondary_pattern,
-        ContentSettingsType::NOTIFICATIONS, base::Value(), {});
+  for (const auto& pattern : patterns) {
+    pref_provider->SetWebsiteSetting(pattern.first, pattern.second,
+                                     ContentSettingsType::NOTIFICATIONS,
+                                     base::Value(), {});
   }
 
   prefs->SetBoolean(prefs::kMigratedToSiteNotificationChannels, true);
@@ -423,7 +426,7 @@
   DCHECK(!origin.opaque());
   const std::string origin_string = origin.Serialize();
   ContentSetting content_setting =
-      content_settings::ValueToContentSetting(rule.value);
+      content_settings::ValueToContentSetting(rule.value());
   switch (content_setting) {
     case CONTENT_SETTING_ALLOW:
       CreateChannelIfRequired(origin_string,
diff --git a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
index 6f796a28..a2a915d 100644
--- a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
@@ -178,10 +178,10 @@
       channels_provider_->GetRuleIterator(ContentSettingsType::NOTIFICATIONS,
                                           false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+  EXPECT_EQ(GetTestPattern(), rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            content_settings::ValueToContentSetting(rule.value));
+            content_settings::ValueToContentSetting(rule->value()));
   EXPECT_FALSE(rule_iterator->HasNext());
 }
 
@@ -198,10 +198,10 @@
       channels_provider_->GetRuleIterator(ContentSettingsType::NOTIFICATIONS,
                                           false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+  EXPECT_EQ(GetTestPattern(), rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
-            content_settings::ValueToContentSetting(rule.value));
+            content_settings::ValueToContentSetting(rule->value()));
   EXPECT_FALSE(rule_iterator->HasNext());
 }
 
@@ -221,10 +221,10 @@
       channels_provider_->GetRuleIterator(ContentSettingsType::NOTIFICATIONS,
                                           false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+  EXPECT_EQ(GetTestPattern(), rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            content_settings::ValueToContentSetting(rule.value));
+            content_settings::ValueToContentSetting(rule->value()));
   EXPECT_FALSE(rule_iterator->HasNext());
 }
 
@@ -244,10 +244,10 @@
       channels_provider_->GetRuleIterator(ContentSettingsType::NOTIFICATIONS,
                                           false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule rule = rule_iterator->Next();
-  EXPECT_EQ(GetTestPattern(), rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+  EXPECT_EQ(GetTestPattern(), rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
-            content_settings::ValueToContentSetting(rule.value));
+            content_settings::ValueToContentSetting(rule->value()));
   EXPECT_FALSE(rule_iterator->HasNext());
 }
 
@@ -309,15 +309,15 @@
       channels_provider_->GetRuleIterator(ContentSettingsType::NOTIFICATIONS,
                                           false /* incognito */);
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule first_rule = rule_iterator->Next();
-  EXPECT_EQ(abc_pattern, first_rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> first_rule = rule_iterator->Next();
+  EXPECT_EQ(abc_pattern, first_rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            content_settings::ValueToContentSetting(first_rule.value));
+            content_settings::ValueToContentSetting(first_rule->value()));
   EXPECT_TRUE(rule_iterator->HasNext());
-  content_settings::Rule second_rule = rule_iterator->Next();
-  EXPECT_EQ(xyz_pattern, second_rule.primary_pattern);
+  std::unique_ptr<content_settings::Rule> second_rule = rule_iterator->Next();
+  EXPECT_EQ(xyz_pattern, second_rule->primary_pattern);
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
-            content_settings::ValueToContentSetting(second_rule.value));
+            content_settings::ValueToContentSetting(second_rule->value()));
   EXPECT_FALSE(rule_iterator->HasNext());
 }
 
diff --git a/chrome/browser/ozone_platform_browsertest.cc b/chrome/browser/ozone_platform_browsertest.cc
index a025045..e6e812d 100644
--- a/chrome/browser/ozone_platform_browsertest.cc
+++ b/chrome/browser/ozone_platform_browsertest.cc
@@ -23,7 +23,17 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(OzonePlatformTest, ExitsGracefullyOnPlatormInitFailure) {
+// TODO(crbug.com/1430388) Flaky during teardown on linux ASan/LSan builder.
+#if BUILDFLAG(IS_LINUX) && \
+    (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER))
+#define MAYBE_ExitsGracefullyOnPlatormInitFailure \
+  DISABLED_ExitsGracefullyOnPlatormInitFailure
+#else
+#define MAYBE_ExitsGracefullyOnPlatormInitFailure \
+  ExitsGracefullyOnPlatormInitFailure
+#endif
+IN_PROC_BROWSER_TEST_F(OzonePlatformTest,
+                       MAYBE_ExitsGracefullyOnPlatormInitFailure) {
   // This should never be hit.  The browser is expected to exit before entering
   // the test body.
   ASSERT_TRUE(false);
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
index 6f82068..967ac3d0 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -501,7 +501,9 @@
         .SetManifestHandled(sw_metrics.manifest_handled)
         .SetManifestFallback(sw_metrics.manifest_fallback)
         .SetSpeculationRulesHandled(sw_metrics.speculation_rules_handled)
-        .SetSpeculationRulesFallback(sw_metrics.speculation_rules_fallback);
+        .SetSpeculationRulesFallback(sw_metrics.speculation_rules_fallback)
+        .SetDictionaryHandled(sw_metrics.dictionary_handled)
+        .SetDictionaryFallback(sw_metrics.dictionary_fallback);
   }
   builder.Record(ukm::UkmRecorder::Get());
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
index e9f9cda..815022ec 100644
--- a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
+++ b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
@@ -33,15 +33,20 @@
     "//base:base_java",
     "//base:jni_java",
     "//chrome/browser/password_manager/android:password_manager_resource_provider_java",
+    "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/bottomsheet/android:java",
+    "//components/version_info/android:version_constants_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_appcompat_appcompat_java",
     "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+    "//third_party/androidx:androidx_fragment_fragment_java",
     "//ui/android:ui_java",
   ]
 
   sources = [
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningBridge.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java",
+    "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java",
@@ -54,7 +59,7 @@
 robolectric_library("junit") {
   testonly = true
 
-  sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java" ]
+  sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java" ]
 
   deps = [
     ":java",
@@ -109,5 +114,9 @@
 
 android_resources("java_resources") {
   deps = [ "//ui/android:ui_java_resources" ]
-  sources = [ "java/res/layout/pwd_migration_warning.xml" ]
+  sources = [
+    "java/res/layout/pwd_migration_warning.xml",
+    "java/res/layout/pwd_migration_warning_intro_fragment.xml",
+    "java/res/values/dimens.xml",
+  ]
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
index a0fa5d5..ac1bbbb 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright 2022 The Chromium Authors
+Copyright 2023 The Chromium Authors
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
@@ -19,11 +19,9 @@
       android:layout_centerHorizontal="true"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
+      android:layout_marginHorizontal="@dimen/pwd_migration_warning_margin"
+      android:layout_marginVertical="6dp"
       android:layout_gravity="center_horizontal"
-      android:layout_marginEnd="16dp"
-      android:layout_marginStart="16dp"
-      android:layout_marginTop="6dp"
-      android:layout_marginBottom="6dp"
       android:importantForAccessibility="no"
       app:srcCompat="@drawable/drag_handlebar" />
 
@@ -32,10 +30,7 @@
       android:layout_below="@id/drag_handlebar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:layout_marginEnd="16dp"
-      android:layout_marginStart="16dp"
-      android:layout_marginTop="16dp"
-      android:layout_marginBottom="15dp"
+      android:layout_marginHorizontal="@dimen/pwd_migration_warning_margin"
       android:clipToPadding="false"
       android:divider="@null"
       tools:listitem="@layout/touch_to_fill_credential_item_modern"
@@ -43,21 +38,26 @@
 
       <ImageView
           android:id="@+id/touch_to_fill_sheet_header_image"
-          android:layout_width="32dp"
-          android:layout_height="32dp"
+          android:layout_width="@dimen/pwd_migration_warning_icon_size"
+          android:layout_height="@dimen/pwd_migration_warning_icon_size"
           android:layout_gravity="center_horizontal"
-          android:layout_marginBottom="8dp"
+          android:layout_marginVertical="16dp"
           android:importantForAccessibility="no"/>
 
       <androidx.appcompat.widget.DialogTitle
           android:id="@+id/touch_to_fill_sheet_title"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
+          android:layout_marginBottom="16dp"
           android:layout_gravity="center_horizontal"
-          android:paddingTop="10dp"
-          android:paddingBottom="10dp"
           android:textAlignment="center"
           android:textAppearance="@style/TextAppearance.AlertDialogTitleStyle"
           android:text="@string/password_migration_warning_title"/>
+
+      <androidx.fragment.app.FragmentContainerView
+        android:id="@+id/fragment_container_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_horizontal" />
   </LinearLayout>
 </RelativeLayout>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml
new file mode 100644
index 0000000..c537287
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2023 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal">
+
+  <org.chromium.ui.widget.TextViewWithLeading
+      android:id="@+id/migration_warning_sheet_subtitle"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
+      android:layout_gravity="center_horizontal"
+      android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
+
+  <org.chromium.ui.widget.ButtonCompat
+      android:descendantFocusability="blocksDescendants"
+      android:id="@+id/acknowledge_password_migration_button"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginBottom="12dp"
+      android:minHeight="@dimen/pwd_migration_warning_button_height"
+      android:layout_gravity="center_horizontal"
+      android:ellipsize="end"
+      android:singleLine="true"
+      android:text="@string/password_migration_warning_acknowledge"
+      style="@style/FilledButton.Flat"/>
+
+  <org.chromium.ui.widget.ButtonCompat
+      android:descendantFocusability="blocksDescendants"
+      android:id="@+id/password_migration_more_options_button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
+      android:minHeight="@dimen/pwd_migration_warning_button_height"
+      android:layout_gravity="center_horizontal"
+      android:ellipsize="end"
+      android:singleLine="true"
+      android:text="@string/password_migration_warning_other_options"
+      style="@style/TextButton"/>
+</LinearLayout>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml
new file mode 100644
index 0000000..f32d911f
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2023 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources>
+    <dimen name="pwd_migration_warning_margin">24dp</dimen>
+    <dimen name="pwd_migration_warning_button_height">48dp</dimen>
+    <dimen name="pwd_migration_warning_icon_size">32dp</dimen>
+</resources>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java
deleted file mode 100644
index 54aab2f2..0000000
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningControllerTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.pwd_migration;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-
-import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
-import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
-
-import android.app.Activity;
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-import org.robolectric.Robolectric;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Tests for {@link PasswordMigrationWarningCoordinator} and {@link
- * PasswordMigrationWarningMediator}
- */
-@RunWith(BaseRobolectricTestRunner.class)
-@Batch(Batch.PER_CLASS)
-public class PasswordMigrationWarningControllerTest {
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
-
-    @Rule
-    public TestRule mProcessor = new Features.JUnitProcessor();
-
-    private final Context mContext = Robolectric.buildActivity(Activity.class).get();
-    private PasswordMigrationWarningCoordinator mCoordinator;
-
-    @Mock
-    private BottomSheetController mBottomSheetController;
-
-    public PasswordMigrationWarningControllerTest() {}
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mCoordinator = new PasswordMigrationWarningCoordinator(mContext, mBottomSheetController);
-    }
-
-    @Test
-    public void testCreatesValidDefaultModel() {
-        PropertyModel model = mCoordinator.getModelForTesting();
-        assertNotNull(model.get(DISMISS_HANDLER));
-        assertFalse(model.get(VISIBLE));
-    }
-}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
index a774ea9..b71b7c6 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -30,11 +29,6 @@
         mMediator.showWarning();
     }
 
-    @VisibleForTesting
-    PropertyModel getModelForTesting() {
-        return mMediator.getModel();
-    }
-
     static void setUpModelChangeProcessors(PropertyModel model, PasswordMigrationWarningView view) {
         PropertyModelChangeProcessor.create(
                 model, view, PasswordMigrationWarningViewBinder::bindPasswordMigrationWarningView);
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java
new file mode 100644
index 0000000..f3467829
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java
@@ -0,0 +1,46 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import org.chromium.components.version_info.VersionInfo;
+import org.chromium.ui.widget.TextViewWithLeading;
+
+/** This fragment contains the UI for the first page of the password migration warning. */
+public class PasswordMigrationWarningIntroFragment extends Fragment {
+    private Context mContext;
+
+    public PasswordMigrationWarningIntroFragment(Context context) {
+        super(R.layout.pwd_migration_warning_intro_fragment);
+        mContext = context;
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        TextViewWithLeading subtitleView = view.findViewById(R.id.migration_warning_sheet_subtitle);
+        subtitleView.setText(mContext.getString(R.string.password_migration_warning_subtitle)
+                                     .replace("%1$s", getChannelString()));
+    }
+
+    private String getChannelString() {
+        if (VersionInfo.isCanaryBuild()) {
+            return "Canary";
+        }
+        if (VersionInfo.isDevBuild()) {
+            return "Dev";
+        }
+        if (VersionInfo.isBetaBuild()) {
+            return "Beta";
+        }
+        assert !VersionInfo.isStableBuild();
+        return "";
+    }
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java
new file mode 100644
index 0000000..d7d4838
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java
@@ -0,0 +1,83 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Tests for {@link PasswordMigrationWarningMediator}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Batch(Batch.PER_CLASS)
+public class PasswordMigrationWarningMediatorTest {
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+    @Rule
+    public TestRule mProcessor = new Features.JUnitProcessor();
+
+    private PasswordMigrationWarningMediator mMediator = new PasswordMigrationWarningMediator();
+
+    @Mock
+    private BottomSheetController mBottomSheetController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mMediator.initialize(
+                PasswordMigrationWarningProperties.createDefaultModel(mMediator::onDismissed));
+    }
+
+    @Test
+    public void testShowWarningChangesVisibility() {
+        PropertyModel model = mMediator.getModel();
+        assertFalse(model.get(VISIBLE));
+        mMediator.showWarning();
+        assertTrue(model.get(VISIBLE));
+    }
+
+    @Test
+    public void testOnDismissedChangesVisibility() {
+        PropertyModel model = mMediator.getModel();
+        mMediator.showWarning();
+        assertTrue(model.get(VISIBLE));
+        mMediator.onDismissed(StateChangeReason.NONE);
+        assertFalse(model.get(VISIBLE));
+    }
+
+    @Test
+    public void testDismissHandlerChangesVisibility() {
+        PropertyModel model = mMediator.getModel();
+        assertNotNull(model.get(DISMISS_HANDLER));
+        assertFalse(model.get(VISIBLE));
+        mMediator.showWarning();
+        assertTrue(model.get(VISIBLE));
+        model.get(DISMISS_HANDLER).onResult(StateChangeReason.NONE);
+        assertFalse(model.get(VISIBLE));
+    }
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
index 5d4f4f3..bf392bc 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
@@ -67,7 +67,7 @@
     @Rule
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus()
-                    .setRevision(0)
+                    .setRevision(1)
                     .setBugComponent(Component.UI_BROWSER_AUTOFILL)
                     .build();
 
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
index f92e017..0f1e411 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
@@ -11,7 +11,9 @@
 import android.widget.RelativeLayout;
 
 import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.content.res.AppCompatResources;
+import androidx.fragment.app.FragmentManager;
 
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.password_manager.PasswordManagerResourceProviderFactory;
@@ -27,6 +29,8 @@
 class PasswordMigrationWarningView implements BottomSheetContent {
     private final BottomSheetController mBottomSheetController;
     private Callback<Integer> mDismissHandler;
+    private FragmentManager mFragmentManager;
+    private PasswordMigrationWarningIntroFragment mIntroFragment;
     private final RelativeLayout mContentView;
 
     private final BottomSheetObserver mBottomSheetObserver = new EmptyBottomSheetObserver() {
@@ -56,6 +60,14 @@
                 mContentView.findViewById(R.id.touch_to_fill_sheet_header_image);
         sheetHeaderImage.setImageDrawable(AppCompatResources.getDrawable(
                 context, PasswordManagerResourceProviderFactory.create().getPasswordManagerIcon()));
+
+        mFragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
+        mIntroFragment = new PasswordMigrationWarningIntroFragment(context);
+        mFragmentManager.beginTransaction()
+                .setReorderingAllowed(true)
+                .add(R.id.fragment_container_view, mIntroFragment,
+                        "PasswordMigrationWarningFragment")
+                .commit();
     }
 
     void setDismissHandler(Callback<Integer> dismissHandler) {
diff --git a/chrome/browser/pdf/pdf_extension_accessibility_test.cc b/chrome/browser/pdf/pdf_extension_accessibility_test.cc
index db8b787..8b8c4b9 100644
--- a/chrome/browser/pdf/pdf_extension_accessibility_test.cc
+++ b/chrome/browser/pdf/pdf_extension_accessibility_test.cc
@@ -916,8 +916,10 @@
   }
 };
 
+// TODO(crbug.com/1444895): Re-enable it when integrating PDF OCR with
+// Select-to-Speak.
 IN_PROC_BROWSER_TEST_F(PDFExtensionAccessibilityPdfOcrTest,
-                       CheckUmaWhenTurnOnPdfOcrFromMoreActions) {
+                       DISABLED_CheckUmaWhenTurnOnPdfOcrFromMoreActions) {
   MimeHandlerViewGuest* guest_view = LoadPdfGetMimeHandlerView(
       embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(guest_view);
@@ -933,8 +935,10 @@
       /*expected_bucket_count=*/1);
 }
 
+// TODO(crbug.com/1444895): Re-enable it when integrating PDF OCR with
+// Select-to-Speak.
 IN_PROC_BROWSER_TEST_F(PDFExtensionAccessibilityPdfOcrTest,
-                       CheckUmaWhenTurnOffPdfOcrFromMoreActions) {
+                       DISABLED_CheckUmaWhenTurnOffPdfOcrFromMoreActions) {
   MimeHandlerViewGuest* guest_view = LoadPdfGetMimeHandlerView(
       embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(guest_view);
diff --git a/chrome/browser/pdf/pdf_extension_js_test.cc b/chrome/browser/pdf/pdf_extension_js_test.cc
index 4c95736..4050ba1 100644
--- a/chrome/browser/pdf/pdf_extension_js_test.cc
+++ b/chrome/browser/pdf/pdf_extension_js_test.cc
@@ -282,7 +282,9 @@
 #endif  // BUILDFLAG(ENABLE_INK)
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-IN_PROC_BROWSER_TEST_F(PDFExtensionJSTest, PdfOcrToolbar) {
+// TODO(crbug.com/1444895): Re-enable it when integrating PDF OCR with
+// Select-to-Speak.
+IN_PROC_BROWSER_TEST_F(PDFExtensionJSTest, DISABLED_PdfOcrToolbar) {
   // Although this test file does not require a PDF to be loaded, loading the
   // elements without loading a PDF is difficult.
   RunTestsInJsModule("pdf_ocr_toolbar_test.js", "test.pdf");
diff --git a/chrome/browser/pdf/pdf_extension_util.cc b/chrome/browser/pdf/pdf_extension_util.cc
index e7ad742..5ce9b784 100644
--- a/chrome/browser/pdf/pdf_extension_util.cc
+++ b/chrome/browser/pdf/pdf_extension_util.cc
@@ -214,7 +214,9 @@
   dict->Set("printingEnabled", printing_enabled);
   dict->Set("pdfAnnotationsEnabled", annotations_enabled);
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-  dict->Set("pdfOcrEnabled", base::FeatureList::IsEnabled(features::kPdfOcr));
+  // TODO(crbug.com/1444895): Re-enable it when integrating PDF OCR with
+  // Select-to-Speak. Consider adding a feature flag.
+  dict->Set("pdfOcrEnabled", false);
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 }
 
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
index ada1944..7f08c9b 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
@@ -690,20 +690,21 @@
 void UserPerformanceTuningManager::OnHighEfficiencyModePrefChanged() {
   HighEfficiencyModeState state =
       prefs::GetCurrentHighEfficiencyModeState(pref_change_registrar_.prefs());
-  if (!IsHighEfficiencyModeManaged() &&
-      base::FeatureList::IsEnabled(features::kForceHeuristicMemorySaver)) {
-    // Set the heuristic policy for experimentation regardless of the pref.
-    state = base::FeatureList::IsEnabled(features::kHeuristicMemorySaver)
-                ? HighEfficiencyModeState::kEnabled
-                : HighEfficiencyModeState::kDisabled;
-  } else if (state != HighEfficiencyModeState::kDisabled &&
-             !base::FeatureList::IsEnabled(
-                 features::kHighEfficiencyMultistateMode)) {
-    // The user has enabled high efficiency mode, but without the multistate UI
-    // they didn't choose a policy. The feature controls which policy to use.
-    state = base::FeatureList::IsEnabled(features::kHeuristicMemorySaver)
-                ? HighEfficiencyModeState::kEnabled
-                : HighEfficiencyModeState::kEnabledOnTimer;
+  if (!base::FeatureList::IsEnabled(features::kHighEfficiencyMultistateMode)) {
+    if (!IsHighEfficiencyModeManaged() &&
+        base::FeatureList::IsEnabled(features::kForceHeuristicMemorySaver)) {
+      // Set the heuristic policy for experimentation regardless of the pref.
+      state = base::FeatureList::IsEnabled(features::kHeuristicMemorySaver)
+                  ? HighEfficiencyModeState::kEnabled
+                  : HighEfficiencyModeState::kDisabled;
+    } else if (state != HighEfficiencyModeState::kDisabled) {
+      // The user has enabled high efficiency mode, but without the multistate
+      // UI they didn't choose a policy. The feature controls which policy to
+      // use.
+      state = base::FeatureList::IsEnabled(features::kHeuristicMemorySaver)
+                  ? HighEfficiencyModeState::kEnabled
+                  : HighEfficiencyModeState::kEnabledOnTimer;
+    }
   }
   high_efficiency_mode_delegate_->ToggleHighEfficiencyMode(state);
   for (auto& obs : observers_) {
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
index 60e010d..5b4f753 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
 
-#include <tuple>
 #include <utility>
 #include <vector>
 
@@ -26,7 +25,6 @@
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/dbus/power/power_manager_client.h"
@@ -579,168 +577,157 @@
 }
 #endif
 
-// States of the HeuristicMemorySaver and MultistateMode features to test, with
-// expected outcomes.
-struct PrefTestFeatureState {
-  // Whether the MultistateMode feature is enabled.
-  bool is_multistate_enabled;
-
+struct PrefTestParams {
   // Whether the HeuristicMemorySaver feature is enabled.
-  bool is_heuristic_memory_saver_enabled;
+  bool is_heuristic_memory_saver_enabled = false;
 
-  // The expected result when the pref is set to kEnabled with these params.
-  HighEfficiencyModeState expected_enabled_state;
+  // State to store in the kHighEfficiencyModeState pref.
+  HighEfficiencyModeState pref_state = HighEfficiencyModeState::kDisabled;
 
-  // The expected result when the pref is set to kEnabledOnTimer with these
-  // params.
-  HighEfficiencyModeState expected_enabled_on_timer_state;
+  // Expected state passed to ToggleHighEfficiencyMode().
+  HighEfficiencyModeState expected_state = HighEfficiencyModeState::kDisabled;
+
+  // Expected state passed to ToggleHighEfficiencyMode() when
+  // ForceHeuristicMemorySaver is enabled and not ignored.
+  HighEfficiencyModeState expected_state_with_force =
+      HighEfficiencyModeState::kDisabled;
 };
 
-// List of feature states to test, not including the ForceHeuristicMemorySaver
-// feature. These include the expected states that should be passed to
-// ToggleHighEfficiencyMode when ForceHeuristicMemorySaver is disabled.
-constexpr PrefTestFeatureState kNonForcedPrefTestFeatureStates[] = {
-    // If multistate is off, both "enabled" states are controlled by the
-    // HeuristicMemorySaver feature.
-    {
-        .is_multistate_enabled = false,
-        .is_heuristic_memory_saver_enabled = false,
-        .expected_enabled_state = HighEfficiencyModeState::kEnabledOnTimer,
-        .expected_enabled_on_timer_state =
-            HighEfficiencyModeState::kEnabledOnTimer,
-    },
-    {
-        .is_multistate_enabled = false,
-        .is_heuristic_memory_saver_enabled = true,
-        .expected_enabled_state = HighEfficiencyModeState::kEnabled,
-        .expected_enabled_on_timer_state = HighEfficiencyModeState::kEnabled,
-    },
-    // If multistate is on, the true "enabled" state is used regardless of the
-    // HeuristicMemorySaver feature.
-    {
-        .is_multistate_enabled = true,
-        .is_heuristic_memory_saver_enabled = false,
-        .expected_enabled_state = HighEfficiencyModeState::kEnabled,
-        .expected_enabled_on_timer_state =
-            HighEfficiencyModeState::kEnabledOnTimer,
-    },
-    {
-        .is_multistate_enabled = true,
-        .is_heuristic_memory_saver_enabled = true,
-        .expected_enabled_state = HighEfficiencyModeState::kEnabled,
-        .expected_enabled_on_timer_state =
-            HighEfficiencyModeState::kEnabledOnTimer,
-    }};
-
-// Test parameters are (feature_state, is_force_heuristic_memory_saver_enabled).
-// Each feature state above is tested once with the ForceHeuristicMemorySaver
-// feature enabled and once with it disabled.
 class UserPerformanceTuningManagerPrefTest
     : public UserPerformanceTuningManagerTest,
-      public ::testing::WithParamInterface<
-          std::tuple<PrefTestFeatureState, bool>> {
+      public ::testing::WithParamInterface<PrefTestParams> {
  protected:
-  void SetUp() override {
-    UserPerformanceTuningManagerTest::SetUp();
-
-    std::tie(feature_state_, is_force_heuristic_memory_saver_enabled_) =
-        GetParam();
-
+  void InstallFeatures(bool is_force_heuristic_memory_saver_enabled,
+                       bool is_multistate_enabled = false) {
     std::vector<base::test::FeatureRef> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
-    if (feature_state_.is_multistate_enabled) {
-      enabled_features.push_back(features::kHighEfficiencyMultistateMode);
-    } else {
-      disabled_features.push_back(features::kHighEfficiencyMultistateMode);
-    }
-    if (feature_state_.is_heuristic_memory_saver_enabled) {
+    if (GetParam().is_heuristic_memory_saver_enabled) {
       enabled_features.push_back(features::kHeuristicMemorySaver);
     } else {
       disabled_features.push_back(features::kHeuristicMemorySaver);
     }
-    if (is_force_heuristic_memory_saver_enabled_) {
+    if (is_force_heuristic_memory_saver_enabled) {
       enabled_features.push_back(features::kForceHeuristicMemorySaver);
     } else {
       disabled_features.push_back(features::kForceHeuristicMemorySaver);
     }
+    if (is_multistate_enabled) {
+      enabled_features.push_back(features::kHighEfficiencyMultistateMode);
+    } else {
+      disabled_features.push_back(features::kHighEfficiencyMultistateMode);
+    }
     feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
-  base::Value ValueForState(HighEfficiencyModeState state) {
-    return base::Value(static_cast<int>(state));
+  base::Value ValueForPrefState() const {
+    return base::Value(static_cast<int>(GetParam().pref_state));
   }
 
-  PrefTestFeatureState feature_state_;
-  bool is_force_heuristic_memory_saver_enabled_;
   base::test::ScopedFeatureList feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         UserPerformanceTuningManagerPrefTest,
-                         Combine(ValuesIn(kNonForcedPrefTestFeatureStates),
-                                 Bool()));
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    UserPerformanceTuningManagerPrefTest,
+    ::testing::Values(
+        // With HeuristicMemorySaver disabled, the timer policy is used whenever
+        // HighEfficiencyMode is enabled. ForceHeuristicMemorySaver forces
+        // HighEfficiencyMode to OFF.
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = false,
+            .pref_state = HighEfficiencyModeState::kDisabled,
+            .expected_state = HighEfficiencyModeState::kDisabled,
+            .expected_state_with_force = HighEfficiencyModeState::kDisabled,
+        },
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = false,
+            .pref_state = HighEfficiencyModeState::kEnabled,
+            .expected_state = HighEfficiencyModeState::kEnabledOnTimer,
+            .expected_state_with_force = HighEfficiencyModeState::kDisabled,
+        },
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = false,
+            .pref_state = HighEfficiencyModeState::kEnabledOnTimer,
+            .expected_state = HighEfficiencyModeState::kEnabledOnTimer,
+            .expected_state_with_force = HighEfficiencyModeState::kDisabled,
+        },
+        // With HeuristicMemorySaver enabled, the heuristic policy is used
+        // whenever HighEfficiencyMode is enabled. ForceHeuristicMemorySaver
+        // forces HighEfficiencyMode to ON.
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = true,
+            .pref_state = HighEfficiencyModeState::kDisabled,
+            .expected_state = HighEfficiencyModeState::kDisabled,
+            .expected_state_with_force = HighEfficiencyModeState::kEnabled,
+        },
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = true,
+            .pref_state = HighEfficiencyModeState::kEnabled,
+            .expected_state = HighEfficiencyModeState::kEnabled,
+            .expected_state_with_force = HighEfficiencyModeState::kEnabled,
+        },
+        PrefTestParams{
+            .is_heuristic_memory_saver_enabled = true,
+            .pref_state = HighEfficiencyModeState::kEnabledOnTimer,
+            .expected_state = HighEfficiencyModeState::kEnabled,
+            .expected_state_with_force = HighEfficiencyModeState::kEnabled,
+        }));
 
-TEST_P(UserPerformanceTuningManagerPrefTest, OnHighEfficiencyModePrefChanged) {
+TEST_P(UserPerformanceTuningManagerPrefTest, OnPrefChanged) {
+  InstallFeatures(/*is_force_heuristic_memory_saver_enabled=*/false);
   StartManager();
-
-  // If the ForceHeuristicMemorySaver feature is overriding the pref, the final
-  // state should always be based on the HeuristicMemorySaver feature.
-  absl::optional<HighEfficiencyModeState> expected_overridden_state;
-  if (is_force_heuristic_memory_saver_enabled_) {
-    expected_overridden_state = feature_state_.is_heuristic_memory_saver_enabled
-                                    ? HighEfficiencyModeState::kEnabled
-                                    : HighEfficiencyModeState::kDisabled;
-  }
-
   local_state_.SetUserPref(prefs::kHighEfficiencyModeState,
-                           ValueForState(HighEfficiencyModeState::kDisabled));
+                           ValueForPrefState());
   EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(expected_overridden_state.value_or(
-                  HighEfficiencyModeState::kDisabled)));
-
-  high_efficiency_mode_delegate_->ClearLastState();
-
-  local_state_.SetUserPref(prefs::kHighEfficiencyModeState,
-                           ValueForState(HighEfficiencyModeState::kEnabled));
-  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(expected_overridden_state.value_or(
-                  feature_state_.expected_enabled_state)));
-  high_efficiency_mode_delegate_->ClearLastState();
-
-  local_state_.SetUserPref(
-      prefs::kHighEfficiencyModeState,
-      ValueForState(HighEfficiencyModeState::kEnabledOnTimer));
-  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(expected_overridden_state.value_or(
-                  feature_state_.expected_enabled_on_timer_state)));
-  high_efficiency_mode_delegate_->ClearLastState();
+              Optional(GetParam().expected_state));
 }
 
-TEST_P(UserPerformanceTuningManagerPrefTest,
-       OnHighEfficiencyModePrefChangedManaged) {
+TEST_P(UserPerformanceTuningManagerPrefTest, OnPrefChangedWithForce) {
+  InstallFeatures(/*is_force_heuristic_memory_saver_enabled=*/true);
+  StartManager();
+  local_state_.SetUserPref(prefs::kHighEfficiencyModeState,
+                           ValueForPrefState());
+  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
+              Optional(GetParam().expected_state_with_force));
+}
+
+TEST_P(UserPerformanceTuningManagerPrefTest, OnPrefChangedMultistate) {
+  InstallFeatures(/*is_force_heuristic_memory_saver_enabled=*/false,
+                  /*is_multistate_enabled=*/true);
+  StartManager();
+
+  // When the HighEfficiencyMultistateMode feature is enabled, all states should
+  // be passed to ToggleHighEfficiencyMode() unchanged.
+  local_state_.SetUserPref(prefs::kHighEfficiencyModeState,
+                           ValueForPrefState());
+  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
+              Optional(GetParam().pref_state));
+}
+
+TEST_P(UserPerformanceTuningManagerPrefTest, OnPrefChangedMultistateWithForce) {
+  InstallFeatures(/*is_force_heuristic_memory_saver_enabled=*/true,
+                  /*is_multistate_enabled=*/true);
+  StartManager();
+
+  // When the HighEfficiencyMultistateMode feature is enabled, all states should
+  // be passed to ToggleHighEfficiencyMode() unchanged, even when
+  // ForceHeuristicMemorySaver is enabled.
+  local_state_.SetUserPref(prefs::kHighEfficiencyModeState,
+                           ValueForPrefState());
+  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
+              Optional(GetParam().pref_state));
+}
+
+TEST_P(UserPerformanceTuningManagerPrefTest, OnManagedPrefChanged) {
+  InstallFeatures(/*is_force_heuristic_memory_saver_enabled=*/true);
   StartManager();
 
   // Since the pref is managed, ForceHeuristicMemorySaver is not allowed to
-  // override it, so ignore `is_force_heuristic_memory_saver_enabled_`.
-  local_state_.SetManagedPref(
-      prefs::kHighEfficiencyModeState,
-      ValueForState(HighEfficiencyModeState::kDisabled));
-  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(HighEfficiencyModeState::kDisabled));
-  high_efficiency_mode_delegate_->ClearLastState();
-
+  // override it, so use the expectation without force.
   local_state_.SetManagedPref(prefs::kHighEfficiencyModeState,
-                              ValueForState(HighEfficiencyModeState::kEnabled));
+                              ValueForPrefState());
   EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(feature_state_.expected_enabled_state));
-  high_efficiency_mode_delegate_->ClearLastState();
-
-  local_state_.SetManagedPref(
-      prefs::kHighEfficiencyModeState,
-      ValueForState(HighEfficiencyModeState::kEnabledOnTimer));
-  EXPECT_THAT(high_efficiency_mode_delegate_->GetLastState(),
-              Optional(feature_state_.expected_enabled_on_timer_state));
-  high_efficiency_mode_delegate_->ClearLastState();
+              Optional(GetParam().expected_state));
 }
 
 }  // namespace performance_manager::user_tuning
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn
index da1cefe..a263815 100644
--- a/chrome/browser/policy/BUILD.gn
+++ b/chrome/browser/policy/BUILD.gn
@@ -197,10 +197,6 @@
     sources += [ "test/policy_certs_browsertest.cc" ]
   }
 
-  if (enable_nacl) {
-    sources += [ "test/ppb_video_decoder_dev_api_policy_browsertest.cc" ]
-  }
-
   deps = [
     ":test_support",
     "//base",
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 6ec5b13d..3a78d25 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1878,14 +1878,6 @@
     prefs::kCloudApAuthEnabled,
     base::Value::Type::INTEGER },
 #endif  // BUILDFLAG(IS_WIN)
-#if BUILDFLAG(ENABLE_PPAPI)
-  { key::kPPAPISharedImagesSwapChainAllowed,
-    policy::policy_prefs::kPPAPISharedImagesSwapChainAllowed,
-    base::Value::Type::BOOLEAN },
-  { key::kForceEnablePepperVideoDecoderDevAPI,
-    policy::policy_prefs::kForceEnablePepperVideoDecoderDevAPI,
-    base::Value::Type::BOOLEAN },
-#endif // BUILDFLAG(ENABLE_PPAPI)
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
   { key::kOutOfProcessSystemDnsResolutionEnabled,
     prefs::kOutOfProcessSystemDnsResolutionEnabled,
diff --git a/chrome/browser/policy/test/ppb_video_decoder_dev_api_policy_browsertest.cc b/chrome/browser/policy/test/ppb_video_decoder_dev_api_policy_browsertest.cc
deleted file mode 100644
index 0e03227..0000000
--- a/chrome/browser/policy/test/ppb_video_decoder_dev_api_policy_browsertest.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/chrome_content_browser_client.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "components/policy/core/browser/browser_policy_connector.h"
-#include "components/policy/core/common/mock_configuration_policy_provider.h"
-#include "components/policy/policy_constants.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/test/browser_test.h"
-
-namespace {
-
-enum class PolicySetting {
-  On,
-  Off,
-  Unset,
-};
-
-enum class FeatureSetting {
-  On,
-  Off,
-  Unset,
-};
-
-// Subclasses ChromeContentBrowserClient to save and expose command lines that
-// are passed to renderer processes.
-class ChromeContentBrowserClientForPolicyTests
-    : public ChromeContentBrowserClient {
- public:
-  ChromeContentBrowserClientForPolicyTests() = default;
-  ChromeContentBrowserClientForPolicyTests(
-      const ChromeContentBrowserClientForPolicyTests&) = delete;
-  ChromeContentBrowserClientForPolicyTests& operator=(
-      const ChromeContentBrowserClientForPolicyTests&) = delete;
-
-  ~ChromeContentBrowserClientForPolicyTests() override = default;
-
-  base::CommandLine* command_line_from_last_renderer() {
-    return command_line_from_last_renderer_.get();
-  }
-
-  void clear_command_line_from_last_renderer() {
-    command_line_from_last_renderer_.reset();
-  }
-
- private:
-  void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
-                                      int child_process_id) override {
-    ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
-        command_line, child_process_id);
-
-    if (command_line->GetSwitchValueASCII(switches::kProcessType) ==
-        switches::kRendererProcess) {
-      command_line_from_last_renderer_ =
-          std::make_unique<base::CommandLine>(*command_line);
-    }
-  }
-
-  std::unique_ptr<base::CommandLine> command_line_from_last_renderer_;
-};
-
-}  // namespace
-
-// NOTE: This test is templated rather than parameterized in the interests of
-// readability: while a parameterized test would be shorter, it was the author's
-// judgment that it would be significantly harder to read and comprehend the
-// meaning of what was being tested across the different permutations.
-template <PolicySetting policy_setting, FeatureSetting feature_setting>
-class PPBVideoDecoderDevAPIPolicyBrowserTest : public PlatformBrowserTest {
- public:
-  PPBVideoDecoderDevAPIPolicyBrowserTest(
-      const PPBVideoDecoderDevAPIPolicyBrowserTest&) = delete;
-  PPBVideoDecoderDevAPIPolicyBrowserTest& operator=(
-      const PPBVideoDecoderDevAPIPolicyBrowserTest&) = delete;
-
- protected:
-  PPBVideoDecoderDevAPIPolicyBrowserTest() = default;
-
-  void SetUpInProcessBrowserTestFixture() override {
-    // Set the feature to the desired setting (if any).
-    if (feature_setting == FeatureSetting::On) {
-      feature_list_.InitAndEnableFeature(
-          features::kSupportPepperVideoDecoderDevAPI);
-    } else if (feature_setting == FeatureSetting::Off) {
-      feature_list_.InitAndDisableFeature(
-          features::kSupportPepperVideoDecoderDevAPI);
-    }
-
-    if (policy_setting == PolicySetting::Unset) {
-      return;
-    }
-
-    // Set up the policy here as the policy must be 'live' before the renderer
-    // is created, since the value for this policy is passed to the renderer via
-    // a command-line. Setting the policy in the test itself or in
-    // SetUpOnMainThread works for update-able policies, but is too late for
-    // this one.
-    provider_.SetDefaultReturns(
-        /*is_initialization_complete_return=*/true,
-        /*is_first_policy_load_complete_return=*/true);
-    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
-
-    policy::PolicyMap values;
-
-    const char* kPolicyName = policy::key::kForceEnablePepperVideoDecoderDevAPI;
-    values.Set(kPolicyName, policy::POLICY_LEVEL_MANDATORY,
-               policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
-               base::Value(policy_setting == PolicySetting::On), nullptr);
-    provider_.UpdateChromePolicy(values);
-  }
-
-  void SetUpOnMainThread() override {
-    content::SetBrowserClientForTesting(&test_browser_client_);
-  }
-
-  // Creates a new renderer process.
-  void CreateRenderer() {
-    test_browser_client_.clear_command_line_from_last_renderer();
-    ASSERT_FALSE(command_line_from_last_renderer());
-
-    ASSERT_TRUE(
-        AddTabAtIndex(0, GURL("chrome://version"), ui::PAGE_TRANSITION_TYPED));
-    ASSERT_TRUE(command_line_from_last_renderer());
-  }
-
-  // Returns whether the last-created renderer was passed the command-line
-  // switch for force-enabling the PPB_VideoDecoder(Dev) API.
-  bool renderer_was_passed_policy_switch() {
-    return command_line_from_last_renderer()->HasSwitch(
-        switches::kForceEnablePepperVideoDecoderDevAPI);
-  }
-
- private:
-  base::CommandLine* command_line_from_last_renderer() {
-    return test_browser_client_.command_line_from_last_renderer();
-  }
-
-  ChromeContentBrowserClientForPolicyTests test_browser_client_;
-  base::test::ScopedFeatureList feature_list_;
-  testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
-};
-
-// Tests of the policy being turned on: the command-line switch should be
-// present, regardless of the setting of the base::Feature.
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::On,
-                                               FeatureSetting::On>
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureEnabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::On,
-                                               FeatureSetting::Off>
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureDisabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::On,
-                                               FeatureSetting::Unset>
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureNotSetBrowserTest;
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureEnabledBrowserTest,
-    CommandLineSwitchPresent) {
-  CreateRenderer();
-  EXPECT_TRUE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureDisabledBrowserTest,
-    CommandLineSwitchPresent) {
-  CreateRenderer();
-  EXPECT_TRUE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyEnabledFeatureNotSetBrowserTest,
-    CommandLineSwitchPresent) {
-  CreateRenderer();
-  EXPECT_TRUE(renderer_was_passed_policy_switch());
-}
-
-// Tests of the policy being turned off: the command-line switch should be
-// missing, regardless of the setting of the base::Feature.
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Off,
-                                               FeatureSetting::On>
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureEnabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Off,
-                                               FeatureSetting::Off>
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureDisabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Off,
-                                               FeatureSetting::Unset>
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureNotSetBrowserTest;
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureEnabledBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureDisabledBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyDisabledFeatureNotSetBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
-
-// Tests of the policy not being set: the command-line switch should be missing,
-// regardless of the setting of the base::Feature.
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Unset,
-                                               FeatureSetting::On>
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureEnabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Unset,
-                                               FeatureSetting::Off>
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureDisabledBrowserTest;
-typedef PPBVideoDecoderDevAPIPolicyBrowserTest<PolicySetting::Unset,
-                                               FeatureSetting::Unset>
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureNotSetBrowserTest;
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureEnabledBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureDisabledBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PPBVideoDecoderDevAPIPolicyNotSetFeatureNotSetBrowserTest,
-    CommandLineSwitchNotPresent) {
-  CreateRenderer();
-  EXPECT_FALSE(renderer_was_passed_policy_switch());
-}
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc
index f84251c..42cf83b 100644
--- a/chrome/browser/predictors/loading_predictor_tab_helper.cc
+++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -75,6 +75,7 @@
     case network::mojom::RequestDestination::kXslt:
     case network::mojom::RequestDestination::kFencedframe:
     case network::mojom::RequestDestination::kWebIdentity:
+    case network::mojom::RequestDestination::kDictionary:
       return net::LOWEST;
   }
 }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index f05d21d7..f5bb14c 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -816,9 +816,22 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
 // Deprecated 05/2023
+const char kForceEnablePepperVideoDecoderDevAPI[] =
+    "policy.force_enable_pepper_video_decoder_dev_api";
+
+// Deprecated 05/2023
 const char kUseMojoVideoDecoderForPepperAllowed[] =
     "policy.use_mojo_video_decoder_for_pepper_allowed";
 
+// Deprecated 05/2023.
+const char kPPAPISharedImagesSwapChainAllowed[] =
+    "policy.ppapi_shared_images_swap_chain_allowed";
+
+// Deprecated 05/2023.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+const char kOfficeSetupComplete[] = "filebrowser.office.setup_complete";
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -910,7 +923,13 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Deprecated 05/2023.
+  registry->RegisterBooleanPref(kForceEnablePepperVideoDecoderDevAPI, false);
+
+  // Deprecated 05/2023.
   registry->RegisterBooleanPref(kUseMojoVideoDecoderForPepperAllowed, true);
+
+  // Deprecated 05/2023.
+  registry->RegisterBooleanPref(kPPAPISharedImagesSwapChainAllowed, true);
 }
 
 // Register prefs used only for migration (clearing or moving to a new key).
@@ -1129,6 +1148,11 @@
                                std::string());
   registry->RegisterTimePref(kVideoTutorialsLastUpdatedTimeKey, base::Time());
 #endif  // BUILDFLAG(IS_ANDROID)
+
+// Deprecated 05/2023.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  registry->RegisterBooleanPref(kOfficeSetupComplete, false);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 }  // namespace
@@ -1893,8 +1917,14 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Added 05/2023.
+  local_state->ClearPref(kForceEnablePepperVideoDecoderDevAPI);
+
+  // Added 05/2023.
   local_state->ClearPref(kUseMojoVideoDecoderForPepperAllowed);
 
+  // Added 05/2023
+  local_state->ClearPref(kPPAPISharedImagesSwapChainAllowed);
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
 
@@ -2174,6 +2204,11 @@
   profile_prefs->ClearPref(kVideoTutorialsLastUpdatedTimeKey);
 #endif  // BUILDFLAG(IS_ANDROID
 
+// Added 05/2023.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  profile_prefs->ClearPref(kOfficeSetupComplete);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc
index 48d5079..123742b 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc
@@ -23,27 +23,6 @@
       identity_manager->FindExtendedAccountInfo(core_account_info);
   return account_info.capabilities.can_run_chrome_privacy_sandbox_trials();
 }
-
-bool PrivacySandboxRestrictedNoticeRequired(Profile* profile) {
-  auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
-
-  if (!identity_manager ||
-      !identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
-    // The user isn't signed in so we can't apply any capabilties-based
-    // restrictions.
-    return false;
-  }
-
-  const auto core_account_info =
-      identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
-  const AccountInfo account_info =
-      identity_manager->FindExtendedAccountInfo(core_account_info);
-  auto capability =
-      account_info.capabilities
-          .is_subject_to_chrome_privacy_sandbox_restricted_measurement_notice();
-  return capability == signin::Tribool::kTrue;
-}
-
 }  // namespace
 
 PrivacySandboxSettingsDelegate::PrivacySandboxSettingsDelegate(Profile* profile)
@@ -94,7 +73,7 @@
   if (!privacy_sandbox::kPrivacySandboxSettings4RestrictedNotice.Get()) {
     return false;
   }
-  return PrivacySandboxRestrictedNoticeRequired(profile_);
+  return PrivacySandboxRestrictedNoticeRequired();
 }
 
 bool PrivacySandboxSettingsDelegate::IsIncognitoProfile() const {
@@ -115,3 +94,23 @@
   return profile_->GetPrefs()->GetBoolean(
       prefs::kPrivacySandboxTopicsConsentGiven);
 }
+
+bool PrivacySandboxSettingsDelegate::PrivacySandboxRestrictedNoticeRequired()
+    const {
+  auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
+
+  if (!identity_manager ||
+      !identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
+    // The user isn't signed in so we can't apply any capabilties-based
+    // restrictions.
+    return false;
+  }
+
+  const AccountInfo account_info =
+      identity_manager->FindExtendedPrimaryAccountInfo(
+          signin::ConsentLevel::kSignin);
+  auto capability =
+      account_info.capabilities
+          .is_subject_to_chrome_privacy_sandbox_restricted_measurement_notice();
+  return capability == signin::Tribool::kTrue;
+}
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h
index 9e0dcb1..6297fa9 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h
@@ -23,6 +23,7 @@
   bool IsSubjectToM1NoticeRestricted() const override;
 
  private:
+  bool PrivacySandboxRestrictedNoticeRequired() const;
   raw_ptr<Profile> profile_;
 };
 
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc
index f67c6cd4..036e0505 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc
@@ -129,6 +129,30 @@
 }
 
 TEST_F(PrivacySandboxSettingsDelegateTest,
+       RestrictedNoticeRequiredWithoutAccountToken) {
+  feature_list()->InitAndEnableFeatureWithParameters(
+      privacy_sandbox::kPrivacySandboxSettings4,
+      {{privacy_sandbox::kPrivacySandboxSettings4RestrictedNotice.name,
+        "true"}});
+  // Sign the user in.
+  identity_test_env()->MakePrimaryAccountAvailable(
+      kTestEmail, signin::ConsentLevel::kSignin);
+
+  // Initially the account capability will be in an unknown state
+  EXPECT_FALSE(delegate()->IsSubjectToM1NoticeRestricted());
+
+  // Enable the account capability
+  SetRestrictedNoticeCapability(kTestEmail, true);
+
+  // Remove the refresh token for the account
+  signin::RemoveRefreshTokenForPrimaryAccount(
+      identity_test_env()->identity_manager());
+
+  // Capability is fetched even if the token is not available
+  EXPECT_TRUE(delegate()->IsSubjectToM1NoticeRestricted());
+}
+
+TEST_F(PrivacySandboxSettingsDelegateTest,
        RestrictedNoticeRequiredForSignedOutUser) {
   feature_list()->InitAndEnableFeatureWithParameters(
       privacy_sandbox::kPrivacySandboxSettings4,
diff --git a/chrome/browser/recent_tabs/internal/android/java/strings/translations/android_restore_tabs_strings_lo.xtb b/chrome/browser/recent_tabs/internal/android/java/strings/translations/android_restore_tabs_strings_lo.xtb
index 6e3e3580..7c74d23 100644
--- a/chrome/browser/recent_tabs/internal/android/java/strings/translations/android_restore_tabs_strings_lo.xtb
+++ b/chrome/browser/recent_tabs/internal/android/java/strings/translations/android_restore_tabs_strings_lo.xtb
@@ -11,5 +11,6 @@
 <translation id="4386361164755260473">{TABS_COUNT,plural, =1{ເປີດ <ph name="TABS_COUNT_ONE" /> ແຖບ}other{ເປີດ <ph name="TABS_COUNT_MANY" /> ແຖບ}}</translation>
 <translation id="4811934403802581334">ແຖບທີ່ເລືອກທັງໝົດຈາກອຸປະກອນທີ່ເລືອກໃນປັດຈຸບັນຈະຖືກກູ້ຄືນມາ.</translation>
 <translation id="5336031759968328813">ກວດສອບແຖບທັງໝົດ</translation>
+<translation id="8019269305087157499">ເປີດຈາກ</translation>
 <translation id="8725404154479306799">ຮັບເອົາແຖບທີ່ທ່ານປະໄວ້ຢູ່ອຸປະກອນເກົ່າ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 432ec25..8bb5115 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -279,6 +279,8 @@
 #include "chrome/browser/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
 #include "ui/aura/window.h"
 #endif
@@ -4007,10 +4009,19 @@
 }
 
 void RenderViewContextMenu::ExecLanguageSettings(int event_flags) {
+// Open the browser language settings.
+// Exception: On Ash, the browser language settings consists solely of a link to
+// the OS language settings, so just open the OS settings directly (this has the
+// added benefit of also doing the right thing when Lacros is enabled).
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+      GetProfile(), chromeos::settings::mojom::kLanguagesAndInputSectionPath);
+#else
   WindowOpenDisposition disposition = ui::DispositionFromEventFlags(
       event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB);
   GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
   OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
+#endif
 }
 
 void RenderViewContextMenu::ExecProtocolHandlerSettings(int event_flags) {
diff --git a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
index 24b5b5c..ac209b17 100644
--- a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
+++ b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
@@ -207,8 +207,8 @@
   // Docs.
   private getDriveAppInfo(fileNames: string[]) {
     // TODO(b:254586358): i18n these names.
-    const fileName = fileNames[0] || '';
-    if (/\.xlsx?$/.test(fileName)) {
+    const fileName = (fileNames[0] || '').toLowerCase();
+    if (/\.xls[m,x]?$/.test(fileName)) {
       return {name: 'Google Sheets', icon: 'sheets', type: 'Excel'};
     } else if (/\.pptx?$/.test(fileName)) {
       return {name: 'Google Slides', icon: 'slides', type: 'Powerpoint'};
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
index 04e1033..468682a 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -113,6 +113,7 @@
   private nextGifPos: {[key: string]: string};
   private status: Status|null;
   private previousGifValidation: Date;
+  private fetchAndProcessDataPromise: Promise<void>|null;
 
   constructor() {
     super();
@@ -194,7 +195,7 @@
                 item => ({'category': item.name, 'urls': dataUrls[item.name]}));
 
     // Fetch and process all the data.
-    this.fetchAndProcessData(categoryDataUrls);
+    this.fetchAndProcessDataPromise = this.fetchAndProcessData(categoryDataUrls);
 
     this.updateStyles({
       '--emoji-group-button-size': constants.EMOJI_GROUP_SIZE_PX,
@@ -215,6 +216,12 @@
     });
   }
 
+  private async ensureFetchAndProcessDataFinished(): Promise<void> {
+    if (this.fetchAndProcessDataPromise !== null) {
+      await this.fetchAndProcessDataPromise;
+    }
+  }
+
   /**
    * Fetches data and updates all the variables that are required to render
    * EmojiPicker UI. This function serves as the main entry for creating and
@@ -638,8 +645,10 @@
   }
 
   private async selectGroup(newGroup: string) {
+    await this.ensureFetchAndProcessDataFinished();
+
     if (this.category === CategoryEnum.GIF) {
-      this.setGifGroupElements(newGroup);
+      await this.setGifGroupElements(newGroup);
     }
 
     // focus and scroll to selected group's first emoji.
@@ -1260,7 +1269,9 @@
     });
   }
 
-  private onCategoryButtonClick(newCategory: CategoryEnum) {
+  private async onCategoryButtonClick(newCategory: CategoryEnum) {
+    await this.ensureFetchAndProcessDataFinished();
+
     this.set('category', newCategory);
     this.set('pagination', 1);
 
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 9f4e31c2..388c08f9 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -308,7 +308,6 @@
     "screens/common/tpm_error.js",
     "screens/common/user_creation.js",
     "screens/common/wrong_hwid.js",
-    "screens/login/active_directory_password_change.js",
     "screens/login/arc_vm_data_migration.js",
     "screens/login/checking_downloading_update.js",
     "screens/login/cryptohome_recovery.js",
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js
index afff4d0..9dfd10c6 100644
--- a/chrome/browser/resources/chromeos/login/cr_ui.js
+++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -48,6 +48,13 @@
   }
 
   /**
+   * Does the initial transition to the OOBE flow after booting animation.
+   */
+  static triggerDown() {
+    Oobe.getInstance().triggerDown();
+  }
+
+  /**
    * Update body class to switch between OOBE UI and Login UI.
    * @param {boolean} showOobe True if UI is in an OOBE mode (as opposed to
    * login).
diff --git a/chrome/browser/resources/chromeos/login/screens.js b/chrome/browser/resources/chromeos/login/screens.js
index e17e56e..6fc1750 100644
--- a/chrome/browser/resources/chromeos/login/screens.js
+++ b/chrome/browser/resources/chromeos/login/screens.js
@@ -47,7 +47,6 @@
 import './screens/common/user_creation.js';
 import './screens/common/wrong_hwid.js';
 // SCREENS USED DURING THE LOGIN FLOW
-import './screens/login/active_directory_password_change.js';
 import './screens/login/arc_vm_data_migration.js';
 import './screens/login/cryptohome_recovery.js';
 import './screens/login/encryption_migration.js';
@@ -145,7 +144,6 @@
  * List of screens that are used during the `login` flow only.
  */
 export const loginScreensList = [
-  {tag: 'active-directory-password-change-element', id: 'ad-password-change'},
   {
     tag: 'arc-vm-data-migration-element',
     id: 'arc-vm-data-migration',
diff --git a/chrome/browser/resources/chromeos/login/screens/login/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/login/BUILD.gn
index 798de1b..429df1c9 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/screens/login/BUILD.gn
@@ -10,7 +10,6 @@
   is_polymer3 = true
   closure_flags = default_closure_args
   deps = [
-    ":active_directory_password_change",
     ":arc_vm_data_migration",
     ":checking_downloading_update",
     ":cryptohome_recovery",
@@ -27,21 +26,6 @@
 ###############################
 # Closure compiler libraries below
 
-js_library("active_directory_password_change") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.js" ]
-  deps = [
-    "../../components/behaviors:login_screen_behavior",
-    "../../components/behaviors:multi_step_behavior",
-    "../../components/behaviors:oobe_i18n_behavior",
-    "../../components/buttons:oobe_next_button",
-    "../../components/buttons:oobe_text_button",
-    "../../components/dialogs:oobe_modal_dialog",
-  ]
-  externs_list =
-      [ "//ui/webui/resources/cr_elements/cr_input/cr_input_externs.js" ]
-  extra_deps = [ ":web_components" ]
-}
-
 js_library("arc_vm_data_migration") {
   sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/login/arc_vm_data_migration.js" ]
   deps = [
@@ -179,7 +163,6 @@
 
 html_to_js("web_components") {
   js_files = [
-    "active_directory_password_change.js",
     "arc_vm_data_migration.js",
     "checking_downloading_update.js",
     "cryptohome_recovery.js",
diff --git a/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.js b/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.js
deleted file mode 100644
index d991db42..0000000
--- a/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.js
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for Active Directory password change screen.
- */
-
-import '//resources/cr_elements/cr_shared_style.css.js';
-import '//resources/cr_elements/cr_input/cr_input.js';
-import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
-import '../../components/oobe_icons.html.js';
-import '../../components/buttons/oobe_next_button.js';
-import '../../components/buttons/oobe_text_button.js';
-import '../../components/common_styles/oobe_common_styles.css.js';
-import '../../components/common_styles/oobe_dialog_host_styles.css.js';
-import '../../components/dialogs/oobe_adaptive_dialog.js';
-import '../../components/dialogs/oobe_loading_dialog.js';
-
-import {html, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {LoginScreenBehavior, LoginScreenBehaviorInterface} from '../../components/behaviors/login_screen_behavior.js';
-import {MultiStepBehavior, MultiStepBehaviorInterface} from '../../components/behaviors/multi_step_behavior.js';
-import {OobeDialogHostBehavior} from '../../components/behaviors/oobe_dialog_host_behavior.js';
-import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../../components/behaviors/oobe_i18n_behavior.js';
-import {OobeModalDialog} from '../../components/dialogs/oobe_modal_dialog.js';
-
-
-/**
- * Possible error states of the screen. Must be in the same order as
- * ActiveDirectoryPasswordChangeErrorState enum values.
- * @enum {number}
- */
-const ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE = {
-  NO_ERROR: 0,
-  WRONG_OLD_PASSWORD: 1,
-  NEW_PASSWORD_REJECTED: 2,
-};
-
-/**
- * UI mode for the dialog.
- * @enum {string}
- */
-const UIState = {
-  PASSWORD: 'password',
-  PROGRESS: 'progress',
-};
-
-/**
- * @constructor
- * @extends {PolymerElement}
- * @implements {LoginScreenBehaviorInterface}
- * @implements {OobeI18nBehaviorInterface}
- * @implements {MultiStepBehaviorInterface}
- */
-const ActiveDirectoryPasswordChangeBase = mixinBehaviors(
-    [
-      OobeI18nBehavior,
-      OobeDialogHostBehavior,
-      LoginScreenBehavior,
-      MultiStepBehavior,
-    ],
-    PolymerElement);
-
-/**
- * @typedef {{
- *   errorDialog:  OobeModalDialog,
- *   oldPassword:  CrInputElement,
- *   newPassword:  CrInputElement,
- * }}
- */
-ActiveDirectoryPasswordChangeBase.$;
-
-class ActiveDirectoryPasswordChange extends ActiveDirectoryPasswordChangeBase {
-  static get is() {
-    return 'active-directory-password-change-element';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      /**
-       * The user principal name.
-       */
-      username_: String,
-      /**
-       * The old password.
-       */
-      oldPassword_: String,
-      /**
-       * The new password (first copy).
-       */
-      newPassword_: String,
-      /**
-       * The new password (second copy).
-       */
-      newPasswordRepeat_: String,
-      /**
-       * The text content for error dialog.
-       */
-      errorDialogText_: String,
-      /**
-       * Indicates if old password is wrong.
-       */
-      oldPasswordWrong_: Boolean,
-      /**
-       * Indicates if new password is rejected.
-       */
-      newPasswordRejected_: Boolean,
-      /**
-       * Indicates if password is not repeated correctly.
-       */
-      passwordMismatch_: Boolean,
-    };
-  }
-
-  constructor() {
-    super();
-    this.username_ = '';
-    this.oldPassword_ = '';
-    this.newPassword_ = '';
-    this.newPasswordRepeat_ = '';
-    this.errorDialogText_ = '';
-    this.oldPasswordWrong_ = false;
-    this.newPasswordRejected_ = false;
-    this.passwordMismatch_ = false;
-  }
-
-  get EXTERNAL_API() {
-    return ['showErrorDialog'];
-  }
-
-  defaultUIStep() {
-    return UIState.PASSWORD;
-  }
-
-  static get UI_STEPS() {
-    return UIState;
-  }
-
-  /** @override */
-  ready() {
-    super.ready();
-    this.initializeLoginScreen('ActiveDirectoryPasswordChangeScreen');
-  }
-
-  /**
-   * Event handler that is invoked just before the frame is shown.
-   * @param {Object} data Screen init payload
-   */
-  onBeforeShow(data) {
-    // Active Directory password change screen is similar to Active
-    // Directory login screen. So we restore bottom bar controls.
-    this.reset();
-    if ('username' in data) {
-      this.username_ = data.username;
-    }
-    if ('error' in data) {
-      this.setInvalid(data.error);
-    }
-  }
-
-  /**
-   * Updates localized content of the screen that is not updated via
-   * template.
-   */
-  updateLocalizedContent() {
-    this.i18nUpdateLocale();
-  }
-
-  /**
-   * @public
-   * Shows sign-in error dialog.
-   * @param {string} content Content to show in dialog.
-   */
-  showErrorDialog(content) {
-    this.errorDialogText_ = content;
-    this.$.errorDialog.showDialog();
-  }
-
-  /** @public */
-  reset() {
-    this.setUIStep(UIState.PASSWORD);
-    this.resetInputFields_();
-  }
-
-  /** @private */
-  resetInputFields_() {
-    this.oldPassword_ = '';
-    this.newPassword_ = '';
-    this.newPasswordRepeat_ = '';
-    this.errorDialogText_ = '';
-
-    this.oldPasswordWrong_ = false;
-    this.newPasswordRejected_ = false;
-    this.passwordMismatch_ = false;
-  }
-
-  /**
-   * @public
-   *  Invalidates a password input. Either the input for old password or for new
-   *  password depending on passed error.
-   * @param {ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE} error
-   */
-  setInvalid(error) {
-    switch (error) {
-      case ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE.NO_ERROR:
-        break;
-      case ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE.WRONG_OLD_PASSWORD:
-        this.oldPasswordWrong_ = true;
-        break;
-      case ACTIVE_DIRECTORY_PASSWORD_CHANGE_ERROR_STATE.NEW_PASSWORD_REJECTED:
-        this.newPasswordRejected_ = true;
-        break;
-      default:
-        console.error('Not handled error: ' + error);
-    }
-  }
-
-  /**
-   *  @private
-  */
-  onSubmit_() {
-    if (!this.$.oldPassword.validate() || !this.$.newPassword.validate()) {
-      return;
-    }
-    if (this.newPassword_ != this.newPasswordRepeat_) {
-      this.passwordMismatch_ = true;
-      return;
-    }
-    this.setUIStep(UIState.PROGRESS);
-    this.userActed(['changePassword', this.oldPassword_, this.newPassword_]);
-    this.resetInputFields_();
-  }
-
-  /**
-   * @private
-   * Cancels password changing.
-   */
-  onClose_() {
-    this.userActed('cancel');
-  }
-}
-
-customElements.define(
-    ActiveDirectoryPasswordChange.is, ActiveDirectoryPasswordChange);
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.html b/chrome/browser/resources/device_log_ui/device_log_ui.html
index c9abd700..8898224b 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.html
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.html
@@ -5,9 +5,20 @@
   <title id="device-log-title">$i18n{titleText}</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="device_log_ui.css">
+<if expr="is_chromeos">
+  <link rel="stylesheet" href="chrome://resources/css/os_header.css">
+</if>
   <script type="module" src="device_log_ui.js"></script>
 </head>
 <body>
+<if expr="is_chromeos">
+  <div class="os-link-container-container" id="os-link-container">
+    <div class="os-link-container">
+      <span class="os-link-icon"></span>
+      $i18nRaw{osLinkContainer}
+    </div>
+  </div>
+</if>
   <div id="header">
     <span>$i18n{autoRefreshText}</span>
   </div>
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.js b/chrome/browser/resources/device_log_ui/device_log_ui.js
index 2949fef..fa79bad 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.js
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.js
@@ -145,6 +145,23 @@
   }
 };
 
+// <if expr="chromeos_ash">
+const updateOsLink = function() {
+  sendWithPromise('isLacrosEnabled').then(function(isLacrosEnabled) {
+    $('os-link-container').hidden = !isLacrosEnabled;
+
+    // we hide the header text if Lacros is enabled because the Ash window doesn't
+    // have the navigation bar and the hint saying "Add a query param in URL to
+    // auto-refresh the page" is no longer helpful for users.
+    $('header').hidden = isLacrosEnabled;
+  });
+
+  $('os-link-href').onclick = function() {
+    chrome.send('openBrowserDeviceLog');
+  };
+};
+// </if>
+
 /**
  * Gets log information from WebUI.
  */
@@ -177,4 +194,7 @@
 
   setRefresh();
   requestLog();
+  // <if expr="chromeos_ash">
+  updateOsLink();
+  // </if>
 });
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog.ts b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog.ts
index 8a3bc30..b7917c1 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog.ts
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog.ts
@@ -41,7 +41,7 @@
   NOTIFICATION_ACCESS_PROHIBITED = 6,
 }
 
-interface SettingsMultideviceNotificationAccessSetupDialogElement {
+export interface SettingsMultideviceNotificationAccessSetupDialogElement {
   $: {
     dialog: CrDialogElement,
   };
@@ -50,7 +50,7 @@
 const SettingsMultideviceNotificationAccessSetupDialogElementBase =
     WebUiListenerMixin(I18nMixin(PolymerElement));
 
-class SettingsMultideviceNotificationAccessSetupDialogElement extends
+export class SettingsMultideviceNotificationAccessSetupDialogElement extends
     SettingsMultideviceNotificationAccessSetupDialogElementBase {
   static get is() {
     return 'settings-multidevice-notification-access-setup-dialog' as const;
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html
index 5f7142a..913e9d3 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html
@@ -40,6 +40,8 @@
 
   .text-row {
     min-height: var(--cr-section-min-height);
+    padding-bottom: 8px;
+    padding-top: 14px;
   }
 
   cr-input {
@@ -47,6 +49,10 @@
     width: 80px;
   }
 
+  cr-expand-button {
+    margin-top: 20px;
+  }
+
   #developerOptionsExpandButton {
     min-height: var(--cr-section-min-height);
     padding-inline-end: var(--cr-section-padding);
@@ -68,30 +74,30 @@
   </settings-toggle-button>
   <settings-toggle-button
       id="autoReadToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.auto_read}}"
       label="$i18n{chromeVoxAutoRead}">
   </settings-toggle-button>
   <settings-toggle-button
       id="speakTextUnderMouseToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.speak_text_under_mouse}}"
       label="$i18n{chromeVoxSpeakTextUnderMouse}">
   </settings-toggle-button>
   <settings-toggle-button
       id="announceRichTextAttributesToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.announce_rich_text_attributes}}"
       label="$i18n{chromeVoxAnnounceRichTextAttributes}">
   </settings-toggle-button>
   <settings-toggle-button
       id="usePitchChangesToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.use_pitch_changes}}"
       label="$i18n{chromeVoxUsePitchChanges}"
       on-change="onUsePitchChangesToggled_">
   </settings-toggle-button>
-  <div class="settings-box continuation">
+  <div class="settings-box">
     <div class="start settings-box-text" aria-hidden="true">
       $i18n{chromeVoxCapitalStrategy}
     </div>
@@ -101,7 +107,7 @@
         menu-options="[[capitalStrategyOptions_]]">
     </settings-dropdown-menu>
   </div>
-  <div class="settings-box continuation">
+  <div class="settings-box">
     <div class="start settings-box-text" aria-hidden="true">
       $i18n{chromeVoxNumberReadingStyle}
     </div>
@@ -111,7 +117,7 @@
         menu-options="[[numberReadingStyleOptions_]]">
     </settings-dropdown-menu>
   </div>
-  <div class="settings-box continuation">
+  <div class="settings-box">
     <div class="start settings-box-text" aria-hidden="true">
       $i18n{chromeVoxPunctuationEcho}
     </div>
@@ -123,17 +129,17 @@
   </div>
   <settings-toggle-button
       id="announceDownloadNotificationsToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.announce_download_notifications}}"
       label="$i18n{chromeVoxAnnounceDownloadNotifications}">
   </settings-toggle-button>
   <settings-toggle-button
       id="smartStickyModeToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.smart_sticky_mode}}"
       label="$i18n{chromeVoxSmartStickyMode}">
   </settings-toggle-button>
-  <div class="settings-box continuation">
+  <div class="settings-box">
     <div class="start settings-box-text" aria-hidden="true">
       $i18n{chromeVoxAudioStrategy}
     </div>
@@ -158,7 +164,7 @@
   </div>
   <settings-toggle-button
       id="languageSwitchingToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.language_switching}}"
       label="$i18n{chromeVoxLanguageSwitching}">
   </settings-toggle-button>
@@ -183,36 +189,38 @@
   </div>
   <settings-toggle-button
       id="brailleWordWrapToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.braille_word_wrap}}"
       label="$i18n{chromeVoxBrailleWordWrap}">
   </settings-toggle-button>
   <settings-toggle-button
       id="menuBrailleCommandsToggle"
-      class="settings-box continuation"
+      class="settings-box"
       pref="{{prefs.settings.a11y.chromevox.menu_braille_commands}}"
       label="$i18n{chromeVoxMenuBrailleCommands}">
   </settings-toggle-button>
-  <bluetooth-braille-display-ui></bluetooth-braille-display-ui>
-  <div class="text-row">
+  <div class="hr">
+    <bluetooth-braille-display-ui></bluetooth-braille-display-ui>
+  </div>
+  <div class="text-row hr">
     <div>$i18n{chromeVoxVirtualBrailleDisplay}</div>
     <div class="secondary">$i18n{chromeVoxVirtualBrailleDisplayDetails}</div>
   </div>
-  <div class="settings-box continuation indented">
+  <div class="settings-box indented continuation">
     $i18n{chromeVoxVirtualBrailleDisplayRows}
     <cr-input id="virtualBrailleDisplayRowsInput" type="number" min="1" max="99"
         value="[[prefs.settings.a11y.chromevox.virtual_braille_rows.value]]"
         on-input="onBrailleRowsInput_" on-focusout="onBrailleRowsFocusout_">
     </cr-input>
   </div>
-  <div class="settings-box continuation indented">
+  <div class="settings-box indented">
     $i18n{chromeVoxVirtualBrailleDisplayColumns}
     <cr-input id="virtualBrailleDisplayColumnsInput" type="number" min="1" max="99"
         value="[[prefs.settings.a11y.chromevox.virtual_braille_columns.value]]"
         on-input="onBrailleColumnsInput_" on-focusout="onBrailleColumnsFocusout_">
     </cr-input>
   </div>
-  <div class="settings-box continuation indented">
+  <div class="settings-box indented">
     <div class="start settings-box-text" aria-hidden="true">
       $i18n{chromeVoxVirtualBrailleDisplayStyleLabel}
     </div>
@@ -229,7 +237,7 @@
 </cr-expand-button>
 <iron-collapse opened="[[developerOptionsExpanded_]]">
   <div class="sub-item">
-    <cr-link-row class="settings-box"
+    <cr-link-row class="settings-box continuation"
         label="$i18n{chromeVoxEventLogLink}"
         sub-label="$i18n{chromeVoxEventLogDescription}"
         on-click="onEventLogClick_"
@@ -238,25 +246,25 @@
     </cr-link-row>
     <settings-toggle-button
         id="enableSpeechLoggingToggle"
-        class="settings-box continuation"
+        class="settings-box"
         pref="{{prefs.settings.a11y.chromevox.enable_speech_logging}}"
         label="$i18n{chromeVoxEnableSpeechLogging}">
     </settings-toggle-button>
     <settings-toggle-button
         id="enableEarconLoggingToggle"
-        class="settings-box continuation"
+        class="settings-box"
         pref="{{prefs.settings.a11y.chromevox.enable_earcon_logging}}"
         label="$i18n{chromeVoxEnableEarconLogging}">
     </settings-toggle-button>
     <settings-toggle-button
         id="enableBrailleLoggingToggle"
-        class="settings-box continuation"
+        class="settings-box"
         pref="{{prefs.settings.a11y.chromevox.enable_braille_logging}}"
         label="$i18n{chromeVoxEnableBrailleLogging}">
     </settings-toggle-button>
     <settings-toggle-button
         id="enableEventStreamLoggingToggle"
-        class="settings-box continuation"
+        class="settings-box"
         pref="{{prefs.settings.a11y.chromevox.enable_event_stream_logging}}"
         label="$i18n{chromeVoxEnableEventStreamLogging}">
     </settings-toggle-button>
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.ts b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.ts
index 1aa03fb0..b2f7ec4 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.ts
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.ts
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {App} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
+import {App, TriState} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
 import {PermissionTypeIndex} from 'chrome://resources/cr_components/app_management/permission_constants.js';
-import {isPermissionEnabled} from 'chrome://resources/cr_components/app_management/permission_util.js';
-import {getPermission} from 'chrome://resources/cr_components/app_management/util.js';
+import {getPermission, getPermissionValueAsTriState} from 'chrome://resources/cr_components/app_management/util.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -82,15 +81,21 @@
     const permission = getPermission(app, permissionType);
     assert(permission);
 
-    const value = isPermissionEnabled(permission.value);
+    const value = getPermissionValueAsTriState(app, permissionType);
 
-    if (value && permission.details) {
+    if (value === TriState.kAllow && permission.details) {
       return this.i18n(
           'appManagementPermissionAllowedWithDetails', permission.details);
     }
 
-    return value ? this.i18n('appManagementPermissionAllowed') :
-                   this.i18n('appManagementPermissionDenied');
+    switch (value) {
+      case TriState.kAllow:
+        return this.i18n('appManagementPermissionAllowed');
+      case TriState.kBlock:
+        return this.i18n('appManagementPermissionDenied');
+      case TriState.kAsk:
+        return this.i18n('appManagementPermissionAsk');
+    }
   }
 }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.ts b/chrome/browser/resources/settings/chromeos/os_settings.ts
index 1a5dba1..ec3e6bf 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings.ts
@@ -141,7 +141,7 @@
 export * as settingMojom from './mojom-webui/setting.mojom-webui.js';
 export {AndroidSmsInfo, MultiDeviceBrowserProxy, MultiDeviceBrowserProxyImpl} from './multidevice_page/multidevice_browser_proxy.js';
 export {MultiDeviceFeature, MultiDeviceFeatureState, MultiDevicePageContentData, MultiDeviceSettingsMode, PhoneHubFeatureAccessProhibitedReason, PhoneHubFeatureAccessStatus, PhoneHubPermissionsSetupAction, PhoneHubPermissionsSetupFeatureCombination, PhoneHubPermissionsSetupFlowScreens, PhoneHubPermissionsSetupMode} from './multidevice_page/multidevice_constants.js';
-export {NotificationAccessSetupOperationStatus} from './multidevice_page/multidevice_notification_access_setup_dialog.js';
+export {NotificationAccessSetupOperationStatus, SettingsMultideviceNotificationAccessSetupDialogElement} from './multidevice_page/multidevice_notification_access_setup_dialog.js';
 export {PermissionsSetupStatus, SetupFlowStatus} from './multidevice_page/multidevice_permissions_setup_dialog.js';
 export {Account, NearbyAccountManagerBrowserProxy, NearbyAccountManagerBrowserProxyImpl} from './nearby_share_page/nearby_account_manager_browser_proxy.js';
 export {NearbyShareConfirmPageElement} from './nearby_share_page/nearby_share_confirm_page.js';
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
index d65f55b7..424b694 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
@@ -25,6 +25,12 @@
     width: calc(100% - 16px);
   }
 
+  :host-context([dir=rtl]) cr-toast {
+    left: auto;
+    right: 50%;
+    transform: translate(50%, 0);
+  }
+
   cr-toolbar-search-field {
     flex-shrink: 0;
     margin: 14px;
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
index afa5e5d..d7b5e74b 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -242,7 +242,6 @@
       setTimeout(() => this.bookmarksApi_.showUi(), 0);
     });
     this.focusOutlineManager_ = FocusOutlineManager.forDocument(document);
-    this.focusOutlineManager_.visible = false;
     this.bookmarksService_.startListening();
     this.shoppingListApi_.getAllPriceTrackedBookmarkProductInfo().then(res => {
       res.productInfos.forEach(
@@ -350,6 +349,7 @@
       getAnnouncerInstance().announce(loadTimeData.getStringF(
           'bookmarkReordered', getBookmarkName(bookmark)));
     } else if (shouldUpdateUIAdded) {
+      const scrollIndex = this.$.shownBookmarksIronList.firstVisibleIndex;
       this.shownBookmarks_.unshift(...bookmarksToShow);
       this.bookmarksService_.sortBookmarks(
           this.shownBookmarks_, this.activeSortIndex_);
@@ -357,7 +357,9 @@
       getAnnouncerInstance().announce(loadTimeData.getStringF(
           'bookmarkMoved', getBookmarkName(bookmark),
           getBookmarkName(newParent)));
+      this.$.shownBookmarksIronList.scrollToIndex(scrollIndex);
     } else if (shouldUpdateUIRemoved) {
+      const scrollIndex = this.$.shownBookmarksIronList.firstVisibleIndex;
       this.splice('shownBookmarks_', this.visibleIndex_(bookmark.id), 1);
       getAnnouncerInstance().announce(loadTimeData.getStringF(
           'bookmarkMoved', getBookmarkName(bookmark),
@@ -368,10 +370,12 @@
       if (visibleIndex > -1) {
         this.notifyPath(`shownBookmarks_.${visibleIndex}.children`);
       }
+      this.$.shownBookmarksIronList.scrollToIndex(scrollIndex);
     }
   }
 
   onBookmarkRemoved(bookmark: chrome.bookmarks.BookmarkTreeNode) {
+    const scrollIndex = this.$.shownBookmarksIronList.firstVisibleIndex;
     const visibleIndex = this.visibleIndex_(bookmark.id);
     if (visibleIndex > -1) {
       this.splice('shownBookmarks_', visibleIndex, 1);
@@ -380,6 +384,9 @@
     }
     this.set(`trackedProductInfos_.${bookmark.id}`, null);
     this.availableProductInfos_.delete(bookmark.id);
+    if (visibleIndex > -1) {
+      this.$.shownBookmarksIronList.scrollToIndex(scrollIndex);
+    }
   }
 
   isPriceTracked(bookmark: chrome.bookmarks.BookmarkTreeNode): boolean {
@@ -441,7 +448,10 @@
         Object.keys(this.trackedProductInfos_)
             .some(key => this.get(`trackedProductInfos_.${key}`) !== null);
     if (showLabel) {
-      return [{
+      // Reuse the current price tracking label if one exists, to maintain its
+      // active state.
+      const currentLabel = this.get('labels_.0');
+      return [currentLabel ? currentLabel : {
         label: loadTimeData.getString('priceTrackingLabel'),
         icon: 'bookmarks:price-tracking',
         active: false,
diff --git a/chrome/browser/resources/side_panel/customize_chrome/categories.html b/chrome/browser/resources/side_panel/customize_chrome/categories.html
index 9b88733..74722f5 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/categories.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/categories.html
@@ -36,6 +36,22 @@
     }
   }
 
+  :host-context([chrome-refresh-2023]) .image-container {
+    background-color: var(--color-side-panel-customize-chrome-theme-background);
+  }
+
+  :host-context([chrome-refresh-2023]) #uploadImageTile .image-container {
+    --cr-icon-color: var(
+        --color-side-panel-customize-chrome-custom-option-foreground);
+    background-color: var(
+        --color-side-panel-customize-chrome-custom-option-background);
+  }
+
+  :host-context([chrome-refresh-2023]) #chromeWebStoreTile .image-container {
+    border: solid 1px
+        var(--color-side-panel-customize-chrome-web-store-option-border);
+  }
+
   .image-container img,
   .image-container div,
   .image-container svg {
diff --git a/chrome/browser/resources/side_panel/customize_chrome/check_mark_wrapper.html b/chrome/browser/resources/side_panel/customize_chrome/check_mark_wrapper.html
index f9b6ae8b..327c5953 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/check_mark_wrapper.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/check_mark_wrapper.html
@@ -1,6 +1,7 @@
 <style>
   :host {
-    --customize-chrome-check-mark-wrapper-color: var(--google-blue-600);
+    --customize-chrome-check-mark-wrapper-background: var(--google-blue-600);
+    --customize-chrome-check-mark-wrapper-color: white;
     --customize-chrome-check-mark-wrapper-end: 0px;
     --customize-chrome-check-mark-wrapper-size: 16px;
     --customize-chrome-check-mark-wrapper-top: 0px;
@@ -10,10 +11,18 @@
 
   @media (prefers-color-scheme: dark) {
     :host {
-      --customize-chrome-check-mark-wrapper-color: var(--google-blue-300);
+      --customize-chrome-check-mark-wrapper-background: var(--google-blue-300);
+      --customize-chrome-check-mark-wrapper-color: var(--google-grey-900);
     }
   }
 
+  :host-context([chrome-refresh-2023]):host {
+    --customize-chrome-check-mark-wrapper-background: var(
+        --color-side-panel-customize-chrome-theme-checkmark-background);
+    --customize-chrome-check-mark-wrapper-color: var(
+        --color-side-panel-customize-chrome-theme-checkmark-foreground);
+  }
+
   svg {
     display: block;
     height: var(--customize-chrome-check-mark-wrapper-size);
@@ -35,21 +44,15 @@
   }
 
   #background {
-    fill: var(--customize-chrome-check-mark-wrapper-color);
+    fill: var(--customize-chrome-check-mark-wrapper-background);
   }
 
   #checkMark {
-    fill: white;
-  }
-
-  @media (prefers-color-scheme: dark) {
-    #checkMark {
-      fill: var(--google-grey-900);
-    }
+    fill: var(--customize-chrome-check-mark-wrapper-color);
   }
 
   :host([checked]) ::slotted(*) {
-    border: 2px solid var(--customize-chrome-check-mark-wrapper-color);
+    border: 2px solid var(--customize-chrome-check-mark-wrapper-background);
   }
 </style>
 <svg id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/color.html b/chrome/browser/resources/side_panel/customize_chrome/color.html
index 5202188..6e2fca14 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/color.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/color.html
@@ -29,6 +29,13 @@
     --customize-chrome-check-mark-wrapper-top: var(--customize-chrome-color-check-mark-top);
   }
 
+  :host-context([chrome-refresh-2023]) customize-chrome-check-mark-wrapper {
+    --customize-chrome-check-mark-wrapper-background: var(
+        --color-side-panel-customize-chrome-color-picker-checkmark-background);
+    --customize-chrome-check-mark-wrapper-color: var(
+        --color-side-panel-customize-chrome-color-picker-checkmark-foreground);
+  }
+
   #background {
     fill: var(--customize-chrome-color-background-color);
   }
diff --git a/chrome/browser/resources/side_panel/customize_chrome/colors.html b/chrome/browser/resources/side_panel/customize_chrome/colors.html
index ef1cfe0..63e9d6e 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/colors.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/colors.html
@@ -18,6 +18,11 @@
     position: relative;
   }
 
+  :host-context([chrome-refresh-2023]) #customColor {
+    background: var(
+        --color-side-panel-customize-chrome-custom-option-background);
+  }
+
   /* colorPicker is placed on top of the theme icon to work around
      https://crbug.com/1162053. */
   #colorPicker {
@@ -46,12 +51,18 @@
     width: 20px;
   }
 
+  :host-context([chrome-refresh-2023]) #colorPickerIcon {
+    background-color: var(
+        --color-side-panel-customize-chrome-custom-option-foreground);
+  }
+
   managed-dialog {
     --cr-dialog-width: min(calc(100% - 32px), 512px);
   }
 
   :host-context([chrome-refresh-2023]) customize-chrome-color {
-    background-color: lightgrey;
+    background-color: var(
+        --color-side-panel-customize-chrome-color-picker-option-background);
     border-radius: 12px;
   }
 </style>
diff --git a/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc b/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc
index 6a77326..0da22d6f 100644
--- a/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc
+++ b/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc
@@ -120,7 +120,7 @@
 
   AccountReconcilor* account_reconcilor =
       AccountReconcilorFactory::GetForProfile(profile);
-  base::OnceClosure reauth_completed_closure =
+  auto reauth_completed_closure =
       base::BindOnce(&SigninUiDelegateImplLacros::OnReauthComplete,
                      // base::Unretained() is fine because
                      // SigninUiDelegateImplLacros is a singleton.
@@ -169,7 +169,13 @@
     const base::FilePath& profile_path,
     signin_metrics::AccessPoint access_point,
     signin_metrics::PromoAction promo_action,
-    const std::string& email) {
+    const std::string& email,
+    const account_manager::AccountUpsertionResult& result) {
+  if (result.status() !=
+      account_manager::AccountUpsertionResult::Status::kSuccess) {
+    return;
+  }
+
   Profile* profile =
       g_browser_process->profile_manager()->GetProfileByPath(profile_path);
   if (!profile)
diff --git a/chrome/browser/signin/signin_ui_delegate_impl_lacros.h b/chrome/browser/signin/signin_ui_delegate_impl_lacros.h
index 0e41fbb..efc6aee 100644
--- a/chrome/browser/signin/signin_ui_delegate_impl_lacros.h
+++ b/chrome/browser/signin/signin_ui_delegate_impl_lacros.h
@@ -56,7 +56,8 @@
       const base::FilePath& profile_path,
       signin_metrics::AccessPoint access_point,
       signin_metrics::PromoAction promo_action,
-      const std::string& email);
+      const std::string& email,
+      const account_manager::AccountUpsertionResult& result);
 };
 
 }  // namespace signin_ui_util
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index cfd07ee2..62e6362 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -220,7 +220,7 @@
   ::GetAccountManagerFacade(profile->GetPath().value())
       ->ShowReauthAccountDialog(account_manager::AccountManagerFacade::
                                     AccountAdditionSource::kContentAreaReauth,
-                                email, base::OnceClosure());
+                                email, base::DoNothing());
 #elif BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // Pass `false` for `enable_sync`, as this function is not expected to start a
   // sync setup flow after the reauth.
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc
index ca333ad4..3bfbc74 100644
--- a/chrome/browser/storage_access_api/api_browsertest.cc
+++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -28,6 +28,7 @@
 #include "components/content_settings/core/common/features.h"
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
+#include "components/permissions/features.h"
 #include "components/permissions/permission_request_manager.h"
 #include "components/permissions/request_type.h"
 #include "components/permissions/test/mock_permission_prompt_factory.h"
@@ -1148,42 +1149,6 @@
             std::make_tuple("", "None", "cross-site=b.test"));
 }
 
-// Validate that in a A(B) frame tree, the embedded B iframe can obtain cookie
-// access if requested and got accepted.
-IN_PROC_BROWSER_TEST_F(StorageAccessAPIBrowserTest,
-                       EmbeddedCrossSiteCookieAccess_Accept) {
-  SetBlockThirdPartyCookies(true);
-
-  NavigateToPageWithFrame(kHostA);
-  NavigateFrameTo(EchoCookiesURL(kHostB));
-
-  prompt_factory()->set_response_type(
-      permissions::PermissionRequestManager::ACCEPT_ALL);
-
-  EXPECT_TRUE(storage::test::RequestAndCheckStorageAccessForFrame(GetFrame()));
-  EXPECT_EQ(1, prompt_factory()->TotalRequestCount());
-  EXPECT_EQ(1, prompt_factory()->RequestTypeSeen(
-                   permissions::RequestType::kStorageAccess));
-}
-
-// Validate that in a A(B) frame tree, the embedded B iframe can not obtain
-// cookie access if requested and got denied.
-IN_PROC_BROWSER_TEST_F(StorageAccessAPIBrowserTest,
-                       EmbeddedCrossSiteCookieAccess_Deny) {
-  SetBlockThirdPartyCookies(true);
-
-  NavigateToPageWithFrame(kHostA);
-  NavigateFrameTo(EchoCookiesURL(kHostB));
-
-  prompt_factory()->set_response_type(
-      permissions::PermissionRequestManager::DENY_ALL);
-
-  EXPECT_FALSE(storage::test::RequestAndCheckStorageAccessForFrame(GetFrame()));
-  EXPECT_EQ(1, prompt_factory()->TotalRequestCount());
-  EXPECT_EQ(1, prompt_factory()->RequestTypeSeen(
-                   permissions::RequestType::kStorageAccess));
-}
-
 // Validate that in a A(A) frame tree, the inner A iframe can obtain cookie
 // access by default.
 IN_PROC_BROWSER_TEST_F(StorageAccessAPIBrowserTest,
@@ -1268,6 +1233,82 @@
             CookieBundle("cross-site=a.test"));
 }
 
+class StorageAccessAPIPromptBrowserTest
+    : public StorageAccessAPIBaseBrowserTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  StorageAccessAPIPromptBrowserTest()
+      : StorageAccessAPIBaseBrowserTest(
+            /*is_storage_partitioned=*/false),
+        is_storage_access_new_UI_(GetParam()) {}
+
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
+    std::vector<base::test::FeatureRefAndParams> enabled =
+        StorageAccessAPIBaseBrowserTest::GetEnabledFeatures();
+
+    if (is_storage_access_new_UI_) {
+      enabled.push_back(
+          {permissions::features::kPermissionStorageAccessAPI, {}});
+    }
+
+    return enabled;
+  }
+
+  std::vector<base::test::FeatureRef> GetDisabledFeatures() override {
+    std::vector<base::test::FeatureRef> disabled =
+        StorageAccessAPIBaseBrowserTest::GetDisabledFeatures();
+
+    if (!is_storage_access_new_UI_) {
+      disabled.push_back(permissions::features::kPermissionStorageAccessAPI);
+    }
+
+    return disabled;
+  }
+
+ private:
+  const bool is_storage_access_new_UI_;
+};
+
+// Validate that in a A(B) frame tree, the embedded B iframe can obtain cookie
+// access if requested and got accepted.
+IN_PROC_BROWSER_TEST_P(StorageAccessAPIPromptBrowserTest,
+                       EmbeddedCrossSiteCookieAccess_Accept) {
+  SetBlockThirdPartyCookies(true);
+
+  NavigateToPageWithFrame(kHostA);
+  NavigateFrameTo(EchoCookiesURL(kHostB));
+
+  prompt_factory()->set_response_type(
+      permissions::PermissionRequestManager::ACCEPT_ALL);
+
+  EXPECT_TRUE(storage::test::RequestAndCheckStorageAccessForFrame(GetFrame()));
+  EXPECT_EQ(1, prompt_factory()->TotalRequestCount());
+  EXPECT_EQ(1, prompt_factory()->RequestTypeSeen(
+                   permissions::RequestType::kStorageAccess));
+}
+
+// Validate that in a A(B) frame tree, the embedded B iframe can not obtain
+// cookie access if requested and got denied.
+IN_PROC_BROWSER_TEST_P(StorageAccessAPIPromptBrowserTest,
+                       EmbeddedCrossSiteCookieAccess_Deny) {
+  SetBlockThirdPartyCookies(true);
+
+  NavigateToPageWithFrame(kHostA);
+  NavigateFrameTo(EchoCookiesURL(kHostB));
+
+  prompt_factory()->set_response_type(
+      permissions::PermissionRequestManager::DENY_ALL);
+
+  EXPECT_FALSE(storage::test::RequestAndCheckStorageAccessForFrame(GetFrame()));
+  EXPECT_EQ(1, prompt_factory()->TotalRequestCount());
+  EXPECT_EQ(1, prompt_factory()->RequestTypeSeen(
+                   permissions::RequestType::kStorageAccess));
+}
+
+INSTANTIATE_TEST_SUITE_P(/*no prefix*/,
+                         StorageAccessAPIPromptBrowserTest,
+                         testing::Bool());
+
 class StorageAccessAPIStorageBrowserTest
     : public StorageAccessAPIBaseBrowserTest,
       public testing::WithParamInterface<std::tuple<TestType, bool>> {
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
index 9efe5e4..9f97aac 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "chrome/browser/supervised_user/supervised_user_navigation_throttle.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/tab_contents/tab_util.h"
@@ -25,6 +24,7 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/sessions/content/content_serialized_navigation_builder.h"
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
 #include "components/supervised_user/core/browser/web_content_handler.h"
@@ -321,10 +321,10 @@
   auto web_content_handler = CreateWebContentHandler(
       web_contents(), url, profile, frame_id, navigation_id);
   CHECK(web_content_handler);
-  std::unique_ptr<SupervisedUserInterstitial> interstitial =
-      SupervisedUserInterstitial::Create(std::move(web_content_handler),
-                                         *supervised_user_service_, url,
-                                         reason);
+  std::unique_ptr<supervised_user::SupervisedUserInterstitial> interstitial =
+      supervised_user::SupervisedUserInterstitial::Create(
+          std::move(web_content_handler), *supervised_user_service_, url,
+          reason);
   supervised_user_interstitials_[frame_id] = std::move(interstitial);
 
   bool already_requested = base::Contains(requested_hosts_, url.host());
@@ -377,7 +377,7 @@
     return;
   }
 
-  SupervisedUserInterstitial* interstitial =
+  supervised_user::SupervisedUserInterstitial* interstitial =
       supervised_user_interstitials_[id].get();
   interstitial->RequestUrlAccessRemote(
       base::BindOnce(&SupervisedUserNavigationObserver::RequestCreated,
@@ -396,7 +396,7 @@
     return;
   }
 
-  SupervisedUserInterstitial* interstitial =
+  supervised_user::SupervisedUserInterstitial* interstitial =
       supervised_user_interstitials_[id].get();
   interstitial->RequestUrlAccessLocal(std::move(callback));
 }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_observer.h b/chrome/browser/supervised_user/supervised_user_navigation_observer.h
index 6198dff..fc04aa9 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_observer.h
+++ b/chrome/browser/supervised_user/supervised_user_navigation_observer.h
@@ -24,9 +24,8 @@
 
 namespace supervised_user {
 class SupervisedUserService;
-}  // namespace supervised_user
-
 class SupervisedUserInterstitial;
+}  // namespace supervised_user
 
 namespace content {
 class NavigationHandle;
@@ -96,7 +95,8 @@
   // frame.
   void OnInterstitialDone(int frame_id);
 
-  const std::map<int, std::unique_ptr<SupervisedUserInterstitial>>&
+  const std::map<int,
+                 std::unique_ptr<supervised_user::SupervisedUserInterstitial>>&
   interstitials_for_test() const {
     return supervised_user_interstitials_;
   }
@@ -160,7 +160,7 @@
 
   // Keeps track of the blocked frames. It maps the frame's globally unique
   // id to its corresponding |SupervisedUserInterstitial| instance.
-  std::map<int, std::unique_ptr<SupervisedUserInterstitial>>
+  std::map<int, std::unique_ptr<supervised_user::SupervisedUserInterstitial>>
       supervised_user_interstitials_;
 
   std::set<std::string> requested_hosts_;
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
index 1817afba..f775249 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
@@ -11,11 +11,12 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "base/task/single_thread_task_runner.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
 #include "content/public/browser/navigation_handle.h"
@@ -277,10 +278,10 @@
       Profile* profile = Profile::FromBrowserContext(
           navigation_handle()->GetWebContents()->GetBrowserContext());
       std::string interstitial_html =
-          SupervisedUserInterstitial::GetHTMLContents(
+          supervised_user::SupervisedUserInterstitial::GetHTMLContents(
               SupervisedUserServiceFactory::GetForProfile(profile),
-              profile->GetPrefs(), reason_, already_sent_request,
-              is_main_frame);
+              profile->GetPrefs(), reason_, already_sent_request, is_main_frame,
+              g_browser_process->GetApplicationLocale());
       CancelDeferredNavigation(content::NavigationThrottle::ThrottleCheckResult(
           CANCEL, net::ERR_BLOCKED_BY_CLIENT, interstitial_html));
     }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
index c8bb6c7..b5ba7e6b 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
 #include "chrome/browser/supervised_user/permission_request_creator_mock.h"
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
@@ -32,6 +31,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_settings_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
@@ -675,11 +675,17 @@
   EXPECT_FALSE(IsInterstitialBeingShownInFrame(blocked_frame_id));
 
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialCommandHistogramName,
-      SupervisedUserInterstitial::Commands::REMOTE_ACCESS_REQUEST, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialCommandHistogramName,
+      supervised_user::SupervisedUserInterstitial::Commands::
+          REMOTE_ACCESS_REQUEST,
+      1);
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialPermissionSourceHistogramName,
-      SupervisedUserInterstitial::RequestPermissionSource::SUB_FRAME, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialPermissionSourceHistogramName,
+      supervised_user::SupervisedUserInterstitial::RequestPermissionSource::
+          SUB_FRAME,
+      1);
 }
 
 IN_PROC_BROWSER_TEST_P(SupervisedUserIframeFilterTest, BlockMultipleSubFrames) {
@@ -1048,11 +1054,17 @@
   CheckPreferredApprovalButton(blocked_frame);
 
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialCommandHistogramName,
-      SupervisedUserInterstitial::Commands::LOCAL_ACCESS_REQUEST, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialCommandHistogramName,
+      supervised_user::SupervisedUserInterstitial::Commands::
+          LOCAL_ACCESS_REQUEST,
+      1);
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialPermissionSourceHistogramName,
-      SupervisedUserInterstitial::RequestPermissionSource::MAIN_FRAME, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialPermissionSourceHistogramName,
+      supervised_user::SupervisedUserInterstitial::RequestPermissionSource::
+          MAIN_FRAME,
+      1);
 }
 
 IN_PROC_BROWSER_TEST_P(ChromeOSLocalWebApprovalsTest,
@@ -1090,11 +1102,17 @@
   CheckPreferredApprovalButton(blocked_frame);
 
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialCommandHistogramName,
-      SupervisedUserInterstitial::Commands::LOCAL_ACCESS_REQUEST, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialCommandHistogramName,
+      supervised_user::SupervisedUserInterstitial::Commands::
+          LOCAL_ACCESS_REQUEST,
+      1);
   histogram_tester.ExpectUniqueSample(
-      SupervisedUserInterstitial::kInterstitialPermissionSourceHistogramName,
-      SupervisedUserInterstitial::RequestPermissionSource::SUB_FRAME, 1);
+      supervised_user::SupervisedUserInterstitial::
+          kInterstitialPermissionSourceHistogramName,
+      supervised_user::SupervisedUserInterstitial::RequestPermissionSource::
+          SUB_FRAME,
+      1);
 }
 
 IN_PROC_BROWSER_TEST_P(ChromeOSLocalWebApprovalsTest,
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter_browsertest.cc b/chrome/browser/supervised_user/supervised_user_url_filter_browsertest.cc
index e154894..7a5f0a2c 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_url_filter_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
@@ -33,6 +32,7 @@
 #include "components/infobars/core/infobar.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_settings_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
diff --git a/chrome/browser/sync/bookmark_sync_service_factory.cc b/chrome/browser/sync/bookmark_sync_service_factory.cc
index 3a0a187..548fb4b6 100644
--- a/chrome/browser/sync/bookmark_sync_service_factory.cc
+++ b/chrome/browser/sync/bookmark_sync_service_factory.cc
@@ -38,5 +38,6 @@
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   return new sync_bookmarks::BookmarkSyncService(
-      BookmarkUndoServiceFactory::GetForProfileIfExists(profile));
+      BookmarkUndoServiceFactory::GetForProfileIfExists(profile),
+      /*wipe_model_on_stopping_sync_with_clear_data=*/false);
 }
diff --git a/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc b/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc
index 00698040..674346b 100644
--- a/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc
+++ b/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc
@@ -172,7 +172,7 @@
   kLanguageRemapSearchKeyTo = 100123,
   kMultiProfileNeverShowIntro = 100124,
   kMultiProfileWarningShowDismissed = 100125,
-  kOfficeSetupComplete = 100126,
+  // kOfficeSetupComplete = 100126, // deprecated
   kResolveTimezoneByGeolocationMethod = 100127,
   kResolveTimezoneByGeolocationMigratedToMethod = 100128,
   kShelfDefaultPinLayoutRolls = 100129,
@@ -645,8 +645,6 @@
         {prefs::kMultiProfileWarningShowDismissed,
          {syncable_prefs_ids::kMultiProfileWarningShowDismissed,
           syncer::OS_PREFERENCES}},
-        {prefs::kOfficeSetupComplete,
-         {syncable_prefs_ids::kOfficeSetupComplete, syncer::OS_PREFERENCES}},
         {prefs::kResolveTimezoneByGeolocationMethod,
          {syncable_prefs_ids::kResolveTimezoneByGeolocationMethod,
           syncer::OS_PREFERENCES}},
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index 59c6862..db8fa22 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -198,11 +198,6 @@
     }
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     case STATUS_CASE_SYNC_RESET_FROM_DASHBOARD: {
-      // Note: On desktop, if there is a primary account, then
-      // DISABLE_REASON_USER_CHOICE can only occur if Sync was reset from the
-      // dashboard, and the UI treats it as such.
-      service->SetDisableReasons(
-          {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
       service->SetSyncFeatureDisabledViaDashboard(true);
       service->SetFirstSetupComplete(true);
       service->SetTransportState(syncer::SyncService::TransportState::ACTIVE);
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index 69c7bef..0dbac793 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -56,17 +56,29 @@
   return user_data_path.AppendASCII("SyncTestTmpCacheGuid");
 }
 
-class SyncDisabledByUserChecker : public SingleClientStatusChangeChecker {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class SyncDisabledViaDashboardChecker : public SingleClientStatusChangeChecker {
  public:
-  explicit SyncDisabledByUserChecker(syncer::SyncServiceImpl* service)
+  explicit SyncDisabledViaDashboardChecker(syncer::SyncServiceImpl* service)
       : SingleClientStatusChangeChecker(service) {}
 
   bool IsExitConditionSatisfied(std::ostream* os) override {
-    *os << "Waiting for sync disabled by user";
-    return service()->HasDisableReason(
-        syncer::SyncService::DISABLE_REASON_USER_CHOICE);
+    *os << "Waiting for sync disabled by dashboard";
+    return service()->IsSyncFeatureDisabledViaDashboard();
   }
 };
+#else
+class SyncConsentDisabledChecker : public SingleClientStatusChangeChecker {
+ public:
+  explicit SyncConsentDisabledChecker(syncer::SyncServiceImpl* service)
+      : SingleClientStatusChangeChecker(service) {}
+
+  bool IsExitConditionSatisfied(std::ostream* os) override {
+    *os << "Waiting for sync consent being disabled";
+    return !service()->HasSyncConsent();
+  }
+};
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class SingleClientStandaloneTransportSyncTest : public SyncTest {
  public:
@@ -163,16 +175,12 @@
   // Trigger a "Reset Sync" from the dashboard and wait for it to apply. This
   // involves clearing the server data so that the birthday gets incremented.
   GetFakeServer()->ClearServerData();
-  EXPECT_TRUE(SyncDisabledByUserChecker(GetSyncService(0)).Wait());
-
-  // On all platforms, Sync-the-feature should now be disabled.
-  EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
-  EXPECT_TRUE(GetSyncService(0)->HasDisableReason(
-      syncer::SyncService::DISABLE_REASON_USER_CHOICE));
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // On Ash, the primary account should remain, and Sync should start up
-  // again in standalone transport mode.
+  // again in standalone transport mode, but report this specific case via
+  // IsSyncFeatureDisabledViaDashboard().
+  EXPECT_TRUE(SyncDisabledViaDashboardChecker(GetSyncService(0)).Wait());
   EXPECT_TRUE(GetSyncService(0)->HasSyncConsent());
   EXPECT_FALSE(GetSyncService(0)->HasDisableReason(
       syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN));
@@ -186,7 +194,7 @@
 #else
   // On platforms other than Ash, the "Reset Sync" operation should revoke
   // the Sync consent. On Mobile, "Reset Sync" also clears the primary account.
-  EXPECT_FALSE(GetSyncService(0)->HasSyncConsent());
+  EXPECT_TRUE(SyncConsentDisabledChecker(GetSyncService(0)).Wait());
   // Note: In real life, on platforms other than Ash and Mobile the account
   // would remain as an *unconsented* primary account, and so Sync would start
   // up again in standalone transport mode. However, since we haven't set up
diff --git a/chrome/browser/sync/test/integration/sync_service_impl_harness.cc b/chrome/browser/sync/test/integration/sync_service_impl_harness.cc
index 63fca23..887288f5 100644
--- a/chrome/browser/sync/test/integration/sync_service_impl_harness.cc
+++ b/chrome/browser/sync/test/integration/sync_service_impl_harness.cc
@@ -532,7 +532,8 @@
   }
 
   service()->GetUserSettings()->SetSelectedTypes(
-      true, service()->GetUserSettings()->GetRegisteredSelectableTypes());
+      /*sync_everything=*/true,
+      service()->GetUserSettings()->GetRegisteredSelectableTypes());
 
   if (AwaitSyncSetupCompletion()) {
     DVLOG(1)
@@ -553,7 +554,8 @@
     return false;
   }
 
-  service()->StopAndClear();
+  service()->GetUserSettings()->SetSelectedTypes(
+      /*sync_everything=*/false, syncer::UserSelectableTypeSet());
 
   DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
            << "datatypes on " << profile_debug_name_;
@@ -610,7 +612,5 @@
 }
 
 bool SyncServiceImplHarness::IsSyncEnabledByUser() const {
-  return service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete() &&
-         !service()->HasDisableReason(
-             SyncServiceImpl::DISABLE_REASON_USER_CHOICE);
+  return service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete();
 }
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardRenderTest.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardRenderTest.java
index 55a4fa6..faf3739 100644
--- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardRenderTest.java
+++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardRenderTest.java
@@ -81,23 +81,24 @@
 
     private static final CreditCard VISA =
             createCreditCard("Visa", "4111111111111111", "05", AutofillTestHelper.nextYear(), true,
-                    "Visa", "• • • • 1111", R.drawable.visa_card, "visa");
+                    "Visa", "• • • • 1111", R.drawable.visa_metadata_card, "visa");
     private static final CreditCard MASTER_CARD =
             createCreditCard("MasterCard", "5555555555554444", "08", AutofillTestHelper.nextYear(),
-                    true, "Mastercard", "• • • • 4444", R.drawable.mc_card, "mastercard");
-    private static final CreditCard SERVER_MASTER_CARD =
-            createCreditCard("MasterCard", "5454545454545454", "11", AutofillTestHelper.nextYear(),
-                    false, "MasterCard-GPay", "• • • • 5454", R.drawable.mc_card, "mastercard");
-    private static final CreditCard DISCOVER =
-            createCreditCard("Discover", "6011111111111117", "09", AutofillTestHelper.nextYear(),
-                    true, "Discover", "• • • • 1117", R.drawable.discover_card, "discover");
+                    true, "Mastercard", "• • • • 4444", R.drawable.mc_metadata_card, "mastercard");
+    private static final CreditCard SERVER_MASTER_CARD = createCreditCard("MasterCard",
+            "5454545454545454", "11", AutofillTestHelper.nextYear(), false, "MasterCard-GPay",
+            "• • • • 5454", R.drawable.mc_metadata_card, "mastercard");
+    private static final CreditCard DISCOVER = createCreditCard("Discover", "6011111111111117",
+            "09", AutofillTestHelper.nextYear(), true, "Discover", "• • • • 1117",
+            R.drawable.discover_metadata_card, "discover");
     private static final CreditCard AMERICAN_EXPRESS = createCreditCard("American Express",
             "378282246310005", "10", AutofillTestHelper.nextYear(), true, "American Express",
-            "• • • • 0005", R.drawable.amex_card, "american express");
+            "• • • • 0005", R.drawable.amex_metadata_card, "american express");
     private static final CreditCard MASTERCARD_VIRTUAL_CARD = createVirtualCreditCard(
             /* name= */ "MasterCard-GPay", /* number= */ "5454545454545454", /* month= */ "11",
             /* year= */ AutofillTestHelper.nextYear(), /* network= */ "Mastercard",
-            /* iconId= */ R.drawable.mc_card, /* cardNameForAutofillDisplay= */ "MasterCard-GPay",
+            /* iconId= */ R.drawable.mc_metadata_card,
+            /* cardNameForAutofillDisplay= */ "MasterCard-GPay",
             /* obfuscatedLastFourDigits= */ "• • • • 5454");
 
     private BottomSheetController mBottomSheetController;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 8e156db..9bf2722 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -859,6 +859,9 @@
       "autofill/payments/autofill_snackbar_controller_impl.h",
       "autofill/payments/autofill_snackbar_type.h",
       "autofill/payments/autofill_snackbar_view.h",
+      "autofill/payments/mandatory_reauth_bubble_controller.h",
+      "autofill/payments/mandatory_reauth_bubble_controller_impl.cc",
+      "autofill/payments/mandatory_reauth_bubble_controller_impl.h",
       "autofill/payments/offer_notification_controller_android.cc",
       "autofill/payments/offer_notification_controller_android.h",
       "autofill/payments/virtual_card_enroll_bubble_controller_impl.cc",
@@ -2806,8 +2809,6 @@
       "webui/ash/lock_screen_reauth/lock_screen_reauth_handler.h",
       "webui/ash/lock_screen_reauth/lock_screen_start_reauth_ui.cc",
       "webui/ash/lock_screen_reauth/lock_screen_start_reauth_ui.h",
-      "webui/ash/login/active_directory_password_change_screen_handler.cc",
-      "webui/ash/login/active_directory_password_change_screen_handler.h",
       "webui/ash/login/app_downloading_screen_handler.cc",
       "webui/ash/login/app_downloading_screen_handler.h",
       "webui/ash/login/app_launch_splash_screen_handler.cc",
@@ -4352,6 +4353,10 @@
       "autofill/payments/local_card_migration_dialog_state.h",
       "autofill/payments/manage_migration_ui_controller.cc",
       "autofill/payments/manage_migration_ui_controller.h",
+      "autofill/payments/mandatory_reauth_bubble_controller.h",
+      "autofill/payments/mandatory_reauth_bubble_controller_impl.cc",
+      "autofill/payments/mandatory_reauth_bubble_controller_impl.h",
+      "autofill/payments/mandatory_reauth_ui.h",
       "autofill/payments/offer_notification_bubble_controller.h",
       "autofill/payments/offer_notification_bubble_controller_impl.cc",
       "autofill/payments/offer_notification_bubble_controller_impl.h",
@@ -4495,6 +4500,10 @@
       "views/autofill/payments/local_card_migration_icon_view.h",
       "views/autofill/payments/manage_saved_iban_bubble_view.cc",
       "views/autofill/payments/manage_saved_iban_bubble_view.h",
+      "views/autofill/payments/mandatory_reauth_icon_view.cc",
+      "views/autofill/payments/mandatory_reauth_icon_view.h",
+      "views/autofill/payments/mandatory_reauth_opt_in_bubble_view.cc",
+      "views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h",
       "views/autofill/payments/migratable_card_view.cc",
       "views/autofill/payments/migratable_card_view.h",
       "views/autofill/payments/offer_notification_bubble_views.cc",
@@ -5126,6 +5135,10 @@
       "views/permissions/permission_prompt_bubble_base_view.h",
       "views/permissions/permission_prompt_bubble_one_origin_view.cc",
       "views/permissions/permission_prompt_bubble_one_origin_view.h",
+      "views/permissions/permission_prompt_bubble_two_origins_view.cc",
+      "views/permissions/permission_prompt_bubble_two_origins_view.h",
+      "views/permissions/permission_prompt_bubble_view_factory.cc",
+      "views/permissions/permission_prompt_bubble_view_factory.h",
       "views/permissions/permission_prompt_chip.cc",
       "views/permissions/permission_prompt_chip.h",
       "views/permissions/permission_prompt_chip_model.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index afd2d18d..9062f0e 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -738,6 +738,16 @@
       <message name="IDS_PASSWORD_MIGRATION_WARNING_TITLE" desc="The title of the password migration warning sheet.">
         We’re changing how passwords are saved on this device
       </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_SUBTITLE" desc="The subtitle of the password migration warning sheet." formatter_data="android_java">
+        Your lists of saved passwords for Chrome and Chrome <ph name="ERROR_DESCRIPTION">%1$s<ex>Dev</ex></ph> will merge after version 121. You’ll be able to autofill all your saved passwords on both apps.
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_ACKNOWLEDGE" desc="The text on the button that acknowledges the password migration warning.">
+        Got it
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_OTHER_OPTIONS" desc="The text on the button that leads to other options in the password migration warning sheet.">
+        Other options
+      </message>
+
 
       <!-- Lock Screen Fragment -->
       <message name="IDS_LOCKSCREEN_DESCRIPTION_COPY" desc="When a user attempts to copy a password for a particular website into clipboard in Chrome's settings, Chrome launches a lock screen to verify the user's identity and displays the following explanation.">
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_ACKNOWLEDGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_ACKNOWLEDGE.png.sha1
new file mode 100644
index 0000000..b9a2a05
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_ACKNOWLEDGE.png.sha1
@@ -0,0 +1 @@
+e126016f234a900595f5c8e0186b80cc85fa9bac
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_OTHER_OPTIONS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_OTHER_OPTIONS.png.sha1
new file mode 100644
index 0000000..b9a2a05
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_OTHER_OPTIONS.png.sha1
@@ -0,0 +1 @@
+e126016f234a900595f5c8e0186b80cc85fa9bac
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_SUBTITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_SUBTITLE.png.sha1
new file mode 100644
index 0000000..b9a2a05
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+e126016f234a900595f5c8e0186b80cc85fa9bac
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
index 0a765e11..3d69762 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google-logoskets: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">Leeslys</translation>
 <translation id="1266864766717917324">Kon nie <ph name="CONTENT_TYPE" /> deel nie.</translation>
+<translation id="1269129608791067105">Jy sal jou geskiedenis hier kry</translation>
 <translation id="1273937721055267968">Blokkeer <ph name="DOMAIN" /></translation>
 <translation id="1283039547216852943">Tik om uit te vou</translation>
 <translation id="1291207594882862231">Maak geskiedenis, webkoekies, werfdata, kas skoon …</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456">Skep geleentheid in <ph name="APP_NAME" /></translation>
 <translation id="5683547024293500885">Chrome kan nie nagaan of daar opdaterings is nie</translation>
 <translation id="5686790454216892815">Lêernaam is te lank</translation>
+<translation id="569435661099256888">Jy kan die bladsye sien wat jy besoek het of hulle van jou geskiedenis uitvee</translation>
 <translation id="569536719314091526">Vertaal hierdie bladsy in enige taal vanaf die Meer Opsies-knoppie</translation>
 <translation id="5696597120588531049">Chrome kan help om jou teen dataskendings, onveilige webwerwe, en meer te beskerm</translation>
 <translation id="570347048394355941">Wissel Na Oortjie</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_am.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_am.xtb
index a77da5c7..7785ed7 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_am.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_am.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google doodle፦ <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">የንባብ ዝርዝር</translation>
 <translation id="1266864766717917324"><ph name="CONTENT_TYPE" /> ን ማጋራት አልተቻለም።</translation>
+<translation id="1269129608791067105">ታሪክዎን እዚህ ያገኛሉ</translation>
 <translation id="1273937721055267968"><ph name="DOMAIN" />ን አግድ</translation>
 <translation id="1283039547216852943">ለመዘርጋት መታ ያድርጉ</translation>
 <translation id="1291207594882862231">ታሪክ፣ ኩኪዎች፣ የጣቢያ ውሂብ፣ መሸጎጫን አጽዳ…</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456">በ<ph name="APP_NAME" /> ውስጥ ክስተት ይፍጠሩ</translation>
 <translation id="5683547024293500885">Chrome ዝማኔዎች ካሉ መፈተሽ አይችልም</translation>
 <translation id="5686790454216892815">የፋይሉ ስም በጣም ረጅም ነው</translation>
+<translation id="569435661099256888">የጎበኟቸዉን ገጾች ማየት ወይም ከታሪክዎ ውስጥ ማፅዳት ይችላሉ</translation>
 <translation id="569536719314091526">ከተጨማሪ አማራጮች አዝራርሩ ይህን ገፅ ወደ ማንኛውም ቋንቋ ያስተርጉሙ</translation>
 <translation id="5696597120588531049">Chrome ከውሂብ ጥሰቶች፣ ደህንነታቸው ካልተጠበቁ ድር ጣቢያዎች እና ከተጨማሪ ነገሮች ደህንነትዎን ለመጠበቅ ሊያግዝዎት ይችላል</translation>
 <translation id="570347048394355941">ወደ ትር ቀይር</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb
index 44d8f42d..61bd1745 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb
@@ -282,6 +282,7 @@
 <translation id="2587052924345400782">يتوفر إصدار أحدث</translation>
 <translation id="2593272815202181319">أحادي المسافة</translation>
 <translation id="2603212228005142861">تسجيل الدخول لإدارة إعداداتك المفضَّلة</translation>
+<translation id="260403163289591229">المحتوى الذي تتم متابعته</translation>
 <translation id="2604446170045642109">يمكنك إيقاف المظهر الداكن للمواقع الإلكترونية من الإعدادات.</translation>
 <translation id="2612676031748830579">رقم البطاقة</translation>
 <translation id="2625189173221582860">تم نسخ كلمة المرور</translation>
@@ -578,6 +579,7 @@
 <translation id="4198423547019359126">ما من مواقع تنزيل متاحة</translation>
 <translation id="4202218894997543208">المواضيع التي حظرتها</translation>
 <translation id="4214315110991671325">‏إذا سمحت بملفات تعريف الارتباط، قد يستخدمها Chrome للتحميل المُسبق.</translation>
+<translation id="4225725533026049334">تتم متابعته حاليًا</translation>
 <translation id="4225895483398857530">اختصارات شريط الأدوات</translation>
 <translation id="4242533952199664413">فتح الإعدادات</translation>
 <translation id="4248098802131000011">لحماية كلمة المرور من عمليات اختراق البيانات ومشاكل الأمان الأخرى</translation>
@@ -910,6 +912,7 @@
 <translation id="6005538289190791541">كلمة المرور المُقترحَة</translation>
 <translation id="6011308810877101166">تحسين اقتراحات البحث</translation>
 <translation id="6026538407078977628">التوسيع إلى وضع ملء الشاشة</translation>
+<translation id="6030719887161080597">إدارة المعلومات التي تستخدمها المواقع الإلكترونية لقياس أداء الإعلانات</translation>
 <translation id="6039379616847168523">الانتقال السريع إلى علامة التبويب التالية</translation>
 <translation id="6040143037577758943">إغلاق</translation>
 <translation id="604124094241169006">تلقائي</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
index 7cf1917..e5b2a49 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google-doodle: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">Læseliste</translation>
 <translation id="1266864766717917324">Det var ikke muligt at dele <ph name="CONTENT_TYPE" /></translation>
+<translation id="1269129608791067105">Her kan du se din historik</translation>
 <translation id="1273937721055267968">Bloker <ph name="DOMAIN" /></translation>
 <translation id="1283039547216852943">Tryk for at udvide</translation>
 <translation id="1291207594882862231">Ryd historik, cookies, websitedata, cache...</translation>
@@ -191,7 +192,7 @@
 <translation id="2067805253194386918">tekst</translation>
 <translation id="2079545284768500474">Fortryd</translation>
 <translation id="2082238445998314030">Resultat <ph name="RESULT_NUMBER" /> af <ph name="TOTAL_RESULTS" /></translation>
-<translation id="2096012225669085171">Synkroniser og tilpas på flere enheder</translation>
+<translation id="2096012225669085171">Synkroniser og personligt tilpas på flere enheder</translation>
 <translation id="2100273922101894616">Automatisk login</translation>
 <translation id="2100314319871056947">Prøv at opdele teksten i mindre stykker</translation>
 <translation id="2111511281910874386">Gå til side</translation>
@@ -611,7 +612,7 @@
 <translation id="4415276339145661267">Administrer din Google-konto</translation>
 <translation id="4425140285732600465">Der holdes øje med prisen. Få besked, hvis prisen falder på et website.</translation>
 <translation id="442518031075347249">Du vil ikke længere kunne bruge dit virtuelle kort med Google Pay. <ph name="BEGIN_LINK1" />Få flere oplysninger om virtuelle kort<ph name="END_LINK1" /></translation>
-<translation id="4428065317363009941">Annoncetilpasning</translation>
+<translation id="4428065317363009941">Personlig tilpasning af annoncer</translation>
 <translation id="4452411734226507615">Luk fanen <ph name="TAB_TITLE" /></translation>
 <translation id="4452548195519783679">Bogmærket er gemt i <ph name="FOLDER_NAME" /></translation>
 <translation id="4461614516424362539">Når du tilknytter en anden enhed med en QR-kode, kan den bruge denne telefon som en sikkerhedsnøgle. Hvis du fjerner den, skal du scanne en QR-kode for at tilknytte den igen.</translation>
@@ -726,7 +727,7 @@
 <translation id="4961107849584082341">Oversæt denne side til et hvilket som helst sprog</translation>
 <translation id="4971735654804503942">Hurtigere proaktiv beskyttelse mod skadelige websites, downloads og udvidelser. Advarer dig om læk af adgangskoder. Kræver, at browserdata sendes til Google.</translation>
 <translation id="497421865427891073">Gå fremad</translation>
-<translation id="4985248278475639481">Om personlig annoncetilpasning</translation>
+<translation id="4985248278475639481">Om personlig tilpasning af annoncer</translation>
 <translation id="4987271110129728827">Siden kan ikke findes. Tjek stavningen, eller prøv med en websøgning.</translation>
 <translation id="4988526792673242964">Sider</translation>
 <translation id="4991110219272367918">Mulighed for at godkende eller ikke godkende et website – lukket</translation>
@@ -777,7 +778,7 @@
 <translation id="5246093389635966745">Rediger genvej til værktøjslinje</translation>
 <translation id="5271967389191913893">Enheden kan ikke åbne det indhold, der skal downloades.</translation>
 <translation id="5292796745632149097">Send til</translation>
-<translation id="5300426565656326054">Browserbaseret personlig annoncetilpasning</translation>
+<translation id="5300426565656326054">Browserbaseret personlig tilpasning af annoncer</translation>
 <translation id="5304593522240415983">Dette felt må ikke være tomt</translation>
 <translation id="5308380583665731573">Opret forbindelse</translation>
 <translation id="5317780077021120954">Gem</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456">Opret begivenhed i <ph name="APP_NAME" /></translation>
 <translation id="5683547024293500885">Chrome kan ikke søge efter opdateringer</translation>
 <translation id="5686790454216892815">Filnavnet er for langt</translation>
+<translation id="569435661099256888">Du kan se de sider, du har besøgt, eller rydde dem fra din historik</translation>
 <translation id="569536719314091526">Oversæt denne side til et hvilket som helst sprog via knappen Flere valgmuligheder</translation>
 <translation id="5696597120588531049">Chrome kan hjælpe med at beskytte dig mod brud på datasikkerheden, usikre websites og meget mere</translation>
 <translation id="570347048394355941">Skift til fanen</translation>
@@ -1124,7 +1126,7 @@
 <translation id="707155805709242880">Vælg, hvad der skal synkroniseres, nedenfor</translation>
 <translation id="7077143737582773186">SD-kort</translation>
 <translation id="7080806333218412752">Sender webadresser til tjek i Beskyttet browsing. Der sendes også et mindre antal sider, downloads, udvidelsesaktivitet og systemoplysninger for at identificere nye trusler. Disse data knyttes midlertidigt til din Google-konto, når du er logget ind, for at beskytte dig i Google-apps.</translation>
-<translation id="7085332316435785646">Vælg, om du vil inkludere Chrome-historikken for at få mere tilpassede oplevelser i Googles tjenester</translation>
+<translation id="7085332316435785646">Vælg, om du vil inkludere Chrome-historikken for at få mere personligt tilpassede oplevelser i Googles tjenester</translation>
 <translation id="7088681679121566888">Chrome er opdateret</translation>
 <translation id="7105047059074518658">Log ind for nemmere at søge på flere enheder</translation>
 <translation id="7106762743910369165">Din browser administreres af din organisation</translation>
@@ -1378,7 +1380,7 @@
 <translation id="8402673309244746971">Gå til Følger</translation>
 <translation id="8413126021676339697">Vis hele historikken</translation>
 <translation id="8414396119627470038">Log ind på <ph name="SITE_ETLD_PLUS_ONE" /> med <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE" /></translation>
-<translation id="8416347857511542594">Få flere oplysninger om personlig annoncetilpasning i Chrome</translation>
+<translation id="8416347857511542594">Få flere oplysninger om personlig tilpasning af annoncer i Chrome</translation>
 <translation id="8419244640277402268">Medtag</translation>
 <translation id="8424781820952413435">Siden er sendt. Åbn Chrome på din <ph name="DEVICE_TYPE" /> for at se den</translation>
 <translation id="8427875596167638501">Fanen forhåndsvisning er åbnet halvt</translation>
@@ -1441,7 +1443,7 @@
 <translation id="8662811608048051533">Logger dig ud af de fleste websites.</translation>
 <translation id="8664215986015753476">Brug Chrome på din måde</translation>
 <translation id="8664979001105139458">Filnavnet findes allerede</translation>
-<translation id="8666759526542103597">Om browserbaseret personlig annoncetilpasning</translation>
+<translation id="8666759526542103597">Om browserbaseret personlig tilpasning af annoncer</translation>
 <translation id="8676276370198826499">Tilmeld dig <ph name="SITE_ETLD_PLUS_ONE" /> med <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE" /></translation>
 <translation id="8676789164135894283">Loginverificeringer</translation>
 <translation id="8683039184091909753">billede</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
index d49095aa..b4343ea6 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
@@ -74,7 +74,7 @@
 <translation id="1332501820983677155">Raccourcis liés aux fonctionnalités de Google Chrome</translation>
 <translation id="1344653310988386453">Inclure le lien vers le texte en surbrillance</translation>
 <translation id="1347468774581902829">Gérer l'activité</translation>
-<translation id="1360432990279830238">Se déconnecter et arrêter la synchro. ?</translation>
+<translation id="1360432990279830238">Se déconnecter et arrêter la synchronisation ?</translation>
 <translation id="1366525380420346469">Lorsque la fonctionnalité est activée</translation>
 <translation id="1373696734384179344">Mémoire insuffisante pour télécharger le contenu sélectionné.</translation>
 <translation id="1376578503827013741">Calcul…</translation>
@@ -329,7 +329,7 @@
 <translation id="2886836735871983413">Une liste de sites s'affichera ici quand vous naviguerez sur le Web</translation>
 <translation id="2888126860611144412">À propos de Chrome</translation>
 <translation id="2891154217021530873">Arrêter le chargement de la page</translation>
-<translation id="2893180576842394309">Google peut utiliser votre historique pour personnaliser la recherche et d'autres services Google</translation>
+<translation id="2893180576842394309">Google pourra utiliser votre historique pour personnaliser la recherche et d'autres de ses services</translation>
 <translation id="2900528713135656174">Créer un événement</translation>
 <translation id="2901411048554510387">Afficher des suggestions pour <ph name="WEBSITE_TITLE" /></translation>
 <translation id="2904414404539560095">La liste des appareils avec lesquels vous pouvez partager un onglet est ouverte à pleine hauteur.</translation>
@@ -755,7 +755,7 @@
 <translation id="5122378528687922675">Si tu as besoin d'aide, demande à ton parent (<ph name="PARENT_NAME_1" /> ou <ph name="PARENT_NAME_2" />)</translation>
 <translation id="5123685120097942451">Onglet de navigation privée</translation>
 <translation id="5126510351761255129">Valider votre carte</translation>
-<translation id="5132942445612118989">Synchroniser vos mots de passe, votre historique et plus encore sur tous les appareils</translation>
+<translation id="5132942445612118989">Synchronisez vos mots de passe, votre historique et plus encore sur tous les appareils</translation>
 <translation id="5139940364318403933">Découvrez comment utiliser Google Drive</translation>
 <translation id="5142281402488957685">Déroulez pour actualiser et voir de nouveaux articles</translation>
 <translation id="5152843274749979095">Aucune application compatible n'est installée</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
index 28188fb2..c6a5e7c4 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google doodle: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">ລາຍການທີ່ຈະອ່ານ</translation>
 <translation id="1266864766717917324">ບໍ່ສາມາດແບ່ງປັນ <ph name="CONTENT_TYPE" /> ໄດ້</translation>
+<translation id="1269129608791067105">ທ່ານຈະເຫັນປະຫວັດຂອງທ່ານຢູ່ບ່ອນນີ້</translation>
 <translation id="1273937721055267968">ບລັອກ <ph name="DOMAIN" /></translation>
 <translation id="1283039547216852943">ແຕະເພື່ອຂະຫຍາຍ</translation>
 <translation id="1291207594882862231">ລຶບລ້າງປະຫວັດ, ຄຸກກີ້, ຂໍ້ມູນເວັບໄຊ, ແຄສ…</translation>
@@ -195,6 +196,7 @@
 <translation id="2100273922101894616">ເຂົ້າສູ່​ລະບົບ​ອັດຕະໂນມັດ</translation>
 <translation id="2100314319871056947">ລອງແບ່ງປັນຂໍ້ຄວາມໃນຈຳນວນທີ່ໜ້ອຍກວ່າ</translation>
 <translation id="2111511281910874386">ໄປຫາໜ້າ</translation>
+<translation id="2119609734654412418">ທ່ານຈະເຫັນບຸກມາກຂອງທ່ານຢູ່ບ່ອນນີ້</translation>
 <translation id="2122601567107267586">ບໍ່ສາມາດເປີດແອັບໄດ້</translation>
 <translation id="2132122640199389833">ລຶບອຸປະກອນທີ່ລິ້ງໄວ້ທັງໝົດອອກ</translation>
 <translation id="213279576345780926">ປິດ <ph name="TAB_TITLE" /> ແລ້ວ</translation>
@@ -598,6 +600,7 @@
 <translation id="433213510553688132">ກຳລັງຕິດຕາມ...</translation>
 <translation id="4335835283689002019">Safe Browsing ປິດ</translation>
 <translation id="4351244548802238354">ປິດ​ໜ້າ​ຕ່າງ</translation>
+<translation id="4355272626458588338">ທ່ານສາມາດກັບໄປຫາໜ້າທີ່ສຳຄັນຕໍ່ກັບທ່ານໂດຍການເພີ່ມບຸກມາກໄດ້</translation>
 <translation id="4369735607080757018">ປະເພດຂອງຂໍ້ມູນທີ່ຈໍາກັດແມ່ນຖືກແບ່ງປັນລະຫວ່າງເວັບໄຊເພື່ອວັດແທກປະສິດທິພາບການໂຄສະນາຂອງເຂົາເຈົ້າເຊັ່ນ: ເວລາຂອງມື້ທີ່ໂຄສະນາຖືກສະແດງໃຫ້ທ່ານເຫັນ</translation>
 <translation id="4378154925671717803">ໂທລະ​ສັບ</translation>
 <translation id="438319986296050901">ແບ່ງປັນບັດເທົ່ານັ້ນ</translation>
@@ -845,6 +848,7 @@
 <translation id="5665379678064389456">ສ້າງເຫດການໃນ <ph name="APP_NAME" /></translation>
 <translation id="5683547024293500885">Chrome ບໍ່ສາມາດກວດຫາການອັບເດດໄດ້</translation>
 <translation id="5686790454216892815">ຊື່ໄຟລ໌ຍາວເກີນໄປ</translation>
+<translation id="569435661099256888">ທ່ານສາມາດເບິ່ງໜ້າເວັບທີ່ທ່ານເຄີຍເຂົ້າເບິ່ງ ຫຼື ລຶບລ້າງພວກມັນອອກຈາກປະຫວັດຂອງທ່ານໄດ້</translation>
 <translation id="569536719314091526">ແປໜ້ານີ້ເປັນພາສາໃດໆກໍໄດ້ຈາກປຸ່ມຕົວເລືອກເພີ່ມເຕີມ</translation>
 <translation id="5696597120588531049">Chrome ສາມາດຊ່ວຍຮັກສາທ່ານໃຫ້ປອດໄພຈາກການລະເມີດຂໍ້ມູນ, ເວັບໄຊທີ່ບໍ່ປອດໄພ ແລະ ອື່ນໆອີກ</translation>
 <translation id="570347048394355941">ປ່ຽນເປັນແຖບ</translation>
@@ -949,6 +953,7 @@
 <translation id="6232535412751077445">ການເປີດໃຊ້ “ຢ່າຕິດຕາມ” ໝາຍຄວາມວ່າ ຄຳຮ້ອງຂໍຈະຖືກເອົາຮວມເຂົ້າກັບການຮັບສົ່ງຂໍ້ມູນການທ່ອງເວັບຂອງທ່ານ. ຜົນຕາມມາແມ່ນຂຶ້ນກັບວ່າເວັບໄຊຕອບສະໜອງຕໍ່ກັບຄຳຮ້ອງຂໍນັ້ນແນວໃດ ແລະຄຳຮ້ອງຂໍນັ້ນຖືກຕີຄວາມໝາຍແນວໃດ.
 
 ຕົວຢ່າງ, ບາງເວັບໄຊອາດຕອບສະໜອງຕໍ່ກັບຄຳຮ້ອງຂໍນີ້ ໂດຍການສະແດງໃຫ້ທ່ານເຫັນໂຄສະນາທີ່ບໍ່ອີງໃສ່ເວັບໄຊອື່ນທີ່ທ່ານເຂົ້າເບິ່ງ. ຫຼາຍໆເວັບໄຊຈະຍັງບັນທຶກ ແລະໃຊ້ຂໍ້ມູນການທ່ອງເວັບຂອງທ່ານ — ຕົວຢ່າງ ເຊັ່ນ: ເພື່ອປັບປຸງຄວາມປອດໄພ, ເພື່ອສະໜອງເນື້ອຫາ, ໂຄສະນາ ແລະຄຳແນະນໍາຕ່າງໆ ແລະເພື່ອສ້າງສະຖິຕິການລາຍງານ.</translation>
+<translation id="6255794742848779505">ພວກເຮົາກຳລັງປ່ຽນວິທີທີ່ລະຫັດຜ່ານຖືກບັນທຶກໄວ້ຢູ່ອຸປະກອນນີ້</translation>
 <translation id="6264376385120300461">ຢືນຢັນການດາວໂຫຼດ</translation>
 <translation id="6277522088822131679">ມີບັນຫາການພິມໜ້າ. ກະລຸນາລອງໃໝ່ອີກ.</translation>
 <translation id="6277722725779679269">ບໍ່ສາມາດອັບເດດການຕິດຕາມລາຄາໄດ້</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb
index 6bcdcec..8c5bc6b 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google केरकार: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">पाठ्य सूची</translation>
 <translation id="1266864766717917324"><ph name="CONTENT_TYPE" /> आदान प्रदान गर्न सकिएन</translation>
+<translation id="1269129608791067105">तपाईंको ब्राउजिङ हिस्ट्री यहाँ देखिने छ</translation>
 <translation id="1273937721055267968"><ph name="DOMAIN" /> ब्लक गर्नुहोस्</translation>
 <translation id="1283039547216852943">विस्तृत गर्न ट्याप गर्नुहोस्</translation>
 <translation id="1291207594882862231">इतिहास, कुकी, साइट सम्बन्धी डेटा, क्यासलाई खाली गर्नुहोस्…</translation>
@@ -844,6 +845,7 @@
 <translation id="5665379678064389456"><ph name="APP_NAME" /> मा घटना सिर्जना गर्नुहोस्</translation>
 <translation id="5683547024293500885">Chrome ले अपडेट उपलब्ध छन् कि छैनन् भन्ने कुरा जाँच गर्न सकेन</translation>
 <translation id="5686790454216892815">फाइलको नाम ज्यादै लामो छ</translation>
+<translation id="569435661099256888">तपाईं आफूले खोलेका पेजहरू हेर्न वा ब्राउजिङ हिस्ट्रीबाट ती पेजहरू हटाउन सक्नुहुन्छ</translation>
 <translation id="569536719314091526">थप विकल्पहरू नामक बटनबाट यस पृष्ठलाई जुनसुकै भाषामा अनुवाद गर्नुहोस्</translation>
 <translation id="5696597120588531049">Chrome ले तपाईंलाई डेटा चोरीका घटना, असुरक्षित वेबसाइटहरू र थप समस्याहरूबाट जोगिन मद्दत गर्न सक्छ</translation>
 <translation id="570347048394355941">ट्याब प्रयोग गर्न थाल्नुहोस्</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
index d88018423..e6a0366 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google doodle: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">పఠన లిస్ట్‌</translation>
 <translation id="1266864766717917324"><ph name="CONTENT_TYPE" />ను షేర్ చేయడం సాధ్యపడలేదు</translation>
+<translation id="1269129608791067105">మీ హిస్టరీని ఇక్కడ చూడవచ్చు</translation>
 <translation id="1273937721055267968"><ph name="DOMAIN" />‌ను బ్లాక్ చేయండి</translation>
 <translation id="1283039547216852943">విస్త‌రించ‌డానికి నొక్కండి</translation>
 <translation id="1291207594882862231">హిస్టరీ, కుక్కీలు, సైట్ డేటా, కాష్‌ను తీసివేస్తుంది…</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456"><ph name="APP_NAME" />లో ఈవెంట్‌ను క్రియేట్ చేయండి</translation>
 <translation id="5683547024293500885">అప్‌డేట్‌లను Chrome చెక్ చేయలేదు</translation>
 <translation id="5686790454216892815">ఫైల్ పేరు చాలా పొడవుగా ఉంది</translation>
+<translation id="569435661099256888">మీరు తెరిచిన పేజీలను చూడవచ్చు లేదా వాటిని మీ హిస్టరీ నుండి క్లియర్ చేయవచ్చు</translation>
 <translation id="569536719314091526">మరిన్ని ఆప్షన్‌లు బటన్‌ని ఉపయోగించి ఈ పేజీని ఏ భాషలోకైనా అనువదించుకోవచ్చు</translation>
 <translation id="5696597120588531049">డేటా ఉల్లంఘనలు, సురక్షితం కాని వెబ్‌సైట్‌లు, మరిన్నింటి నుండి మిమ్మల్ని సురక్షితంగా ఉంచడంలో Chrome సహాయపడగలదు</translation>
 <translation id="570347048394355941">ట్యాబ్‌కు మారండి</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
index 62e6292d..7d4b1f3 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">Google-dudl: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">Mutolaa ro‘yxati</translation>
 <translation id="1266864766717917324"><ph name="CONTENT_TYPE" /> yuborilmadi</translation>
+<translation id="1269129608791067105">Brauzer tarixi shu yerda chiqadi</translation>
 <translation id="1273937721055267968"><ph name="DOMAIN" /> ilovasini bloklash</translation>
 <translation id="1283039547216852943">Bosib yoyish</translation>
 <translation id="1291207594882862231">Brauzer tarixi, cookie-fayllar, kesh va boshqa sayt ma’lumotlarini tozalash...</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456"><ph name="APP_NAME" /> ilovasida tadbir yaratish</translation>
 <translation id="5683547024293500885">Chrome yangilanishlar chiqqanini tekshira olmadi</translation>
 <translation id="5686790454216892815">Fayl nomi juda uzun</translation>
+<translation id="569435661099256888">Tarix orqali ochilgan sahifalarni koʻrish yoki tozalash mumkin</translation>
 <translation id="569536719314091526">“Yana” tugmasidan bu sahifani boshqa tilga tarjima qilishingiz mumkin</translation>
 <translation id="5696597120588531049">Chrome maʼlumotlaringizni axborotlar sizib chiqishi va xavfsizlikka oid boshqa muammolardan himoyalaydi</translation>
 <translation id="570347048394355941">Varaqqa oʻtish</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_vi.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_vi.xtb
index c9be39e..e0f4f55 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_vi.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_vi.xtb
@@ -212,7 +212,7 @@
 <translation id="2194856509914051091">Những yếu tố cần xem xét</translation>
 <translation id="2200113223741723867">Quản lý cách chia sẻ dữ liệu sử dụng</translation>
 <translation id="2218567645332692482">Nâng các hình thức chuyển hướng lên giao thức HTTPS và cảnh báo bạn trước khi tải những trang web không hỗ trợ giao thức HTTPS</translation>
-<translation id="2227444325776770048">Tiếp tục bằng <ph name="USER_FULL_NAME" /></translation>
+<translation id="2227444325776770048">Tiếp tục bằng tài khoản của <ph name="USER_FULL_NAME" /></translation>
 <translation id="2230777942707397948">Cửa sổ trống</translation>
 <translation id="223356358902285214">Hoạt động trên web và ứng dụng</translation>
 <translation id="2234827758954819389">Hướng dẫn về quyền riêng tư</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zu.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zu.xtb
index 881b56a..67e5aa7c 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zu.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zu.xtb
@@ -56,6 +56,7 @@
 <translation id="1258753120186372309">I-Google doodle: <ph name="DOODLE_DESCRIPTION" /></translation>
 <translation id="1263231323834454256">Uhlu lokufunda</translation>
 <translation id="1266864766717917324">Ayikwazanga ukwabelana nge-<ph name="CONTENT_TYPE" /></translation>
+<translation id="1269129608791067105">Uzothola umlando wakho lapha</translation>
 <translation id="1273937721055267968">Vimba i-<ph name="DOMAIN" /></translation>
 <translation id="1283039547216852943">Thepha ukuze unwebe</translation>
 <translation id="1291207594882862231">Sula umlando, amakhukhi, idatha yesayithi, inqolobane…</translation>
@@ -845,6 +846,7 @@
 <translation id="5665379678064389456">Dala umcimbi ku-<ph name="APP_NAME" /></translation>
 <translation id="5683547024293500885">I-Chrome ayikwazi ukuhlola izibuyekezo</translation>
 <translation id="5686790454216892815">Igama lefayela lide kakhulu</translation>
+<translation id="569435661099256888">Ungakwazi ukubona amakhasi owavakashele noma uwasule kumlando wakho</translation>
 <translation id="569536719314091526">Humusha leli khasi ukuya kunoma iluphi ulimi kusukela kunkinobho yezinketho zokuningi</translation>
 <translation id="5696597120588531049">I-Chrome ingakusiza ukukugcina uphephile ekuphulweni kwesivumelwano sedatha, kumawebhusayithi angaphephile, nokuningi</translation>
 <translation id="570347048394355941">Shintshela Kuthebhu</translation>
diff --git a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
index 098a91a..f5388d8 100644
--- a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/global_media_controls/cast_media_notification_item.h"
+#include "chrome/browser/ui/global_media_controls/supplemental_device_picker_producer.h"
 #include "chrome/browser/ui/views/global_media_controls/media_item_ui_device_selector_view.h"
 #include "chrome/browser/ui/views/global_media_controls/media_item_ui_helper.h"
 #include "chrome/browser/ui/views/global_media_controls/media_item_ui_legacy_cast_footer_view.h"
@@ -33,7 +34,8 @@
 
 std::unique_ptr<global_media_controls::MediaItemUIFooter> BuildFooterView(
     base::WeakPtr<media_message_center::MediaNotificationItem> item,
-    Profile* profile) {
+    Profile* profile,
+    global_media_controls::GlobalMediaControlsEntryPoint entry_point) {
   if (item->SourceType() != media_message_center::SourceType::kCast ||
       !media_router::GlobalMediaControlsCastStartStopEnabled(profile)) {
     return nullptr;
@@ -42,7 +44,7 @@
   return std::make_unique<MediaItemUILegacyCastFooterView>(base::BindRepeating(
       &CastMediaNotificationItem::StopCasting,
       static_cast<CastMediaNotificationItem*>(item.get())->GetWeakPtr(),
-      global_media_controls::GlobalMediaControlsEntryPoint::kSystemTray));
+      entry_point));
 }
 
 }  // namespace
@@ -75,7 +77,6 @@
       std::make_unique<global_media_controls::MediaSessionItemProducer>(
           std::move(audio_focus_remote), std::move(controller_manager_remote),
           item_manager_.get(), /*source_id=*/absl::nullopt);
-
   item_manager_->AddItemProducer(media_session_item_producer_.get());
 }
 
@@ -84,6 +85,12 @@
   MediaNotificationProvider::Set(nullptr);
 
   item_manager_->RemoveObserver(this);
+  if (crosapi::CrosapiManager::IsInitialized()) {
+    crosapi::CrosapiManager::Get()
+        ->crosapi_ash()
+        ->media_ui_ash()
+        ->RemoveObserver(this);
+  }
 }
 
 void MediaNotificationProviderImpl::AddObserver(
@@ -124,13 +131,16 @@
           should_clip_height);
   active_session_view_ = notification_list_view->GetWeakPtr();
   if (item_id.empty()) {
+    entry_point_ =
+        global_media_controls::GlobalMediaControlsEntryPoint::kSystemTray;
     item_manager_->SetDialogDelegate(this);
   } else {
+    entry_point_ =
+        global_media_controls::GlobalMediaControlsEntryPoint::kPresentation;
     item_manager_->SetDialogDelegateForId(this, item_id);
   }
-  base::UmaHistogramEnumeration(
-      "Media.GlobalMediaControls.EntryPoint",
-      global_media_controls::GlobalMediaControlsEntryPoint::kSystemTray);
+  base::UmaHistogramEnumeration("Media.GlobalMediaControls.EntryPoint",
+                                entry_point_);
   return notification_list_view;
 }
 
@@ -148,6 +158,24 @@
   return item_manager_.get();
 }
 
+void MediaNotificationProviderImpl::OnPrimaryUserSessionStarted() {
+  if (!media_router::GlobalMediaControlsCastStartStopEnabled(GetProfile()) ||
+      !crosapi::CrosapiManager::IsInitialized()) {
+    return;
+  }
+  supplemental_device_picker_producer_ =
+      std::make_unique<SupplementalDevicePickerProducer>(item_manager_.get());
+  item_manager_->AddItemProducer(supplemental_device_picker_producer_.get());
+  crosapi::MediaUIAsh* media_ui =
+      crosapi::CrosapiManager::Get()->crosapi_ash()->media_ui_ash();
+  media_ui->AddObserver(this);
+
+  for (const auto& device_service : media_ui->device_services()) {
+    device_service.second->SetDevicePickerProvider(
+        supplemental_device_picker_producer_->PassRemote());
+  }
+}
+
 global_media_controls::MediaItemUI*
 MediaNotificationProviderImpl::ShowMediaItem(
     const std::string& id,
@@ -155,14 +183,11 @@
   if (!active_session_view_) {
     return nullptr;
   }
-  Profile* profile = profile_for_testing_
-                         ? profile_for_testing_.get()
-                         : ProfileManager::GetActiveUserProfile();
   auto item_ui = std::make_unique<global_media_controls::MediaItemUIView>(
-      id, item, BuildFooterView(item, profile),
-      BuildDeviceSelector(
-          id, item, GetDeviceService(item), &device_selector_delegate_, profile,
-          global_media_controls::GlobalMediaControlsEntryPoint::kSystemTray),
+      id, item, BuildFooterView(item, GetProfile(), entry_point_),
+      BuildDeviceSelector(id, item, GetDeviceService(item),
+                          &device_selector_delegate_, GetProfile(),
+                          entry_point_),
       color_theme_, GetCrosMediaColorTheme(),
       media_message_center::MediaDisplayPage::kQuickSettingsMediaDetailedView);
   auto* item_ui_ptr = item_ui.get();
@@ -202,6 +227,12 @@
   item_ui_observer_set_.StopObserving(id);
 }
 
+void MediaNotificationProviderImpl::OnDeviceServiceRegistered(
+    global_media_controls::mojom::DeviceService* device_service) {
+  device_service->SetDevicePickerProvider(
+      supplemental_device_picker_producer_->PassRemote());
+}
+
 global_media_controls::mojom::DeviceService*
 MediaNotificationProviderImpl::GetDeviceService(
     base::WeakPtr<media_message_center::MediaNotificationItem> item) const {
@@ -217,4 +248,9 @@
       ->GetDeviceService(*item->GetSourceId());
 }
 
+Profile* MediaNotificationProviderImpl::GetProfile() {
+  return profile_for_testing_ ? profile_for_testing_.get()
+                              : ProfileManager::GetActiveUserProfile();
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
index 6447fbb..d68000a0 100644
--- a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
@@ -9,7 +9,10 @@
 #include "ash/system/media/media_notification_provider.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "chrome/browser/ash/crosapi/media_ui_ash.h"
 #include "chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.h"
+#include "chrome/browser/ui/global_media_controls/supplemental_device_picker_producer.h"
+#include "components/global_media_controls/public/constants.h"
 #include "components/global_media_controls/public/media_dialog_delegate.h"
 #include "components/global_media_controls/public/media_item_manager_observer.h"
 #include "components/global_media_controls/public/media_item_ui_observer.h"
@@ -38,7 +41,8 @@
     : public MediaNotificationProvider,
       public global_media_controls::MediaDialogDelegate,
       public global_media_controls::MediaItemManagerObserver,
-      public global_media_controls::MediaItemUIObserver {
+      public global_media_controls::MediaItemUIObserver,
+      public crosapi::MediaUIAsh::Observer {
  public:
   explicit MediaNotificationProviderImpl(
       media_session::MediaSessionService* service);
@@ -57,6 +61,7 @@
   void SetColorTheme(
       const media_message_center::NotificationTheme& color_theme) override;
   global_media_controls::MediaItemManager* GetMediaItemManager() override;
+  void OnPrimaryUserSessionStarted() override;
 
   // global_media_controls::MediaDialogDelegate:
   global_media_controls::MediaItemUI* ShowMediaItem(
@@ -79,6 +84,10 @@
   void OnMediaItemUISizeChanged() override;
   void OnMediaItemUIDestroyed(const std::string& id) override;
 
+  // crosapi::MediaUIAsh::Observer:
+  void OnDeviceServiceRegistered(
+      global_media_controls::mojom::DeviceService* device_service) override;
+
   global_media_controls::MediaSessionItemProducer*
   media_session_item_producer_for_testing() {
     return media_session_item_producer_.get();
@@ -94,6 +103,8 @@
   }
 
  private:
+  Profile* GetProfile();
+
   global_media_controls::mojom::DeviceService* GetDeviceService(
       base::WeakPtr<media_message_center::MediaNotificationItem> item) const;
 
@@ -106,6 +117,8 @@
 
   std::unique_ptr<global_media_controls::MediaSessionItemProducer>
       media_session_item_producer_;
+  std::unique_ptr<SupplementalDevicePickerProducer>
+      supplemental_device_picker_producer_;
 
   absl::optional<media_message_center::NotificationTheme> color_theme_;
 
@@ -113,9 +126,14 @@
 
   MediaItemUIDeviceSelectorDelegateAsh device_selector_delegate_;
 
+  global_media_controls::GlobalMediaControlsEntryPoint entry_point_{
+      global_media_controls::GlobalMediaControlsEntryPoint::kSystemTray};
+
   raw_ptr<Profile> profile_for_testing_ = nullptr;
   raw_ptr<global_media_controls::mojom::DeviceService>
       device_service_for_testing_ = nullptr;
+
+  base::WeakPtrFactory<MediaNotificationProviderImpl> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
index 028e938..dd4f151 100644
--- a/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
@@ -8,8 +8,12 @@
 #include "ash/system/media/media_notification_provider_observer.h"
 #include "ash/test_shell_delegate.h"
 #include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/unguessable_token.h"
+#include "chrome/browser/ash/crosapi/crosapi_ash.h"
+#include "chrome/browser/ash/crosapi/crosapi_manager.h"
+#include "chrome/browser/ash/crosapi/media_ui_ash.h"
 #include "chrome/browser/ash/crosapi/test_crosapi_environment.h"
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_registry.h"
 #include "chrome/browser/media/router/media_router_feature.h"
@@ -21,6 +25,7 @@
 #include "components/global_media_controls/public/media_item_manager.h"
 #include "components/global_media_controls/public/media_session_item_producer.h"
 #include "components/global_media_controls/public/mojom/device_service.mojom.h"
+#include "components/global_media_controls/public/test/mock_device_service.h"
 #include "components/global_media_controls/public/views/media_item_ui_footer.h"
 #include "components/global_media_controls/public/views/media_item_ui_list_view.h"
 #include "components/global_media_controls/public/views/media_item_ui_view.h"
@@ -41,6 +46,7 @@
 using global_media_controls::mojom::DeviceListClient;
 using global_media_controls::mojom::DeviceListHost;
 using global_media_controls::mojom::DevicePickerProvider;
+using global_media_controls::test::MockDeviceService;
 using media_session::mojom::AudioFocusRequestState;
 using media_session::mojom::AudioFocusRequestStatePtr;
 using media_session::mojom::MediaSessionInfo;
@@ -63,21 +69,6 @@
               (global_media_controls::GlobalMediaControlsEntryPoint));
 };
 
-class MockDeviceService : public global_media_controls::mojom::DeviceService {
-  MOCK_METHOD(void,
-              GetDeviceListHostForSession,
-              (const std::string& session_id,
-               mojo::PendingReceiver<DeviceListHost> host_receiver,
-               mojo::PendingRemote<DeviceListClient> client_remote));
-  MOCK_METHOD(void,
-              GetDeviceListHostForPresentation,
-              (mojo::PendingReceiver<DeviceListHost> host_receiver,
-               mojo::PendingRemote<DeviceListClient> client_remote));
-  MOCK_METHOD(void,
-              SetDevicePickerProvider,
-              (mojo::PendingRemote<DevicePickerProvider> provider_remote));
-};
-
 class MockMediaNotificationProviderObserver
     : public MediaNotificationProviderObserver {
  public:
@@ -144,8 +135,11 @@
   ~MediaNotificationProviderImplTest() override = default;
 
   void SetUp() override {
-    ChromeAshTestBase::SetUp(std::make_unique<MediaTestShellDelegate>());
+    auto shell_delegate = std::make_unique<MediaTestShellDelegate>();
+    shell_delegate_ = shell_delegate.get();
+    ChromeAshTestBase::SetUp(std::move(shell_delegate));
 
+    crosapi_environment_.SetUp();
     provider_ = static_cast<MediaNotificationProviderImpl*>(
         MediaNotificationProvider::Get());
     observer_ = std::make_unique<MockMediaNotificationProviderObserver>();
@@ -155,6 +149,7 @@
 
   void TearDown() override {
     observer_.reset();
+    crosapi_environment_.TearDown();
     AshTestBase::TearDown();
   }
 
@@ -179,7 +174,9 @@
 
   std::unique_ptr<ChromeLayoutProvider> layout_provider_;
   std::unique_ptr<MockMediaNotificationProviderObserver> observer_;
-  raw_ptr<MediaNotificationProviderImpl, ExperimentalAsh> provider_;
+  raw_ptr<MediaNotificationProviderImpl, ExperimentalAsh> provider_ = nullptr;
+  raw_ptr<MediaTestShellDelegate, ExperimentalAsh> shell_delegate_ = nullptr;
+  crosapi::TestCrosapiEnvironment crosapi_environment_;
 };
 
 TEST_F(MediaNotificationProviderImplTest, NotificationListTest) {
@@ -246,18 +243,19 @@
     : public MediaNotificationProviderImplTest {
  public:
   void SetUp() override {
-    MediaNotificationProviderImplTest::SetUp();
-    crosapi_environment_.SetUp();
-    profile_ = crosapi_environment_.profile_manager()->CreateTestingProfile(
-        "Profile", /*is_main_profile=*/true);
+    // This must be called before MediaNotificationProviderImplTest::SetUp()
+    // starts the GPU service thread.
     scoped_feature_list_.InitAndEnableFeature(
         media_router::kGlobalMediaControlsCastStartStop);
+    MediaNotificationProviderImplTest::SetUp();
+
+    profile_ = crosapi_environment_.profile_manager()->CreateTestingProfile(
+        "Profile", /*is_main_profile=*/true);
     InitProvider();
   }
 
   void TearDown() override {
     profile_ = nullptr;
-    crosapi_environment_.TearDown();
     // This is needed for avoiding a DCHECK failure caused by
     // TestNetworkConnectionTracker having an observer when it's destroyed.
     media_router::DnsSdRegistry::GetInstance()->ResetForTest();
@@ -276,7 +274,6 @@
   }
 
   raw_ptr<Profile, ExperimentalAsh> profile_ = nullptr;
-  crosapi::TestCrosapiEnvironment crosapi_environment_;
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<views::View> list_view_;
 };
@@ -317,4 +314,18 @@
   EXPECT_TRUE(selector_view);
 }
 
+TEST_F(CastStartStopMediaNotificationProviderImplTest,
+       SetDevicePickerProvider) {
+  provider_->OnPrimaryUserSessionStarted();
+
+  MockDeviceService device_service;
+  EXPECT_CALL(device_service, SetDevicePickerProvider);
+  crosapi::CrosapiManager::Get()
+      ->crosapi_ash()
+      ->media_ui_ash()
+      ->RegisterDeviceService(base::UnguessableToken::Create(),
+                              device_service.PassRemote());
+  device_service.FlushForTesting();
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ui/autofill/autofill_bubble_handler.h b/chrome/browser/ui/autofill/autofill_bubble_handler.h
index 0e3c394..adbe679 100644
--- a/chrome/browser/ui/autofill/autofill_bubble_handler.h
+++ b/chrome/browser/ui/autofill/autofill_bubble_handler.h
@@ -21,6 +21,7 @@
 class SaveUPIBubbleController;
 class VirtualCardManualFallbackBubbleController;
 class VirtualCardEnrollBubbleController;
+class MandatoryReauthBubbleController;
 enum class IbanBubbleType;
 
 // TODO(crbug.com/1337392): consider removing this class and give the logic back
@@ -86,6 +87,11 @@
       VirtualCardEnrollBubbleController* controller,
       bool is_user_gesture) = 0;
 
+  virtual AutofillBubbleBase* ShowMandatoryReauthBubble(
+      content::WebContents* web_contents,
+      MandatoryReauthBubbleController* controller,
+      bool is_user_gesture) = 0;
+
   // TODO(crbug.com/964127): Wait for the integration with sign in after local
   // save to be landed to see if we need to merge password saved and credit card
   // saved functions.
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 90256abc..5f1a017 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h"
 #include "chrome/browser/ui/autofill/payments/credit_card_scanner_controller.h"
 #include "chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/risk_util.h"
 #include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
@@ -529,6 +530,17 @@
                          std::move(decline_virtual_card_callback));
 }
 
+void ChromeAutofillClient::ShowMandatoryReauthOptInPrompt(
+    base::OnceClosure accept_mandatory_reauth_callback,
+    base::OnceClosure cancel_mandatory_reauth_callback,
+    base::RepeatingClosure close_mandatory_reauth_callback) {
+  MandatoryReauthBubbleControllerImpl::CreateForWebContents(web_contents());
+  MandatoryReauthBubbleControllerImpl::FromWebContents(web_contents())
+      ->ShowBubble(std::move(accept_mandatory_reauth_callback),
+                   std::move(cancel_mandatory_reauth_callback),
+                   std::move(close_mandatory_reauth_callback));
+}
+
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 void ChromeAutofillClient::HideVirtualCardEnrollBubbleAndIconIfVisible() {
   VirtualCardEnrollBubbleControllerImpl::CreateForWebContents(web_contents());
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 2116b48..d0261f7 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -146,6 +146,10 @@
       const VirtualCardEnrollmentFields& virtual_card_enrollment_fields,
       base::OnceClosure accept_virtual_card_callback,
       base::OnceClosure decline_virtual_card_callback) override;
+  void ShowMandatoryReauthOptInPrompt(
+      base::OnceClosure accept_mandatory_reauth_callback,
+      base::OnceClosure cancel_mandatory_reauth_callback,
+      base::RepeatingClosure close_mandatory_reauth_callback) override;
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
   void HideVirtualCardEnrollBubbleAndIconIfVisible() override;
 #endif
diff --git a/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h
new file mode 100644
index 0000000..eb51c75
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_H_
+
+#include <string>
+
+#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_ui.h"
+#include "components/autofill/core/browser/ui/payments/payments_bubble_closed_reasons.h"
+#include "content/public/browser/web_contents.h"
+
+namespace autofill {
+
+class AutofillBubbleBase;
+
+// Interface that exposes controller functionality to autofill mandatory
+// reauthentication bubbles.
+class MandatoryReauthBubbleController {
+ public:
+  MandatoryReauthBubbleController() = default;
+  MandatoryReauthBubbleController(const MandatoryReauthBubbleController&) =
+      delete;
+  MandatoryReauthBubbleController& operator=(
+      const MandatoryReauthBubbleController&) = delete;
+  virtual ~MandatoryReauthBubbleController() = default;
+
+  virtual std::u16string GetWindowTitle() const = 0;
+  virtual std::u16string GetAcceptButtonText() const = 0;
+  virtual std::u16string GetCancelButtonText() const = 0;
+  virtual std::u16string GetExplanationText() const = 0;
+
+  virtual void OnAcceptButton() = 0;
+  virtual void OnCancelButton() = 0;
+  virtual void OnBubbleClosed(PaymentsBubbleClosedReason closed_reason) = 0;
+
+  // Returns the current bubble view. Can return nullptr if bubble is not
+  // visible.
+  virtual AutofillBubbleBase* GetBubbleView() = 0;
+
+  // Determines if the page action icon should be shown.
+  virtual bool IsIconVisible() = 0;
+
+  // The type of bubble currently displayed to the user.
+  virtual MandatoryReauthBubbleType GetBubbleType() const = 0;
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.cc
new file mode 100644
index 0000000..d58995d
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.cc
@@ -0,0 +1,139 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
+
+#include <string>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/page_action/page_action_icon_type.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#endif  // !BUILDFLAG(IS_ANDROID)
+
+namespace autofill {
+
+MandatoryReauthBubbleControllerImpl::MandatoryReauthBubbleControllerImpl(
+    content::WebContents* web_contents)
+    : AutofillBubbleControllerBase(web_contents),
+      content::WebContentsUserData<MandatoryReauthBubbleControllerImpl>(
+          *web_contents) {}
+
+MandatoryReauthBubbleControllerImpl::~MandatoryReauthBubbleControllerImpl() =
+    default;
+
+void MandatoryReauthBubbleControllerImpl::ShowBubble(
+    base::OnceClosure accept_mandatory_reauth_callback,
+    base::OnceClosure cancel_mandatory_reauth_callback,
+    base::RepeatingClosure close_mandatory_reauth_callback) {
+  if (bubble_view()) {
+    return;
+  }
+
+  accept_mandatory_reauth_callback_ =
+      std::move(accept_mandatory_reauth_callback);
+  cancel_mandatory_reauth_callback_ =
+      std::move(cancel_mandatory_reauth_callback);
+  close_mandatory_reauth_callback_ = std::move(close_mandatory_reauth_callback);
+  current_bubble_type_ = MandatoryReauthBubbleType::kOptIn;
+
+  Show();
+}
+
+void MandatoryReauthBubbleControllerImpl::ReshowBubble() {
+  // Don't show the bubble if it's already visible.
+  if (bubble_view()) {
+    return;
+  }
+
+  CHECK(accept_mandatory_reauth_callback_ &&
+        cancel_mandatory_reauth_callback_ && close_mandatory_reauth_callback_);
+
+  Show();
+}
+
+std::u16string MandatoryReauthBubbleControllerImpl::GetWindowTitle() const {
+  return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_TITLE);
+}
+
+std::u16string MandatoryReauthBubbleControllerImpl::GetAcceptButtonText()
+    const {
+  return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_ACCEPT);
+}
+
+std::u16string MandatoryReauthBubbleControllerImpl::GetCancelButtonText()
+    const {
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_NO_THANKS);
+}
+
+std::u16string MandatoryReauthBubbleControllerImpl::GetExplanationText() const {
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_EXPLANATION);
+}
+
+void MandatoryReauthBubbleControllerImpl::OnAcceptButton() {
+  std::move(accept_mandatory_reauth_callback_).Run();
+}
+
+void MandatoryReauthBubbleControllerImpl::OnCancelButton() {
+  std::move(cancel_mandatory_reauth_callback_).Run();
+}
+
+void MandatoryReauthBubbleControllerImpl::OnBubbleClosed(
+    PaymentsBubbleClosedReason closed_reason) {
+  set_bubble_view(nullptr);
+
+  if (closed_reason == PaymentsBubbleClosedReason::kCancelled ||
+      closed_reason == PaymentsBubbleClosedReason::kAccepted) {
+    // If the user explicitly cancelled or accepted the dialog, we don't want to
+    // display it anymore so we set it to inactive.
+    current_bubble_type_ = MandatoryReauthBubbleType::kInactive;
+  } else {
+    close_mandatory_reauth_callback_.Run();
+  }
+
+  UpdatePageActionIcon();
+}
+
+AutofillBubbleBase* MandatoryReauthBubbleControllerImpl::GetBubbleView() {
+  return bubble_view();
+}
+
+bool MandatoryReauthBubbleControllerImpl::IsIconVisible() {
+  return current_bubble_type_ != MandatoryReauthBubbleType::kInactive;
+}
+
+MandatoryReauthBubbleType MandatoryReauthBubbleControllerImpl::GetBubbleType()
+    const {
+  return current_bubble_type_;
+}
+
+PageActionIconType
+MandatoryReauthBubbleControllerImpl::GetPageActionIconType() {
+  return PageActionIconType::kMandatoryReauth;
+}
+
+void MandatoryReauthBubbleControllerImpl::DoShowBubble() {
+#if !BUILDFLAG(IS_ANDROID)
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
+  AutofillBubbleHandler* autofill_bubble_handler =
+      browser->window()->GetAutofillBubbleHandler();
+  set_bubble_view(autofill_bubble_handler->ShowMandatoryReauthBubble(
+      web_contents(), this, /*is_user_gesture=*/false));
+#endif  // !BUILDFLAG(IS_ANDROID)
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(MandatoryReauthBubbleControllerImpl);
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h
new file mode 100644
index 0000000..b568a98
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h
@@ -0,0 +1,70 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_IMPL_H_
+#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_IMPL_H_
+
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace autofill {
+
+class MandatoryReauthBubbleControllerImpl
+    : public AutofillBubbleControllerBase,
+      public MandatoryReauthBubbleController,
+      public content::WebContentsUserData<MandatoryReauthBubbleControllerImpl> {
+ public:
+  MandatoryReauthBubbleControllerImpl(
+      const MandatoryReauthBubbleControllerImpl&) = delete;
+  MandatoryReauthBubbleControllerImpl& operator=(
+      const MandatoryReauthBubbleControllerImpl&) = delete;
+  ~MandatoryReauthBubbleControllerImpl() override;
+
+  void ShowBubble(base::OnceClosure accept_mandatory_reauth_callback,
+                  base::OnceClosure cancel_mandatory_reauth_callback,
+                  base::RepeatingClosure close_mandatory_reauth_callback);
+  void ReshowBubble();
+
+  // MandatoryReauthBubbleController:
+  std::u16string GetWindowTitle() const override;
+  std::u16string GetAcceptButtonText() const override;
+  std::u16string GetCancelButtonText() const override;
+  std::u16string GetExplanationText() const override;
+  void OnAcceptButton() override;
+  void OnCancelButton() override;
+  void OnBubbleClosed(PaymentsBubbleClosedReason closed_reason) override;
+  AutofillBubbleBase* GetBubbleView() override;
+  bool IsIconVisible() override;
+  MandatoryReauthBubbleType GetBubbleType() const override;
+
+ protected:
+  explicit MandatoryReauthBubbleControllerImpl(
+      content::WebContents* web_contents);
+
+  // AutofillBubbleControllerBase:
+  PageActionIconType GetPageActionIconType() override;
+  void DoShowBubble() override;
+
+ private:
+  friend class content::WebContentsUserData<
+      MandatoryReauthBubbleControllerImpl>;
+
+  base::OnceClosure accept_mandatory_reauth_callback_;
+  base::OnceClosure cancel_mandatory_reauth_callback_;
+  base::RepeatingClosure close_mandatory_reauth_callback_;
+
+  // The type of bubble currently displayed to the user.
+  MandatoryReauthBubbleType current_bubble_type_ =
+      MandatoryReauthBubbleType::kInactive;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_BUBBLE_CONTROLLER_IMPL_H_
diff --git a/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl_unittest.cc
new file mode 100644
index 0000000..061308a
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
+
+#include "base/functional/bind.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class TestMandatoryReauthBubbleControllerImpl
+    : public MandatoryReauthBubbleControllerImpl {
+ public:
+  static void CreateForTesting(content::WebContents* web_contents) {
+    web_contents->SetUserData(
+        UserDataKey(),
+        std::make_unique<TestMandatoryReauthBubbleControllerImpl>(
+            web_contents));
+  }
+
+  explicit TestMandatoryReauthBubbleControllerImpl(
+      content::WebContents* web_contents)
+      : MandatoryReauthBubbleControllerImpl(web_contents) {}
+};
+
+class MandatoryReauthBubbleControllerImplTest
+    : public BrowserWithTestWindowTest {
+ public:
+  MandatoryReauthBubbleControllerImplTest() = default;
+  MandatoryReauthBubbleControllerImplTest(
+      MandatoryReauthBubbleControllerImplTest&) = delete;
+  MandatoryReauthBubbleControllerImplTest& operator=(
+      MandatoryReauthBubbleControllerImplTest&) = delete;
+
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+    AddTab(browser(), GURL("about:blank"));
+    content::WebContents* web_contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    TestMandatoryReauthBubbleControllerImpl::CreateForTesting(web_contents);
+  }
+
+  void ShowBubble() {
+    controller()->ShowBubble(accept_callback.Get(), cancel_callback.Get(),
+                             close_callback.Get());
+  }
+
+  void ClickAcceptButton() {
+    controller()->OnAcceptButton();
+    controller()->OnBubbleClosed(PaymentsBubbleClosedReason::kAccepted);
+  }
+
+  void ClickCancelButton() {
+    controller()->OnCancelButton();
+    controller()->OnBubbleClosed(PaymentsBubbleClosedReason::kCancelled);
+  }
+
+  void CloseBubble() {
+    controller()->OnBubbleClosed(PaymentsBubbleClosedReason::kClosed);
+  }
+
+  base::MockOnceClosure accept_callback;
+  base::MockOnceClosure cancel_callback;
+  base::MockRepeatingClosure close_callback;
+
+ protected:
+  TestMandatoryReauthBubbleControllerImpl* controller() {
+    return static_cast<TestMandatoryReauthBubbleControllerImpl*>(
+        TestMandatoryReauthBubbleControllerImpl::FromWebContents(
+            browser()->tab_strip_model()->GetActiveWebContents()));
+  }
+
+ private:
+  base::WeakPtrFactory<MandatoryReauthBubbleControllerImplTest>
+      weak_ptr_factory_{this};
+};
+
+TEST_F(MandatoryReauthBubbleControllerImplTest,
+       SuccessfullyInvokesAcceptCallback) {
+  ShowBubble();
+  EXPECT_CALL(accept_callback, Run).Times(1);
+  ClickAcceptButton();
+}
+
+TEST_F(MandatoryReauthBubbleControllerImplTest,
+       SuccessfullyInvokesCancelCallback) {
+  ShowBubble();
+  EXPECT_CALL(cancel_callback, Run).Times(1);
+  ClickCancelButton();
+}
+
+TEST_F(MandatoryReauthBubbleControllerImplTest,
+       SuccessfullyInvokesCloseCallback) {
+  ShowBubble();
+  EXPECT_CALL(close_callback, Run).Times(1);
+  CloseBubble();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/mandatory_reauth_ui.h b/chrome/browser/ui/autofill/payments/mandatory_reauth_ui.h
new file mode 100644
index 0000000..18d9cca
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/mandatory_reauth_ui.h
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_UI_H_
+#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_UI_H_
+
+namespace autofill {
+
+// The type of Mandatory Reauth bubble to display.
+enum class MandatoryReauthBubbleType {
+  // There is no bubble to show anymore. This also indicates that the icon
+  // should not be visible.
+  kInactive = 0,
+
+  // Bubble prompting the user to enable mandatory reauth.
+  kOptIn = 1,
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_UI_H_
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
index 15de9139..d1f12e80 100644
--- a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
+++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
@@ -32,6 +32,16 @@
   return iban_bubble_view_.get();
 }
 
+AutofillBubbleBase* TestAutofillBubbleHandler::ShowMandatoryReauthBubble(
+    content::WebContents* web_contents,
+    MandatoryReauthBubbleController* controller,
+    bool is_user_gesture) {
+  if (!mandatory_reauth_bubble_view_) {
+    mandatory_reauth_bubble_view_ = std::make_unique<TestAutofillBubble>();
+  }
+  return mandatory_reauth_bubble_view_.get();
+}
+
 AutofillBubbleBase* TestAutofillBubbleHandler::ShowLocalCardMigrationBubble(
     content::WebContents* web_contents,
     LocalCardMigrationBubbleController* controller,
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
index f49cdd8e..016fb825 100644
--- a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
+++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
@@ -72,6 +72,10 @@
       content::WebContents* web_contents,
       VirtualCardEnrollBubbleController* controller,
       bool is_user_gesture) override;
+  AutofillBubbleBase* ShowMandatoryReauthBubble(
+      content::WebContents* web_contents,
+      MandatoryReauthBubbleController* controller,
+      bool is_user_gesture) override;
   void OnPasswordSaved() override;
 
  private:
@@ -85,6 +89,7 @@
   std::unique_ptr<TestAutofillBubble> edit_address_profile_bubble_view_;
   std::unique_ptr<TestAutofillBubble> virtual_card_manual_fallback_bubble_view_;
   std::unique_ptr<TestAutofillBubble> virtual_card_enroll_bubble_view_;
+  std::unique_ptr<TestAutofillBubble> mandatory_reauth_bubble_view_;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 759c1038c5..2c8636f 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -617,6 +617,9 @@
     case IDC_SAVE_IBAN_FOR_PAGE:
       SaveIBAN(browser_);
       break;
+    case IDC_AUTOFILL_MANDATORY_REAUTH:
+      ShowMandatoryReauthOptInPrompt(browser_);
+      break;
     case IDC_MIGRATE_LOCAL_CREDIT_CARD_FOR_PAGE:
       MigrateLocalCards(browser_);
       break;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index bc2f7b1..e0ba15a 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/ui/accelerator_utils.h"
 #include "chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/manage_migration_ui_controller.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.h"
@@ -1383,6 +1384,15 @@
   controller->ReshowBubble();
 }
 
+void ShowMandatoryReauthOptInPrompt(Browser* browser) {
+  WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  autofill::MandatoryReauthBubbleControllerImpl* controller =
+      autofill::MandatoryReauthBubbleControllerImpl::FromWebContents(
+          web_contents);
+  controller->ReshowBubble();
+}
+
 void MigrateLocalCards(Browser* browser) {
   WebContents* web_contents =
       browser->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h
index 6de12265..9862ab53 100644
--- a/chrome/browser/ui/browser_commands.h
+++ b/chrome/browser/ui/browser_commands.h
@@ -169,6 +169,7 @@
 void ShowOffersAndRewardsForPage(Browser* browser);
 void SaveCreditCard(Browser* browser);
 void SaveIBAN(Browser* browser);
+void ShowMandatoryReauthOptInPrompt(Browser* browser);
 void MigrateLocalCards(Browser* browser);
 void SaveAutofillAddress(Browser* browser);
 void ShowVirtualCardManualFallbackBubble(Browser* browser);
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index 3dfcf94a..75a96cc 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -345,6 +345,15 @@
   E_CPONLY(kColorSidePanelCardSecondaryForeground) \
   E_CPONLY(kColorSidePanelContentAreaSeparator) \
   E_CPONLY(kColorSidePanelContentBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeColorPickerCheckmarkBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeColorPickerCheckmarkForeground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeColorPickerOptionBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeCustomOptionBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeCustomOptionForeground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeThemeBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeThemeCheckmarkBackground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeThemeCheckmarkForeground) \
+  E_CPONLY(kColorSidePanelCustomizeChromeWebStoreOptionBorder) \
   E_CPONLY(kColorSidePanelDivider) \
   E_CPONLY(kColorSidePanelEditFooterBorder) \
   E_CPONLY(kColorSidePanelFilterChipBorder) \
diff --git a/chrome/browser/ui/color/material_side_panel_color_mixer.cc b/chrome/browser/ui/color/material_side_panel_color_mixer.cc
index a701482..fb74500 100644
--- a/chrome/browser/ui/color/material_side_panel_color_mixer.cc
+++ b/chrome/browser/ui/color/material_side_panel_color_mixer.cc
@@ -45,4 +45,24 @@
   mixer[kColorSidePanelTextfieldBackgroundHover] = {
       ui::kColorSysStateHoverOnSubtle};
   mixer[kColorSidePanelTextfieldBorder] = {ui::kColorSysNeutralOutline};
+
+  /* Customize Chrome */
+  mixer[kColorSidePanelCustomizeChromeColorPickerCheckmarkBackground] = {
+      ui::kColorSysOnSurface};
+  mixer[kColorSidePanelCustomizeChromeColorPickerCheckmarkForeground] = {
+      ui::kColorSysInverseOnSurface};
+  mixer[kColorSidePanelCustomizeChromeColorPickerOptionBackground] = {
+      ui::kColorSysNeutralContainer};
+  mixer[kColorSidePanelCustomizeChromeCustomOptionBackground] = {
+      ui::kColorSysTertiaryContainer};
+  mixer[kColorSidePanelCustomizeChromeCustomOptionForeground] = {
+      ui::kColorSysOnTertiaryContainer};
+  mixer[kColorSidePanelCustomizeChromeThemeBackground] = {
+      ui::kColorSysBaseContainerElevated};
+  mixer[kColorSidePanelCustomizeChromeThemeCheckmarkBackground] = {
+      ui::kColorSysPrimary};
+  mixer[kColorSidePanelCustomizeChromeThemeCheckmarkForeground] = {
+      ui::kColorSysOnPrimary};
+  mixer[kColorSidePanelCustomizeChromeWebStoreOptionBorder] = {
+      ui::kColorSysNeutralOutline};
 }
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service.cc b/chrome/browser/ui/global_media_controls/media_notification_service.cc
index 0df87d7..c28edd3 100644
--- a/chrome/browser/ui/global_media_controls/media_notification_service.cc
+++ b/chrome/browser/ui/global_media_controls/media_notification_service.cc
@@ -142,11 +142,15 @@
   if (!media_router::MediaRouterEnabled(profile)) {
     return;
   }
-  // base::Unretained() is safe here because cast_notification_producer_ is
-  // deleted before item_manager_.
+  // CastMediaNotificationProducer is owned by
+  // CastMediaNotificationProducerKeyedService in Ash.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+  // base::Unretained() is safe here because `cast_notification_producer_` is
+  // deleted before `item_manager_`.
   cast_notification_producer_ = std::make_unique<CastMediaNotificationProducer>(
       profile, item_manager_.get());
   item_manager_->AddItemProducer(cast_notification_producer_.get());
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (media_router::GlobalMediaControlsCastStartStopEnabled(profile)) {
     presentation_request_notification_producer_ =
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc
index 3d53ebee..ebdec2f8 100644
--- a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc
@@ -333,6 +333,9 @@
   base::MockCallback<base::OnceClosure> receiver_disconnect_handler_;
 };
 
+// CastMediaNotificationProducer is owned by
+// CastMediaNotificationProducerKeyedService in Ash.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(MediaNotificationServiceCastTest,
        ShowCastSessionsForPresentationRequest) {
   NiceMock<global_media_controls::test::MockMediaDialogDelegate>
@@ -371,6 +374,7 @@
   testing::Mock::VerifyAndClearExpectations(&dialog_delegate);
   SimulateCloseDialog();
 }
+#endif
 
 TEST_F(MediaNotificationServiceCastTest, ShowMediaItemsForPresentationRequest) {
   std::unique_ptr<content::WebContents> web_contents_1(
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc
index b5bc899b..1928f75 100644
--- a/chrome/browser/ui/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.cc
@@ -116,7 +116,8 @@
         return touch_ui ? 12 : 8;
       }
     case PAGE_INFO_ICON_SIZE:
-      return 16;
+      return base::FeatureList::IsEnabled(features::kChromeRefresh2023) ? 20
+                                                                        : 16;
     case DOWNLOAD_ICON_SIZE:
       return 16;
     case TOOLBAR_CORNER_RADIUS:
diff --git a/chrome/browser/ui/page_action/page_action_icon_type.h b/chrome/browser/ui/page_action/page_action_icon_type.h
index b77a9d3..6c1c80e 100644
--- a/chrome/browser/ui/page_action/page_action_icon_type.h
+++ b/chrome/browser/ui/page_action/page_action_icon_type.h
@@ -35,7 +35,8 @@
   kVirtualCardManualFallback,
   kZoom,
   kSaveIban,
-  kMaxValue = kSaveIban,
+  kMandatoryReauth,
+  kMaxValue = kMandatoryReauth,
 };
 
 static_assert(static_cast<int>(PageActionIconType::kBookmarkStar) == 0);
@@ -65,4 +66,5 @@
     static_cast<int>(PageActionIconType::kVirtualCardManualFallback) == 22);
 static_assert(static_cast<int>(PageActionIconType::kZoom) == 23);
 static_assert(static_cast<int>(PageActionIconType::kSaveIban) == 24);
+static_assert(static_cast<int>(PageActionIconType::kMandatoryReauth) == 25);
 #endif  // CHROME_BROWSER_UI_PAGE_ACTION_PAGE_ACTION_ICON_TYPE_H_
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.cc b/chrome/browser/ui/passwords/manage_passwords_test.cc
index fe12b2b..fb737824 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_test.cc
@@ -210,14 +210,11 @@
 
   if (is_enabled) {
     sync_service->SetHasSyncConsent(true);
-    sync_service->SetDisableReasons({});
     sync_service->GetUserSettings()->SetSelectedTypes(
         /*sync_everything=*/false,
         /*types=*/{syncer::UserSelectableType::kPasswords});
   } else {
     sync_service->SetHasSyncConsent(false);
-    sync_service->SetDisableReasons(
-        {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
     sync_service->GetUserSettings()->SetSelectedTypes(
         /*sync_everything=*/false,
         /*types=*/syncer::UserSelectableTypeSet());
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
index 0d14598..c419711 100644
--- a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
+++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/manage_saved_iban_bubble_view.h"
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h"
 #include "chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/payments/offer_notification_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
@@ -307,6 +308,29 @@
   return bubble;
 }
 
+AutofillBubbleBase* AutofillBubbleHandlerImpl::ShowMandatoryReauthBubble(
+    content::WebContents* web_contents,
+    MandatoryReauthBubbleController* controller,
+    bool is_user_gesture) {
+  PageActionIconView* icon_view =
+      toolbar_button_provider_->GetPageActionIconView(
+          PageActionIconType::kMandatoryReauth);
+  DCHECK(icon_view);
+  views::View* anchor_view = toolbar_button_provider_->GetAnchorView(
+      PageActionIconType::kMandatoryReauth);
+
+  MandatoryReauthOptInBubbleView* bubble =
+      new MandatoryReauthOptInBubbleView(anchor_view, web_contents, controller);
+
+  DCHECK(bubble);
+  bubble->SetHighlightedButton(icon_view);
+
+  views::BubbleDialogDelegateView::CreateBubble(bubble);
+  bubble->Show(is_user_gesture ? LocationBarBubbleDelegateView::USER_GESTURE
+                               : LocationBarBubbleDelegateView::AUTOMATIC);
+  return bubble;
+}
+
 void AutofillBubbleHandlerImpl::OnPasswordSaved() {}
 
 void AutofillBubbleHandlerImpl::OnCreditCardSaved(
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
index 5458fc5..8c7d350 100644
--- a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
+++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
@@ -80,6 +80,10 @@
       content::WebContents* web_contents,
       VirtualCardEnrollBubbleController* controller,
       bool is_user_gesture) override;
+  AutofillBubbleBase* ShowMandatoryReauthBubble(
+      content::WebContents* web_contents,
+      MandatoryReauthBubbleController* controller,
+      bool is_user_gesture) override;
 
   void OnPasswordSaved() override;
 
diff --git a/chrome/browser/ui/views/autofill/payments/mandatory_reauth_bubble_view_uitest.cc b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_bubble_view_uitest.cc
new file mode 100644
index 0000000..614555e
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_bubble_view_uitest.cc
@@ -0,0 +1,137 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h"
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "content/public/test/browser_test.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/views/test/widget_test.h"
+
+namespace autofill {
+
+class MandatoryReauthBubbleViewUiTest : public InProcessBrowserTest {
+ public:
+  MandatoryReauthBubbleViewUiTest() = default;
+  ~MandatoryReauthBubbleViewUiTest() override = default;
+  MandatoryReauthBubbleViewUiTest(const MandatoryReauthBubbleViewUiTest&) =
+      delete;
+  MandatoryReauthBubbleViewUiTest& operator=(
+      const MandatoryReauthBubbleViewUiTest&) = delete;
+
+  // InProcessBrowserTest:
+  void SetUpOnMainThread() override {
+    auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+    MandatoryReauthBubbleControllerImpl::CreateForWebContents(web_contents);
+    MandatoryReauthBubbleControllerImpl* controller = GetController();
+    DCHECK(controller);
+  }
+
+  void ShowBubble() {
+    MandatoryReauthBubbleControllerImpl* controller = GetController();
+    controller->ShowBubble(base::DoNothing(), base::DoNothing(),
+                           base::DoNothing());
+    views::test::WidgetVisibleWaiter visible_waiter(
+        static_cast<MandatoryReauthOptInBubbleView*>(
+            controller->GetBubbleView())
+            ->GetWidget());
+    visible_waiter.Wait();
+  }
+
+  bool IsIconVisible() { return GetIconView() && GetIconView()->GetVisible(); }
+
+  MandatoryReauthBubbleControllerImpl* GetController() {
+    if (!browser() || !browser()->tab_strip_model() ||
+        !browser()->tab_strip_model()->GetActiveWebContents()) {
+      return nullptr;
+    }
+
+    return MandatoryReauthBubbleControllerImpl::FromWebContents(
+        browser()->tab_strip_model()->GetActiveWebContents());
+  }
+
+  views::BubbleDialogDelegate* GetOptInBubble() {
+    return GetIconView()->GetBubble();
+  }
+
+  MandatoryReauthIconView* GetIconView() {
+    BrowserView* browser_view =
+        BrowserView::GetBrowserViewForBrowser(browser());
+    PageActionIconView* icon =
+        browser_view->toolbar_button_provider()->GetPageActionIconView(
+            PageActionIconType::kMandatoryReauth);
+    DCHECK(icon);
+    return static_cast<MandatoryReauthIconView*>(icon);
+  }
+
+  void ClickOnView(views::View* view) {
+    ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                           ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                           ui::EF_LEFT_MOUSE_BUTTON);
+    view->OnMousePressed(pressed);
+    ui::MouseEvent released_event =
+        ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_LEFT_MOUSE_BUTTON);
+    view->OnMouseReleased(released_event);
+  }
+
+  void ClickOnViewAndWait(
+      views::View* view,
+      views::BubbleDialogDelegate* mandatory_reauth_bubble) {
+    views::test::WidgetDestroyedWaiter destroyed_waiter(
+        mandatory_reauth_bubble->GetWidget());
+    mandatory_reauth_bubble->ResetViewShownTimeStampForTesting();
+    views::BubbleFrameView* bubble_frame_view =
+        static_cast<views::BubbleFrameView*>(
+            mandatory_reauth_bubble->GetWidget()
+                ->non_client_view()
+                ->frame_view());
+    bubble_frame_view->ResetViewShownTimeStampForTesting();
+    ClickOnView(view);
+    destroyed_waiter.Wait();
+  }
+
+  void ClickOnOkButton(views::BubbleDialogDelegate* mandatory_reauth_bubble) {
+    views::View* ok_button = mandatory_reauth_bubble->GetOkButton();
+    ClickOnViewAndWait(ok_button, mandatory_reauth_bubble);
+  }
+
+  void ClickOnCancelButton(
+      views::BubbleDialogDelegate* mandatory_reauth_bubble) {
+    views::View* cancel_button = mandatory_reauth_bubble->GetCancelButton();
+    ClickOnViewAndWait(cancel_button, mandatory_reauth_bubble);
+  }
+
+ protected:
+  test::AutofillBrowserTestEnvironment autofill_test_environment_;
+};
+
+IN_PROC_BROWSER_TEST_F(MandatoryReauthBubbleViewUiTest, ShowBubble) {
+  ShowBubble();
+  EXPECT_TRUE(GetOptInBubble());
+  EXPECT_TRUE(IsIconVisible());
+}
+
+IN_PROC_BROWSER_TEST_F(MandatoryReauthBubbleViewUiTest,
+                       ClickOptInCancelButton) {
+  ShowBubble();
+  ClickOnCancelButton(GetOptInBubble());
+  EXPECT_FALSE(GetOptInBubble());
+  EXPECT_FALSE(IsIconVisible());
+}
+
+IN_PROC_BROWSER_TEST_F(MandatoryReauthBubbleViewUiTest, ClickOptInOkButton) {
+  ShowBubble();
+  ClickOnOkButton(GetOptInBubble());
+  EXPECT_FALSE(GetOptInBubble());
+  EXPECT_FALSE(IsIconVisible());
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.cc b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.cc
new file mode 100644
index 0000000..797d726
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.cc
@@ -0,0 +1,81 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h"
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl.h"
+#include "chrome/browser/ui/browser_command_controller.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/gfx/paint_vector_icon.h"
+
+namespace autofill {
+
+MandatoryReauthIconView::MandatoryReauthIconView(
+    CommandUpdater* command_updater,
+    IconLabelBubbleView::Delegate* icon_label_bubble_delegate,
+    PageActionIconView::Delegate* delegate)
+    : PageActionIconView(command_updater,
+                         IDC_AUTOFILL_MANDATORY_REAUTH,
+                         icon_label_bubble_delegate,
+                         delegate,
+                         "MandatoryReauth") {
+  SetAccessibilityProperties(
+      /*role=*/absl::nullopt,
+      l10n_util::GetStringUTF16(IDS_AUTOFILL_MANDATORY_REAUTH_ICON_TOOLTIP));
+}
+
+MandatoryReauthIconView::~MandatoryReauthIconView() = default;
+
+views::BubbleDialogDelegate* MandatoryReauthIconView::GetBubble() const {
+  MandatoryReauthBubbleController* controller = GetController();
+  if (!controller) {
+    return nullptr;
+  }
+
+  return static_cast<autofill::MandatoryReauthOptInBubbleView*>(
+      controller->GetBubbleView());
+}
+
+void MandatoryReauthIconView::UpdateImpl() {
+  if (!GetWebContents()) {
+    return;
+  }
+
+  // `controller` may be nullptr due to lazy initialization.
+  MandatoryReauthBubbleController* controller = GetController();
+  bool command_enabled = controller && controller->IsIconVisible();
+  SetVisible(SetCommandEnabled(command_enabled));
+}
+
+void MandatoryReauthIconView::OnExecuting(
+    PageActionIconView::ExecuteSource execute_source) {}
+
+const gfx::VectorIcon& MandatoryReauthIconView::GetVectorIcon() const {
+  return kCreditCardIcon;
+}
+
+MandatoryReauthBubbleController* MandatoryReauthIconView::GetController()
+    const {
+  content::WebContents* web_contents = GetWebContents();
+  if (!web_contents) {
+    return nullptr;
+  }
+
+  return MandatoryReauthBubbleControllerImpl::FromWebContents(web_contents);
+}
+
+BEGIN_METADATA(MandatoryReauthIconView, PageActionIconView)
+END_METADATA
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h
new file mode 100644
index 0000000..83aa1c90
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_ICON_VIEW_H_
+
+#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+
+class CommandUpdater;
+
+namespace autofill {
+
+class MandatoryReauthBubbleController;
+
+class MandatoryReauthIconView : public PageActionIconView {
+ public:
+  METADATA_HEADER(MandatoryReauthIconView);
+  MandatoryReauthIconView(
+      CommandUpdater* command_updater,
+      IconLabelBubbleView::Delegate* icon_label_bubble_delegate,
+      PageActionIconView::Delegate* page_action_icon_delegate);
+  MandatoryReauthIconView(const MandatoryReauthIconView&) = delete;
+  MandatoryReauthIconView& operator=(const MandatoryReauthIconView&) = delete;
+  ~MandatoryReauthIconView() override;
+
+  // PageActionIconView:
+  views::BubbleDialogDelegate* GetBubble() const override;
+  void UpdateImpl() override;
+
+ protected:
+  // PageActionIconView:
+  void OnExecuting(PageActionIconView::ExecuteSource execute_source) override;
+  const gfx::VectorIcon& GetVectorIcon() const override;
+
+ private:
+  MandatoryReauthBubbleController* GetController() const;
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.cc b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.cc
new file mode 100644
index 0000000..11cc495
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.cc
@@ -0,0 +1,104 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h"
+#include "chrome/browser/ui/views/accessibility/theme_tracking_non_accessible_image_view.h"
+#include "chrome/browser/ui/views/autofill/payments/dialog_view_ids.h"
+#include "chrome/browser/ui/views/autofill/payments/payments_view_util.h"
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/vector_icon_utils.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/view_class_properties.h"
+
+namespace autofill {
+
+MandatoryReauthOptInBubbleView::MandatoryReauthOptInBubbleView(
+    views::View* anchor_view,
+    content::WebContents* web_contents,
+    MandatoryReauthBubbleController* controller)
+    : LocationBarBubbleDelegateView(anchor_view, web_contents),
+      controller_(controller) {
+  SetButtonLabel(ui::DIALOG_BUTTON_OK, controller->GetAcceptButtonText());
+  SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, controller->GetCancelButtonText());
+  SetCancelCallback(
+      base::BindOnce(&MandatoryReauthOptInBubbleView::OnDialogCancelled,
+                     base::Unretained(this)));
+  SetAcceptCallback(
+      base::BindOnce(&MandatoryReauthOptInBubbleView::OnDialogAccepted,
+                     base::Unretained(this)));
+  SetShowCloseButton(true);
+  set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
+      views::DISTANCE_BUBBLE_PREFERRED_WIDTH));
+}
+
+void MandatoryReauthOptInBubbleView::Show(DisplayReason reason) {
+  ShowForReason(reason);
+}
+
+void MandatoryReauthOptInBubbleView::Hide() {
+  CloseBubble();
+  WindowClosing();
+  controller_ = nullptr;
+}
+
+void MandatoryReauthOptInBubbleView::AddedToWidget() {
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  auto* mandatory_reauth_opt_in_banner =
+      bundle.GetImageSkiaNamed(IDR_AUTOFILL_MANDATORY_REAUTH_OPT_IN);
+  GetBubbleFrameView()->SetHeaderView(
+      std::make_unique<ThemeTrackingNonAccessibleImageView>(
+          *mandatory_reauth_opt_in_banner, *mandatory_reauth_opt_in_banner,
+          base::BindRepeating(&views::BubbleDialogDelegate::GetBackgroundColor,
+                              base::Unretained(this))));
+}
+
+std::u16string MandatoryReauthOptInBubbleView::GetWindowTitle() const {
+  return controller_ ? controller_->GetWindowTitle() : std::u16string();
+}
+
+void MandatoryReauthOptInBubbleView::WindowClosing() {
+  if (controller_) {
+    controller_->OnBubbleClosed(
+        GetPaymentsBubbleClosedReasonFromWidget(GetWidget()));
+    controller_ = nullptr;
+  }
+}
+
+MandatoryReauthOptInBubbleView::~MandatoryReauthOptInBubbleView() = default;
+
+void MandatoryReauthOptInBubbleView::OnDialogAccepted() {
+  if (controller_) {
+    controller_->OnAcceptButton();
+  }
+}
+
+void MandatoryReauthOptInBubbleView::OnDialogCancelled() {
+  if (controller_) {
+    controller_->OnCancelButton();
+  }
+}
+
+void MandatoryReauthOptInBubbleView::Init() {
+  SetID(DialogViewId::MAIN_CONTENT_VIEW_LOCAL);
+  SetProperty(views::kMarginsKey, gfx::Insets());
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+  AddChildView(views::Builder<views::Label>()
+                   .SetText(controller_->GetExplanationText())
+                   .SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT)
+                   .SetTextStyle(views::style::STYLE_SECONDARY)
+                   .SetMultiLine(true)
+                   .SetHorizontalAlignment(gfx::ALIGN_LEFT)
+                   .Build());
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h
new file mode 100644
index 0000000..dfca64fa
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/mandatory_reauth_opt_in_bubble_view.h
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_OPT_IN_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_OPT_IN_BUBBLE_VIEW_H_
+
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
+#include "chrome/browser/ui/autofill/payments/mandatory_reauth_bubble_controller.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
+
+namespace autofill {
+
+class MandatoryReauthOptInBubbleView : public AutofillBubbleBase,
+                                       public LocationBarBubbleDelegateView {
+ public:
+  MandatoryReauthOptInBubbleView(views::View* anchor_view,
+                                 content::WebContents* web_contents,
+                                 MandatoryReauthBubbleController* controller);
+  MandatoryReauthOptInBubbleView(const MandatoryReauthOptInBubbleView&) =
+      delete;
+  MandatoryReauthOptInBubbleView& operator=(
+      const MandatoryReauthOptInBubbleView&) = delete;
+
+  void Show(DisplayReason reason);
+
+  // AutofillBubbleBase:
+  void Hide() override;
+
+  // LocationBarBubbleDelegateView:
+  void AddedToWidget() override;
+  std::u16string GetWindowTitle() const override;
+  void WindowClosing() override;
+
+ protected:
+  ~MandatoryReauthOptInBubbleView() override;
+
+  void OnDialogAccepted();
+  void OnDialogCancelled();
+
+  // LocationBarBubbleDelegateView:
+  void Init() override;
+
+ private:
+  raw_ptr<MandatoryReauthBubbleController> controller_;
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_MANDATORY_REAUTH_OPT_IN_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/chrome_layout_provider.cc b/chrome/browser/ui/views/chrome_layout_provider.cc
index 89fea02..54c5b1c 100644
--- a/chrome/browser/ui/views/chrome_layout_provider.cc
+++ b/chrome/browser/ui/views/chrome_layout_provider.cc
@@ -88,7 +88,9 @@
       const gfx::Insets insets =
           LayoutProvider::GetInsetsMetric(views::INSETS_LABEL_BUTTON);
       const int horizontal_padding =
-          GetDistanceMetric(views::DISTANCE_BUTTON_HORIZONTAL_PADDING);
+          features::IsChromeRefresh2023()
+              ? 20
+              : GetDistanceMetric(views::DISTANCE_BUTTON_HORIZONTAL_PADDING);
       // Hover button in page info requires double the height compared to the
       // label button because it behaves like a menu control.
       return gfx::Insets::VH(insets.height(), horizontal_padding);
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 532460701..347b221d 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -981,7 +981,7 @@
 // static
 std::unique_ptr<DesktopMediaPicker> DesktopMediaPicker::Create(
     const content::MediaStreamRequest* request) {
-  if (base::FeatureList::IsEnabled(media::kShareThisTabDialog) &&
+  if (base::FeatureList::IsEnabled(media::kShareThisTabDialog) && request &&
       request->video_type ==
           blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB) {
     return std::make_unique<ShareThisTabDialogViews>();
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_security_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_security_view.cc
index 7d907a0..bbcf455 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_security_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_security_view.cc
@@ -8,6 +8,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
 #include "chrome/browser/download/bubble/download_bubble_ui_controller.h"
+#include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/download_item_warning_data.h"
 #include "chrome/browser/download/download_ui_model.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/ui/views/download/bubble/download_bubble_row_view.h"
 #include "chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/download/public/common/download_danger_type.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -51,6 +53,7 @@
   kMaxValue = kPressedPrimaryButton
 };
 const char kSubpageActionHistogram[] = "Download.Bubble.SubpageAction";
+
 }  // namespace
 
 void DownloadBubbleSecurityView::AddHeader() {
@@ -161,6 +164,29 @@
     checkbox_->SetChecked(false);
     checkbox_->SetText(ui_info.checkbox_label);
   }
+
+  if (model_->GetDangerType() ==
+      download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING) {
+    size_t link_offset;
+    std::u16string link_text = l10n_util::GetStringUTF16(
+        IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK);
+    std::u16string link_label_text = l10n_util::GetStringFUTF16(
+        IDS_DOWNLOAD_BUBBLE_SUBPAGE_DEEP_SCANNING_LINK_WRAPPER, link_text,
+        &link_offset);
+    deep_scanning_link_->SetText(link_label_text);
+
+    gfx::Range link_range(link_offset, link_offset + link_text.length());
+    views::StyledLabel::RangeStyleInfo link_style =
+        views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating(
+            &DownloadBubbleUIController::ProcessDownloadButtonPress,
+            bubble_controller_, model_.get(),
+            DownloadCommands::LEARN_MORE_SCANNING, /*is_main_view=*/false));
+    deep_scanning_link_->AddStyleRange(link_range, link_style);
+    deep_scanning_link_->SetVisible(true);
+    deep_scanning_link_->SizeToFit(min_label_width);
+  } else {
+    deep_scanning_link_->SetVisible(false);
+  }
 }
 
 void DownloadBubbleSecurityView::AddIconAndText() {
@@ -221,6 +247,11 @@
                                /*adjust_height_for_width=*/true));
   // Set min height for checkbox, so that it can layout label accordingly.
   checkbox_->SetMinSize(gfx::Size(0, kCheckboxHeight));
+
+  deep_scanning_link_ =
+      wrapper->AddChildView(std::make_unique<views::StyledLabel>());
+  deep_scanning_link_->SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT);
+  deep_scanning_link_->SetDefaultTextStyle(views::style::STYLE_SECONDARY);
 }
 
 void DownloadBubbleSecurityView::ProcessButtonClick(
@@ -245,8 +276,7 @@
 void DownloadBubbleSecurityView::UpdateButton(
     DownloadUIModel::BubbleUIInfo::SubpageButton button_info,
     bool is_secondary_button,
-    bool has_checkbox,
-    ui::ColorId color_id) {
+    bool has_checkbox) {
   ui::DialogButton button_type =
       is_secondary_button ? ui::DIALOG_BUTTON_CANCEL : ui::DIALOG_BUTTON_OK;
 
@@ -258,7 +288,9 @@
     bubble_delegate_->SetCancelCallback(std::move(callback));
     bubble_delegate_->SetButtonEnabled(button_type, !has_checkbox);
     views::LabelButton* button = bubble_delegate_->GetCancelButton();
-    button->SetEnabledTextColorIds(color_id);
+    if (button_info.color) {
+      button->SetEnabledTextColorIds(*button_info.color);
+    }
     secondary_button_ = button;
   } else {
     bubble_delegate_->SetAcceptCallback(std::move(callback));
@@ -284,14 +316,14 @@
   if (ui_info.subpage_buttons.size() > 0) {
     bubble_delegate_->SetButtons(ui::DIALOG_BUTTON_OK);
     UpdateButton(ui_info.subpage_buttons[0], /*is_secondary_button=*/false,
-                 ui_info.has_checkbox, ui_info.GetColorForSecondaryText());
+                 ui_info.has_checkbox);
   }
 
   if (ui_info.subpage_buttons.size() > 1) {
     bubble_delegate_->SetButtons(ui::DIALOG_BUTTON_OK |
                                  ui::DIALOG_BUTTON_CANCEL);
     UpdateButton(ui_info.subpage_buttons[1], /*is_secondary_button=*/true,
-                 ui_info.has_checkbox, ui_info.GetColorForSecondaryText());
+                 ui_info.has_checkbox);
   }
 }
 
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_security_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_security_view.h
index 156fdfb..30a3909 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_security_view.h
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_security_view.h
@@ -62,8 +62,7 @@
   // state, if it is a secondary button.
   void UpdateButton(DownloadUIModel::BubbleUIInfo::SubpageButton button,
                     bool is_secondary_button,
-                    bool has_checkbox,
-                    ui::ColorId color_id);
+                    bool has_checkbox);
   void UpdateButtons();
 
   // |is_secondary_button| checks if the command/action originated from the
@@ -85,6 +84,7 @@
   raw_ptr<views::ImageView> icon_ = nullptr;
   raw_ptr<views::StyledLabel> styled_label_ = nullptr;
   raw_ptr<views::ImageButton> back_button_ = nullptr;
+  raw_ptr<views::StyledLabel> deep_scanning_link_ = nullptr;
   absl::optional<base::Time> warning_time_;
   bool did_log_action_ = false;
 };
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc
index d72e2ec..0d7b590 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc
@@ -21,6 +21,7 @@
 #include "content/public/test/mock_download_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/color/color_id.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/vector_icons.h"
 #include "ui/views/view.h"
@@ -137,43 +138,47 @@
           .AddIconAndColor(views::kInfoIcon, ui::kColorAlertHighSeverity)
           .AddPrimaryButton(DownloadCommands::Command::KEEP)
           // OK button
-          .AddSubpageButton(std::u16string(),
-                            DownloadCommands::Command::DISCARD,
-                            /*is_prominent=*/true)
+          .AddPrimarySubpageButton(std::u16string(),
+                                   DownloadCommands::Command::DISCARD)
           // Cancel button
-          .AddSubpageButton(std::u16string(), DownloadCommands::Command::KEEP,
-                            /*is_prominent=*/false));
+          .AddSecondarySubpageButton(std::u16string(),
+                                     DownloadCommands::Command::KEEP,
+                                     ui::kColorAlertHighSeverity));
   security_view_->UpdateSecurityView(row_view_.get());
   EXPECT_EQ(bubble_delegate_->GetDialogButtons(),
             ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
   EXPECT_EQ(bubble_delegate_->GetDefaultDialogButton(), ui::DIALOG_BUTTON_OK);
 
   // Two buttons, none prominent
-  row_view_->SetUIInfoForTesting(
+  DownloadUIModel::BubbleUIInfo info =
       DownloadUIModel::BubbleUIInfo(std::u16string())
           .AddIconAndColor(views::kInfoIcon, ui::kColorAlertHighSeverity)
           .AddPrimaryButton(DownloadCommands::Command::KEEP)
           // OK button
-          .AddSubpageButton(std::u16string(),
-                            DownloadCommands::Command::DISCARD,
-                            /*is_prominent=*/false)
+          .AddPrimarySubpageButton(std::u16string(),
+                                   DownloadCommands::Command::DISCARD)
           // Cancel button
-          .AddSubpageButton(std::u16string(), DownloadCommands::Command::KEEP,
-                            /*is_prominent=*/false));
+          .AddSecondarySubpageButton(std::u16string(),
+                                     DownloadCommands::Command::KEEP,
+                                     ui::kColorAlertHighSeverity);
+  info.subpage_buttons[0].is_prominent = false;  // Primary buttons are
+                                                 // prominent by default.
+  row_view_->SetUIInfoForTesting(std::move(info));
   security_view_->UpdateSecurityView(row_view_.get());
   EXPECT_EQ(bubble_delegate_->GetDialogButtons(),
             ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
   EXPECT_EQ(bubble_delegate_->GetDefaultDialogButton(), ui::DIALOG_BUTTON_NONE);
 
   // One button, none prominent
-  row_view_->SetUIInfoForTesting(
-      DownloadUIModel::BubbleUIInfo(std::u16string())
-          .AddIconAndColor(views::kInfoIcon, ui::kColorAlertHighSeverity)
-          .AddPrimaryButton(DownloadCommands::Command::KEEP)
-          // OK button
-          .AddSubpageButton(std::u16string(),
-                            DownloadCommands::Command::DISCARD,
-                            /*is_prominent=*/false));
+  info = DownloadUIModel::BubbleUIInfo(std::u16string())
+             .AddIconAndColor(views::kInfoIcon, ui::kColorAlertHighSeverity)
+             .AddPrimaryButton(DownloadCommands::Command::KEEP)
+             // OK button
+             .AddPrimarySubpageButton(std::u16string(),
+                                      DownloadCommands::Command::DISCARD);
+  info.subpage_buttons[0].is_prominent = false;  // Primary buttons are
+                                                 // prominent by default.
+  row_view_->SetUIInfoForTesting(std::move(info));
   security_view_->UpdateSecurityView(row_view_.get());
   EXPECT_EQ(bubble_delegate_->GetDialogButtons(), ui::DIALOG_BUTTON_OK);
   EXPECT_EQ(bubble_delegate_->GetDefaultDialogButton(), ui::DIALOG_BUTTON_NONE);
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_handler.h b/chrome/browser/ui/views/extensions/extensions_menu_handler.h
index f8814e67..f98b930 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_handler.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_handler.h
@@ -7,6 +7,7 @@
 
 #include "extensions/browser/permissions_manager.h"
 #include "extensions/common/extension_id.h"
+#include "ui/views/controls/button/toggle_button.h"
 
 // An interface that provides callbacks to the extensions menu pages.
 class ExtensionsMenuHandler {
@@ -28,6 +29,11 @@
   virtual void OnSiteAccessSelected(
       extensions::ExtensionId extension_id,
       extensions::PermissionsManager::UserSiteAccess site_access) = 0;
+
+  // Grants or withhelds site access for `extension_id` depending on
+  // `site_access_toggle`.
+  virtual void OnExtensionToggleSelected(extensions::ExtensionId extension_id,
+                                         bool is_on) = 0;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_MENU_HANDLER_H_
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
index a649023a..74ea329c 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
@@ -173,7 +173,7 @@
 ExtensionMenuItemView::ExtensionMenuItemView(
     Browser* browser,
     std::unique_ptr<ToolbarActionViewController> controller,
-    views::Button::PressedCallback site_access_toggle_callback,
+    base::RepeatingCallback<void(bool)> site_access_toggle_callback,
     views::Button::PressedCallback site_permissions_button_callback)
     : browser_(browser),
       controller_(std::move(controller)),
@@ -220,7 +220,14 @@
                   // Site access toggle.
                   views::Builder<views::ToggleButton>()
                       .CopyAddressTo(&site_access_toggle_)
-                      .SetCallback(site_access_toggle_callback),
+                      .SetCallback(base::BindRepeating(
+                          [](views::ToggleButton* toggle_button,
+                             base::RepeatingCallback<void(bool)>
+                                 site_access_toggle_callback) {
+                            site_access_toggle_callback.Run(
+                                toggle_button->GetIsOn());
+                          },
+                          site_access_toggle_, site_access_toggle_callback)),
                   // Context menu button.
                   views::Builder<HoverButton>(
                       std::make_unique<HoverButton>(
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
index 48bdbda..042d6d10 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
@@ -71,10 +71,8 @@
   ExtensionMenuItemView(
       Browser* browser,
       std::unique_ptr<ToolbarActionViewController> controller,
-      views::Button::PressedCallback site_access_toggle_callback =
-          base::RepeatingClosure(base::NullCallback()),
-      views::Button::PressedCallback site_permissions_button_callback =
-          base::RepeatingClosure(base::NullCallback()));
+      base::RepeatingCallback<void(bool)> site_access_toggle_callback,
+      views::Button::PressedCallback site_permissions_button_callback);
   ExtensionMenuItemView(const ExtensionMenuItemView&) = delete;
   ExtensionMenuItemView& operator=(const ExtensionMenuItemView&) = delete;
   ~ExtensionMenuItemView() override;
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc
index 6c42dec..b89dde6 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc
@@ -254,11 +254,12 @@
     ExtensionMenuItemView::SitePermissionsButtonAccess
         site_permissions_button_access,
     int index) {
+  // base::Unretained() below is safe because `menu_handler_` lifetime is
+  // tied to this view lifetime by the extensions menu coordinator.
   auto item = std::make_unique<ExtensionMenuItemView>(
       browser_, std::move(action_controller),
-      // TODO(crbug.com/1390952): Create callback that grants/withhelds site
-      // access when toggling the site access toggle.
-      base::RepeatingClosure(base::NullCallback()),
+      base::BindRepeating(&ExtensionsMenuHandler::OnExtensionToggleSelected,
+                          base::Unretained(menu_handler_), extension_id),
       base::BindRepeating(&ExtensionsMenuHandler::OpenSitePermissionsPage,
                           base::Unretained(menu_handler_), extension_id));
   item->Update(site_access_toggle_state, site_permissions_button_state,
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
index 06dd62b..5bc07266 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/extensions/active_tab_permission_granter.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
@@ -74,6 +73,13 @@
 
   void ClickSitePermissionsButton(ExtensionMenuItemView* menu_item);
 
+  // Clicks the site access toggle in the extension's menu main page. If
+  // `active_tab_only` is false, it waits for user site access updated (toggling
+  // an extension with just active tab grants tab permission, but doesn't change
+  // the extension site access).
+  void ClickSiteAccessToggle(ExtensionMenuItemView* menu_item,
+                             bool active_tab_only = false);
+
   content::WebContentsTester* web_contents_tester() {
     return web_contents_tester_;
   }
@@ -118,6 +124,20 @@
   WaitForAnimation();
 }
 
+void ExtensionsMenuMainPageViewUnitTest::ClickSiteAccessToggle(
+    ExtensionMenuItemView* menu_item,
+    bool active_tab_only) {
+  extensions::PermissionsManagerWaiter waiter(
+      PermissionsManager::Get(browser()->profile()));
+  ClickButton(menu_item->site_access_toggle_for_testing());
+  if (!active_tab_only) {
+    waiter.WaitForExtensionPermissionsUpdate();
+  }
+
+  WaitForAnimation();
+  LayoutMenuIfNecessary();
+}
+
 ExtensionsMenuMainPageView* ExtensionsMenuMainPageViewUnitTest::main_page() {
   ExtensionsMenuViewController* menu_controller =
       menu_coordinator()->GetControllerForTesting();
@@ -167,10 +187,9 @@
   EXPECT_EQ(GetNamesFromMenuItems(items), expected_items);
 }
 
-// Verifies the site access toggle is always hidden for an extension that
-// doesn't request site access.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SiteAccessToggle_NoSiteAccessRequested) {
+// Verifies the site access toggle and site permissions button properties for an
+// extension that doesn't request site access.
+TEST_F(ExtensionsMenuMainPageViewUnitTest, NoSiteAccessRequested) {
   auto extension = InstallExtension("Extension");
 
   const GURL url("http://www.example.com");
@@ -179,317 +198,34 @@
   ShowMenu();
   ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
 
-  // Button is hidden when site is set to "customize by extension" (default
-  // setting).
+  // When site setting is set to "customize by extension" (default):
+  //   - site access toggle is hidden.
+  //   - site permissions button is visible, disabled, has no icon and has
+  //   "none" text.
   EXPECT_EQ(GetUserSiteSetting(url),
             PermissionsManager::UserSiteSetting::kCustomizeByExtension);
   EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
-}
-
-// Verifies the site access toggle properties for an extension that
-// requests site access and access is withheld.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SiteAccessToggle_SiteAccessWithheld) {
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
-  WithholdHostPermissions(extension.get());
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible and off when site setting is set to "customize by
-  // extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-}
-
-// Verifies the site access properties for an extension that
-// requests access to a specific site.
-TEST_F(ExtensionsMenuMainPageViewUnitTest, SiteAccessToggle_SiteAccessGranted) {
-  const GURL url("http://www.example.com");
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {url.spec()});
-
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible and on when site setting is set to "customize by
-  // extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-}
-
-// Verifies the site access toggle properties for an extension that
-// requests access to all sites.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SiteAccessToggle_AllSitesAccessGranted) {
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible and on when site setting is set to "customize by
-  // extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-}
-
-// Verifies the site access toggle properties for an extension that only
-// requests active tab access.
-TEST_F(ExtensionsMenuMainPageViewUnitTest, SiteAccessToggle_ActiveTab) {
-  auto extension = InstallExtensionWithPermissions("Extension", {"activeTab"});
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible and off when site setting is set to "customize by
-  // extension" (default setting) and active tab hasn't been granted.
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
-
-  // Button is visible and on when site setting is set to "customize by
-  // extension" and active tab as been granted.
-  extensions::ActiveTabPermissionGranter* active_tab_permission_granter =
-      extensions::TabHelper::FromWebContents(
-          browser()->tab_strip_model()->GetActiveWebContents())
-          ->active_tab_permission_granter();
-  ASSERT_TRUE(active_tab_permission_granter);
-  active_tab_permission_granter->GrantIfRequested(extension.get());
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-}
-
-// Verifies the site access toggle is always hidden for enterprise extensions,
-// even if the extension has site access.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SiteAccessToggle_EnterpriseExtension) {
-  auto extension =
-      InstallEnterpriseExtension("Extension",
-                                 /*host_permissions=*/{"<all_urls>"});
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is hidden when site setting is set to "customize by extension"
-  // (default setting) because extension has site access but user cannot change
-  // it.
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
-}
-
-// Verifies the site permissions button properties for an extension that doesn't
-// request site access.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_NoSiteAccessRequested) {
-  auto extension = InstallExtension("Extension");
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible, disabled, has no icon and has "none" text when site
-  // setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
   EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_FALSE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
   EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
             l10n_util::GetStringUTF16(
                 IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_NONE));
-  EXPECT_FALSE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
 
-  // Button is hidden when site setting is set to "block all extensions".
+  // when site setting is set to "block all extensions":
+  //   - site access toggle is hidden
+  //   - site permissions button is hidden
   UpdateUserSiteSetting(
       PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
 }
 
-// Verifies the site permissions button properties for an extension that
-// requests site access and access is withheld.
+// Verifies the site access toggle and site permissions button properties for an
+// enterprise extension that doesn't request host permissions.
 TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_SiteAccessWithheld) {
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
-  WithholdHostPermissions(extension.get());
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible, enabled, has icon and has "on click" text when site
-  // setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
-  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
-            l10n_util::GetStringUTF16(
-                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
-  EXPECT_TRUE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
-}
-
-// Verifies the site permissions button properties for an extension that
-// requests access to a specific site.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_SiteAccessGranted) {
-  const GURL url("http://www.example.com");
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {url.spec()});
-
-  web_contents_tester()->NavigateAndCommit(url);
-  WaitForAnimation();
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible, enabled, has icon and has "on site" text when site
-  // setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
-  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
-            l10n_util::GetStringUTF16(
-                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_SITE));
-  EXPECT_TRUE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
-}
-
-// Verifies the site permissions button properties for an extension that
-// requests access to all sites.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_AllSitesAccessGranted) {
-  auto extension =
-      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible, enabled, has icon and has "on all sites" text when
-  // site setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
-  EXPECT_EQ(
-      menu_item->site_permissions_button_for_testing()->GetText(),
-      l10n_util::GetStringUTF16(
-          IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_ALL_SITES));
-  EXPECT_TRUE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
-}
-
-// Verifies the site permissions button properties for an extension that
-// only requests activeTab permission.
-TEST_F(ExtensionsMenuMainPageViewUnitTest, SitePermissionsButton_ActiveTab) {
-  auto extension = InstallExtensionWithPermissions("Extension", {"activeTab"});
-
-  const GURL url("http://www.example.com");
-  web_contents_tester()->NavigateAndCommit(url);
-
-  ShowMenu();
-  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
-
-  // Button is visible, enabled, has icon and has "on click" text when
-  // site setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
-            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
-  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
-  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
-            l10n_util::GetStringUTF16(
-                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
-  EXPECT_TRUE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
-
-  // Button is hidden when site setting is set to "block all extensions".
-  UpdateUserSiteSetting(
-      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
-  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
-}
-
-// Verifies the site permissions button properties for an enterprise extension
-// that doesn't request site access.
-TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_EnterpriseExtension_NoSiteAccessRequested) {
+       NoSiteAccessRequested_EnterpriseExtension) {
   auto extension =
       InstallEnterpriseExtension("Extension", /*host_permissions*/ {});
 
@@ -499,28 +235,238 @@
   ShowMenu();
   ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
 
-  // Button is visible, disabled, has no icon and has "none" text when
-  // site setting is set to "customize by extension" (default setting).
+  // When site setting is set to "customize by extension" (default):
+  //   - site access toggle is hidden.
+  //   - site permissions button is visible, disabled, has no icon and has
+  //     "none" text.
   EXPECT_EQ(GetUserSiteSetting(url),
             PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
   EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_FALSE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
   EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
             l10n_util::GetStringUTF16(
                 IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_NONE));
-  EXPECT_FALSE(
-      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
 
-  // Button is hidden when site setting is set to "block all extensions".
+  // When site setting is set to "block all extensions":
+  //   - site access toggle is hidden
+  //   - site permissions button is hidden
   UpdateUserSiteSetting(
       PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
 }
 
-// Verifies the site permissions button properties for an enterprise extension
-// that requests access to all sites.
+// Verifies the site access toggle and site permissions button properties when
+// toggling site access for an extension that requests host permissions for a
+// specific site.
 TEST_F(ExtensionsMenuMainPageViewUnitTest,
-       SitePermissionsButton_EnterpriseExtension_OnAllSitesAccess) {
+       HostPermissionsRequested_ToggleSiteAccess_OnSite) {
+  const GURL url("http://www.example.com");
+  auto extension =
+      InstallExtensionWithHostPermissions("Extension", {url.spec()});
+
+  web_contents_tester()->NavigateAndCommit(url);
+
+  ShowMenu();
+  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
+
+  // By default, site setting is set to "customize by extension" (default) and
+  // extension has granted "on site" access:
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     site" text.
+  ASSERT_EQ(GetUserSiteSetting(url),
+            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  ASSERT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnSite);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_SITE));
+
+  // When site access is toggled OFF:
+  //   - extension site access is "on click".
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  ClickSiteAccessToggle(menu_item);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnClick);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site access is toggled ON:
+  //   - extension site access is "on site".
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     site" text.
+  ClickSiteAccessToggle(menu_item);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnSite);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_SITE));
+}
+
+// Verifies the site access toggle and site permissions button properties when
+// toggling site access for an extension that requests host permissions for all
+// sites.
+TEST_F(ExtensionsMenuMainPageViewUnitTest,
+       HostPermissionsRequested_ToggleSiteAccess_OnAllSites) {
+  auto extension =
+      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
+
+  const GURL url("http://www.example.com");
+  web_contents_tester()->NavigateAndCommit(url);
+
+  ShowMenu();
+  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
+
+  // By default, site setting is set to "customize by extension" (default) and
+  // extension has granted "on all sites" access:
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     all sites" text.
+  ASSERT_EQ(GetUserSiteSetting(url),
+            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  ASSERT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(
+      menu_item->site_permissions_button_for_testing()->GetText(),
+      l10n_util::GetStringUTF16(
+          IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_ALL_SITES));
+
+  // When site access is toggled OFF:
+  //   - extension site access is changed to "on click".
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  ClickSiteAccessToggle(menu_item);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnClick);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site access is toggled ON:
+  //   - extension site access is "on site". Even though previously extension
+  //     had on all sites, toggling site access on grants access just to this
+  //     site. User can still grant all sites in the site permissions page.
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     site" text.
+  ClickSiteAccessToggle(menu_item);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnSite);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_SITE));
+}
+
+// Verifies the site access toggle and site permissions button properties for an
+// extension that requests host permissions when host permission change with the
+// menu open.
+TEST_F(ExtensionsMenuMainPageViewUnitTest,
+       HostPermissionsRequested_DynamicUpdates) {
+  auto extension =
+      InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
+
+  const GURL url("http://www.example.com");
+  web_contents_tester()->NavigateAndCommit(url);
+
+  ShowMenu();
+  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
+
+  // When site setting is set to "customize by extension" and extension site
+  // permissions are granted "on all sites" (default):
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on all
+  //     sites" text.
+  ASSERT_EQ(GetUserSiteSetting(url),
+            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  ASSERT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(
+      menu_item->site_permissions_button_for_testing()->GetText(),
+      l10n_util::GetStringUTF16(
+          IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_ALL_SITES));
+
+  // When site setting is set to "customize by extension" and extension site
+  // permissions are withheld.
+  //   - site access toggle is visible and off
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  WithholdHostPermissions(extension.get());
+  LayoutMenuIfNecessary();
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site setting is set to "block all extensions":
+  //   - site access toggle is hidden.
+  //   - site permissions button is hidden.
+  UpdateUserSiteSetting(
+      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
+  LayoutMenuIfNecessary();
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
+}
+
+// Verifies the site access toggle and site permissions button properties for an
+// extension that requests host permissions.
+TEST_F(ExtensionsMenuMainPageViewUnitTest,
+       HostPermissionsRequested_EnterpriseExtension) {
   auto extension =
       InstallEnterpriseExtension("Extension",
                                  /*host_permissions=*/{"<all_urls>"});
@@ -531,10 +477,17 @@
   ShowMenu();
   ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
 
-  // Button is visible, disabled, has no icon and has "on all sites" text when
-  // site setting is set to "customize by extension" (default setting).
-  EXPECT_EQ(GetUserSiteSetting(url),
+  // When site setting is set to "customize by extension" and has granted "on
+  // all sites" access (default):
+  //   - site access toggle is hidden, because extension has site access but
+  //     user cannot withheld it.
+  //   - site permissions button is visible, disabled, has no icon and has "on
+  //     all sites".
+  ASSERT_EQ(GetUserSiteSetting(url),
             PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  ASSERT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
   EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetEnabled());
   EXPECT_EQ(
@@ -544,15 +497,21 @@
   EXPECT_FALSE(
       menu_item->site_permissions_button_icon_for_testing()->GetVisible());
 
-  // Button is visible, disabled, has no icon and has "on all sites" text when
-  // site setting is set to "block all extensions".
-  // Note: Policy-installed extension can still run on the site even if the user
-  // blocked all extensions because enterprise-installed extensions take
-  // priority over user settings. Therefore, the button is visible (so the user
-  // can see that it can run), but not clickable (because the user can't modify
-  // the settings).
+  // When site setting is set to "block all extensions":
+  //   - extension site access is still "on all sites".
+  //   - site access toggle is hidden.
+  //   - site permissions button is visible, disabled, has no icon and has "on
+  //     all sites" text.
+  // Note: Policy-installed extension can still run on the site even if the
+  // user blocked all extensions because enterprise-installed extensions take
+  // priority over user settings. Therefore, the button is visible (so the
+  // user can see that it can run), but not clickable (because the user can't
+  // modify the settings).
   UpdateUserSiteSetting(
       PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
   EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
   EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetEnabled());
   EXPECT_EQ(
@@ -563,6 +522,162 @@
       menu_item->site_permissions_button_icon_for_testing()->GetVisible());
 }
 
+// Verifies the site access toggle and site permissions button properties when
+// toggling site access for an extension that only requests active tab.
+// TODO(crbug.com/1445397): Flaky on Linux TSan and Win ASan.
+#if (BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)) || \
+    (BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER))
+#define MAYBE_ActiveTabRequested_ToggleSiteAccess \
+  DISABLED_ActiveTabRequested_ToggleSiteAccess
+#else
+#define MAYBE_ActiveTabRequested_ToggleSiteAccess \
+  ActiveTabRequested_ToggleSiteAccess
+#endif
+TEST_F(ExtensionsMenuMainPageViewUnitTest,
+       MAYBE_ActiveTabRequested_ToggleSiteAccess) {
+  auto extension = InstallExtensionWithPermissions("Extension", {"activeTab"});
+
+  const GURL url("http://www.example.com");
+  web_contents_tester()->NavigateAndCommit(url);
+
+  ShowMenu();
+  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
+
+  // By default, site setting is set to "customize by extension" (default) and
+  // extension has not active tab granted.
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  ASSERT_EQ(GetUserSiteSetting(url),
+            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  ASSERT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnClick);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site access toggle is toggled ON:
+  //   - extension site access is "on click". Since extension only requested
+  //     active tab, toggling site access on grants tab permissions but doesn't
+  //     change the user site access.
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  ClickSiteAccessToggle(menu_item, /*active_tab_only=*/true);
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnClick);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site access toggle is toggled OFF:
+  //   - extension site access is "on click".
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  EXPECT_EQ(GetUserSiteAccess(*extension.get(), url),
+            PermissionsManager::UserSiteAccess::kOnClick);
+  ClickSiteAccessToggle(menu_item, /*active_tab_only=*/true);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+}
+
+// Verifies the site access toggle and site permissions button properties for an
+// extension that only requests active tab when site permissions change with the
+// menu open.
+TEST_F(ExtensionsMenuMainPageViewUnitTest, ActiveTabRequested_DynamicUpdates) {
+  auto extension = InstallExtensionWithPermissions("Extension", {"activeTab"});
+
+  const GURL url("http://www.example.com");
+  web_contents_tester()->NavigateAndCommit(url);
+
+  ShowMenu();
+  ExtensionMenuItemView* menu_item = GetOnlyMenuItem();
+
+  // When site setting is set to "customize by extension" (default) and active
+  // tab is not granted:
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  ASSERT_EQ(GetUserSiteSetting(url),
+            PermissionsManager::UserSiteSetting::kCustomizeByExtension);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site setting is set to "customize by extension" active tab is granted:
+  //   - site access toggle is visible and on.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text. Since extension only requested active tab, toggling site
+  //     access on grants tab permissions but doesn't change the user site
+  //     access.
+  extensions::ActiveTabPermissionGranter* active_tab_permission_granter =
+      extensions::TabHelper::FromWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents())
+          ->active_tab_permission_granter();
+  ASSERT_TRUE(active_tab_permission_granter);
+  active_tab_permission_granter->GrantIfRequested(extension.get());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // Navigating to the same url after navigating to other url should remove tab
+  // permissions. Therefore:
+  //   - site access toggle is visible and off.
+  //   - site permissions button is visible, enabled, with icon and has "on
+  //     click" text.
+  // Note: refreshing the page doesn't revoke tab permissions, thus we
+  // need to re navigate to the url.
+  web_contents_tester()->NavigateAndCommit(GURL("http://other-url.com"));
+  web_contents_tester()->NavigateAndCommit(url);
+  EXPECT_TRUE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetIsOn());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetVisible());
+  EXPECT_TRUE(menu_item->site_permissions_button_for_testing()->GetEnabled());
+  EXPECT_TRUE(
+      menu_item->site_permissions_button_icon_for_testing()->GetVisible());
+  EXPECT_EQ(menu_item->site_permissions_button_for_testing()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_EXTENSIONS_MENU_MAIN_PAGE_EXTENSION_SITE_ACCESS_ON_CLICK));
+
+  // When site setting is set to "block all extensions":
+  //   - site access toggle is hidden.
+  //   - site permissions button is hidden.
+  UpdateUserSiteSetting(
+      PermissionsManager::UserSiteSetting::kBlockAllExtensions, url);
+  EXPECT_FALSE(menu_item->site_access_toggle_for_testing()->GetVisible());
+  EXPECT_FALSE(menu_item->site_permissions_button_for_testing()->GetVisible());
+}
+
 // Verifies the site permissions button opens the site permissions page when it
 // is enabled.
 TEST_F(ExtensionsMenuMainPageViewUnitTest,
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
index d3e9278..123d803 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
@@ -7,12 +7,14 @@
 #include "base/functional/bind.h"
 #include "base/i18n/case_conversion.h"
 #include "base/notreached.h"
+#include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/site_permissions_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
 #include "chrome/browser/ui/extensions/extensions_container.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/extensions/extensions_dialogs_utils.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
@@ -302,6 +304,50 @@
                                GetActiveWebContents(), site_access);
 }
 
+void ExtensionsMenuViewController::OnExtensionToggleSelected(
+    extensions::ExtensionId extension_id,
+    bool is_on) {
+  const extensions::Extension* extension = GetExtension(browser_, extension_id);
+  content::WebContents* web_contents = GetActiveWebContents();
+  CHECK(CanUserCustomizeExtensionSiteAccess(*extension, *browser_->profile(),
+                                            *toolbar_model_, *web_contents));
+
+  // Toggling the button off removes site access.
+  SitePermissionsHelper permissions_helper(browser_->profile());
+  if (!is_on) {
+    // TODO(crbug.com/1433399): Clear tab permissions for extension.
+    permissions_helper.UpdateSiteAccess(
+        *extension, web_contents, PermissionsManager::UserSiteAccess::kOnClick);
+    return;
+  }
+
+  // Toggling the button on grants site access. Note that extension should
+  // currently have "on click" access.
+  auto* permissions_manager = PermissionsManager::Get(browser_->profile());
+  DCHECK_EQ(permissions_manager->GetUserSiteAccess(
+                *GetExtension(browser_, extension_id),
+                GetActiveWebContents()->GetLastCommittedURL()),
+            PermissionsManager::UserSiteAccess::kOnClick);
+
+  // If user can select "on site" access (that means the extension requested
+  // access to that site), then we update site access to "on site".
+  if (permissions_manager->CanUserSelectSiteAccess(
+          *extension, web_contents->GetLastCommittedURL(),
+          PermissionsManager::UserSiteAccess::kOnSite)) {
+    permissions_helper.UpdateSiteAccess(
+        *extension, web_contents, PermissionsManager::UserSiteAccess::kOnSite);
+    return;
+  }
+
+  // Otherwise just grant one-time tab permissions.
+  extensions::ExtensionActionRunner* action_runner =
+      extensions::ExtensionActionRunner::GetForWebContents(web_contents);
+  if (!action_runner) {
+    return;
+  }
+  action_runner->GrantTabPermissions({extension});
+}
+
 void ExtensionsMenuViewController::TabChangedAt(content::WebContents* contents,
                                                 int index,
                                                 TabChangeType change_type) {
@@ -352,7 +398,6 @@
     ExtensionsMenuMainPageView* main_page,
     content::WebContents* web_contents) {
   CHECK(web_contents);
-
   std::u16string current_site = GetCurrentHost(web_contents);
   bool is_site_settings_toggle_visible =
       IsSiteSettingsToggleVisible(*toolbar_model_, web_contents);
@@ -389,9 +434,8 @@
   extensions::ExtensionId extension_id = site_permissions_page->extension_id();
   const int icon_size = ChromeLayoutProvider::Get()->GetDistanceMetric(
       DISTANCE_EXTENSIONS_MENU_EXTENSION_ICON_SIZE);
-  std::unique_ptr<ExtensionActionViewController> action_controller =
-      ExtensionActionViewController::Create(extension_id, browser_,
-                                            extensions_container_);
+  ToolbarActionViewController* action_controller =
+      extensions_container_->GetActionForId(extension_id);
 
   std::u16string extension_name = action_controller->GetActionName();
   ui::ImageModel extension_icon = action_controller->GetIcon(
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.h b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.h
index 0cb2aaf..4ef911f4 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.h
@@ -47,6 +47,8 @@
   void OnSiteAccessSelected(
       extensions::ExtensionId extension_id,
       extensions::PermissionsManager::UserSiteAccess site_access) override;
+  void OnExtensionToggleSelected(extensions::ExtensionId extension_id,
+                                 bool is_on) override;
 
   // TabStripModelObserver:
   // Sometimes, menu can stay open when tab changes (e.g keyboard shortcuts) or
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc
index b462156a..aa8c5d6d 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc
@@ -184,6 +184,12 @@
   return permissions_manager_->GetUserSiteSetting(url::Origin::Create(url));
 }
 
+PermissionsManager::UserSiteAccess ExtensionsToolbarUnitTest::GetUserSiteAccess(
+    const extensions::Extension& extension,
+    const GURL& url) const {
+  return permissions_manager_->GetUserSiteAccess(extension, url);
+}
+
 std::vector<ToolbarActionView*>
 ExtensionsToolbarUnitTest::GetPinnedExtensionViews() {
   std::vector<ToolbarActionView*> result;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h
index eabb74e..0f88d76 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h
@@ -109,6 +109,11 @@
   extensions::PermissionsManager::UserSiteSetting GetUserSiteSetting(
       const GURL& url);
 
+  // Returns the user's `extension` site access for `url`.
+  extensions::PermissionsManager::UserSiteAccess GetUserSiteAccess(
+      const extensions::Extension& extension,
+      const GURL& url) const;
+
   // Returns a list of the views of the currently pinned extensions, in order
   // from left to right.
   std::vector<ToolbarActionView*> GetPinnedExtensionViews();
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm
index 0b8e2c30..eb1570b 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -372,7 +372,8 @@
       params->window_title_hidden = true;
   } else if (browser_view_->GetIsPictureInPictureType()) {
     params->window_class = remote_cocoa::mojom::WindowClass::kFrameless;
-    params->style_mask = NSWindowStyleMaskFullSizeContentView;
+    params->style_mask = NSWindowStyleMaskFullSizeContentView |
+                         NSWindowStyleMaskTitled | NSWindowStyleMaskResizable;
   } else {
     params->window_class = remote_cocoa::mojom::WindowClass::kDefault;
   }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index e72c4cc..d308923 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -333,6 +333,7 @@
   params.types_enabled.push_back(
       PageActionIconType::kVirtualCardManualFallback);
   params.types_enabled.push_back(PageActionIconType::kVirtualCardEnroll);
+  params.types_enabled.push_back(PageActionIconType::kMandatoryReauth);
 
   // TODO(crbug.com/1167060): Place this in the proper order upon having final
   // mocks.
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
index 0dcdb24..6a9e363 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.h"
+#include "chrome/browser/ui/views/autofill/payments/mandatory_reauth_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/offer_notification_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/save_payment_icon_view.h"
 #include "chrome/browser/ui/views/autofill/payments/virtual_card_enroll_icon_view.h"
@@ -153,6 +154,12 @@
                       params.command_updater, params.icon_label_bubble_delegate,
                       params.page_action_icon_delegate));
         break;
+      case PageActionIconType::kMandatoryReauth:
+        add_page_action_icon(
+            type, std::make_unique<autofill::MandatoryReauthIconView>(
+                      params.command_updater, params.icon_label_bubble_delegate,
+                      params.page_action_icon_delegate));
+        break;
       case PageActionIconType::kFileSystemAccess:
         add_page_action_icon(type, std::make_unique<FileSystemAccessIconView>(
                                        params.icon_label_bubble_delegate,
diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chrome/browser/ui/views/page_info/page_info_main_view.cc
index 3044e6e..9800155 100644
--- a/chrome/browser/ui/views/page_info/page_info_main_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_main_view.cc
@@ -37,6 +37,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/views/background.h"
 #include "ui/views/bubble/bubble_frame_view.h"
@@ -248,8 +249,9 @@
     UpdateResetButton(permission_info_list);
     return;
   }
-
-  permissions_view_->AddChildView(PageInfoViewFactory::CreateSeparator());
+  const int separator_padding = features::IsChromeRefresh2023() ? 20 : 0;
+  permissions_view_->AddChildView(
+      PageInfoViewFactory::CreateSeparator(separator_padding));
 
   auto* scroll_view =
       permissions_view_->AddChildView(std::make_unique<views::ScrollView>());
@@ -334,7 +336,8 @@
   // show reset button.
   reset_button_->SetVisible(false);
   UpdateResetButton(permission_info_list);
-  permissions_view_->AddChildView(PageInfoViewFactory::CreateSeparator());
+  permissions_view_->AddChildView(
+      PageInfoViewFactory::CreateSeparator(separator_padding));
 
   PreferredSizeChanged();
 }
@@ -562,7 +565,8 @@
 std::unique_ptr<views::View> PageInfoMainView::CreateBubbleHeaderView() {
   auto header = std::make_unique<views::View>();
   header->SetLayoutManager(std::make_unique<views::FlexLayout>())
-      ->SetInteriorMargin(gfx::Insets::VH(0, kIconColumnWidth));
+      ->SetInteriorMargin(
+          gfx::Insets::VH(0, features::IsChromeRefresh2023() ? 20 : 16));
   title_ = header->AddChildView(std::make_unique<views::Label>(
       std::u16string(), views::style::CONTEXT_DIALOG_TITLE,
       views::style::STYLE_PRIMARY,
diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.h b/chrome/browser/ui/views/page_info/page_info_main_view.h
index f64f2b49..a0b84e4 100644
--- a/chrome/browser/ui/views/page_info/page_info_main_view.h
+++ b/chrome/browser/ui/views/page_info/page_info_main_view.h
@@ -42,8 +42,6 @@
                          public PermissionToggleRowViewObserver,
                          public ChosenObjectViewObserver {
  public:
-  // The width of the column size for permissions and chosen object icons.
-  static constexpr int kIconColumnWidth = 16;
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kCookieButtonElementId);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMainLayoutElementId);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPermissionsElementId);
diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrome/browser/ui/views/page_info/page_info_view_factory.cc
index f42dad9..b9bcb9a2 100644
--- a/chrome/browser/ui/views/page_info/page_info_view_factory.cc
+++ b/chrome/browser/ui/views/page_info/page_info_view_factory.cc
@@ -81,7 +81,8 @@
 }  // namespace
 
 // static
-std::unique_ptr<views::View> PageInfoViewFactory::CreateSeparator() {
+std::unique_ptr<views::View> PageInfoViewFactory::CreateSeparator(
+    int horizontal_inset) {
   // Distance for multi content list is used, but split in half, since there is
   // a separator in the middle of it.
   const int separator_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric(
@@ -89,7 +90,7 @@
                                 2;
   auto separator = std::make_unique<views::Separator>();
   separator->SetProperty(views::kMarginsKey,
-                         gfx::Insets::VH(separator_spacing, 0));
+                         gfx::Insets::VH(separator_spacing, horizontal_inset));
   return separator;
 }
 
@@ -200,7 +201,7 @@
       base::BindRepeating(&PageInfoNavigationHandler::OpenMainPage,
                           base::Unretained(navigation_handler_),
                           base::DoNothing()),
-      vector_icons::kArrowBackIcon);
+      vector_icons::kArrowBackIcon, GetIconSize());
   views::InstallCircleHighlightPathGenerator(back_button.get());
   back_button->SetID(VIEW_ID_PAGE_INFO_BACK_BUTTON);
   back_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK));
@@ -591,11 +592,14 @@
 
 // static
 const ui::ImageModel PageInfoViewFactory::GetOpenSubpageIcon() {
+  // GetIconSize() does not work for subpage icons because the default size of
+  // kSubmenuArrowIcon is 8 rather than 16.
+  const int icon_size = features::IsChromeRefresh2023() ? 20 : 8;
   return ui::ImageModel::FromVectorIcon(
       features::IsChromeRefresh2023()
           ? vector_icons::kSubmenuArrowChromeRefreshIcon
           : vector_icons::kSubmenuArrowIcon,
-      ui::kColorIcon);
+      ui::kColorIcon, icon_size);
 }
 
 // static
diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.h b/chrome/browser/ui/views/page_info/page_info_view_factory.h
index 1d9a18e0..3ab4c33f 100644
--- a/chrome/browser/ui/views/page_info/page_info_view_factory.h
+++ b/chrome/browser/ui/views/page_info/page_info_view_factory.h
@@ -64,7 +64,8 @@
 
   // Creates a separator view with padding on top and bottom. Use with flex
   // layout only.
-  [[nodiscard]] static std::unique_ptr<views::View> CreateSeparator();
+  [[nodiscard]] static std::unique_ptr<views::View> CreateSeparator(
+      int horizontal_inset = 0);
 
   // Creates a label container view with padding on left and right side.
   // Supports multiple multiline labels in a column (ex. title and subtitle
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc
index 3409f10..d45797df 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc
@@ -257,19 +257,93 @@
   return password_label_with_eye_icon_view;
 }
 
+// Creates the label for the note with custom logic for logging
+// metrics for selecting and copying text of the note.
+class NoteLabel : public views::Label {
+ public:
+  explicit NoteLabel(std::u16string note)
+      : views::Label(note,
+                     views::style::CONTEXT_DIALOG_BODY_TEXT,
+                     views::style::STYLE_SECONDARY),
+        note_(std::move(note)) {
+    std::u16string note_to_display =
+        note_.empty()
+            ? l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_EMPTY_NOTE)
+            : note_;
+    if (note_.empty()) {
+      SetText(note_to_display);
+    }
+    SetAccessibleName(l10n_util::GetStringFUTF16(
+        IDS_MANAGE_PASSWORDS_NOTE_ACCESSIBLE_NAME, note_to_display));
+  }
+
+ public:
+  void ExecuteCommand(int command_id, int event_flags) override {
+    views::Label::ExecuteCommand(command_id, event_flags);
+    if (note_.empty()) {
+      return;
+    }
+
+    if (command_id == MenuCommands::kCopy && HasSelection()) {
+      LogUserInteractionsInPasswordManagementBubble(
+          HasFullSelection()
+              ? PasswordManagementBubbleInteractions::kNoteFullyCopied
+              : PasswordManagementBubbleInteractions::kNotePartiallyCopied);
+    }
+
+    if (command_id == MenuCommands::kSelectAll) {
+      LogUserInteractionsInPasswordManagementBubble(
+          PasswordManagementBubbleInteractions::kNoteFullySelected);
+    }
+  }
+
+ protected:
+  bool OnKeyPressed(const ui::KeyEvent& event) override {
+    if (note_.empty()) {
+      return views::Label::OnKeyPressed(event);
+    }
+
+    const bool alt = event.IsAltDown() || event.IsAltGrDown();
+    const bool control = event.IsControlDown() || event.IsCommandDown();
+
+    if (control && !alt) {
+      if (event.key_code() == ui::VKEY_A) {
+        LogUserInteractionsInPasswordManagementBubble(
+            PasswordManagementBubbleInteractions::kNoteFullySelected);
+      }
+
+      if (event.key_code() == ui::VKEY_C && HasSelection()) {
+        LogUserInteractionsInPasswordManagementBubble(
+            HasFullSelection()
+                ? PasswordManagementBubbleInteractions::kNoteFullyCopied
+                : PasswordManagementBubbleInteractions::kNotePartiallyCopied);
+      }
+    }
+
+    return views::Label::OnKeyPressed(event);
+  }
+
+  void OnMouseReleased(const ui::MouseEvent& event) override {
+    views::Label::OnMouseReleased(event);
+    if (note_.empty() || !HasSelection()) {
+      return;
+    }
+
+    LogUserInteractionsInPasswordManagementBubble(
+        HasFullSelection()
+            ? PasswordManagementBubbleInteractions::kNoteFullySelected
+            : PasswordManagementBubbleInteractions::kNotePartiallySelected);
+  }
+
+ private:
+  std::u16string note_;
+};
+
 std::unique_ptr<views::View> CreateNoteLabel(
     const password_manager::PasswordForm& form) {
-  std::u16string note = form.GetNoteWithEmptyUniqueDisplayName();
-  std::u16string note_to_display =
-      note.empty() ? l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_EMPTY_NOTE)
-                   : note;
-
-  auto note_label = std::make_unique<views::Label>(
-      note_to_display, views::style::CONTEXT_DIALOG_BODY_TEXT,
-      views::style::STYLE_SECONDARY);
+  auto note_label =
+      std::make_unique<NoteLabel>(form.GetNoteWithEmptyUniqueDisplayName());
   note_label->SetMultiLine(true);
-  note_label->SetAccessibleName(l10n_util::GetStringFUTF16(
-      IDS_MANAGE_PASSWORDS_NOTE_ACCESSIBLE_NAME, note_to_display));
   note_label->SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_TOP);
   note_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
   note_label->SetSelectable(true);
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
index 567b73da..70d77e4 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -811,6 +811,156 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagementRevampedBubbleInteractiveUiTest,
+                       RecordsMetricsForCopyingFullNoteWithKeyboardShortcuts) {
+  base::HistogramTester histogram_tester;
+
+  SetupManagingPasswords();
+  EXPECT_FALSE(IsBubbleShowing());
+  ExecuteManagePasswordsCommand();
+  ASSERT_TRUE(IsBubbleShowing());
+
+  auto* bubble = PasswordBubbleViewBase::manage_password_bubble();
+  test_form()->SetNoteWithEmptyUniqueDisplayName(u"current note");
+  static_cast<ManagePasswordsView*>(bubble)->DisplayDetailsOfPasswordForTesting(
+      *test_form());
+
+  views::View* note_view = bubble->GetViewByID(
+      static_cast<int>(password_manager::ManagePasswordsViewIDs::kNoteLabel));
+  note_view->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_CONTROL_DOWN));
+  note_view->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, ui::EF_CONTROL_DOWN));
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples(
+          "PasswordManager.PasswordManagementBubble.UserAction"),
+      ElementsAre(
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullySelected,
+                 1),
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullyCopied,
+                 1)));
+}
+
+IN_PROC_BROWSER_TEST_F(
+    PasswordManagementRevampedBubbleInteractiveUiTest,
+    RecordsMetricsForCopyingFullNoteWithSelectAllAndCopyCommands) {
+  base::HistogramTester histogram_tester;
+
+  SetupManagingPasswords();
+  EXPECT_FALSE(IsBubbleShowing());
+  ExecuteManagePasswordsCommand();
+  ASSERT_TRUE(IsBubbleShowing());
+
+  auto* bubble = PasswordBubbleViewBase::manage_password_bubble();
+  test_form()->SetNoteWithEmptyUniqueDisplayName(u"current note");
+  static_cast<ManagePasswordsView*>(bubble)->DisplayDetailsOfPasswordForTesting(
+      *test_form());
+
+  auto* note_label = static_cast<views::Label*>(bubble->GetViewByID(
+      static_cast<int>(password_manager::ManagePasswordsViewIDs::kNoteLabel)));
+  note_label->ExecuteCommand(views::Label::MenuCommands::kSelectAll,
+                             /*event_flags=*/0);
+  note_label->ExecuteCommand(views::Label::MenuCommands::kCopy,
+                             /*event_flags=*/0);
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples(
+          "PasswordManager.PasswordManagementBubble.UserAction"),
+      ElementsAre(
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullySelected,
+                 1),
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullyCopied,
+                 1)));
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagementRevampedBubbleInteractiveUiTest,
+                       RecordsMetricsForCopyingFullNoteAfterMouseSelection) {
+  base::HistogramTester histogram_tester;
+
+  SetupManagingPasswords();
+  EXPECT_FALSE(IsBubbleShowing());
+  ExecuteManagePasswordsCommand();
+  ASSERT_TRUE(IsBubbleShowing());
+
+  auto* bubble = PasswordBubbleViewBase::manage_password_bubble();
+  test_form()->SetNoteWithEmptyUniqueDisplayName(u"current note");
+  static_cast<ManagePasswordsView*>(bubble)->DisplayDetailsOfPasswordForTesting(
+      *test_form());
+
+  views::View* note_view = bubble->GetViewByID(
+      static_cast<int>(password_manager::ManagePasswordsViewIDs::kNoteLabel));
+  auto* note_label = static_cast<views::Label*>(note_view);
+  note_view->OnMousePressed(
+      ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(0, 0), gfx::Point(0, 0),
+                     ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
+  note_label->SelectAll();
+  note_view->OnMouseReleased(
+      ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(0, 0), gfx::Point(0, 0),
+                     ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
+  note_view->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, ui::EF_CONTROL_DOWN));
+  note_label->ExecuteCommand(views::Label::MenuCommands::kCopy,
+                             /*event_flags=*/0);
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples(
+          "PasswordManager.PasswordManagementBubble.UserAction"),
+      ElementsAre(
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullySelected,
+                 1),
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNoteFullyCopied,
+                 2)));
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagementRevampedBubbleInteractiveUiTest,
+                       RecordsMetricsForCopyingPartOfNoteAfterMouseSelection) {
+  base::HistogramTester histogram_tester;
+
+  SetupManagingPasswords();
+  EXPECT_FALSE(IsBubbleShowing());
+  ExecuteManagePasswordsCommand();
+  ASSERT_TRUE(IsBubbleShowing());
+
+  auto* bubble = PasswordBubbleViewBase::manage_password_bubble();
+  test_form()->SetNoteWithEmptyUniqueDisplayName(u"current note");
+  static_cast<ManagePasswordsView*>(bubble)->DisplayDetailsOfPasswordForTesting(
+      *test_form());
+
+  views::View* note_view = bubble->GetViewByID(
+      static_cast<int>(password_manager::ManagePasswordsViewIDs::kNoteLabel));
+  auto* note_label = static_cast<views::Label*>(note_view);
+  note_view->OnMousePressed(
+      ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(0, 0), gfx::Point(0, 0),
+                     ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
+  note_label->SelectRange(gfx::Range(0, 5));
+  note_view->OnMouseReleased(
+      ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(0, 0), gfx::Point(0, 0),
+                     ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
+  note_view->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, ui::EF_CONTROL_DOWN));
+  note_label->ExecuteCommand(views::Label::MenuCommands::kCopy,
+                             /*event_flags=*/0);
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples(
+          "PasswordManager.PasswordManagementBubble.UserAction"),
+      ElementsAre(
+          Bucket(
+              password_manager::metrics_util::
+                  PasswordManagementBubbleInteractions::kNotePartiallySelected,
+              1),
+          Bucket(password_manager::metrics_util::
+                     PasswordManagementBubbleInteractions::kNotePartiallyCopied,
+                 2)));
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagementRevampedBubbleInteractiveUiTest,
                        NavigateToManagementDetailsViewAndTakeScreenshot) {
   const char kFirstCredentialsRow[] = "FirstCredentialsRow";
 
diff --git a/chrome/browser/ui/views/permissions/chip_controller.cc b/chrome/browser/ui/views/permissions/chip_controller.cc
index 40b9bac..7ecb5ae 100644
--- a/chrome/browser/ui/views/permissions/chip_controller.cc
+++ b/chrome/browser/ui/views/permissions/chip_controller.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
 #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
-#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h"
 #include "chrome/browser/ui/views/permissions/permission_prompt_chip_model.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -509,7 +509,7 @@
       PermissionPromptStyle::kChip) {
     // Loud prompt bubble
     raw_ptr<PermissionPromptBubbleBaseView> prompt_bubble =
-        new PermissionPromptBubbleOneOriginView(
+        CreatePermissionPromptBubbleView(
             browser_,
             permission_prompt_model_->GetDelegate().value()->GetWeakPtr(),
             request_chip_shown_time_, PermissionPromptStyle::kChip);
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
index 49bdfaf..05d1dcc 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
@@ -6,7 +6,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
-#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h"
 #include "chrome/browser/ui/views/permissions/permission_prompt_style.h"
 #include "components/permissions/features.h"
 #include "content/public/browser/web_contents.h"
@@ -36,7 +36,7 @@
 }
 
 void PermissionPromptBubble::ShowBubble() {
-  prompt_bubble_ = new PermissionPromptBubbleOneOriginView(
+  prompt_bubble_ = CreatePermissionPromptBubbleView(
       browser(), delegate()->GetWeakPtr(), permission_requested_time_,
       PermissionPromptStyle::kBubbleOnly);
   prompt_bubble_->Show();
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
index 080bfd8..22988add 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
@@ -179,6 +179,11 @@
 PermissionPromptBubbleBaseView::~PermissionPromptBubbleBaseView() = default;
 
 void PermissionPromptBubbleBaseView::Show() {
+  CreateWidget();
+  ShowWidget();
+}
+
+void PermissionPromptBubbleBaseView::CreateWidget() {
   DCHECK(browser_->window());
 
   UpdateAnchorPosition();
@@ -193,13 +198,15 @@
   if (base::FeatureList::IsEnabled(views::features::kWidgetLayering)) {
     widget->SetZOrderSublevel(ChromeWidgetSublevel::kSublevelSecurity);
   }
+}
 
+void PermissionPromptBubbleBaseView::ShowWidget() {
   // If a browser window (or popup) other than the bubble parent has focus,
   // don't take focus.
   if (browser_->window()->IsActive()) {
-    widget->Show();
+    GetWidget()->Show();
   } else {
-    widget->ShowInactive();
+    GetWidget()->ShowInactive();
   }
 
   SizeToContents();
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
index 10864d2..ef2a1a8e 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
@@ -55,12 +55,14 @@
       const PermissionPromptBubbleBaseView&) = delete;
   ~PermissionPromptBubbleBaseView() override;
 
-  void Show();
+  virtual void Show();
 
   // Anchors the bubble to the view or rectangle returned from
   // bubble_anchor_util::GetPageInfoAnchorConfiguration.
   void UpdateAnchorPosition();
 
+  void ShowWidget();
+
   void SetPromptStyle(PermissionPromptStyle prompt_style);
 
   // views::BubbleDialogDelegateView:
@@ -80,6 +82,8 @@
   void ClosingPermission();
 
  protected:
+  void CreateWidget();
+
   UrlIdentity GetUrlIdentityObject() { return url_identity_; }
 
   // Determines whether the current request should also display an
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc
index 3c10c9d2..5b12b45 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc
@@ -54,6 +54,13 @@
 #include "ui/views/test/ax_event_counter.h"
 #include "ui/views/test/button_test_api.h"
 
+// To run the pixel tests of this file run: browser_tests
+// --gtest_filter=BrowserUiTest.Invoke --test-launcher-interactive
+// --enable-pixel-output-in-tests --ui=<test name e.g.
+// PermissionPromptBubbleBaseViewBrowserTest>.*
+//
+// Check go/brapp-desktop-pixel-tests for more info.
+
 namespace {
 // Test implementation of PermissionUiSelector that always returns a canned
 // decision.
@@ -88,11 +95,13 @@
  public:
   PermissionPromptBubbleBaseViewBrowserTest() {
     if (GetParam()) {
-      feature_list_.InitWithFeatures({permissions::features::kPermissionChip},
-                                     {});
+      feature_list_.InitWithFeatures(
+          {permissions::features::kPermissionChip},
+          {permissions::features::kPermissionStorageAccessAPI});
     } else {
-      feature_list_.InitWithFeatures({},
-                                     {permissions::features::kPermissionChip});
+      feature_list_.InitWithFeatures(
+          {}, {permissions::features::kPermissionChip,
+               permissions::features::kPermissionStorageAccessAPI});
     }
   }
 
@@ -201,6 +210,17 @@
     }
     permissions::PermissionRequestManager* manager = test_api_->manager();
     content::RenderFrameHost* source_frame = GetActiveMainFrame();
+
+    // Pixel verification for storage_access test checks a permission
+    // request prompt that has an origin and port. Because these tests run
+    // on localhost, the port changes, and the test pixel verification
+    // fails. We need a fixed URL, so the Gold image used in the pixel test
+    // always matches with the output of the test.
+    if (it->type == ContentSettingsType::STORAGE_ACCESS) {
+      test_api_->manager()->set_embedding_origin_for_testing(
+          GURL("https://test.com"));
+    }
+
     switch (it->type) {
       case ContentSettingsType::PROTOCOL_HANDLERS:
         manager->AddRequest(source_frame, MakeRegisterProtocolHandlerRequest());
@@ -392,14 +412,9 @@
   ShowAndVerifyUi();
 }
 
-// TODO(crbug.com/1232028): Pixel verification for storage_access test checks
-// permission request prompt that has origin and port. Because these tests run
-// on localhost, the port constantly changes its value and hence test pixel
-// verification fails. Host wants to access storage from the site in which it's
-// embedded.
 // Host wants to access storage from the site in which it's embedded.
 IN_PROC_BROWSER_TEST_P(PermissionPromptBubbleBaseViewBrowserTest,
-                       DISABLED_InvokeUi_storage_access) {
+                       InvokeUi_storage_access) {
   ShowAndVerifyUi();
 }
 
@@ -421,6 +436,39 @@
   ShowAndVerifyUi();
 }
 
+// Test fixture to test the Storage Access prompt with the new Google UI.
+//
+// We have created a new test fixture for the new Google UI so we can have a
+// test for the new and old prompt UI and avoid adding unnecessary Gold images.
+// If were to add a new parameter to |PermissionPromptBubbleBaseViewBrowserTest|
+// to toggle the PermissionStorageAccessAPI, we would have to add extra Gold
+// images for each of the other eleven tests, even though this flag only affects
+// the SAA prompt.
+class SAAEnabledPermissionPromptBubbleViewBrowserTest
+    : public PermissionPromptBubbleBaseViewBrowserTest {
+ public:
+  SAAEnabledPermissionPromptBubbleViewBrowserTest() {
+    if (GetParam()) {
+      feature_list_.InitWithFeatures(
+          {permissions::features::kPermissionStorageAccessAPI,
+           permissions::features::kPermissionChip},
+          {});
+    } else {
+      feature_list_.InitWithFeatures(
+          {permissions::features::kPermissionStorageAccessAPI},
+          {permissions::features::kPermissionChip});
+    }
+  }
+  base::test::ScopedFeatureList feature_list_;
+};
+
+// Host wants to access storage from the site in which it's embedded. Prompt
+// with new Google UI.
+IN_PROC_BROWSER_TEST_P(SAAEnabledPermissionPromptBubbleViewBrowserTest,
+                       InvokeUi_storage_access) {
+  ShowAndVerifyUi();
+}
+
 class QuietUIPromoBrowserTest
     : public PermissionPromptBubbleBaseViewBrowserTest {
  public:
@@ -991,6 +1039,9 @@
                          PermissionPromptBubbleBaseViewBrowserTest,
                          ::testing::Values(false, true));
 INSTANTIATE_TEST_SUITE_P(All,
+                         SAAEnabledPermissionPromptBubbleViewBrowserTest,
+                         ::testing::Values(false, true));
+INSTANTIATE_TEST_SUITE_P(All,
                          PermissionPromptBubbleBaseViewQuietUiBrowserTest,
                          ::testing::Values(false, true));
 INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
new file mode 100644
index 0000000..b9e9ab84
--- /dev/null
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
@@ -0,0 +1,208 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h"
+
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "components/favicon/core/favicon_service.h"
+#include "components/favicon_base/favicon_callback.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/url_formatter/elide_url.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/vector_icons.h"
+
+namespace {
+
+// TODO(b/278181254): We might need to fetch larger icons on higher dpi
+// screens.
+constexpr int kDesiredFaviconSizeInPixel = 32;
+// TODO(b/278181254): Add metrics for how long the favicons take to be fetched,
+// so we can adjust this delay accordingly.
+constexpr int kMaxShowDelayMs = 200;
+
+absl::optional<std::u16string> GetExtraTextTwoOrigin(
+    permissions::PermissionPrompt::Delegate& delegate) {
+  CHECK_GT(delegate.Requests().size(), 0u);
+  switch (delegate.Requests()[0]->request_type()) {
+    case permissions::RequestType::kStorageAccess:
+      return l10n_util::GetStringFUTF16(
+          IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_EXPLANATION,
+          url_formatter::FormatUrlForSecurityDisplay(
+              delegate.GetRequestingOrigin(),
+              url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
+    default:
+      NOTREACHED_NORETURN();
+  }
+}
+
+std::u16string GetWindowTitleTwoOrigin(
+    permissions::PermissionPrompt::Delegate& delegate) {
+  CHECK_GT(delegate.Requests().size(), 0u);
+  switch (delegate.Requests()[0]->request_type()) {
+    case permissions::RequestType::kStorageAccess:
+      return l10n_util::GetStringFUTF16(
+          IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_PROMPT_TITLE,
+          url_formatter::FormatUrlForSecurityDisplay(
+              delegate.GetRequestingOrigin(),
+              url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC),
+          url_formatter::FormatUrlForSecurityDisplay(
+              delegate.GetEmbeddingOrigin(),
+              url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
+    default:
+      NOTREACHED_NORETURN();
+  }
+}
+
+}  // namespace
+
+PermissionPromptBubbleTwoOriginsView::PermissionPromptBubbleTwoOriginsView(
+    Browser* browser,
+    base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate,
+    base::TimeTicks permission_requested_time,
+    PermissionPromptStyle prompt_style)
+    : PermissionPromptBubbleBaseView(browser,
+                                     delegate,
+                                     permission_requested_time,
+                                     prompt_style,
+                                     GetWindowTitleTwoOrigin(*delegate),
+                                     GetWindowTitleTwoOrigin(*delegate),
+                                     GetExtraTextTwoOrigin(*delegate)) {
+  // Only requests for SAA should use this prompt.
+  CHECK(delegate);
+  CHECK_GT(delegate->Requests().size(), 0u);
+  CHECK_EQ(delegate->Requests()[0]->request_type(),
+           permissions::RequestType::kStorageAccess);
+
+  AddFaviconRow();
+
+  CHECK(browser);
+
+  // Initializing favicon service.
+  favicon::FaviconService* const favicon_service =
+      FaviconServiceFactory::GetForProfile(browser->profile(),
+                                           ServiceAccessType::EXPLICIT_ACCESS);
+  favicon_tracker_ = std::make_unique<base::CancelableTaskTracker>();
+
+  // Fetching requesting origin favicon.
+  favicon_service->GetRawFaviconForPageURL(
+      delegate->GetRequestingOrigin(), {favicon_base::IconType::kFavicon},
+      kDesiredFaviconSizeInPixel, /*fallback_to_host=*/true,
+      base::BindOnce(&PermissionPromptBubbleTwoOriginsView::
+                         OnRequestingOriginFaviconLoaded,
+                     base::Unretained(this)),
+      favicon_tracker_.get());
+
+  // Fetching embedding origin favicon.
+  favicon_service->GetRawFaviconForPageURL(
+      delegate->GetEmbeddingOrigin(), {favicon_base::IconType::kFavicon},
+      kDesiredFaviconSizeInPixel, /*fallback_to_host=*/true,
+      base::BindOnce(
+          &PermissionPromptBubbleTwoOriginsView::OnEmbeddingOriginFaviconLoaded,
+          base::Unretained(this)),
+      favicon_tracker_.get());
+}
+
+PermissionPromptBubbleTwoOriginsView::~PermissionPromptBubbleTwoOriginsView() =
+    default;
+
+void PermissionPromptBubbleTwoOriginsView::AddedToWidget() {
+  if (GetUrlIdentityObject().type == UrlIdentity::Type::kDefault) {
+    // TODO(crbug/1433644): There might be a risk of URL spoofing from origins
+    // that are too wide to fit in the bubble.
+    std::unique_ptr<views::Label> label = std::make_unique<views::Label>(
+        GetWindowTitle(), views::style::CONTEXT_DIALOG_TITLE);
+    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    label->SetCollapseWhenHidden(true);
+    label->SetMultiLine(true);
+    label->SetMaxLines(4);
+    GetBubbleFrameView()->SetTitleView(std::move(label));
+  }
+}
+
+void PermissionPromptBubbleTwoOriginsView::Show() {
+  CreateWidget();
+
+  if (favicon_left_received_ && favicon_right_received_) {
+    ShowWidget();
+    return;
+  }
+
+  show_timer_.Start(FROM_HERE, base::Milliseconds(kMaxShowDelayMs),
+                    base::BindOnce(&PermissionPromptBubbleBaseView::ShowWidget,
+                                   base::Unretained(this)));
+}
+
+void PermissionPromptBubbleTwoOriginsView::AddFaviconRow() {
+  // Line container for the favicon icons.
+  auto* line_container =
+      AddChildViewAt(std::make_unique<views::View>(), /*index=*/0);
+
+  views::BoxLayout* box_layout =
+      line_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+          /*between_child_spacing=*/4));
+
+  // Center box_layout children horizontally and vertically.
+  box_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+  box_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
+
+  // Getting default favicon.
+  const ui::NativeTheme* native_theme =
+      ui::NativeTheme::GetInstanceForNativeUi();
+  bool is_dark = native_theme && native_theme->ShouldUseDarkColors();
+  int resource_id =
+      is_dark ? IDR_DEFAULT_FAVICON_DARK_32 : IDR_DEFAULT_FAVICON_32;
+  ui::ImageModel default_favicon_ = ui::ImageModel::FromResourceId(resource_id);
+
+  // Left favicon for embedding origin.
+  favicon_left_ = line_container->AddChildView(
+      std::make_unique<views::ImageView>(default_favicon_));
+  favicon_left_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
+
+  // Three dots.
+  line_container->AddChildView(
+      std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon(
+          views::kOptionsIcon, ui::kColorIcon, /*icon_size=*/40)));
+
+  // Right favicon for requesting origin.
+  favicon_right_ = line_container->AddChildView(
+      std::make_unique<views::ImageView>(default_favicon_));
+  favicon_right_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
+}
+
+void PermissionPromptBubbleTwoOriginsView::OnEmbeddingOriginFaviconLoaded(
+    const favicon_base::FaviconRawBitmapResult& favicon_result) {
+  favicon_left_received_ = true;
+
+  if (favicon_result.is_valid()) {
+    favicon_left_->SetImage(ui::ImageModel::FromImage(
+        gfx::Image::CreateFrom1xPNGBytes(favicon_result.bitmap_data->front(),
+                                         favicon_result.bitmap_data->size())));
+  }
+  MaybeShow();
+}
+
+void PermissionPromptBubbleTwoOriginsView::OnRequestingOriginFaviconLoaded(
+    const favicon_base::FaviconRawBitmapResult& favicon_result) {
+  favicon_right_received_ = true;
+
+  if (favicon_result.is_valid()) {
+    favicon_right_->SetImage(ui::ImageModel::FromImage(
+        gfx::Image::CreateFrom1xPNGBytes(favicon_result.bitmap_data->front(),
+                                         favicon_result.bitmap_data->size())));
+  }
+  MaybeShow();
+}
+
+void PermissionPromptBubbleTwoOriginsView::MaybeShow() {
+  if (favicon_left_received_ && favicon_right_received_ &&
+      show_timer_.IsRunning()) {
+    show_timer_.FireNow();
+  }
+}
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h
new file mode 100644
index 0000000..fde9dc4
--- /dev/null
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h
@@ -0,0 +1,69 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_TWO_ORIGINS_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_TWO_ORIGINS_VIEW_H_
+
+#include "base/task/cancelable_task_tracker.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
+#include "components/favicon_base/favicon_types.h"
+
+// Bubble that prompts the user to grant or deny a permission request from from
+// a pair of origins.
+//
+// ----------------------------------------------
+// |                                       [ X ]|
+// | Prompt title mentioning the two origins    |
+// | ------------------------------------------ |
+// | Favicons from the two origins              |
+// | ------------------------------------------ |
+// | Extra text                                 |
+// | ------------------------------------------ |
+// |                        [ Block ] [ Allow ] |
+// ----------------------------------------------
+class PermissionPromptBubbleTwoOriginsView
+    : public PermissionPromptBubbleBaseView {
+ public:
+  PermissionPromptBubbleTwoOriginsView(
+      Browser* browser,
+      base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate,
+      base::TimeTicks permission_requested_time,
+      PermissionPromptStyle prompt_style);
+  PermissionPromptBubbleTwoOriginsView(
+      const PermissionPromptBubbleTwoOriginsView&) = delete;
+  PermissionPromptBubbleTwoOriginsView& operator=(
+      const PermissionPromptBubbleTwoOriginsView&) = delete;
+  ~PermissionPromptBubbleTwoOriginsView() override;
+
+  // views::BubbleDialogDelegateView:
+  void AddedToWidget() override;
+
+  // PermissionPromptBubbleBaseView
+  void Show() override;
+
+ private:
+  void AddFaviconRow();
+
+  void OnEmbeddingOriginFaviconLoaded(
+      const favicon_base::FaviconRawBitmapResult& favicon_result);
+  void OnRequestingOriginFaviconLoaded(
+      const favicon_base::FaviconRawBitmapResult& favicon_result);
+
+  void MaybeShow();
+
+  // The task tracker for loading favicons.
+  std::unique_ptr<base::CancelableTaskTracker> favicon_tracker_;
+
+  raw_ptr<views::ImageView> favicon_right_;
+  raw_ptr<views::ImageView> favicon_left_;
+  bool favicon_right_received_ = false;
+  bool favicon_left_received_ = false;
+
+  // Timer that waits for a short period of time before showing the prompt to
+  // give the favicon service a chance to fetch the origins' favicons.
+  base::OneShotTimer show_timer_;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_TWO_ORIGINS_VIEW_H_
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view_unittest.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view_unittest.cc
new file mode 100644
index 0000000..07b9ead
--- /dev/null
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h"
+
+#include "base/ranges/algorithm.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_style.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/views/chrome_views_test_base.h"
+#include "components/permissions/permission_util.h"
+#include "components/permissions/request_type.h"
+#include "components/permissions/test/mock_permission_request.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace {
+
+class TestDelegateTwoOrigins : public permissions::PermissionPrompt::Delegate {
+ private:
+  const GURL embedding_origin_;
+
+ public:
+  explicit TestDelegateTwoOrigins(
+      const GURL& requesting_origin,
+      const GURL& embedding_origin,
+      const std::vector<permissions::RequestType> request_types)
+      : embedding_origin_(embedding_origin) {
+    base::ranges::transform(
+        request_types, std::back_inserter(requests_), [&](auto& request_type) {
+          return std::make_unique<permissions::MockPermissionRequest>(
+              requesting_origin, request_type);
+        });
+    base::ranges::transform(
+        requests_, std::back_inserter(raw_requests_),
+        &std::unique_ptr<permissions::PermissionRequest>::get);
+  }
+
+  const std::vector<permissions::PermissionRequest*>& Requests() override {
+    return raw_requests_;
+  }
+
+  GURL GetRequestingOrigin() const override {
+    return raw_requests_.front()->requesting_origin();
+  }
+
+  GURL GetEmbeddingOrigin() const override { return embedding_origin_; }
+
+  void Accept() override {}
+  void AcceptThisTime() override {}
+  void Deny() override {}
+  void Dismiss() override {}
+  void Ignore() override {}
+  void PreIgnoreQuietPrompt() override {}
+  void SetManageClicked() override {}
+  void SetLearnMoreClicked() override {}
+  void SetHatsShownCallback(base::OnceCallback<void()> callback) override {}
+
+  bool WasCurrentRequestAlreadyDisplayed() override { return false; }
+  bool ShouldDropCurrentRequestIfCannotShowQuietly() const override {
+    return false;
+  }
+  bool ShouldCurrentRequestUseQuietUI() const override { return false; }
+  absl::optional<permissions::PermissionUiSelector::QuietUiReason>
+  ReasonForUsingQuietUi() const override {
+    return absl::nullopt;
+  }
+  void SetDismissOnTabClose() override {}
+  void SetPromptShown() override {}
+  void SetDecisionTime() override {}
+  bool RecreateView() override { return false; }
+
+  base::WeakPtr<permissions::PermissionPrompt::Delegate> GetWeakPtr() override {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  content::WebContents* GetAssociatedWebContents() override { return nullptr; }
+
+ private:
+  std::vector<std::unique_ptr<permissions::PermissionRequest>> requests_;
+  std::vector<permissions::PermissionRequest*> raw_requests_;
+  base::WeakPtrFactory<TestDelegateTwoOrigins> weak_factory_{this};
+};
+}  // namespace
+
+class PermissionPromptBubbleTwoOriginsViewTest : public ChromeViewsTestBase {
+ public:
+  void SetUp() override {
+    ChromeViewsTestBase::SetUp();
+    CreateBrowser();
+  }
+
+  Browser* browser() { return browser_.get(); }
+
+  std::unique_ptr<PermissionPromptBubbleBaseView> CreateBubble(
+      TestDelegateTwoOrigins* delegate) {
+    return std::make_unique<PermissionPromptBubbleTwoOriginsView>(
+        browser(), delegate->GetWeakPtr(), base::TimeTicks::Now(),
+        PermissionPromptStyle::kBubbleOnly);
+  }
+
+ private:
+  void CreateBrowser() {
+    TestingProfile::Builder profile_builder;
+    profile_builder.AddTestingFactory(
+        HistoryServiceFactory::GetInstance(),
+        HistoryServiceFactory::GetDefaultFactory());
+    profile_builder.AddTestingFactory(
+        FaviconServiceFactory::GetInstance(),
+        FaviconServiceFactory::GetDefaultFactory());
+    profile_ = profile_builder.Build();
+    browser_window_ = std::make_unique<TestBrowserWindow>();
+    Browser::CreateParams params(profile_.get(), /*user_gesture=*/true);
+    params.type = Browser::TYPE_NORMAL;
+    params.window = browser_window_.get();
+    browser_.reset(Browser::Create(params));
+  }
+
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<Browser> browser_;
+  std::unique_ptr<TestBrowserWindow> browser_window_;
+};
+
+TEST_F(PermissionPromptBubbleTwoOriginsViewTest,
+       TitleMentionsTwoOriginsAndPermission) {
+  TestDelegateTwoOrigins delegate(GURL("https://test.requesting.origin"),
+                                  GURL("https://test.embedding.origin"),
+                                  {permissions::RequestType::kStorageAccess});
+  auto bubble = CreateBubble(&delegate);
+
+  const auto title = base::UTF16ToUTF8(bubble->GetWindowTitle());
+  EXPECT_PRED_FORMAT2(::testing::IsSubstring, "displaying content", title);
+  // The scheme is not included.
+  EXPECT_PRED_FORMAT2(::testing::IsSubstring, "test.requesting.origin", title);
+  EXPECT_PRED_FORMAT2(::testing::IsSubstring, "test.embedding.origin", title);
+}
+
+TEST_F(PermissionPromptBubbleTwoOriginsViewTest, DiesIfPermissionNotAllowed) {
+  TestDelegateTwoOrigins delegate(GURL("https://test.requesting.origin"),
+                                  GURL("https://test.embedding.origin"),
+                                  {permissions::RequestType::kCameraStream});
+  EXPECT_DEATH_IF_SUPPORTED(CreateBubble(&delegate), "");
+}
+
+// TODO(b/276716358): Add behavior tests to ensure the prompt works and updates
+// the content setting accordingly when accepted/declined.
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.cc
new file mode 100644
index 0000000..5df9b7e
--- /dev/null
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.cc
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h"
+
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.h"
+
+base::raw_ptr<PermissionPromptBubbleBaseView> CreatePermissionPromptBubbleView(
+    Browser* browser,
+    base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate,
+    base::TimeTicks permission_requested_time,
+    PermissionPromptStyle prompt_style) {
+  if (delegate->Requests()[0]->ShouldUseTwoOriginPrompt()) {
+    return new PermissionPromptBubbleTwoOriginsView(
+        browser, delegate, permission_requested_time, prompt_style);
+  } else {
+    return new PermissionPromptBubbleOneOriginView(
+        browser, delegate, permission_requested_time, prompt_style);
+  }
+}
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h
new file mode 100644
index 0000000..2450b8c
--- /dev/null
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h
@@ -0,0 +1,18 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_VIEW_FACTORY_H_
+#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_VIEW_FACTORY_H_
+
+#include "chrome/browser/ui/permission_bubble/permission_prompt.h"
+#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
+
+// Constructs the appropriate prompt bubble view for the |delegate| request.
+base::raw_ptr<PermissionPromptBubbleBaseView> CreatePermissionPromptBubbleView(
+    Browser* browser,
+    base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate,
+    base::TimeTicks permission_requested_time,
+    PermissionPromptStyle prompt_style);
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_VIEW_FACTORY_H_
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 3b2e8052..2b22dcd 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -763,7 +763,9 @@
 
   if (profiles_selectable) {
     AddProfileManagementShortcutFeatureButton(
-        vector_icons::kSettingsIcon,
+        features::IsChromeRefresh2023()
+            ? vector_icons::kSettingsChromeRefreshIcon
+            : vector_icons::kSettingsIcon,
         l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_PROFILES_BUTTON_TOOLTIP),
         base::BindRepeating(&ProfileMenuView::OnManageProfilesButtonClicked,
                             base::Unretained(this)));
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index 5fd7615..75402abc 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -879,11 +879,20 @@
                         gfx::Insets::TLBR(0, 0, 0, kMenuEdgeMargin)));
   }
 
-  profile_mgmt_shortcut_features_container_->AddChildView(
-      std::make_unique<CircularImageButton>(
-          base::BindRepeating(&ProfileMenuViewBase::ButtonPressed,
-                              base::Unretained(this), std::move(action)),
-          icon, text));
+  if (features::IsChromeRefresh2023()) {
+    profile_mgmt_shortcut_features_container_->AddChildView(
+        views::ImageButton::CreateIconButton(
+            base::BindRepeating(&ProfileMenuViewBase::ButtonPressed,
+                                base::Unretained(this), std::move(action)),
+            icon, text, CircularImageButton::MaterialIconStyle::kSmall));
+
+  } else {
+    profile_mgmt_shortcut_features_container_->AddChildView(
+        std::make_unique<CircularImageButton>(
+            base::BindRepeating(&ProfileMenuViewBase::ButtonPressed,
+                                base::Unretained(this), std::move(action)),
+            icon, text));
+  }
 }
 
 void ProfileMenuViewBase::AddProfileManagementManagedHint(
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index d14f3af..939f37fe 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -98,6 +98,7 @@
 #include "chrome/browser/lacros/account_manager/fake_account_manager_ui_dialog_waiter.h"
 #include "chrome/browser/signin/signin_ui_delegate_impl_lacros.h"
 #include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
+#include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
 #endif
 
 namespace {
@@ -738,6 +739,15 @@
       .WillOnce([&loop]() { loop.Quit(); });
 
   // Complete reauth.
+  // Fake that this account was successfully reauthenticated via the UI.
+  crosapi::AccountManagerMojoService* mojo_service =
+      MaybeGetAshAccountManagerMojoServiceForTests();
+  DCHECK(mojo_service);
+  account_manager::AccountKey kAccountKey{account_info_.gaia,
+                                          account_manager::AccountType::kGaia};
+  mojo_service->OnAccountUpsertionFinishedForTesting(
+      account_manager::AccountUpsertionResult::FromAccount(
+          {kAccountKey, account_info_.email}));
   account_manager_ui->CloseDialog();
 
   // Wait until the Sync confirmation is shown.
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
index 8fa6be5..ada8426 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -523,7 +523,7 @@
       crosapi::AccountManagerMojoService* mojo_service =
           MaybeGetAshAccountManagerMojoServiceForTests();
       DCHECK(mojo_service);
-      mojo_service->OnAccountAdditionFinishedForTesting(
+      mojo_service->OnAccountUpsertionFinishedForTesting(
           account_manager::AccountUpsertionResult::FromAccount(
               {kAccountKey, email}));
       fake_ui->CloseDialog();
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 7e0dc17..d5826ad 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -5,8 +5,6 @@
 #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
 
 #include <algorithm>
-#include <cctype>
-#include <cwctype>
 #include <ios>
 #include <limits>
 #include <memory>
@@ -19,6 +17,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
@@ -196,19 +195,20 @@
       base::StringPiece16(text).substr(paren_pos + 1));
 
   // Look for the image width.
-  if (!std::isdigit(it.get()))
+  if (!base::IsAsciiDigit(it.get())) {
     return std::u16string::npos;
-  while (it.Advance() && std::isdigit(it.get())) {
+  }
+  while (it.Advance() && base::IsAsciiDigit(it.get())) {
     // empty loop
   }
 
   // Look for the × character and the height.
   constexpr char16_t kMultiplicationSymbol = u'\u00D7';
   if (it.end() || it.get() != kMultiplicationSymbol || !it.Advance() ||
-      !std::isdigit(it.get())) {
+      !base::IsAsciiDigit(it.get())) {
     return std::u16string::npos;
   }
-  while (it.Advance() && std::isdigit(it.get())) {
+  while (it.Advance() && base::IsAsciiDigit(it.get())) {
     // empty loop
   }
 
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
index dce81b3..6dd0f8b 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest-spi.h"
+#include "web_app_integration_test_driver.h"
 
 namespace web_app::integration_tests {
 namespace {
@@ -181,16 +182,16 @@
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckSubAppInstallation) {
   helper_.InstallMenuOption(InstallableSite::kHasSubApps);
-  helper_.CheckNoSubApps();
+  helper_.CheckNoSubApps(Site::kHasSubApps);
   helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
                         SubAppInstallDialogOptions::kUserAllow);
-  helper_.CheckHasSubApp(Site::kSubApp1);
-  helper_.CheckNotHasSubApp(Site::kSubApp2);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp2);
   helper_.CheckAppInListWindowed(Site::kSubApp1);
-  EXPECT_NONFATAL_FAILURE(helper_.CheckNoSubApps(),
+  EXPECT_NONFATAL_FAILURE(helper_.CheckNoSubApps(Site::kHasSubApps),
                           "Expected equality of these values");
   helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
-  helper_.CheckNoSubApps();
+  helper_.CheckNoSubApps(Site::kHasSubApps);
 }
 
 // Generated tests:
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
index 8dde33a0..34401fd1 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
@@ -252,5 +252,1881 @@
   helper_.SetOpenInTabFromAppSettings(Site::kFileHandler);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsWindowed_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_10HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallFromList(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsWindowed_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsWindowed_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsBrowser_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_10HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallFromList(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsBrowser_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29HasSubAppsBrowser_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_10HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallFromList(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_44HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallPolicyApp(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_44HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallPolicyApp(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsWithShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_44HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallPolicyApp(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutWindowedWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_44HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallPolicyApp(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32HasSubAppsNoShortcutBrowserWebApp_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_10HasSubApps_15SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.UninstallFromList(Site::kHasSubApps);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_138HasSubAppsSubApp2UserAllow_140HasSubAppsSubApp1_140HasSubAppsSubApp2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp2,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47HasSubApps_142HasSubApps_138HasSubAppsSubApp1UserAllow_12SubApp1_140HasSubAppsSubApp1_7SubApp1_139HasSubAppsSubApp1_15SubApp1_142HasSubApps) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppNotInList(Site::kSubApp1);
+  helper_.CheckNoSubApps(Site::kHasSubApps);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Windowed_12SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kWindowed);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_31SubApp1_12SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutWindowedWebApp_12SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutWindowedWebApp_12SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_47SubApp1_12SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_12SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption(InstallableSite::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListWindowed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29SubApp1Browser_11SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kSubApp1, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1WithShortcutBrowserWebApp_11SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_29HasSubAppsWindowed_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kWindowed);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_29HasSubAppsBrowser_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.CreateShortcut(Site::kHasSubApps, WindowOptions::kBrowser);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_31HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallOmniboxIcon(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsWithShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsWithShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsNoShortcutWindowedWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_32HasSubAppsNoShortcutBrowserWebApp_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallPolicyApp(Site::kHasSubApps, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32SubApp1NoShortcutBrowserWebApp_11SubApp1_7SubApp1_47HasSubApps_141HasSubAppsSubApp1_138HasSubAppsSubApp1UserAllow_140HasSubAppsSubApp1_139HasSubAppsSubApp1_141HasSubAppsSubApp1_11SubApp1_7SubApp1) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kSubApp1, ShortcutOptions::kNoShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+  helper_.InstallMenuOption(InstallableSite::kHasSubApps);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.InstallSubApp(Site::kHasSubApps, Site::kSubApp1,
+                        SubAppInstallDialogOptions::kUserAllow);
+  helper_.CheckHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.RemoveSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckNotHasSubApp(Site::kHasSubApps, Site::kSubApp1);
+  helper_.CheckAppInListTabbed(Site::kSubApp1);
+  helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
index 1d6ef51e..fee03bc 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -471,7 +471,7 @@
   base::RunLoop run_loop_;
 };
 
-Browser* GetBrowserForAppId(const Profile* profile, const AppId& app_id) {
+Browser* GetAppBrowserForAppId(const Profile* profile, const AppId& app_id) {
   const BrowserList* browser_list = BrowserList::GetInstance();
   for (auto it = browser_list->begin_browsers_ordered_by_activation();
        it != browser_list->end_browsers_ordered_by_activation(); ++it) {
@@ -487,7 +487,22 @@
 }
 
 bool AreAppBrowsersOpen(const Profile* profile, const AppId& app_id) {
-  return GetBrowserForAppId(profile, app_id) != nullptr;
+  return GetAppBrowserForAppId(profile, app_id) != nullptr;
+}
+
+content::WebContents* GetAnyWebContentsForAppId(const AppId& app_id) {
+  auto* browser_list = BrowserList::GetInstance();
+  for (Browser* browser : *browser_list) {
+    for (int i = 0; i < browser->tab_strip_model()->GetTabCount(); i++) {
+      content::WebContents* web_contents =
+          browser->tab_strip_model()->GetWebContentsAt(i);
+      const AppId* web_contents_id = WebAppTabHelper::GetAppId(web_contents);
+      if (web_contents_id && *web_contents_id == app_id) {
+        return web_contents;
+      }
+    }
+  }
+  return nullptr;
 }
 
 class UninstallCompleteWaiter final : public BrowserListObserver,
@@ -952,13 +967,13 @@
     // Only close windows if immediate updating is not enabled.
     if (!base::FeatureList::IsEnabled(
             features::kWebAppManifestImmediateUpdating)) {
-      Browser* browser = GetBrowserForAppId(profile(), app_id);
+      Browser* browser = GetAppBrowserForAppId(profile(), app_id);
       while (browser != nullptr) {
         if (browser == app_browser_) {
           app_browser_ = nullptr;
         }
         delegate_->CloseBrowserSynchronously(browser);
-        browser = GetBrowserForAppId(profile(), app_id);
+        browser = GetAppBrowserForAppId(profile(), app_id);
       }
     }
     waiting_for_update_run_loop_->Run();
@@ -1510,7 +1525,7 @@
 
   // The app_browser_ is needed only for apps that open in a new window, and is
   // nullptr for apps that launch in a tab.
-  app_browser_ = GetBrowserForAppId(profile(), app_id);
+  app_browser_ = GetAppBrowserForAppId(profile(), app_id);
   active_app_id_ = app_id;
 #endif
   AfterStateChangeAction();
@@ -1597,7 +1612,7 @@
     // If there already is an open app browser for this app the launch is not
     // expected to open a new one, so only wait for a new browser to be added
     // if there wasn't an open one already.
-    app_browser_ = GetBrowserForAppId(profile(), app_id);
+    app_browser_ = GetAppBrowserForAppId(profile(), app_id);
     bool had_open_browsers = false;
     for (auto* profile : GetAllProfiles()) {
       auto* provider = GetProviderForProfile(profile);
@@ -3361,14 +3376,18 @@
   AfterStateCheckAction();
 }
 
-void WebAppIntegrationTestDriver::CheckHasSubApp(Site subapp) {
+void WebAppIntegrationTestDriver::CheckHasSubApp(Site parent_app,
+                                                 Site sub_app) {
   if (!BeforeStateCheckAction(__FUNCTION__)) {
     return;
   }
-  content::WebContents* web_contents =
-      app_browser()->tab_strip_model()->GetActiveWebContents();
 
-  auto subapp_url = GetSiteConfiguration(subapp).relative_url;
+  content::WebContents* web_contents =
+      GetAnyWebContentsForAppId(GetAppIdBySiteMode(parent_app));
+  ASSERT_TRUE(web_contents)
+      << "No open tab or window for the parent app was found.";
+
+  auto sub_app_url = GetSiteConfiguration(sub_app).relative_url;
 
   const base::Value& list_result =
       content::EvalJs(web_contents, "navigator.subApps.list()").value;
@@ -3376,37 +3395,44 @@
   const base::Value::Dict& list_result_dict = list_result.GetDict();
 
   // Check that list() contained the subapp_url key.
-  EXPECT_NE(nullptr, list_result_dict.FindDict(subapp_url));
+  EXPECT_NE(nullptr, list_result_dict.FindDict(sub_app_url));
 
   AfterStateCheckAction();
 }
 
-void WebAppIntegrationTestDriver::CheckNotHasSubApp(Site subapp) {
+void WebAppIntegrationTestDriver::CheckNotHasSubApp(Site parent_app,
+                                                    Site sub_app) {
   if (!BeforeStateCheckAction(__FUNCTION__)) {
     return;
   }
-  content::WebContents* web_contents =
-      app_browser()->tab_strip_model()->GetActiveWebContents();
 
-  auto subapp_url = GetSiteConfiguration(subapp).relative_url;
+  content::WebContents* web_contents =
+      GetAnyWebContentsForAppId(GetAppIdBySiteMode(parent_app));
+  ASSERT_TRUE(web_contents)
+      << "No open tab or window for the parent app was found.";
+
+  auto sub_app_url = GetSiteConfiguration(sub_app).relative_url;
 
   const base::Value& list_result =
       content::EvalJs(web_contents, "navigator.subApps.list()").value;
 
   const base::Value::Dict& list_result_dict = list_result.GetDict();
 
-  // Check that list() did not contain the subapp_url key.
-  EXPECT_EQ(nullptr, list_result_dict.FindDict(subapp_url));
+  // Check that list() did not contain the sub_app_url key.
+  EXPECT_EQ(nullptr, list_result_dict.FindDict(sub_app_url));
 
   AfterStateCheckAction();
 }
 
-void WebAppIntegrationTestDriver::CheckNoSubApps() {
+void WebAppIntegrationTestDriver::CheckNoSubApps(Site parent_app) {
   if (!BeforeStateCheckAction(__FUNCTION__)) {
     return;
   }
+
   content::WebContents* web_contents =
-      app_browser()->tab_strip_model()->GetActiveWebContents();
+      GetAnyWebContentsForAppId(GetAppIdBySiteMode(parent_app));
+  ASSERT_TRUE(web_contents)
+      << "No open tab or window for the parent app was found.";
 
   const base::Value& result =
       content::EvalJs(web_contents, "navigator.subApps.list()").value;
@@ -3786,6 +3812,10 @@
     base::Value default_launch_container,
     const bool create_shortcut,
     const bool install_as_shortcut) {
+  // Many CUJs rely on operating on an opened window / tab after installation,
+  // and this state is true for all installations except for policy install. To
+  // help keep CUJs combined for all installs, do a navigation here.
+  MaybeNavigateTabbedBrowserInScope(site);
   GURL url = GetUrlForSite(site);
   WebAppTestInstallWithOsHooksObserver observer(profile());
   observer.BeginListening();
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
index b6e2b0c..dc02ea7 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
@@ -376,9 +376,9 @@
   void CheckWindowDisplayMinimal();
   void CheckWindowDisplayTabbed();
   void CheckWindowDisplayStandalone();
-  void CheckNotHasSubApp(Site subapp);
-  void CheckHasSubApp(Site subapp);
-  void CheckNoSubApps();
+  void CheckNotHasSubApp(Site parent_app, Site sub_app);
+  void CheckHasSubApp(Site parent_app, Site sub_app);
+  void CheckNoSubApps(Site parent_app);
   void CheckAppLoadedInTab(Site site);
 
  protected:
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn
index 253b136..f089419 100644
--- a/chrome/browser/ui/webui/BUILD.gn
+++ b/chrome/browser/ui/webui/BUILD.gn
@@ -19,7 +19,7 @@
   deps = [
     "//components/lens:buildflags",
     "//content/public/browser",
-    "//printing/buildflags:buildflags",
+    "//printing/buildflags",
     "//skia",
     "//third_party/abseil-cpp:absl",
   ]
@@ -51,20 +51,21 @@
   if (is_chromeos_ash) {
     deps += [
       "//ash/constants",
-      "//ash/webui/color_internals:color_internals",
+      "//ash/webui/color_internals",
       "//ash/webui/demo_mode_app_ui",
-      "//ash/webui/diagnostics_ui:diagnostics_ui",
+      "//ash/webui/diagnostics_ui",
       "//ash/webui/eche_app_ui",
       "//ash/webui/face_ml_app_ui",
       "//ash/webui/file_manager:file_manager_untrusted_ui",
-      "//ash/webui/firmware_update_ui:firmware_update_ui",
-      "//ash/webui/guest_os_installer:guest_os_installer",
+      "//ash/webui/firmware_update_ui",
+      "//ash/webui/guest_os_installer",
       "//ash/webui/help_app_ui",
       "//ash/webui/os_feedback_ui",
-      "//ash/webui/scanning:scanning",
-      "//ash/webui/shimless_rma:shimless_rma",
+      "//ash/webui/print_management",
+      "//ash/webui/scanning",
+      "//ash/webui/shimless_rma",
       "//ash/webui/shortcut_customization_ui",
-      "//ash/webui/system_extensions_internals_ui:system_extensions_internals_ui",
+      "//ash/webui/system_extensions_internals_ui",
       "//chrome/browser/ash",
     ]
     if (!is_official_build) {
diff --git a/chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.cc b/chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.cc
index 78c3b94..4f5cb02 100644
--- a/chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.cc
+++ b/chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.cc
@@ -67,7 +67,7 @@
         ->ShowReauthAccountDialog(
             account_manager::AccountManagerFacade::AccountAdditionSource::
                 kAccountManagerMigrationWelcomeScreen,
-            account_email, base::OnceClosure());
+            account_email, base::DoNothing());
     HandleCloseDialog(args);
   }
 
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
index 141a74f5..38f116e 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -772,7 +772,6 @@
   using file_manager::file_tasks::
       SetOfficeMoveConfirmationShownForLocalToOneDrive;
   using file_manager::file_tasks::SetOfficeMoveConfirmationShownForOneDrive;
-  using file_manager::file_tasks::SetOfficeSetupComplete;
   using file_manager::file_tasks::SetPowerPointFileHandlerToFilesSWA;
   using file_manager::file_tasks::SetWordFileHandlerToFilesSWA;
 
@@ -798,10 +797,8 @@
           profile_,
           file_manager::file_tasks::kActionIdWebDriveOfficePowerPoint);
     }
-    SetOfficeSetupComplete(profile_);
     OpenOrMoveFiles();
   } else if (user_response == kUserActionConfirmOrUploadToOneDrive) {
-    SetOfficeSetupComplete(profile_);
     // Default handlers have already been set by this point for
     // Office/OneDrive.
     OpenOrMoveFiles();
@@ -893,7 +890,6 @@
   if (HasPowerPointFile(file_urls_)) {
     SetPowerPointFileHandler(profile_, task);
   }
-  file_manager::file_tasks::SetOfficeSetupComplete(profile_);
 }
 
 // Find the file tasks that can open the `file_urls` and pass them to the
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc
index d869100..3923752 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc
@@ -129,7 +129,6 @@
       profile_, kActionIdOpenInOffice);
   file_manager::file_tasks::SetPowerPointFileHandlerToFilesSWA(
       profile_, kActionIdOpenInOffice);
-  file_manager::file_tasks::SetOfficeSetupComplete(profile_);
 }
 
 void CloudUploadPageHandler::GetAlwaysMoveOfficeFilesToDrive(
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
index 6814e4f..35ace7c 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
@@ -6,9 +6,11 @@
 
 #include "base/check_op.h"
 #include "base/files/file_path.h"
+#include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/file_manager/copy_or_move_io_task.h"
+#include "chrome/browser/ash/file_manager/file_tasks.h"
 #include "chrome/browser/ash/file_manager/fileapi_util.h"
 #include "chrome/browser/ash/file_manager/io_task.h"
 #include "chrome/browser/ash/file_manager/volume_manager.h"
@@ -39,14 +41,17 @@
 }
 
 std::string GetTargetAppName(base::FilePath file_path) {
-  const std::string extension = file_path.FinalExtension();
-  if (extension == ".doc" || extension == ".docx") {
+  const std::string extension = base::ToLowerASCII(file_path.FinalExtension());
+  if (base::Contains(file_manager::file_tasks::WordGroupExtensions(),
+                     extension)) {
     return "Google Docs";
   }
-  if (extension == ".xls" || extension == ".xlsx") {
+  if (base::Contains(file_manager::file_tasks::ExcelGroupExtensions(),
+                     extension)) {
     return "Google Sheets";
   }
-  if (extension == ".ppt" || extension == ".pptx") {
+  if (base::Contains(file_manager::file_tasks::PowerPointGroupExtensions(),
+                     extension)) {
     return "Google Slides";
   }
   return "Google Docs";
@@ -120,7 +125,7 @@
   }
 
   if (!drive_integration_service_) {
-    OnEndUpload(GURL(), "No drive integration service");
+    OnEndUpload(GURL(), "No Drive integration service");
     return;
   }
 
@@ -130,6 +135,11 @@
   // Observe Drive updates.
   drive_integration_service_->GetDriveFsHost()->AddObserver(this);
 
+  if (!drive_integration_service_->IsMounted()) {
+    OnEndUpload(GURL(), "Google Drive is not mounted");
+    return;
+  }
+
   // Destination url.
   base::FilePath destination_folder_path =
       drive_integration_service_->GetMountPointPath().Append("root");
diff --git a/chrome/browser/ui/webui/ash/emoji/emoji_page_handler.cc b/chrome/browser/ui/webui/ash/emoji/emoji_page_handler.cc
index 0be4623..3ca62fbc 100644
--- a/chrome/browser/ui/webui/ash/emoji/emoji_page_handler.cc
+++ b/chrome/browser/ui/webui/ash/emoji/emoji_page_handler.cc
@@ -81,7 +81,7 @@
   clipboard->WriteHTML(base::UTF8ToUTF16(BuildGifHTML(gif_to_copy)), "",
                        ui::ClipboardContentType::kSanitized);
 
-  // Show a toast that says the GIF has been copied to the clipboard.
+  // Show a toast that says "GIF copied to clipboard".
   ToastManager::Get()->Show(ToastData(
       kEmojiPickerToastId, ToastCatalogName::kCopyGifToClipboardAction,
       l10n_util::GetStringUTF16(IDS_ASH_EMOJI_PICKER_COPY_GIF_TO_CLIPBOARD)));
diff --git a/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.cc b/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.cc
deleted file mode 100644
index 2276c4b..0000000
--- a/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h"
-
-#include "chrome/browser/ash/login/screens/active_directory_password_change_screen.h"
-#include "chrome/browser/ui/webui/ash/login/core_oobe_handler.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/login/localized_values_builder.h"
-
-namespace ash {
-
-namespace {
-
-constexpr char kUsernameKey[] = "username";
-constexpr char kErrorKey[] = "error";
-
-}  // namespace
-
-ActiveDirectoryPasswordChangeScreenHandler::
-    ActiveDirectoryPasswordChangeScreenHandler()
-    : BaseScreenHandler(kScreenId) {}
-
-ActiveDirectoryPasswordChangeScreenHandler::
-    ~ActiveDirectoryPasswordChangeScreenHandler() = default;
-
-void ActiveDirectoryPasswordChangeScreenHandler::DeclareLocalizedValues(
-    ::login::LocalizedValuesBuilder* builder) {
-  builder->Add("adPassChangeMessage", IDS_AD_PASSWORD_CHANGE_MESSAGE);
-}
-
-void ActiveDirectoryPasswordChangeScreenHandler::Show(
-    const std::string& username,
-    int error) {
-  base::Value::Dict data;
-  data.Set(kUsernameKey, username);
-  data.Set(kErrorKey, error);
-  ShowInWebUI(std::move(data));
-}
-
-void ActiveDirectoryPasswordChangeScreenHandler::ShowSignInError(
-    const std::string& error_text) {
-  CallExternalAPI("showErrorDialog", error_text);
-}
-
-}  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h b/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h
deleted file mode 100644
index 8ed164f2..0000000
--- a/chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_ASH_LOGIN_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_ASH_LOGIN_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_HANDLER_H_
-
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ui/webui/ash/login/base_screen_handler.h"
-
-namespace ash {
-
-class ActiveDirectoryPasswordChangeScreen;
-
-// Interface for dependency injection between
-// ActiveDirectoryPasswordChangeScreen and its WebUI representation.
-class ActiveDirectoryPasswordChangeView
-    : public base::SupportsWeakPtr<ActiveDirectoryPasswordChangeView> {
- public:
-  inline static constexpr StaticOobeScreenId kScreenId{
-      "ad-password-change", "ActiveDirectoryPasswordChangeScreen"};
-
-  virtual ~ActiveDirectoryPasswordChangeView() = default;
-
-  // Shows the contents of the screen.
-  virtual void Show(const std::string& username, int error) = 0;
-
-  // Shows sign-in error bubble.
-  virtual void ShowSignInError(const std::string& error_text) = 0;
-};
-
-// A class that handles WebUI hooks in Active Directory password change screen.
-class ActiveDirectoryPasswordChangeScreenHandler
-    : public ActiveDirectoryPasswordChangeView,
-      public BaseScreenHandler {
- public:
-  using TView = ActiveDirectoryPasswordChangeView;
-
-  ActiveDirectoryPasswordChangeScreenHandler();
-
-  ActiveDirectoryPasswordChangeScreenHandler(
-      const ActiveDirectoryPasswordChangeScreenHandler&) = delete;
-  ActiveDirectoryPasswordChangeScreenHandler& operator=(
-      const ActiveDirectoryPasswordChangeScreenHandler&) = delete;
-
-  ~ActiveDirectoryPasswordChangeScreenHandler() override;
-
-  // BaseScreenHandler implementation:
-  void DeclareLocalizedValues(
-      ::login::LocalizedValuesBuilder* builder) override;
-
-  // ActiveDirectoryPasswordChangeView:
-  void Show(const std::string& username, int error) override;
-  void ShowSignInError(const std::string& error_text) override;
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_UI_WEBUI_ASH_LOGIN_ACTIVE_DIRECTORY_PASSWORD_CHANGE_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc b/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc
index f94ad1a..f997433 100644
--- a/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc
@@ -170,7 +170,7 @@
 }
 
 void CoreOobeHandler::HandleBackdropLoaded() {
-  // TODO (b/269104621) Event picked up by b/269104621
+  GetOobeUI()->OnBackdropLoaded();
 }
 
 void CoreOobeHandler::HandleEnableShelfButtons(bool enable) {
@@ -230,6 +230,10 @@
   CallJS("cr.ui.Oobe.toggleSystemInfo");
 }
 
+void CoreOobeHandler::TriggerDown() {
+  CallJS("cr.ui.Oobe.triggerDown");
+}
+
 void CoreOobeHandler::LaunchHelpApp(int help_topic_id) {
   HandleLaunchHelpApp(help_topic_id);
 }
diff --git a/chrome/browser/ui/webui/ash/login/core_oobe_handler.h b/chrome/browser/ui/webui/ash/login/core_oobe_handler.h
index 3844ff9..e6ffe73 100644
--- a/chrome/browser/ui/webui/ash/login/core_oobe_handler.h
+++ b/chrome/browser/ui/webui/ash/login/core_oobe_handler.h
@@ -37,6 +37,7 @@
   virtual void ReloadContent(base::Value::Dict dictionary) = 0;
   virtual void UpdateClientAreaSize(const gfx::Size& size) = 0;
   virtual void ToggleSystemInfo() = 0;
+  virtual void TriggerDown() = 0;
   virtual void ForwardCancel() = 0;
   virtual void LaunchHelpApp(int help_topic_id) = 0;
 };
@@ -82,6 +83,7 @@
   // Updates client area size based on the primary screen size.
   void UpdateClientAreaSize(const gfx::Size& size) override;
   void ToggleSystemInfo() override;
+  void TriggerDown() override;
   // Forwards the cancel accelerator value to the shown screen.
   void ForwardCancel() override;
   void LaunchHelpApp(int help_topic_id) override;
diff --git a/chrome/browser/ui/webui/ash/login/oobe_ui.cc b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
index 15a184f..d54ea79 100644
--- a/chrome/browser/ui/webui/ash/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
@@ -42,7 +42,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/about_ui.h"
-#include "chrome/browser/ui/webui/ash/login/active_directory_password_change_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/app_downloading_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/app_launch_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/ash/login/arc_vm_data_migration_screen_handler.h"
@@ -436,9 +435,6 @@
 
   AddScreenHandler(std::make_unique<GaiaPasswordChangedScreenHandler>());
 
-  auto password_change_handler =
-      std::make_unique<ActiveDirectoryPasswordChangeScreenHandler>();
-
   if (features::IsOobeGaiaInfoScreenEnabled()) {
     AddScreenHandler(std::make_unique<GaiaInfoScreenHandler>());
   }
@@ -452,8 +448,6 @@
 
   AddScreenHandler(std::make_unique<OfflineLoginScreenHandler>());
 
-  AddScreenHandler(std::move(password_change_handler));
-
   AddWebUIHandler(std::make_unique<SshConfiguredHandler>());
 
   AddScreenHandler(std::make_unique<AppLaunchSplashScreenHandler>(
@@ -761,6 +755,12 @@
     observer.OnCurrentScreenChanged(previous_screen_, new_screen);
 }
 
+void OobeUI::OnBackdropLoaded() {
+  for (Observer& observer : observer_list_) {
+    observer.OnBackdropLoaded();
+  }
+}
+
 bool OobeUI::IsJSReady(base::OnceClosure display_is_ready_callback) {
   if (!ready_)
     ready_callbacks_.AddUnsafe(std::move(display_is_ready_callback));
diff --git a/chrome/browser/ui/webui/ash/login/oobe_ui.h b/chrome/browser/ui/webui/ash/login/oobe_ui.h
index 0de27e2e..94e6795e 100644
--- a/chrome/browser/ui/webui/ash/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/ash/login/oobe_ui.h
@@ -74,6 +74,7 @@
     virtual void OnCurrentScreenChanged(OobeScreenId current_screen,
                                         OobeScreenId new_screen) = 0;
 
+    virtual void OnBackdropLoaded() {}
     virtual void OnDestroyingOobeUI() = 0;
 
    protected:
@@ -99,6 +100,9 @@
   // Called when the screen has changed.
   void CurrentScreenChanged(OobeScreenId screen);
 
+  // Called when the backdrop image of the OOBE is loaded.
+  void OnBackdropLoaded();
+
   bool IsJSReady(base::OnceClosure display_is_ready_callback);
 
   gfx::NativeView GetNativeView();
diff --git a/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.cc b/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.cc
index 9c9b67f..9d14def 100644
--- a/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.cc
+++ b/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.cc
@@ -61,18 +61,9 @@
     case ash::office_fallback::FallbackReason::kDriveUnavailable:
       title_id = IDS_OFFICE_FALLBACK_TITLE_DRIVE_UNAVAILABLE;
       reason_message_id = IDS_OFFICE_FALLBACK_REASON_DRIVE_UNAVAILABLE;
+      instructions_message_id =
+          IDS_OFFICE_FALLBACK_INSTRUCTIONS_DRIVE_UNAVAILABLE;
       break;
-    case ash::office_fallback::FallbackReason::kOneDriveUnavailable:
-      title_id = IDS_OFFICE_FALLBACK_TITLE_ONEDRIVE_UNAVAILABLE;
-      reason_message_id = IDS_OFFICE_FALLBACK_REASON_ONEDRIVE_UNAVAILABLE;
-      break;
-    case ash::office_fallback::FallbackReason::kErrorOpeningWeb:
-      title_id = IDS_OFFICE_FALLBACK_TITLE_ERROR_OPENING_WEB;
-      reason_message_id = IDS_OFFICE_FALLBACK_REASON_ERROR_OPENING_WEB;
-      break;
-    case ash::office_fallback::FallbackReason::kInvalidGoogleDocsURL:
-      title_id = IDS_OFFICE_FALLBACK_TITLE_INVALID_GOOGLE_DOCS_URL;
-      reason_message_id = IDS_OFFICE_FALLBACK_REASON_INVALID_GOOGLE_DOCS_URL;
   }
 }
 }  // namespace
diff --git a/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h b/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h
index bbde6df..6192d92f 100644
--- a/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h
+++ b/chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h
@@ -15,14 +15,10 @@
 using DialogChoiceCallback =
     base::OnceCallback<void(const std::string& choice)>;
 
-// The reason for why the user's file can't open. The enum should be consistent
-// with the FallbackReason enum in office_fallback_dialog.ts.
+// The reason why the user's file can't open.
 enum class FallbackReason {
   kOffline,
   kDriveUnavailable,
-  kOneDriveUnavailable,
-  kErrorOpeningWeb,
-  kInvalidGoogleDocsURL,
 };
 
 // Defines the web dialog used to allow users to choose what to do when failing
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index f67172ec..197c3af1 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -197,8 +197,6 @@
 #include "ash/webui/os_feedback_ui/backend/os_feedback_delegate.h"
 #include "ash/webui/os_feedback_ui/os_feedback_ui.h"
 #include "ash/webui/os_feedback_ui/url_constants.h"
-#include "ash/webui/print_management/print_management_ui.h"
-#include "ash/webui/print_management/url_constants.h"
 #include "ash/webui/system_extensions_internals_ui/system_extensions_internals_ui.h"
 #include "ash/webui/system_extensions_internals_ui/url_constants.h"
 #include "base/system/sys_info.h"
@@ -211,8 +209,6 @@
 #include "chrome/browser/ash/login/login_pref_names.h"
 #include "chrome/browser/ash/net/network_health/network_health_manager.h"
 #include "chrome/browser/ash/os_feedback/chrome_os_feedback_delegate.h"
-#include "chrome/browser/ash/printing/print_management/printing_manager.h"
-#include "chrome/browser/ash/printing/print_management/printing_manager_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/ash/web_applications/files_internals_ui_delegate.h"
@@ -456,31 +452,6 @@
           history_clusters_internals::kChromeUIHistoryClustersInternalsHost));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-
-void BindPrintManagement(
-    Profile* profile,
-    mojo::PendingReceiver<
-        chromeos::printing::printing_manager::mojom::PrintingMetadataProvider>
-        receiver) {
-  ash::printing::print_management::PrintingManager* handler =
-      ash::printing::print_management::PrintingManagerFactory::GetForProfile(
-          profile);
-  if (handler)
-    handler->BindInterface(std::move(receiver));
-}
-
-template <>
-WebUIController* NewWebUI<ash::printing::printing_manager::PrintManagementUI>(
-    WebUI* web_ui,
-    const GURL& url) {
-  return new ash::printing::printing_manager::PrintManagementUI(
-      web_ui,
-      base::BindRepeating(&BindPrintManagement, Profile::FromWebUI(web_ui)));
-}
-
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 template <>
 WebUIController* NewWebUI<WelcomeUI>(WebUI* web_ui, const GURL& url) {
@@ -753,8 +724,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (url.host_piece() == chrome::kChromeUIMobileSetupHost)
     return &NewWebUI<ash::cellular_setup::MobileSetupUI>;
-  if (url.host_piece() == ash::kChromeUIPrintManagementHost)
-    return &NewWebUI<ash::printing::printing_manager::PrintManagementUI>;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   if (url.host_piece() == chrome::kChromeUIWebUIJsErrorHost)
diff --git a/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
index 2369992..a6dcb35 100644
--- a/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
+++ b/chrome/browser/ui/webui/chromeos/chrome_web_ui_configs_chromeos.cc
@@ -33,6 +33,7 @@
 #include "ash/webui/media_app_ui/media_app_ui.h"
 #include "ash/webui/os_feedback_ui/os_feedback_ui.h"
 #include "ash/webui/personalization_app/personalization_app_ui.h"
+#include "ash/webui/print_management/print_management_ui.h"
 #include "ash/webui/scanning/scanning_ui.h"
 #include "ash/webui/shimless_rma/shimless_rma.h"
 #include "ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.h"
@@ -42,6 +43,7 @@
 #include "chrome/browser/ash/multidevice_debug/proximity_auth_ui_config.h"
 #include "chrome/browser/ash/net/network_health/network_health_manager.h"
 #include "chrome/browser/ash/os_feedback/chrome_os_feedback_delegate.h"
+#include "chrome/browser/ash/printing/print_management/printing_manager_factory.h"
 #include "chrome/browser/ash/scanning/chrome_scanning_app_delegate.h"
 #include "chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h"
 #include "chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h"
@@ -115,7 +117,7 @@
 class WebUIController;
 }  // namespace content
 
-namespace {
+namespace ash {
 using CreateWebUIControllerFunc = base::RepeatingCallback<std::unique_ptr<
     content::WebUIController>(content::WebUI*, const GURL& url)>;
 
@@ -152,14 +154,14 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 std::unique_ptr<content::WebUIConfig> MakeConnectivityDiagnosticsUIConfig() {
-  return MakeComponentConfigWithArgs<ash::ConnectivityDiagnosticsUIConfig,
-                                     ash::ConnectivityDiagnosticsUI>(
+  return MakeComponentConfigWithArgs<ConnectivityDiagnosticsUIConfig,
+                                     ConnectivityDiagnosticsUI>(
       /* BindNetworkDiagnosticsServiceCallback */
-      base::BindRepeating(&ash::network_health::NetworkHealthManager::
+      base::BindRepeating(&network_health::NetworkHealthManager::
                               NetworkDiagnosticsServiceCallback),
       /* BindNetworkHealthServiceCallback */
-      base::BindRepeating(&ash::network_health::NetworkHealthManager::
-                              NetworkHealthServiceCallback),
+      base::BindRepeating(
+          &network_health::NetworkHealthManager::NetworkHealthServiceCallback),
       /* SendFeedbackReportCallback */
       base::BindRepeating(
           &chrome::ShowFeedbackDialogForWebUI,
@@ -171,14 +173,14 @@
   CreateWebUIControllerFunc create_controller_func = base::BindRepeating(
       [](content::WebUI* web_ui,
          const GURL& url) -> std::unique_ptr<content::WebUIController> {
-        ash::HoldingSpaceKeyedService* holding_space_keyed_service =
-            ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(
+        HoldingSpaceKeyedService* holding_space_keyed_service =
+            HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(
                 web_ui->GetWebContents()->GetBrowserContext());
         // This directory stores routine and network event logs for a given
         // |profile|.
         static constexpr base::FilePath::CharType
             kDiagnosticsLogDirectoryName[] = FILE_PATH_LITERAL("diagnostics");
-        return std::make_unique<ash::DiagnosticsDialogUI>(
+        return std::make_unique<DiagnosticsDialogUI>(
             web_ui,
             base::BindRepeating([](content::WebContents* web_contents)
                                     -> std::unique_ptr<ui::SelectFilePolicy> {
@@ -189,8 +191,7 @@
                 kDiagnosticsLogDirectoryName));
       });
 
-  return std::make_unique<ash::DiagnosticsDialogUIConfig>(
-      create_controller_func);
+  return std::make_unique<DiagnosticsDialogUIConfig>(create_controller_func);
 }
 
 std::unique_ptr<content::WebUIConfig> MakeEcheAppUIConfig() {
@@ -198,137 +199,137 @@
       [](content::WebUI* web_ui,
          const GURL& url) -> std::unique_ptr<content::WebUIController> {
         Profile* profile = Profile::FromWebUI(web_ui);
-        ash::eche_app::EcheAppManager* manager =
-            ash::eche_app::EcheAppManagerFactory::GetForProfile(profile);
-        return std::make_unique<ash::eche_app::EcheAppUI>(web_ui, manager);
+        eche_app::EcheAppManager* manager =
+            eche_app::EcheAppManagerFactory::GetForProfile(profile);
+        return std::make_unique<eche_app::EcheAppUI>(web_ui, manager);
       });
 
-  return std::make_unique<ash::eche_app::EcheAppUIConfig>(
-      create_controller_func);
+  return std::make_unique<eche_app::EcheAppUIConfig>(create_controller_func);
 }
 
 void RegisterAshChromeWebUIConfigs() {
   // Add `WebUIConfig`s for Ash ChromeOS to the list here.
   auto& map = content::WebUIConfigMap::GetInstance();
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::CameraAppUIConfig, ash::CameraAppUI,
+      MakeComponentConfigWithDelegate<CameraAppUIConfig, CameraAppUI,
                                       ChromeCameraAppUIDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::AccountManagerErrorUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::AccountMigrationWelcomeUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::AddSupervisionUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::ArcGraphicsTracingUIConfig<
-                         ash::ArcGraphicsTracingMode::kFull>>());
-  map.AddWebUIConfig(std::make_unique<ash::ArcGraphicsTracingUIConfig<
-                         ash::ArcGraphicsTracingMode::kOverview>>());
-  map.AddWebUIConfig(std::make_unique<ash::ArcPowerControlUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::AssistantOptInUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::AudioUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::BluetoothPairingDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::CertificateManagerDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<AccountManagerErrorUIConfig>());
+  map.AddWebUIConfig(std::make_unique<AccountMigrationWelcomeUIConfig>());
+  map.AddWebUIConfig(std::make_unique<AddSupervisionUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::cloud_upload::CloudUploadUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::ColorInternalsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::ConfirmPasswordChangeUIConfig>());
+      std::make_unique<
+          ArcGraphicsTracingUIConfig<ArcGraphicsTracingMode::kFull>>());
+  map.AddWebUIConfig(
+      std::make_unique<
+          ArcGraphicsTracingUIConfig<ArcGraphicsTracingMode::kOverview>>());
+  map.AddWebUIConfig(std::make_unique<ArcPowerControlUIConfig>());
+  map.AddWebUIConfig(std::make_unique<AssistantOptInUIConfig>());
+  map.AddWebUIConfig(std::make_unique<AudioUIConfig>());
+  map.AddWebUIConfig(std::make_unique<BluetoothPairingDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<CertificateManagerDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<cloud_upload::CloudUploadUIConfig>());
+  map.AddWebUIConfig(std::make_unique<ColorInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<ConfirmPasswordChangeUIConfig>());
   map.AddWebUIConfig(MakeConnectivityDiagnosticsUIConfig());
-  map.AddWebUIConfig(std::make_unique<ash::CrostiniInstallerUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::CrostiniUpgraderUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::CryptohomeUIConfig>());
+  map.AddWebUIConfig(std::make_unique<CrostiniInstallerUIConfig>());
+  map.AddWebUIConfig(std::make_unique<CrostiniUpgraderUIConfig>());
+  map.AddWebUIConfig(std::make_unique<CryptohomeUIConfig>());
   map.AddWebUIConfig(MakeDiagnosticsUIConfig());
-  map.AddWebUIConfig(std::make_unique<ash::DriveInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<DriveInternalsUIConfig>());
   map.AddWebUIConfig(MakeEcheAppUIConfig());
-  map.AddWebUIConfig(std::make_unique<ash::EmojiUIConfig>());
+  map.AddWebUIConfig(std::make_unique<EmojiUIConfig>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::FaceMLAppUIConfig, ash::FaceMLAppUI,
-                                      ash::ChromeFaceMLUserProvider>());
+      MakeComponentConfigWithDelegate<FaceMLAppUIConfig, FaceMLAppUI,
+                                      ChromeFaceMLUserProvider>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::FilesInternalsUIConfig,
-                                      ash::FilesInternalsUI,
+      MakeComponentConfigWithDelegate<FilesInternalsUIConfig, FilesInternalsUI,
                                       ChromeFilesInternalsUIDelegate>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::file_manager::FileManagerUIConfig,
-                                      ash::file_manager::FileManagerUI,
+      MakeComponentConfigWithDelegate<file_manager::FileManagerUIConfig,
+                                      file_manager::FileManagerUI,
                                       ChromeFileManagerUIDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::FirmwareUpdateAppUIConfig>());
-  map.AddWebUIConfig(MakeComponentConfigWithArgs<ash::GuestOSInstallerUIConfig,
-                                                 ash::GuestOSInstallerUI>(
-      base::BindRepeating(&guest_os::InstallerDelegateFactory)));
-  map.AddWebUIConfig(std::make_unique<ash::HealthdInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<FirmwareUpdateAppUIConfig>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::HelpAppUIConfig, ash::HelpAppUI,
-                                      ash::ChromeHelpAppUIDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::HumanPresenceInternalsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::InternetConfigDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::InternetDetailDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::KerberosInBrowserUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::LauncherInternalsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::LockScreenNetworkUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::LockScreenStartReauthUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::ManageMirrorSyncUIConfig>());
+      MakeComponentConfigWithArgs<GuestOSInstallerUIConfig, GuestOSInstallerUI>(
+          base::BindRepeating(&guest_os::InstallerDelegateFactory)));
+  map.AddWebUIConfig(std::make_unique<HealthdInternalsUIConfig>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::MediaAppUIConfig, ash::MediaAppUI,
+      MakeComponentConfigWithDelegate<HelpAppUIConfig, HelpAppUI,
+                                      ChromeHelpAppUIDelegate>());
+  map.AddWebUIConfig(std::make_unique<HumanPresenceInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<InternetConfigDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<InternetDetailDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<KerberosInBrowserUIConfig>());
+  map.AddWebUIConfig(std::make_unique<LauncherInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<LockScreenNetworkUIConfig>());
+  map.AddWebUIConfig(std::make_unique<LockScreenStartReauthUIConfig>());
+  map.AddWebUIConfig(std::make_unique<ManageMirrorSyncUIConfig>());
+  map.AddWebUIConfig(
+      MakeComponentConfigWithDelegate<MediaAppUIConfig, MediaAppUI,
                                       ChromeMediaAppUIDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::MultideviceInternalsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<
-                     ash::multidevice_setup::MultiDeviceSetupDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<MultideviceInternalsUIConfig>());
+  map.AddWebUIConfig(
+      std::make_unique<multidevice_setup::MultiDeviceSetupDialogUIConfig>());
   map.AddWebUIConfig(std::make_unique<NearbyInternalsUIConfig>());
   map.AddWebUIConfig(
       std::make_unique<nearby_share::NearbyShareDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::NetworkUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::NotificationTesterUIConfig>());
+  map.AddWebUIConfig(std::make_unique<NetworkUIConfig>());
+  map.AddWebUIConfig(std::make_unique<NotificationTesterUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::office_fallback::OfficeFallbackUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::OobeUIConfig>());
+      std::make_unique<office_fallback::OfficeFallbackUIConfig>());
+  map.AddWebUIConfig(std::make_unique<OobeUIConfig>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::OSFeedbackUIConfig,
-                                      ash::OSFeedbackUI,
-                                      ash::ChromeOsFeedbackDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::settings::OSSettingsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::ParentAccessUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::PasswordChangeUIConfig>());
+      MakeComponentConfigWithDelegate<OSFeedbackUIConfig, OSFeedbackUI,
+                                      ChromeOsFeedbackDelegate>());
+  map.AddWebUIConfig(std::make_unique<settings::OSSettingsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<ParentAccessUIConfig>());
+  map.AddWebUIConfig(std::make_unique<PasswordChangeUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::reporting::EnterpriseReportingUIConfig>());
+      std::make_unique<reporting::EnterpriseReportingUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::personalization_app::PersonalizationAppUIConfig>(
+      std::make_unique<personalization_app::PersonalizationAppUIConfig>(
           base::BindRepeating(
-              ash::personalization_app::CreatePersonalizationAppUI)));
-  map.AddWebUIConfig(std::make_unique<ash::PowerUIConfig>());
+              personalization_app::CreatePersonalizationAppUI)));
+  map.AddWebUIConfig(std::make_unique<PowerUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::multidevice::ProximityAuthUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::RemoteMaintenanceCurtainUIConfig>());
+      std::make_unique<printing::printing_manager::PrintManagementUIConfig>(
+          base::BindRepeating(
+              &printing::print_management::PrintingManagerFactory::
+                  CreatePrintManagementUIController)));
+  map.AddWebUIConfig(std::make_unique<multidevice::ProximityAuthUIConfig>());
+  map.AddWebUIConfig(std::make_unique<RemoteMaintenanceCurtainUIConfig>());
   map.AddWebUIConfig(
-      MakeComponentConfigWithDelegate<ash::ScanningUIConfig, ash::ScanningUI,
-                                      ash::ChromeScanningAppDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::SetTimeUIConfig>());
+      MakeComponentConfigWithDelegate<ScanningUIConfig, ScanningUI,
+                                      ChromeScanningAppDelegate>());
+  map.AddWebUIConfig(std::make_unique<SetTimeUIConfig>());
   map.AddWebUIConfig(MakeComponentConfigWithDelegate<
-                     ash::ShimlessRMADialogUIConfig, ash::ShimlessRMADialogUI,
-                     ash::shimless_rma::ChromeShimlessRmaDelegate>());
-  map.AddWebUIConfig(std::make_unique<ash::ShortcutCustomizationAppUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::SlowTraceControllerConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::SlowUIConfig>());
+                     ShimlessRMADialogUIConfig, ShimlessRMADialogUI,
+                     shimless_rma::ChromeShimlessRmaDelegate>());
+  map.AddWebUIConfig(std::make_unique<ShortcutCustomizationAppUIConfig>());
+  map.AddWebUIConfig(std::make_unique<SlowTraceControllerConfig>());
+  map.AddWebUIConfig(std::make_unique<SlowUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::smb_dialog::SmbCredentialsDialogUIConfig>());
+      std::make_unique<smb_dialog::SmbCredentialsDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<smb_dialog::SmbShareDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<SysInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<SystemExtensionsInternalsUIConfig>());
+  map.AddWebUIConfig(std::make_unique<TrustedProjectorUIConfig>());
   map.AddWebUIConfig(
-      std::make_unique<ash::smb_dialog::SmbShareDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::SysInternalsUIConfig>());
-  map.AddWebUIConfig(
-      std::make_unique<ash::SystemExtensionsInternalsUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::TrustedProjectorUIConfig>());
-  map.AddWebUIConfig(
-      std::make_unique<ash::UrgentPasswordExpiryNotificationUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::VcTrayTesterUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ash::VmUIConfig>());
+      std::make_unique<UrgentPasswordExpiryNotificationUIConfig>());
+  map.AddWebUIConfig(std::make_unique<VcTrayTesterUIConfig>());
+  map.AddWebUIConfig(std::make_unique<VmUIConfig>());
 #if !defined(OFFICIAL_BUILD)
-  map.AddWebUIConfig(std::make_unique<ash::SampleSystemWebAppUIConfig>());
+  map.AddWebUIConfig(std::make_unique<SampleSystemWebAppUIConfig>());
 #if !defined(USE_REAL_DBUS_CLIENTS)
-  map.AddWebUIConfig(std::make_unique<ash::DeviceEmulatorUIConfig>());
+  map.AddWebUIConfig(std::make_unique<DeviceEmulatorUIConfig>());
 #endif  // !defined(USE_REAL_DBUS_CLIENTS)
 #endif  // !defined(OFFICIAL_BUILD)
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}  // namespace
+}  // namespace ash
 
 void RegisterChromeOSChromeWebUIConfigs() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  RegisterAshChromeWebUIConfigs();
+  ash::RegisterAshChromeWebUIConfigs();
 #endif
 }
diff --git a/chrome/browser/ui/webui/device_log_ui.cc b/chrome/browser/ui/webui/device_log_ui.cc
index d8d557a..caa508db 100644
--- a/chrome/browser/ui/webui/device_log_ui.cc
+++ b/chrome/browser/ui/webui/device_log_ui.cc
@@ -21,6 +21,16 @@
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/base/webui/web_ui_util.h"
 
+#if BUILDFLAG(IS_CHROMEOS)
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/webui_url_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/crosapi/browser_manager.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 namespace chromeos {
 
 namespace {
@@ -42,6 +52,16 @@
     web_ui()->RegisterMessageCallback(
         "clearLog", base::BindRepeating(&DeviceLogMessageHandler::ClearLog,
                                         base::Unretained(this)));
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    web_ui()->RegisterMessageCallback(
+        "isLacrosEnabled",
+        base::BindRepeating(&DeviceLogMessageHandler::IsLacrosEnabled,
+                            base::Unretained(this)));
+    web_ui()->RegisterMessageCallback(
+        "openBrowserDeviceLog",
+        base::BindRepeating(&DeviceLogMessageHandler::OpenBrowserDevieLog,
+                            base::Unretained(this)));
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   }
 
  private:
@@ -57,6 +77,24 @@
   void ClearLog(const base::Value::List& value) const {
     device_event_log::ClearAll();
   }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  void IsLacrosEnabled(const base::Value::List& value) {
+    AllowJavascript();
+    const bool is_lacros_enabled = crosapi::browser_util::IsLacrosEnabled();
+    std::string callback_id = value[0].GetString();
+    ResolveJavascriptCallback(base::Value(callback_id),
+                              base::Value(is_lacros_enabled));
+  }
+
+  void OpenBrowserDevieLog(const base::Value::List& args) const {
+    // Note: This will only be called by the UI when Lacros is available.
+    DCHECK(crosapi::BrowserManager::Get());
+    crosapi::BrowserManager::Get()->SwitchToTab(
+        GURL(chrome::kChromeUIDeviceLogUrl),
+        /*path_behavior=*/NavigateParams::RESPECT);
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 };
 
 }  // namespace
@@ -99,6 +137,17 @@
   };
   html->AddLocalizedStrings(kStrings);
 
+#if BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  auto device_log_url = base::UTF8ToUTF16(chrome::kChromeUIDeviceLogUrl);
+#elif BUILDFLAG(IS_CHROMEOS_LACROS)
+  auto device_log_url = base::UTF8ToUTF16(chrome::kOsUIDeviceLogURL);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  auto os_link_container = l10n_util::GetStringFUTF16(
+      IDS_DEVICE_LOG_OS_LINK_CONTAINER, device_log_url);
+  html->AddString("osLinkContainer", os_link_container);
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
   html->UseStringsJs();
   html->AddResourcePath("device_log_ui.css", IDR_DEVICE_LOG_UI_CSS);
   html->AddResourcePath("device_log_ui.js", IDR_DEVICE_LOG_UI_JS);
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index c35f7724..7b5f398 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -68,8 +68,8 @@
 #endif
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "components/supervised_user/core/browser/supervised_user_error_page.h"  // nogncheck
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 #endif
 
 using security_interstitials::TestSafeBrowsingBlockingPageQuiet;
diff --git a/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc b/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc
index d7c9492..c27d4ad 100644
--- a/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc
+++ b/chrome/browser/ui/webui/settings/ash/account_manager_ui_handler.cc
@@ -417,7 +417,7 @@
       ->ShowReauthAccountDialog(
           account_manager::AccountManagerFacade::AccountAdditionSource::
               kSettingsReauthAccountButton,
-          account_email, base::OnceClosure());
+          account_email, base::DoNothing());
 }
 
 void AccountManagerUIHandler::HandleMigrateAccount(
diff --git a/chrome/browser/ui/webui/settings/ash/apps_section.cc b/chrome/browser/ui/webui/settings/ash/apps_section.cc
index 6b2d221e..6e7b7fd 100644
--- a/chrome/browser/ui/webui/settings/ash/apps_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/apps_section.cc
@@ -275,6 +275,7 @@
       {"appManagementPermissionAllowed", IDS_APP_MANAGEMENT_PERMISSION_ALLOWED},
       {"appManagementPermissionAllowedWithDetails",
        IDS_APP_MANAGEMENT_PERMISSION_ALLOWED_WITH_DETAILS},
+      {"appManagementPermissionAsk", IDS_APP_MANAGEMENT_PERMISSION_ASK},
       {"appManagementPermissionDenied", IDS_APP_MANAGEMENT_PERMISSION_DENIED},
       {"appManagementPermissionsLabel", IDS_APP_MANAGEMENT_PERMISSIONS},
       {"appManagementPinToShelfLabel", IDS_APP_MANAGEMENT_PIN_TO_SHELF},
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index 96f5807..df987a6 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -516,11 +516,6 @@
 TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClear) {
   SigninUser();
   CreatePeopleHandler();
-  // Clearing sync from the dashboard results in DISABLE_REASON_USER_CHOICE
-  // being set.
-  ON_CALL(*mock_sync_service_, GetDisableReasons())
-      .WillByDefault(Return(syncer::SyncService::DisableReasonSet(
-          {syncer::SyncService::DISABLE_REASON_USER_CHOICE})));
   ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
       .WillByDefault(Return(true));
   ON_CALL(*mock_sync_service_, GetTransportState())
@@ -529,8 +524,8 @@
   // Attempting to open the setup UI should restart sync.
   EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested())
       .WillOnce([&]() {
-        // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and
-        // immediately starts initializing the engine.
+        // SetSyncFeatureRequested() clears IsSyncFeatureDisabledViaDashboard()
+        // and immediately starts initializing the engine.
         ON_CALL(*mock_sync_service_, GetDisableReasons())
             .WillByDefault(Return(syncer::SyncService::DisableReasonSet()));
         ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
@@ -550,12 +545,9 @@
        RestartSyncAfterDashboardClearWithStandaloneTransport) {
   SigninUser();
   CreatePeopleHandler();
-  // Clearing sync from the dashboard results in DISABLE_REASON_USER_CHOICE
-  // being set. However, the sync engine has restarted in standalone transport
-  // mode.
-  ON_CALL(*mock_sync_service_, GetDisableReasons())
-      .WillByDefault(Return(syncer::SyncService::DisableReasonSet(
-          {syncer::SyncService::DISABLE_REASON_USER_CHOICE})));
+  // Clearing sync from the dashboard results in
+  // IsSyncFeatureDisabledViaDashboard() returning true. However, the sync
+  // engine has restarted in standalone transport mode.
   ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
       .WillByDefault(Return(true));
   ON_CALL(*mock_sync_service_, GetTransportState())
@@ -564,10 +556,6 @@
   // Attempting to open the setup UI should re-enable sync-the-feature.
   EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested())
       .WillOnce([&]() {
-        // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE. Since
-        // the engine is already running, it just gets reconfigured.
-        ON_CALL(*mock_sync_service_, GetDisableReasons())
-            .WillByDefault(Return(syncer::SyncService::DisableReasonSet()));
         ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
             .WillByDefault(Return(false));
         ON_CALL(*mock_sync_service_, GetTransportState())
@@ -1133,13 +1121,11 @@
   handler_->HandleShowSyncSetupUI(base::Value::List());
 
   // Now sync gets reset from the dashboard (the user clicked the "Manage synced
-  // data" link), which results in the sync-requested and first-setup-complete
-  // bits being cleared.
-  ON_CALL(*mock_sync_service_, GetDisableReasons())
-      .WillByDefault(Return(syncer::SyncService::DisableReasonSet(
-          {syncer::SyncService::DISABLE_REASON_USER_CHOICE})));
+  // data" link), which results in the first-setup-complete bit being cleared.
+  // While first-setup isn't completed, IsSyncFeatureDisabledViaDashboard() also
+  // returns false.
   ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
-      .WillByDefault(Return(true));
+      .WillByDefault(Return(false));
   ON_CALL(*mock_sync_service_->GetMockUserSettings(),
           IsInitialSyncFeatureSetupComplete())
       .WillByDefault(Return(false));
@@ -1154,12 +1140,6 @@
   // and the first-setup-complete bits.
   EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested())
       .WillOnce([&]() {
-        // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and
-        // immediately starts initializing the engine.
-        ON_CALL(*mock_sync_service_, GetDisableReasons())
-            .WillByDefault(Return(syncer::SyncService::DisableReasonSet()));
-        ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
-            .WillByDefault(Return(false));
         ON_CALL(*mock_sync_service_, GetTransportState())
             .WillByDefault(
                 Return(syncer::SyncService::TransportState::INITIALIZING));
@@ -1189,13 +1169,11 @@
   handler_->HandleShowSyncSetupUI(base::Value::List());
 
   // Now sync gets reset from the dashboard (the user clicked the "Manage synced
-  // data" link), which results in the sync-requested and first-setup-complete
-  // bits being cleared.
-  ON_CALL(*mock_sync_service_, GetDisableReasons())
-      .WillByDefault(Return(syncer::SyncService::DisableReasonSet(
-          {syncer::SyncService::DISABLE_REASON_USER_CHOICE})));
+  // data" link), which results in the first-setup-complete bit being cleared.
+  // While first-setup isn't completed, IsSyncFeatureDisabledViaDashboard() also
+  // returns false.
   ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
-      .WillByDefault(Return(true));
+      .WillByDefault(Return(false));
   ON_CALL(*mock_sync_service_->GetMockUserSettings(),
           IsInitialSyncFeatureSetupComplete())
       .WillByDefault(Return(false));
@@ -1224,12 +1202,6 @@
   // first-setup-complete bit.
   EXPECT_CALL(*mock_sync_service_, SetSyncFeatureRequested())
       .WillOnce([&]() {
-        // SetSyncFeatureRequested() clears DISABLE_REASON_USER_CHOICE, and
-        // immediately starts initializing the engine.
-        ON_CALL(*mock_sync_service_, GetDisableReasons())
-            .WillByDefault(Return(syncer::SyncService::DisableReasonSet()));
-        ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard())
-            .WillByDefault(Return(false));
         ON_CALL(*mock_sync_service_, GetTransportState())
             .WillByDefault(
                 Return(syncer::SyncService::TransportState::INITIALIZING));
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 96ca784..4fd1d0a 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -354,6 +354,10 @@
       !chrome::ShouldDisplayManagedUi(profile) && !profile->IsChild();
   html_source->AddBoolean("showPrivacyGuide", show_privacy_guide);
 
+  html_source->AddBoolean(
+      "enableExtendedSettingsDescriptions",
+      base::FeatureList::IsEnabled(features::kExtendedSettingsDescriptions));
+
   html_source->AddBoolean("esbSettingsImprovementsEnabled",
                           base::FeatureList::IsEnabled(
                               safe_browsing::kEsbIphBubbleAndCollapseSettings));
diff --git a/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc b/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc
index 134787e51..cfe16345 100644
--- a/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_permissions_handler.cc
@@ -163,13 +163,12 @@
     const base::Value& stored_value = revoked_permissions.setting_value;
     DCHECK(stored_value.is_dict());
 
-    // The revoked permissions list should be reachable by given key.
-    DCHECK(stored_value.GetDict().FindList(permissions::kRevokedKey));
+    const base::Value::List* type_list =
+        stored_value.GetDict().FindList(permissions::kRevokedKey);
+    CHECK(type_list);
 
-    auto type_list =
-        stored_value.GetDict().FindList(permissions::kRevokedKey)->Clone();
     base::Value::List permissions_value_list;
-    for (base::Value& type : type_list) {
+    for (base::Value& type : type_list->Clone()) {
       permissions_value_list.Append(
           site_settings::ContentSettingsTypeToGroupName(
               static_cast<ContentSettingsType>(type.GetInt())));
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_app_browsertest.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_app_browsertest.cc
index 6240bcac..3e6bbf65 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_app_browsertest.cc
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_app_browsertest.cc
@@ -167,6 +167,17 @@
       "update_content_selection_partially_outside_distilled_content.js"));
 }
 
+IN_PROC_BROWSER_TEST_F(ReadAnythingAppTest,
+                       UpdateContent_Selection_Backwards_WithInlineText) {
+  ASSERT_TRUE(
+      RunTest("update_content_selection_backwards_with_inline_text.js"));
+}
+
+IN_PROC_BROWSER_TEST_F(ReadAnythingAppTest,
+                       UpdateContent_Selection_WithInlineText) {
+  ASSERT_TRUE(RunTest("update_content_selection_with_inline_text.js"));
+}
+
 IN_PROC_BROWSER_TEST_F(ReadAnythingAppTest, UpdateContent_SetSelectedText) {
   ASSERT_TRUE(RunTest("update_content_set_selected_text.js"));
 }
diff --git a/chrome/browser/ui/webui/signin/ash/signin_helper.cc b/chrome/browser/ui/webui/signin/ash/signin_helper.cc
index dffe40f5..b7ea867 100644
--- a/chrome/browser/ui/webui/signin/ash/signin_helper.cc
+++ b/chrome/browser/ui/webui/signin/ash/signin_helper.cc
@@ -108,7 +108,7 @@
 
   // Notify `AccountManagerMojoService` about account addition failure and send
   // `error`.
-  account_manager_mojo_service_->OnAccountAdditionFinished(
+  account_manager_mojo_service_->OnAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromError(error));
   CloseDialogAndExit();
 }
@@ -135,7 +135,7 @@
   }
   // Notify `AccountManagerMojoService` about successful account addition and
   // send the account.
-  account_manager_mojo_service_->OnAccountAdditionFinished(
+  account_manager_mojo_service_->OnAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromAccount(
           account_manager::Account{account_key_, email_}));
 }
@@ -180,7 +180,7 @@
     // The sign-in is blocked by SecondaryGoogleAccountUsage policy.
     // Notify `AccountManagerMojoService` about account addition failure and
     // send `error`.
-    account_manager_mojo_service_->OnAccountAdditionFinished(
+    account_manager_mojo_service_->OnAccountUpsertionFinished(
         account_manager::AccountUpsertionResult::FromStatus(
             account_manager::AccountUpsertionResult::Status::kBlockedByPolicy));
     ShowSigninBlockedErrorPageAndExit(hosted_domain);
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index 00b6fcc..df8848c 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -1379,7 +1379,8 @@
   UpdateAvailableAccounts();
 }
 
-void ProfilePickerHandler::OnReauthDialogClosed() {
+void ProfilePickerHandler::OnReauthDialogClosed(
+    const account_manager::AccountUpsertionResult& result) {
   // After the reauth screen is closed, we can now reuse the profile picker
   // account list to select an account.
   FireWebUIListener("reauth-dialog-closed", base::Value());
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h
index cda60a94..97d3ebd2 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.h
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -223,7 +223,8 @@
 
   // Resets account_selected state through JS to allow another account to be
   // selected, also resets `lacros_sign_in_provider_`.
-  void OnReauthDialogClosed();
+  void OnReauthDialogClosed(
+      const account_manager::AccountUpsertionResult& result);
 
   // AccountProfileMapper::Observer:
   void OnAccountUpserted(const base::FilePath& profile_path,
diff --git a/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc b/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc
index 44ca0541..859be7d 100644
--- a/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc
+++ b/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc
@@ -279,7 +279,7 @@
   bool is_hanging_ = false;
 };
 
-class FakePolicyService : public policy::MockPolicyService {
+class FakePolicyService : public testing::NiceMock<policy::MockPolicyService> {
  public:
   void SimulateCloudPolicyUpdate() {
     ASSERT_TRUE(observer_);
diff --git a/chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js b/chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js
index 33e4d07e..7dccd351 100644
--- a/chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js
+++ b/chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js
@@ -244,7 +244,7 @@
 TEST_F('SyncInternalsWebUITest', 'SyncDisabledByDefault', function() {
   assertTrue(this.hasInDetails(true, 'Transport State', 'Disabled'));
   assertTrue(
-      this.hasInDetails(true, 'Disable Reasons', 'Not signed in, User choice'));
+      this.hasInDetails(true, 'Disable Reasons', 'Not signed in'));
   assertTrue(this.hasInDetails(true, 'Username', ''));
 });
 
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index dac0f7ce..98e9a3f 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -71,6 +71,8 @@
     "install_bounce_metric.h",
     "isolated_web_apps/error/uma_logging.cc",
     "isolated_web_apps/error/uma_logging.h",
+    "isolated_web_apps/error/unusable_swbn_file_error.cc",
+    "isolated_web_apps/error/unusable_swbn_file_error.h",
     "isolated_web_apps/get_isolated_web_app_browsing_data_command.cc",
     "isolated_web_apps/get_isolated_web_app_browsing_data_command.h",
     "isolated_web_apps/install_isolated_web_app_command.cc",
@@ -620,6 +622,7 @@
     "externally_managed_app_manager_impl_unittest.cc",
     "externally_managed_app_manager_unittest.cc",
     "isolated_web_apps/error/uma_logging_unittest.cc",
+    "isolated_web_apps/error/unusable_swbn_file_error_unittest.cc",
     "isolated_web_apps/install_isolated_web_app_command_unittest.cc",
     "isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc",
     "isolated_web_apps/isolated_web_app_dev_mode_unittest.cc",
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.cc b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.cc
new file mode 100644
index 0000000..d456787
--- /dev/null
+++ b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.cc
@@ -0,0 +1,74 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
+#include "components/web_package/mojom/web_bundle_parser.mojom.h"
+
+namespace web_app {
+namespace {
+
+enum class ParsingContext { kIntegrityBlock, kMetadata };
+
+UnusableSwbnFileError::Error ConvertError(
+    const web_package::mojom::BundleParseErrorType& error,
+    ParsingContext parsing_context) {
+  switch (parsing_context) {
+    case ParsingContext::kIntegrityBlock:
+      switch (error) {
+        case web_package::mojom::BundleParseErrorType::kParserInternalError:
+          return UnusableSwbnFileError::Error::
+              kIntegrityBlockParserInternalError;
+        case web_package::mojom::BundleParseErrorType::kFormatError:
+          return UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError;
+        case web_package::mojom::BundleParseErrorType::kVersionError:
+          return UnusableSwbnFileError::Error::
+              kIntegrityBlockParserVersionError;
+      }
+    case ParsingContext::kMetadata: {
+      switch (error) {
+        case web_package::mojom::BundleParseErrorType::kParserInternalError:
+          return UnusableSwbnFileError::Error::kMetadataParserInternalError;
+        case web_package::mojom::BundleParseErrorType::kFormatError:
+          return UnusableSwbnFileError::Error::kMetadataParserFormatError;
+        case web_package::mojom::BundleParseErrorType::kVersionError:
+          return UnusableSwbnFileError::Error::kMetadataParserVersionError;
+      }
+    }
+  }
+}
+
+}  // namespace
+
+UnusableSwbnFileError::UnusableSwbnFileError(UnusableSwbnFileError::Error error,
+                                             std::string message)
+    : error_(error), message_(std::move(message)) {}
+
+UnusableSwbnFileError::UnusableSwbnFileError(
+    const web_package::mojom::BundleIntegrityBlockParseErrorPtr& error)
+    : error_(ConvertError(error->type, ParsingContext::kIntegrityBlock)),
+      message_(error->message) {}
+
+UnusableSwbnFileError::UnusableSwbnFileError(
+    const web_package::mojom::BundleMetadataParseErrorPtr& error)
+    : error_(ConvertError(error->type, ParsingContext::kMetadata)),
+      message_(error->message) {}
+
+UnusableSwbnFileError::UnusableSwbnFileError(
+    const web_package::SignedWebBundleSignatureVerifier::Error& error)
+    : error_(UnusableSwbnFileError::Error::kSignatureVerificationError),
+      message_(error.message) {}
+
+bool operator==(const UnusableSwbnFileError& lhs,
+                const UnusableSwbnFileError& rhs) {
+  return (lhs.value() == rhs.value()) && (lhs.message() == rhs.message());
+}
+
+// static
+UnusableSwbnFileError::Error ToErrorEnum(const UnusableSwbnFileError& err) {
+  return err.value();
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h
new file mode 100644
index 0000000..a4dcd21
--- /dev/null
+++ b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h
@@ -0,0 +1,77 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UNUSABLE_SWBN_FILE_ERROR_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UNUSABLE_SWBN_FILE_ERROR_H_
+
+#include <string>
+
+#include "base/types/expected.h"
+#include "components/web_package/mojom/web_bundle_parser.mojom.h"
+#include "components/web_package/signed_web_bundles/signed_web_bundle_signature_verifier.h"
+
+namespace web_app {
+
+// The status provides information about if the Signed Web Bundle (.swbn) file
+// can be used at all. If this error occurs then we should not read any
+// response that this .swbn file contains. This error means that the file
+// has critical errors (bad signature, wrong format, etc). If such an error
+// occurs we can't do much with it and most probably we should delete
+// the file.
+class UnusableSwbnFileError {
+ public:
+  // So far this enum represents every error type that can occur during
+  // integrity block and metadata parsing, before responses are read from
+  // Signed Web Bundles. In future we may add more errors here.
+  //
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class Error {
+    // Integrity Block-related errors
+    kIntegrityBlockParserInternalError = 1,
+    kIntegrityBlockParserFormatError = 2,
+    kIntegrityBlockParserVersionError = 3,
+    kIntegrityBlockValidationError = 4,
+
+    // Signature verification errors
+    kSignatureVerificationError = 5,
+
+    // Metadata-related errors
+    kMetadataParserInternalError = 6,
+    kMetadataParserFormatError = 7,
+    kMetadataParserVersionError = 8,
+    kMetadataValidationError = 9,
+
+    kMaxValue = kMetadataValidationError
+  };
+
+  explicit UnusableSwbnFileError(Error error, std::string message = "");
+  explicit UnusableSwbnFileError(
+      const web_package::mojom::BundleIntegrityBlockParseErrorPtr& error);
+  explicit UnusableSwbnFileError(
+      const web_package::mojom::BundleMetadataParseErrorPtr& error);
+  explicit UnusableSwbnFileError(
+      const web_package::SignedWebBundleSignatureVerifier::Error& error);
+
+  UnusableSwbnFileError(const UnusableSwbnFileError& other) = default;
+  UnusableSwbnFileError& operator=(const UnusableSwbnFileError& other) =
+      default;
+  UnusableSwbnFileError(UnusableSwbnFileError&& other) = default;
+  UnusableSwbnFileError& operator=(UnusableSwbnFileError&& other) = default;
+
+  Error value() const { return error_; }
+  const std::string& message() const { return message_; }
+  static void UmaLogStatus(UnusableSwbnFileError);
+
+ private:
+  Error error_;
+  std::string message_;
+};
+
+bool operator==(const UnusableSwbnFileError& lhs,
+                const UnusableSwbnFileError& rhs);
+UnusableSwbnFileError::Error ToErrorEnum(const UnusableSwbnFileError& err);
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UNUSABLE_SWBN_FILE_ERROR_H_
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error_unittest.cc
new file mode 100644
index 0000000..b0dca4fc
--- /dev/null
+++ b/chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
+
+#include "components/web_package/mojom/web_bundle_parser.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace web_app {
+namespace {
+
+TEST(UnusableSwbnFileError, General) {
+  {
+    UnusableSwbnFileError one_parameter_error_ctor = UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kSignatureVerificationError);
+    EXPECT_EQ(one_parameter_error_ctor.value(),
+              UnusableSwbnFileError::Error::kSignatureVerificationError);
+    EXPECT_TRUE(one_parameter_error_ctor.message().empty());
+  }
+
+  {
+    UnusableSwbnFileError two_parameters_error_ctor = UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kSignatureVerificationError,
+        "Unknown error message");
+    EXPECT_EQ(two_parameters_error_ctor.value(),
+              UnusableSwbnFileError::Error::kSignatureVerificationError);
+    EXPECT_EQ(two_parameters_error_ctor.message(), "Unknown error message");
+  }
+
+  {
+    auto ib_parse_error =
+        web_package::mojom::BundleIntegrityBlockParseError::New();
+    ib_parse_error->type =
+        web_package::mojom::BundleParseErrorType::kVersionError;
+    ib_parse_error->message = "Error message";
+    UnusableSwbnFileError error = UnusableSwbnFileError(ib_parse_error);
+    EXPECT_EQ(error.value(),
+              UnusableSwbnFileError::Error::kIntegrityBlockParserVersionError);
+    EXPECT_EQ(error.message(), "Error message");
+  }
+
+  {
+    auto metadata_error = web_package::mojom::BundleMetadataParseError::New();
+    metadata_error->type =
+        web_package::mojom::BundleParseErrorType::kVersionError;
+    metadata_error->message = "Error message";
+    UnusableSwbnFileError error = UnusableSwbnFileError(metadata_error);
+    EXPECT_EQ(error.value(),
+              UnusableSwbnFileError::Error::kMetadataParserVersionError);
+    EXPECT_EQ(error.message(), "Error message");
+  }
+
+  {
+    auto signature_error = web_package::SignedWebBundleSignatureVerifier::
+        Error::ForInvalidSignature("Error message");
+    UnusableSwbnFileError error = UnusableSwbnFileError(signature_error);
+    EXPECT_EQ(error.value(),
+              UnusableSwbnFileError::Error::kSignatureVerificationError);
+    EXPECT_EQ(error.message(), "Error message");
+  }
+}
+
+}  // namespace
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
index 1846c05..b389b47 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
@@ -25,6 +25,7 @@
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_dev_mode.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.h"
@@ -204,9 +205,8 @@
       /*skip_signature_verification=*/false,
       base::BindOnce(
           [](base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
-                            IsolatedWebAppResponseReaderFactory::Error> reader)
-              -> base::expected<void,
-                                IsolatedWebAppResponseReaderFactory::Error> {
+                            UnusableSwbnFileError> reader)
+              -> base::expected<void, UnusableSwbnFileError> {
             if (!reader.has_value()) {
               return base::unexpected(std::move(reader.error()));
             }
@@ -218,10 +218,10 @@
 }
 
 void InstallIsolatedWebAppCommand::OnTrustAndSignaturesChecked(
-    base::expected<void, IsolatedWebAppResponseReaderFactory::Error> result) {
-  if (!result.has_value()) {
+    base::expected<void, UnusableSwbnFileError> status) {
+  if (!status.has_value()) {
     ReportFailure(
-        IsolatedWebAppResponseReaderFactory::ErrorToString(result.error()));
+        IsolatedWebAppResponseReaderFactory::ErrorToString(status.error()));
     return;
   }
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
index 0ae6357..ecb3797c 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
@@ -18,6 +18,7 @@
 #include "base/values.h"
 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
@@ -131,7 +132,7 @@
 
   void CheckTrustAndSignaturesOfBundle(const base::FilePath& path);
   void OnTrustAndSignaturesChecked(
-      base::expected<void, IsolatedWebAppResponseReaderFactory::Error> result);
+      base::expected<void, UnusableSwbnFileError> status);
 
   void CreateStoragePartition();
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command_unittest.cc
index 94b53a8..c7b0685 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command_unittest.cc
@@ -28,6 +28,7 @@
 #include "base/test/test_future.h"
 #include "base/types/expected.h"
 #include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
@@ -181,7 +182,7 @@
 class FakeResponseReaderFactory : public IsolatedWebAppResponseReaderFactory {
  public:
   explicit FakeResponseReaderFactory(
-      absl::optional<IsolatedWebAppResponseReaderFactory::Error> bundle_error)
+      base::expected<void, UnusableSwbnFileError> bundle_status)
       : IsolatedWebAppResponseReaderFactory(
             nullptr,
             base::BindRepeating(
@@ -189,7 +190,7 @@
                          web_package::SignedWebBundleSignatureVerifier> {
                   return nullptr;
                 })),
-        bundle_error_(std::move(bundle_error)) {}
+        bundle_status_(std::move(bundle_status)) {}
 
   void CreateResponseReader(const base::FilePath& web_bundle_path,
                             const web_package::SignedWebBundleId& web_bundle_id,
@@ -197,15 +198,15 @@
                             Callback callback) override {
     // Signatures _must_ be verified during installation.
     CHECK(!skip_signature_verification);
-    if (bundle_error_) {
-      std::move(callback).Run(base::unexpected(std::move(*bundle_error_)));
+    if (!bundle_status_.has_value()) {
+      std::move(callback).Run(base::unexpected(bundle_status_.error()));
     } else {
       std::move(callback).Run(nullptr);
     }
   }
 
  private:
-  absl::optional<IsolatedWebAppResponseReaderFactory::Error> bundle_error_;
+  base::expected<void, UnusableSwbnFileError> bundle_status_;
 };
 
 class InstallIsolatedWebAppCommandTest : public ::testing::Test {
@@ -251,7 +252,7 @@
     std::unique_ptr<content::WebContents> web_contents;
     absl::optional<IsolatedWebAppLocation> location;
     raw_ptr<WebAppInstallFinalizer> install_finalizer = nullptr;
-    absl::optional<IsolatedWebAppResponseReaderFactory::Error> bundle_error;
+    base::expected<void, UnusableSwbnFileError> bundle_status = base::ok();
   };
 
   base::expected<InstallIsolatedWebAppCommandSuccess,
@@ -285,7 +286,7 @@
     auto command = CreateCommand(parameters.url_info, std::move(web_contents),
                                  parameters.location, std::move(url_loader),
                                  test_future.GetCallback(),
-                                 std::move(parameters.bundle_error));
+                                 std::move(parameters.bundle_status));
 
     command->SetDataRetrieverForTesting(
         data_retriever != nullptr ? std::move(data_retriever)
@@ -303,8 +304,7 @@
       base::OnceCallback<
           void(base::expected<InstallIsolatedWebAppCommandSuccess,
                               InstallIsolatedWebAppCommandError>)> callback,
-      absl::optional<IsolatedWebAppResponseReaderFactory::Error> bundle_error =
-          absl::nullopt) {
+      base::expected<void, UnusableSwbnFileError> bundle_status = base::ok()) {
     if (!location.has_value()) {
       location = CreateDevProxyLocation();
     }
@@ -313,7 +313,7 @@
         url_info, location.value(), std::move(web_contents),
         std::move(url_loader), /*keep_alive=*/nullptr,
         /*profile_keep_alive=*/nullptr, std::move(callback),
-        std::make_unique<FakeResponseReaderFactory>(std::move(bundle_error)));
+        std::make_unique<FakeResponseReaderFactory>(std::move(bundle_status)));
   }
 
   base::expected<InstallIsolatedWebAppCommandSuccess,
@@ -1170,21 +1170,24 @@
 
 TEST_P(InstallIsolatedWebAppCommandBundleTest, InstallsWhenThereIsNoError) {
   IsolatedWebAppUrlInfo url_info = CreateEd25519IsolatedWebAppUrlInfo();
+
   EXPECT_TRUE(ExecuteCommand(Parameters{
                                  .url_info = url_info,
                                  .location = location_,
-                                 .bundle_error = absl::nullopt,
+                                 .bundle_status = base::ok(),
                              })
                   .has_value());
 }
 
 TEST_P(InstallIsolatedWebAppCommandBundleTest, ErrorsOnBundleError) {
   IsolatedWebAppUrlInfo url_info = CreateEd25519IsolatedWebAppUrlInfo();
-  EXPECT_THAT(
-      ExecuteCommand(Parameters{.url_info = url_info,
-                                .location = location_,
-                                .bundle_error = MetadataError("test error")}),
-      IsInstallationError(HasSubstr("test error")));
+  EXPECT_THAT(ExecuteCommand(Parameters{
+                  .url_info = url_info,
+                  .location = location_,
+                  .bundle_status = base::unexpected(UnusableSwbnFileError(
+                      UnusableSwbnFileError::Error::kMetadataParserVersionError,
+                      "test error"))}),
+              IsInstallationError(HasSubstr("test error")));
 }
 
 TEST_P(InstallIsolatedWebAppCommandBundleTest,
@@ -1196,7 +1199,7 @@
   auto installation_result =
       ExecuteCommand(Parameters{.url_info = url_info,
                                 .location = location_,
-                                .bundle_error = absl::nullopt});
+                                .bundle_status = base::ok()});
   if (GetParam()) {
     EXPECT_TRUE(installation_result.has_value());
   } else {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page.cc
index c4d413e..b5968f2d 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page.cc
@@ -6,12 +6,32 @@
 
 #include <string>
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/common/alternative_error_page_override_info.mojom.h"
 #include "net/base/net_errors.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace {
+
+std::u16string GetNetErrorMessage(net::Error error_code) {
+  switch (error_code) {
+    case net::ERR_INVALID_WEB_BUNDLE:
+      return l10n_util::GetStringUTF16(
+          IDS_ERRORPAGES_MESSAGE_IWA_INVALID_WEB_BUNDLE);
+    case net::ERR_CONNECTION_REFUSED:
+      return l10n_util::GetStringUTF16(
+          IDS_ERRORPAGES_MESSAGE_IWA_CONNECTION_REFUSED);
+    default:
+      break;
+  }
+
+  return base::UTF8ToUTF16(net::ErrorToString(error_code));
+}
+
+}  // namespace
+
 namespace web_app {
 
 content::mojom::AlternativeErrorPageOverrideInfoPtr
@@ -19,21 +39,10 @@
                                     content::RenderFrameHost* render_frame_host,
                                     content::BrowserContext* browser_context,
                                     int32_t error_code) {
-  std::u16string message;
-  switch (error_code) {
-    case net::ERR_INTERNET_DISCONNECTED:
-      message =
-          l10n_util::GetStringUTF16(IDS_ERRORPAGES_HEADING_YOU_ARE_OFFLINE);
-      break;
-    default:
-      // TODO(crbug.com/1434818): Add localized IWA error message.
-      message = u"DEFAULT IWA ERROR PAGE";
-      break;
-  }
-
-  return ConstructWebAppErrorPage(url, render_frame_host, browser_context,
-                                  message,
-                                  /*supplementary_icon=*/std::u16string());
+  return ConstructWebAppErrorPage(
+      url, render_frame_host, browser_context,
+      GetNetErrorMessage(static_cast<net::Error>(error_code)),
+      /*supplementary_icon=*/std::u16string());
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page_browsertest.cc
index 15dc805..9390029a 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page_browsertest.cc
@@ -23,8 +23,10 @@
 
 base::flat_map</*error code*/ net::Error, /*error message*/ std::string>
     kTestCases{
-        {net::ERR_INTERNET_DISCONNECTED, "You're offline"},
-        {net::ERR_INVALID_URL, "DEFAULT IWA ERROR PAGE"},
+        {net::ERR_INVALID_WEB_BUNDLE, "This application is missing or damaged"},
+        {net::ERR_CONNECTION_REFUSED,
+         "The development server for this application cannot be reached"},
+        {net::ERR_INVALID_URL, "net::ERR_INVALID_URL"},
     };
 
 }  // namespace
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
index e5d1be1..d7e49ac 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
@@ -155,7 +155,7 @@
     const base::FilePath& web_bundle_path,
     const web_package::SignedWebBundleId& web_bundle_id,
     base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
-                   IsolatedWebAppResponseReaderFactory::Error> reader) {
+                   UnusableSwbnFileError> reader) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   auto cache_entry_it = reader_cache_.Find(web_bundle_path);
@@ -235,7 +235,7 @@
 // static
 IsolatedWebAppReaderRegistry::ReadResponseError
 IsolatedWebAppReaderRegistry::ReadResponseError::ForError(
-    const IsolatedWebAppResponseReaderFactory::Error& error) {
+    const UnusableSwbnFileError& error) {
   return ForOtherError(
       IsolatedWebAppResponseReaderFactory::ErrorToString(error));
 }
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
index 6979171..9af2f7da 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
@@ -55,8 +55,7 @@
       kResponseNotFound,
     };
 
-    static ReadResponseError ForError(
-        const IsolatedWebAppResponseReaderFactory::Error& error);
+    static ReadResponseError ForError(const UnusableSwbnFileError& error);
 
     static ReadResponseError ForError(
         const IsolatedWebAppResponseReader::Error& error);
@@ -110,7 +109,7 @@
       const base::FilePath& web_bundle_path,
       const web_package::SignedWebBundleId& web_bundle_id,
       base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
-                     IsolatedWebAppResponseReaderFactory::Error> reader);
+                     UnusableSwbnFileError> reader);
 
   void DoReadResponse(IsolatedWebAppResponseReader& reader,
                       network::ResourceRequest resource_request,
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
index a36f7906..eedd19e4 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
@@ -445,9 +445,9 @@
 
 class IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest
     : public IsolatedWebAppReaderRegistryTest,
-      public ::testing::WithParamInterface<std::pair<
-          web_package::mojom::BundleParseErrorType,
-          IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {};
+      public ::testing::WithParamInterface<
+          std::pair<web_package::mojom::BundleParseErrorType,
+                    UnusableSwbnFileError::Error>> {};
 
 TEST_P(IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest,
        TestIntegrityBlockParserError) {
@@ -482,16 +482,13 @@
     ::testing::Values(
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kParserInternalError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserInternalError),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError),
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kVersionError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserVersionError),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserVersionError),
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kFormatError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserFormatError)));
+            UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError)));
 
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidIntegrityBlockContents) {
   base::HistogramTester histogram_tester;
@@ -521,9 +518,7 @@
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-      IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-          kIntegrityBlockValidationError,
-      1);
+      UnusableSwbnFileError::Error::kIntegrityBlockValidationError, 1);
 }
 
 class IsolatedWebAppReaderRegistrySignatureVerificationErrorTest
@@ -572,9 +567,7 @@
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-      IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-          kSignatureVerificationError,
-      1);
+      UnusableSwbnFileError::Error::kSignatureVerificationError, 1);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
@@ -586,9 +579,9 @@
 
 class IsolatedWebAppReaderRegistryMetadataParserErrorTest
     : public IsolatedWebAppReaderRegistryTest,
-      public ::testing::WithParamInterface<std::pair<
-          web_package::mojom::BundleParseErrorType,
-          IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {};
+      public ::testing::WithParamInterface<
+          std::pair<web_package::mojom::BundleParseErrorType,
+                    UnusableSwbnFileError::Error>> {};
 
 TEST_P(IsolatedWebAppReaderRegistryMetadataParserErrorTest,
        TestMetadataParserError) {
@@ -624,14 +617,13 @@
     ::testing::Values(
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kParserInternalError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kMetadataParserInternalError),
-        std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError,
-                       IsolatedWebAppResponseReaderFactory::
-                           UnusableSwbnFileError::kMetadataParserVersionError),
-        std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError,
-                       IsolatedWebAppResponseReaderFactory::
-                           UnusableSwbnFileError::kMetadataParserFormatError)));
+            UnusableSwbnFileError::Error::kMetadataParserInternalError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kVersionError,
+            UnusableSwbnFileError::Error::kMetadataParserVersionError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kFormatError,
+            UnusableSwbnFileError::Error::kMetadataParserFormatError)));
 
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadataPrimaryUrl) {
   base::HistogramTester histogram_tester;
@@ -659,9 +651,7 @@
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-      IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-          kMetadataValidationError,
-      1);
+      UnusableSwbnFileError::Error::kMetadataValidationError, 1);
 }
 
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadataInvalidExchange) {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
index d4f89ac..c16f0c7 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
@@ -9,9 +9,12 @@
 
 #include "base/functional/overloaded.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
+#include "base/types/expected.h"
 #include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h"
 #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
 #include "chrome/common/url_constants.h"
@@ -66,32 +69,28 @@
 
 // static
 std::string IsolatedWebAppResponseReaderFactory::ErrorToString(
-    const Error& error) {
-  return (absl::visit(
-      base::Overloaded{
-          [](const web_package::mojom::BundleIntegrityBlockParseErrorPtr&
-                 error) {
-            return base::StringPrintf("Failed to parse integrity block: %s",
-                                      error->message.c_str());
-          },
-          [](const IntegrityBlockError& error) {
-            return base::StringPrintf("Failed to validate integrity block: %s",
-                                      error.message.c_str());
-          },
-          [](const web_package::SignedWebBundleSignatureVerifier::Error&
-                 error) {
-            return base::StringPrintf("Failed to verify signatures: %s",
-                                      error.message.c_str());
-          },
-          [](const web_package::mojom::BundleMetadataParseErrorPtr& error) {
-            return base::StringPrintf("Failed to parse metadata: %s",
-                                      error->message.c_str());
-          },
-          [](const MetadataError& error) {
-            return base::StringPrintf("Failed to validate metadata: %s",
-                                      error.message.c_str());
-          }},
-      error));
+    const UnusableSwbnFileError& error) {
+  switch (error.value()) {
+    case UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError:
+    case UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError:
+    case UnusableSwbnFileError::Error::kIntegrityBlockParserVersionError:
+      return base::StringPrintf("Failed to parse integrity block: %s",
+                                error.message().c_str());
+    case UnusableSwbnFileError::Error::kIntegrityBlockValidationError:
+      return base::StringPrintf("Failed to validate integrity block: %s",
+                                error.message().c_str());
+    case UnusableSwbnFileError::Error::kSignatureVerificationError:
+      return base::StringPrintf("Failed to verify signatures: %s",
+                                error.message().c_str());
+    case UnusableSwbnFileError::Error::kMetadataParserInternalError:
+    case UnusableSwbnFileError::Error::kMetadataParserFormatError:
+    case UnusableSwbnFileError::Error::kMetadataParserVersionError:
+      return base::StringPrintf("Failed to parse metadata: %s",
+                                error.message().c_str());
+    case UnusableSwbnFileError::Error::kMetadataValidationError:
+      return base::StringPrintf("Failed to validate metadata: %s",
+                                error.message().c_str());
+  }
 }
 
 void IsolatedWebAppResponseReaderFactory::OnIntegrityBlockRead(
@@ -142,92 +141,23 @@
     const base::FilePath& web_bundle_path,
     const web_package::SignedWebBundleId& web_bundle_id,
     Callback callback,
-    absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>
-        read_integrity_block_and_metadata_error) {
+    base::expected<void, UnusableSwbnFileError> status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  absl::optional<std::pair<Error, UnusableSwbnFileError>> two_errors;
-  if (read_integrity_block_and_metadata_error.has_value()) {
-    Error error = absl::visit(
-        base::Overloaded{
-            [](const web_package::mojom::BundleIntegrityBlockParseErrorPtr&
-                   error) -> Error { return error->Clone(); },
-            [](const SignedWebBundleReader::AbortedByCaller& error) -> Error {
-              return IntegrityBlockError(error.message);
-            },
-            [](const web_package::SignedWebBundleSignatureVerifier::Error&
-                   error) -> Error { return error; },
-            [](const web_package::mojom::BundleMetadataParseErrorPtr& error)
-                -> Error { return error->Clone(); },
-        },
-        *read_integrity_block_and_metadata_error);
-    two_errors = std::make_pair(
-        std::move(error),
-        ToUnusableSwbnFileError(*read_integrity_block_and_metadata_error));
+  if (status.has_value()) {
+    status = base::expected(validator_->ValidateMetadata(
+        web_bundle_id, reader->GetPrimaryURL(), reader->GetEntries()));
   }
 
-  if (!two_errors.has_value()) {
-    if (auto error_message = validator_->ValidateMetadata(
-            web_bundle_id, reader->GetPrimaryURL(), reader->GetEntries());
-        !error_message.has_value()) {
-      two_errors =
-          std::make_pair(MetadataError(error_message.error()),
-                         UnusableSwbnFileError::kMetadataValidationError);
-    }
-  }
+  UmaLogExpectedStatus("WebApp.Isolated.SwbnFileUsability", status);
 
-  const base::expected<void, UnusableSwbnFileError> usability_status =
-      two_errors.has_value()
-          ? base::expected<void, UnusableSwbnFileError>(
-                base::unexpected(two_errors->second))
-          : base::expected<void, UnusableSwbnFileError>(base::ok());
-  UmaLogExpectedStatus("WebApp.Isolated.SwbnFileUsability", usability_status);
-
-  if (two_errors.has_value()) {
-    std::move(callback).Run(base::unexpected(std::move(two_errors->first)));
+  if (!status.has_value()) {
+    std::move(callback).Run(base::unexpected(status.error()));
     return;
   }
+
   std::move(callback).Run(
       std::make_unique<IsolatedWebAppResponseReader>(std::move(reader)));
 }
 
-IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError
-IsolatedWebAppResponseReaderFactory::ToUnusableSwbnFileError(
-    const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error) {
-  return absl::visit(
-      base::Overloaded{
-          [](const web_package::mojom::BundleIntegrityBlockParseErrorPtr&
-                 error) {
-            switch (error->type) {
-              case web_package::mojom::BundleParseErrorType::
-                  kParserInternalError:
-                return UnusableSwbnFileError::
-                    kIntegrityBlockParserInternalError;
-              case web_package::mojom::BundleParseErrorType::kFormatError:
-                return UnusableSwbnFileError::kIntegrityBlockParserFormatError;
-              case web_package::mojom::BundleParseErrorType::kVersionError:
-                return UnusableSwbnFileError::kIntegrityBlockParserVersionError;
-            }
-          },
-          [](const SignedWebBundleReader::AbortedByCaller& error) {
-            return UnusableSwbnFileError::kIntegrityBlockValidationError;
-          },
-          [](const web_package::SignedWebBundleSignatureVerifier::Error&
-                 error) {
-            return UnusableSwbnFileError::kSignatureVerificationError;
-          },
-          [](const web_package::mojom::BundleMetadataParseErrorPtr& error) {
-            switch (error->type) {
-              case web_package::mojom::BundleParseErrorType::
-                  kParserInternalError:
-                return UnusableSwbnFileError::kMetadataParserInternalError;
-              case web_package::mojom::BundleParseErrorType::kFormatError:
-                return UnusableSwbnFileError::kMetadataParserFormatError;
-              case web_package::mojom::BundleParseErrorType::kVersionError:
-                return UnusableSwbnFileError::kMetadataParserVersionError;
-            }
-          }},
-      error);
-}
-
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h
index 576a0f9..f3bf287 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h
@@ -29,23 +29,6 @@
 
 class IsolatedWebAppValidator;
 
-// Simple struct used to represent errors related to the integrity block of the
-// Signed Web Bundle.
-struct IntegrityBlockError {
-  explicit IntegrityBlockError(std::string message)
-      : message(std::move(message)) {}
-
-  std::string message;
-};
-
-// Simple struct used to represent errors related to the metadata of the Signed
-// Web Bundle.
-struct MetadataError {
-  explicit MetadataError(std::string message) : message(std::move(message)) {}
-
-  std::string message;
-};
-
 // Factory for creating instances of `IsolatedWebAppResponseReader` that are
 // ready to read responses from the bundle. Instances returned by this class are
 // guaranteed to have previously read a valid integrity block and metadata, as
@@ -68,22 +51,9 @@
   IsolatedWebAppResponseReaderFactory& operator=(
       const IsolatedWebAppResponseReaderFactory&) = delete;
 
-  using Error = absl::variant<
-      // Triggered when the integrity block of the Signed Web
-      // Bundle does not exist or parsing it fails.
-      web_package::mojom::BundleIntegrityBlockParseErrorPtr,
-      // Triggered when the integrity block is not valid for this Isolated Web
-      // App or when the user agent does not trust the Isolated Web App.
-      IntegrityBlockError,
-      // Triggered when signature verification fails.
-      web_package::SignedWebBundleSignatureVerifier::Error,
-      // Triggered when metadata parsing fails.
-      web_package::mojom::BundleMetadataParseErrorPtr,
-      // Triggered when the metadata is not valid for this Isolated Web App.
-      MetadataError>;
-
   using Callback = base::OnceCallback<void(
-      base::expected<std::unique_ptr<IsolatedWebAppResponseReader>, Error>)>;
+      base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
+                     UnusableSwbnFileError>)>;
 
   virtual void CreateResponseReader(
       const base::FilePath& web_bundle_path,
@@ -91,32 +61,7 @@
       bool skip_signature_verification,
       Callback callback);
 
-  static std::string ErrorToString(const Error& error);
-
-  // This enum represents every error type that can occur during integrity block
-  // and metadata parsing, before responses are read from Signed Web Bundles.
-  // Any of these errors means that the .swbn file is unusable.
-  //
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class UnusableSwbnFileError {
-    // Integrity Block-related errors
-    kIntegrityBlockParserInternalError = 1,
-    kIntegrityBlockParserFormatError = 2,
-    kIntegrityBlockParserVersionError = 3,
-    kIntegrityBlockValidationError = 4,
-
-    // Signature verification errors
-    kSignatureVerificationError = 5,
-
-    // Metadata-related errors
-    kMetadataParserInternalError = 6,
-    kMetadataParserFormatError = 7,
-    kMetadataParserVersionError = 8,
-    kMetadataValidationError = 9,
-
-    kMaxValue = kMetadataValidationError
-  };
+  static std::string ErrorToString(const UnusableSwbnFileError& error);
 
  private:
   void OnIntegrityBlockRead(
@@ -138,11 +83,7 @@
       const base::FilePath& web_bundle_path,
       const web_package::SignedWebBundleId& web_bundle_id,
       Callback callback,
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>
-          read_integrity_block_and_metadata_error);
-
-  UnusableSwbnFileError ToUnusableSwbnFileError(
-      const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error);
+      base::expected<void, UnusableSwbnFileError> status);
 
   std::unique_ptr<IsolatedWebAppValidator> validator_;
   base::RepeatingCallback<
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc
index 357b946..115ef63 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc
@@ -46,7 +46,6 @@
 using testing::Eq;
 using testing::IsFalse;
 using testing::IsTrue;
-using testing::NotNull;
 using testing::StartsWith;
 using testing::VariantWith;
 
@@ -203,13 +202,13 @@
 
 using ReaderResult =
     base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
-                   IsolatedWebAppResponseReaderFactory::Error>;
+                   UnusableSwbnFileError>;
 
 class IsolatedWebAppResponseReaderFactoryIntegrityBlockParserErrorTest
     : public IsolatedWebAppResponseReaderFactoryTest,
-      public ::testing::WithParamInterface<std::pair<
-          web_package::mojom::BundleParseErrorType,
-          IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {};
+      public ::testing::WithParamInterface<
+          std::pair<web_package::mojom::BundleParseErrorType,
+                    UnusableSwbnFileError::Error>> {};
 
 TEST_P(IsolatedWebAppResponseReaderFactoryIntegrityBlockParserErrorTest,
        TestIntegrityBlockParserError) {
@@ -226,13 +225,10 @@
   parser_factory_->RunIntegrityBlockCallback(nullptr, error->Clone());
 
   ReaderResult result = reader_future.Take();
+
   ASSERT_FALSE(result.has_value());
-  auto* actual_error =
-      absl::get_if<web_package::mojom::BundleIntegrityBlockParseErrorPtr>(
-          &result.error());
-  ASSERT_THAT(actual_error, NotNull());
-  EXPECT_THAT((*actual_error)->type, Eq(error->type));
-  EXPECT_THAT((*actual_error)->message, Eq(error->message));
+  auto actual_error = result.error();
+  EXPECT_EQ(actual_error, UnusableSwbnFileError(error));
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
@@ -245,16 +241,13 @@
     ::testing::Values(
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kParserInternalError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserInternalError),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError),
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kVersionError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserVersionError),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserVersionError),
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kFormatError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kIntegrityBlockParserFormatError)));
+            UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError)));
 
 TEST_F(IsolatedWebAppResponseReaderFactoryTest,
        TestInvalidIntegrityBlockContents) {
@@ -276,16 +269,14 @@
   FulfillIntegrityBlock();
 
   ReaderResult result = reader_future.Take();
+
   ASSERT_FALSE(result.has_value());
-  auto* actual_error = absl::get_if<IntegrityBlockError>(&result.error());
-  ASSERT_THAT(actual_error, NotNull());
-  EXPECT_THAT(actual_error->message, Eq("test error"));
+  auto actual_error = result.error();
+  EXPECT_THAT(actual_error.message(), Eq("test error"));
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-      IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-          kIntegrityBlockValidationError,
-      1);
+      UnusableSwbnFileError::Error::kIntegrityBlockValidationError, 1);
 }
 
 class IsolatedWebAppResponseReaderFactorySignatureVerificationErrorTest
@@ -332,23 +323,17 @@
 
     histogram_tester.ExpectBucketCount(
         ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-        IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-            kSignatureVerificationError,
-        0);
+        UnusableSwbnFileError::Error::kSignatureVerificationError, 0);
   } else {
     ReaderResult result = reader_future.Take();
+
     ASSERT_FALSE(result.has_value());
-    auto* actual_error =
-        absl::get_if<web_package::SignedWebBundleSignatureVerifier::Error>(
-            &result.error());
-    ASSERT_THAT(actual_error, NotNull());
-    EXPECT_THAT(actual_error->message, Eq(error_.message));
+    auto actual_error = result.error();
+    EXPECT_THAT(actual_error.message(), Eq(error_.message));
 
     histogram_tester.ExpectBucketCount(
         ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-        IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-            kSignatureVerificationError,
-        1);
+        UnusableSwbnFileError::Error::kSignatureVerificationError, 1);
   }
 }
 
@@ -364,9 +349,9 @@
 
 class IsolatedWebAppResponseReaderFactoryMetadataParserErrorTest
     : public IsolatedWebAppResponseReaderFactoryTest,
-      public ::testing::WithParamInterface<std::pair<
-          web_package::mojom::BundleParseErrorType,
-          IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {};
+      public ::testing::WithParamInterface<
+          std::pair<web_package::mojom::BundleParseErrorType,
+                    UnusableSwbnFileError::Error>> {};
 
 TEST_P(IsolatedWebAppResponseReaderFactoryMetadataParserErrorTest,
        TestMetadataParserError) {
@@ -385,13 +370,10 @@
                                        error->Clone());
 
   ReaderResult result = reader_future.Take();
+
   ASSERT_FALSE(result.has_value());
-  auto* actual_error =
-      absl::get_if<web_package::mojom::BundleMetadataParseErrorPtr>(
-          &result.error());
-  ASSERT_THAT(actual_error, NotNull());
-  EXPECT_THAT((*actual_error)->type, Eq(error->type));
-  EXPECT_THAT((*actual_error)->message, Eq(error->message));
+  auto actual_error = result.error();
+  EXPECT_THAT(actual_error, Eq(UnusableSwbnFileError(error)));
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
@@ -404,14 +386,13 @@
     ::testing::Values(
         std::make_pair(
             web_package::mojom::BundleParseErrorType::kParserInternalError,
-            IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-                kMetadataParserInternalError),
-        std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError,
-                       IsolatedWebAppResponseReaderFactory::
-                           UnusableSwbnFileError::kMetadataParserVersionError),
-        std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError,
-                       IsolatedWebAppResponseReaderFactory::
-                           UnusableSwbnFileError::kMetadataParserFormatError)));
+            UnusableSwbnFileError::Error::kMetadataParserInternalError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kVersionError,
+            UnusableSwbnFileError::Error::kMetadataParserVersionError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kFormatError,
+            UnusableSwbnFileError::Error::kMetadataParserFormatError)));
 
 TEST_F(IsolatedWebAppResponseReaderFactoryTest, TestInvalidMetadataPrimaryUrl) {
   base::HistogramTester histogram_tester;
@@ -428,17 +409,15 @@
                                        std::move(metadata));
 
   ReaderResult result = reader_future.Take();
+
   ASSERT_FALSE(result.has_value());
-  auto* actual_error = absl::get_if<MetadataError>(&result.error());
-  ASSERT_THAT(actual_error, NotNull());
-  EXPECT_THAT(actual_error->message,
+  auto actual_error = result.error();
+  EXPECT_THAT(actual_error.message(),
               StartsWith("Primary URL must not be present"));
 
   histogram_tester.ExpectBucketCount(
       ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"),
-      IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError::
-          kMetadataValidationError,
-      1);
+      UnusableSwbnFileError::Error::kMetadataValidationError, 1);
 }
 
 TEST_F(IsolatedWebAppResponseReaderFactoryTest,
@@ -457,10 +436,10 @@
                                        std::move(metadata));
 
   ReaderResult result = reader_future.Take();
+
   ASSERT_FALSE(result.has_value());
-  auto* actual_error = absl::get_if<MetadataError>(&result.error());
-  ASSERT_THAT(actual_error, NotNull());
-  EXPECT_THAT(actual_error->message,
+  auto actual_error = result.error();
+  EXPECT_THAT(actual_error.message(),
               StartsWith("The URL of an exchange is invalid"));
 }
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_unittest.cc
index 132c22b..ccddd48 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
 #include "chrome/browser/web_applications/test/signed_web_bundle_utils.h"
@@ -52,11 +53,9 @@
     return web_bundle_path;
   }
 
-  absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>
-  ReadIntegrityBlockAndMetadata(SignedWebBundleReader& reader) {
-    base::test::TestFuture<absl::optional<
-        SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-        future;
+  base::expected<void, UnusableSwbnFileError> ReadIntegrityBlockAndMetadata(
+      SignedWebBundleReader& reader) {
+    base::test::TestFuture<base::expected<void, UnusableSwbnFileError>> future;
     reader.StartReading(
         base::BindOnce(
             [](web_package::SignedWebBundleIntegrityBlock integrity_block,
@@ -90,8 +89,8 @@
        ReadResponseStripsQueryParametersAndFragment) {
   base::FilePath web_bundle_path = CreateSignedBundleAndWriteToDisk();
   auto reader = SignedWebBundleReader::Create(web_bundle_path, base_url_);
-  auto error = ReadIntegrityBlockAndMetadata(*reader.get());
-  ASSERT_THAT(error.has_value(), IsFalse());
+  auto status = ReadIntegrityBlockAndMetadata(*reader.get());
+  ASSERT_TRUE(status.has_value());
 
   auto response_reader =
       std::make_unique<IsolatedWebAppResponseReader>(std::move(reader));
@@ -122,8 +121,8 @@
 TEST_F(IsolatedWebAppResponseReaderTest, ReadResponseBody) {
   base::FilePath web_bundle_path = CreateSignedBundleAndWriteToDisk();
   auto reader = SignedWebBundleReader::Create(web_bundle_path, base_url_);
-  auto error = ReadIntegrityBlockAndMetadata(*reader.get());
-  ASSERT_THAT(error.has_value(), IsFalse());
+  auto status = ReadIntegrityBlockAndMetadata(*reader.get());
+  ASSERT_TRUE(status.has_value());
 
   auto response_reader =
       std::make_unique<IsolatedWebAppResponseReader>(std::move(reader));
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
index 24ec7516..875e285 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
@@ -12,6 +12,7 @@
 #include "base/functional/overloaded.h"
 #include "base/strings/strcat.h"
 #include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
@@ -60,28 +61,22 @@
       [](std::unique_ptr<SignedWebBundleReader> reader_ownership,
          base::OnceCallback<void(
              base::expected<IsolatedWebAppUrlInfo, std::string>)> callback,
-         absl::optional<
-             SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>
-             read_error) {
-        DCHECK(read_error.has_value());
+         base::expected<void, UnusableSwbnFileError> read_status) {
+        CHECK(!read_status.has_value());
 
-        if (!absl::holds_alternative<SignedWebBundleReader::AbortedByCaller>(
-                read_error.value())) {
-          web_package::mojom::BundleIntegrityBlockParseErrorPtr* error_ptr =
-              absl::get_if<
-                  web_package::mojom::BundleIntegrityBlockParseErrorPtr>(
-                  &read_error.value());
-          // only other possible variant, as the other 2 variants shouldn't be
-          // reachable.
-          DCHECK(error_ptr);
-
+        // If the operation was aborted intentionally the reader will return
+        // kIntegrityBlockValidationError error. Strictly speaking we should
+        // have a separate error for this purpose. But because the code of this
+        // function will be soon refactored, let's use this temporary hacky
+        // solution.
+        if (read_status.error().value() !=
+            UnusableSwbnFileError::Error::kIntegrityBlockValidationError) {
           std::move(callback).Run(base::unexpected(
               "Failed to read the integrity block of the signed web bundle: " +
-              (*error_ptr)->message));
+              read_status.error().message()));
         }
       },
       std::move(reader), std::move(callback_second));
-  ;
 
   reader_raw_ptr->StartReading(std::move(integrity_block_result_callback),
                                std::move(read_error_callback));
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
index e8d364e..9bc3cee 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/functional/callback.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_trust_checker.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/common/url_constants.h"
@@ -46,7 +47,8 @@
   std::move(callback).Run(absl::nullopt);
 }
 
-base::expected<void, std::string> IsolatedWebAppValidator::ValidateMetadata(
+base::expected<void, UnusableSwbnFileError>
+IsolatedWebAppValidator::ValidateMetadata(
     const web_package::SignedWebBundleId& web_bundle_id,
     const absl::optional<GURL>& primary_url,
     const std::vector<GURL>& entries) {
@@ -54,8 +56,11 @@
   // URLs make no sense for Isolated Web Apps - the "primary URL" should be
   // retrieved from the web app manifest's `start_url` field.
   if (primary_url.has_value()) {
-    return base::unexpected("Primary URL must not be present, but was " +
-                            primary_url->possibly_invalid_spec());
+    std::string error_msg = "Primary URL must not be present, but was " +
+                            primary_url->possibly_invalid_spec();
+    return base::unexpected(UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kMetadataValidationError,
+        std::move(error_msg)));
   }
 
   // Verify that the bundle only contains isolated-app:// URLs using the
@@ -64,26 +69,37 @@
     base::expected<IsolatedWebAppUrlInfo, std::string> url_info =
         IsolatedWebAppUrlInfo::Create(entry);
     if (!url_info.has_value()) {
-      return base::unexpected("The URL of an exchange is invalid: " +
-                              url_info.error());
+      std::string error_msg =
+          "The URL of an exchange is invalid: " + url_info.error();
+      return base::unexpected(UnusableSwbnFileError(
+          UnusableSwbnFileError::Error::kMetadataValidationError,
+          std::move(error_msg)));
     }
 
     const web_package::SignedWebBundleId& entry_web_bundle_id =
         url_info->web_bundle_id();
     if (entry_web_bundle_id != web_bundle_id) {
-      return base::unexpected(
+      std::string error_msg =
           "The URL of an exchange contains the wrong Signed Web Bundle ID: " +
-          entry_web_bundle_id.id());
+          entry_web_bundle_id.id();
+      return base::unexpected(UnusableSwbnFileError(
+          UnusableSwbnFileError::Error::kMetadataValidationError,
+          std::move(error_msg)));
     }
     if (entry.has_ref()) {
-      return base::unexpected(
+      std::string error_msg =
           "The URL of an exchange is invalid: URLs must not have a fragment "
-          "part.");
+          "part.";
+      return base::unexpected(UnusableSwbnFileError(
+          UnusableSwbnFileError::Error::kMetadataValidationError,
+          std::move(error_msg)));
     }
     if (entry.has_query()) {
-      return base::unexpected(
-          "The URL of an exchange is invalid: URLs must not have a query "
-          "part.");
+      std::string error_msg =
+          "The URL of an exchange is invalid: URLs must not have a query part.";
+      return base::unexpected(UnusableSwbnFileError(
+          UnusableSwbnFileError::Error::kMetadataValidationError,
+          std::move(error_msg)));
     }
   }
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
index c9ddc34..91c0e74 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
@@ -10,6 +10,7 @@
 
 #include "base/functional/callback_forward.h"
 #include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -40,10 +41,10 @@
 
   // Validates that the metadata of the Isolated Web App is valid given the
   // `web_bundle_id`.
-  [[nodiscard]] virtual base::expected<void, std::string> ValidateMetadata(
-      const web_package::SignedWebBundleId& web_bundle_id,
-      const absl::optional<GURL>& primary_url,
-      const std::vector<GURL>& entries);
+  [[nodiscard]] virtual base::expected<void, UnusableSwbnFileError>
+  ValidateMetadata(const web_package::SignedWebBundleId& web_bundle_id,
+                   const absl::optional<GURL>& primary_url,
+                   const std::vector<GURL>& entries);
 
  private:
   std::unique_ptr<const IsolatedWebAppTrustChecker>
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
index 14c1600..9a875ac0 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
@@ -13,6 +13,8 @@
 #include "base/strings/string_util.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
+#include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_trust_checker.h"
 #include "chrome/common/url_constants.h"
 #include "components/prefs/pref_service.h"
@@ -160,11 +162,11 @@
       public ::testing::WithParamInterface<
           std::tuple<absl::optional<std::string>,
                      std::vector<std::string>,
-                     std::string>> {
+                     base::expected<void, UnusableSwbnFileError>>> {
  public:
   IsolatedWebAppValidatorMetadataTest()
       : primary_url_(std::get<0>(GetParam())),
-        error_message_(std::get<2>(GetParam())) {
+        status_(std::get<2>(GetParam())) {
     for (const std::string& entry : std::get<1>(GetParam())) {
       entries_.emplace_back(entry);
     }
@@ -173,7 +175,7 @@
  protected:
   absl::optional<GURL> primary_url_;
   std::vector<GURL> entries_;
-  std::string error_message_;
+  base::expected<void, UnusableSwbnFileError> status_;
 };
 
 TEST_P(IsolatedWebAppValidatorMetadataTest, Validate) {
@@ -184,9 +186,10 @@
   auto isolated_web_app_trust_checker =
       std::make_unique<MockIsolatedWebAppTrustChecker>();
   IsolatedWebAppValidator validator(std::move(isolated_web_app_trust_checker));
-  EXPECT_EQ(validator.ValidateMetadata(*web_bundle_id, primary_url_, entries_)
-                .error_or(std::string()),
-            error_message_);
+  auto validation_status =
+      validator.ValidateMetadata(*web_bundle_id, primary_url_, entries_);
+
+  EXPECT_EQ(validation_status, status_);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -195,28 +198,42 @@
     ::testing::Values(
         std::make_tuple(absl::nullopt,
                         std::vector<std::string>({kUrl}),
-                        std::string()),
-        std::make_tuple(absl::nullopt,
-                        std::vector<std::string>({kUrl, kUrl + "/foo#bar"}),
-                        "The URL of an exchange is invalid: URLs must not have "
-                        "a fragment part."),
-        std::make_tuple(absl::nullopt,
-                        std::vector<std::string>({kUrl, kUrl + "/foo?bar"}),
-                        "The URL of an exchange is invalid: URLs must not have "
-                        "a query part."),
+                        base::ok()),
+        std::make_tuple(
+            absl::nullopt,
+            std::vector<std::string>({kUrl, kUrl + "/foo#bar"}),
+            base::unexpected(UnusableSwbnFileError(
+                UnusableSwbnFileError::Error::kMetadataValidationError,
+                "The URL of an exchange is invalid: URLs must not have "
+                "a fragment part."))),
+        std::make_tuple(
+            absl::nullopt,
+            std::vector<std::string>({kUrl, kUrl + "/foo?bar"}),
+            base::unexpected(UnusableSwbnFileError(
+                UnusableSwbnFileError::Error::kMetadataValidationError,
+                "The URL of an exchange is invalid: URLs must not have "
+                "a query part."))),
         std::make_tuple(
             kUrl,
             std::vector<std::string>({kUrl}),
-            "Primary URL must not be present, but was isolated-app://"
-            "aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic/"),
-        std::make_tuple(absl::nullopt,
-                        std::vector<std::string>({kUrl, "https://foo/"}),
-                        "The URL of an exchange is invalid: The URL scheme "
-                        "must be isolated-app, but was https"),
+            base::unexpected(UnusableSwbnFileError(
+                UnusableSwbnFileError::Error::kMetadataValidationError,
+                "Primary URL must not be present, but was isolated-app://"
+                "aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic/"))),
+        std::make_tuple(
+            absl::nullopt,
+            std::vector<std::string>({kUrl, "https://foo/"}),
+            base::unexpected(UnusableSwbnFileError(
+                UnusableSwbnFileError::Error::kMetadataValidationError,
+                "The URL of an exchange is invalid: The URL scheme "
+                "must be isolated-app, but was https"))),
         std::make_tuple(
             absl::nullopt,
             std::vector<std::string>({kUrl, kUrlFromAnotherIsolatedWebApp}),
-            "The URL of an exchange contains the wrong Signed Web Bundle ID: "
-            "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic")));
+            base::unexpected(UnusableSwbnFileError(
+                UnusableSwbnFileError::Error::kMetadataValidationError,
+                "The URL of an exchange contains the wrong Signed Web Bundle "
+                "ID: "
+                "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic")))));
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
index 4edb9887..101ffb8 100644
--- a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -19,6 +20,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "components/web_package/mojom/web_bundle_parser.mojom.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_integrity_block.h"
 #include "mojo/public/cpp/system/data_pipe_producer.h"
@@ -94,11 +96,10 @@
   CHECK_EQ(state_, State::kInitializing);
 
   if (!file->IsValid()) {
-    FulfillWithError(
-        std::move(read_error_callback),
-        web_package::mojom::BundleIntegrityBlockParseError::New(
-            web_package::mojom::BundleParseErrorType::kParserInternalError,
-            base::File::ErrorToString(file->error_details())));
+    UnusableSwbnFileError error = UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError,
+        base::File::ErrorToString(file->error_details()));
+    FulfillWithError(std::move(read_error_callback), std::move(error));
     return;
   }
 
@@ -116,13 +117,12 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK_EQ(state_, State::kInitializing);
 
-  base::File::Error error = parser_->OpenFile(std::move(file));
-  if (error != base::File::FILE_OK) {
-    FulfillWithError(
-        std::move(read_error_callback),
-        web_package::mojom::BundleIntegrityBlockParseError::New(
-            web_package::mojom::BundleParseErrorType::kParserInternalError,
-            base::File::ErrorToString(error)));
+  base::File::Error file_error = parser_->OpenFile(std::move(file));
+  if (file_error != base::File::FILE_OK) {
+    UnusableSwbnFileError error = UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError,
+        base::File::ErrorToString(file_error));
+    FulfillWithError(std::move(read_error_callback), std::move(error));
     return;
   }
 
@@ -141,24 +141,23 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK_EQ(state_, State::kInitializing);
 
-  auto integrity_block = [&]()
-      -> base::expected<web_package::SignedWebBundleIntegrityBlock,
-                        web_package::mojom::BundleIntegrityBlockParseErrorPtr> {
-    if (error) {
-      return base::unexpected(std::move(error));
-    }
-    return web_package::SignedWebBundleIntegrityBlock::Create(
-               std::move(raw_integrity_block))
-        .transform_error([&](std::string error) {
-          return web_package::mojom::BundleIntegrityBlockParseError::New(
-              web_package::mojom::BundleParseErrorType::kFormatError,
-              "Error while parsing the Signed Web Bundle's integrity block: " +
-                  std::move(error));
-        });
-  }();
-  if (!integrity_block.has_value()) {
+  if (error) {
     FulfillWithError(std::move(read_error_callback),
-                     std::move(integrity_block.error()));
+                     UnusableSwbnFileError(error));
+    return;
+  }
+
+  auto integrity_block = web_package::SignedWebBundleIntegrityBlock::Create(
+      std::move(raw_integrity_block));
+
+  if (!integrity_block.has_value()) {
+    FulfillWithError(
+        std::move(read_error_callback),
+        UnusableSwbnFileError(
+            UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError,
+            "Error while parsing the Signed Web Bundle's integrity "
+            "block: " +
+                integrity_block.error()));
     return;
   }
 
@@ -181,8 +180,11 @@
 
   switch (action.type()) {
     case SignatureVerificationAction::Type::kAbort:
-      FulfillWithError(std::move(callback),
-                       AbortedByCaller({.message = action.abort_message()}));
+      FulfillWithError(
+          std::move(callback),
+          UnusableSwbnFileError(
+              UnusableSwbnFileError::Error::kIntegrityBlockValidationError,
+              action.abort_message()));
       return;
     case SignatureVerificationAction::Type::kContinueAndVerifySignatures:
       VerifySignatures(std::move(integrity_block), std::move(callback));
@@ -222,11 +224,10 @@
     ReadErrorCallback callback,
     base::expected<uint64_t, base::File::Error> file_length) {
   if (!file_length.has_value()) {
-    FulfillWithError(
-        std::move(callback),
-        web_package::mojom::BundleIntegrityBlockParseError::New(
-            web_package::mojom::BundleParseErrorType::kParserInternalError,
-            base::File::ErrorToString(file_length.error())));
+    UnusableSwbnFileError error = UnusableSwbnFileError(
+        UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError,
+        base::File::ErrorToString(file_length.error()));
+    FulfillWithError(std::move(callback), std::move(error));
     return;
   }
 
@@ -255,7 +256,8 @@
       base::saturated_cast<int>(std::round(file_length / (1024.0 * 1024.0))));
 
   if (verification_error.has_value()) {
-    FulfillWithError(std::move(callback), *verification_error);
+    FulfillWithError(std::move(callback),
+                     UnusableSwbnFileError(*verification_error));
     return;
   }
 
@@ -281,7 +283,7 @@
   CHECK_EQ(state_, State::kInitializing);
 
   if (error) {
-    FulfillWithError(std::move(callback), std::move(error));
+    FulfillWithError(std::move(callback), UnusableSwbnFileError(error));
     return;
   }
 
@@ -296,19 +298,18 @@
                      // `parser_` will be deleted before `this` is deleted.
                      base::Unretained(this)));
 
-  std::move(callback).Run(absl::nullopt);
+  std::move(callback).Run(base::ok());
 }
 
-void SignedWebBundleReader::FulfillWithError(
-    ReadErrorCallback callback,
-    ReadIntegrityBlockAndMetadataError error) {
+void SignedWebBundleReader::FulfillWithError(ReadErrorCallback callback,
+                                             UnusableSwbnFileError error) {
   state_ = State::kError;
 
   // This is an irrecoverable error state, thus we can safely delete `parser_`
   // here to free up resources.
   parser_.reset();
 
-  std::move(callback).Run(std::move(error));
+  std::move(callback).Run(base::unexpected(std::move(error)));
 }
 
 const absl::optional<GURL>& SignedWebBundleReader::GetPrimaryURL() const {
diff --git a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h
index 1c2cac2..8593887 100644
--- a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h
+++ b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h
@@ -6,12 +6,14 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_SIGNED_WEB_BUNDLE_READER_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/files/file_path.h"
 #include "base/functional/callback_forward.h"
 #include "base/sequence_checker.h"
 #include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "components/web_package/mojom/web_bundle_parser.mojom-forward.h"
 #include "components/web_package/shared_file.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_signature_verifier.h"
@@ -96,25 +98,8 @@
       web_package::SignedWebBundleIntegrityBlock integrity_block,
       base::OnceCallback<void(SignatureVerificationAction)> callback)>;
 
-  // This error will be passed to `read_error_callback` if parsing is aborted by
-  // the caller as part of `integrity_block_result_callback`.
-  struct AbortedByCaller {
-    std::string message;
-  };
-
-  using ReadIntegrityBlockAndMetadataError = absl::variant<
-      // Triggered when the integrity block of the Signed Web Bundle does not
-      // exist or parsing it fails.
-      web_package::mojom::BundleIntegrityBlockParseErrorPtr,
-      // Triggered when the caller aborts parsing as part of
-      // `integrity_block_result_callback`.
-      AbortedByCaller,
-      // Triggered when signature verification fails.
-      web_package::SignedWebBundleSignatureVerifier::Error,
-      // Triggered when metadata parsing fails.
-      web_package::mojom::BundleMetadataParseErrorPtr>;
   using ReadErrorCallback = base::OnceCallback<void(
-      absl::optional<ReadIntegrityBlockAndMetadataError> error)>;
+      base::expected<void, UnusableSwbnFileError> status)>;
 
   // Creates a new instance of this class. `base_url` is used inside the
   // `WebBundleParser` to convert relative URLs contained in the Web Bundle into
@@ -275,7 +260,7 @@
                         web_package::mojom::BundleMetadataParseErrorPtr error);
 
   void FulfillWithError(ReadErrorCallback callback,
-                        ReadIntegrityBlockAndMetadataError error);
+                        UnusableSwbnFileError error);
 
   void ReadResponseInternal(
       web_package::mojom::BundleResponseLocationPtr location,
diff --git a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader_unittest.cc
index e4b8839..cc3283a 100644
--- a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader_unittest.cc
@@ -15,6 +15,8 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/repeating_test_future.h"
 #include "base/test/test_future.h"
+#include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolated_web_apps/error/unusable_swbn_file_error.h"
 #include "chrome/browser/web_applications/test/signed_web_bundle_utils.h"
 #include "components/web_package/mojom/web_bundle_parser.mojom.h"
 #include "components/web_package/signed_web_bundles/ed25519_public_key.h"
@@ -198,18 +200,19 @@
 };
 
 TEST_F(SignedWebBundleReaderTest, ReadValidIntegrityBlockAndMetadata) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
   base::HistogramTester histogram_tester;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   EXPECT_EQ(reader->GetPrimaryURL(), kUrl);
@@ -227,17 +230,18 @@
   auto metadata = metadata_->Clone();
   metadata->primary_url = absl::nullopt;
 
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        std::move(metadata));
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   EXPECT_FALSE(reader->GetPrimaryURL().has_value());
@@ -246,78 +250,64 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadIntegrityBlockError) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(
       nullptr, web_package::mojom::BundleIntegrityBlockParseError::New());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_TRUE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  EXPECT_TRUE(
-      absl::holds_alternative<
-          web_package::mojom::BundleIntegrityBlockParseErrorPtr>(*parse_error));
+  EXPECT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError);
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadInvalidIntegrityBlockSize) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   web_package::mojom::BundleIntegrityBlockPtr integrity_block =
       web_package::mojom::BundleIntegrityBlock::New();
   integrity_block->size = 0;
   parser_factory_->RunIntegrityBlockCallback(std::move(integrity_block));
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_TRUE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  EXPECT_TRUE(
-      absl::holds_alternative<
-          web_package::mojom::BundleIntegrityBlockParseErrorPtr>(*parse_error));
+  EXPECT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserFormatError);
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadIntegrityBlockWithParserCrash) {
   parser_factory_->SimulateParseIntegrityBlockCrash();
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_TRUE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  EXPECT_TRUE(
-      absl::holds_alternative<
-          web_package::mojom::BundleIntegrityBlockParseErrorPtr>(*parse_error));
-  EXPECT_EQ(absl::get<web_package::mojom::BundleIntegrityBlockParseErrorPtr>(
-                *parse_error)
-                ->type,
-            web_package::mojom::BundleParseErrorType::kParserInternalError);
+  EXPECT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kIntegrityBlockParserInternalError);
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadIntegrityBlockAndAbort) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
   auto reader =
-      CreateReaderAndInitialize(parse_error_future.GetCallback(),
+      CreateReaderAndInitialize(parse_status_future.GetCallback(),
                                 VerificationAction::Abort("test error"));
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_.Clone());
 
-  auto parse_error = parse_error_future.Take();
+  auto parse_status = parse_status_future.Take();
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  ASSERT_TRUE(parse_error.has_value());
-
-  auto* error =
-      absl::get_if<SignedWebBundleReader::AbortedByCaller>(&*parse_error);
-  ASSERT_TRUE(error);
-  EXPECT_EQ(error->message, "test error");
+  ASSERT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kIntegrityBlockValidationError);
+  EXPECT_EQ(parse_status.error().message(), "test error");
 }
 
 class SignedWebBundleReaderSignatureVerificationErrorTest
@@ -327,25 +317,20 @@
 
 TEST_P(SignedWebBundleReaderSignatureVerificationErrorTest,
        SignatureVerificationError) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
   auto reader = CreateReaderAndInitialize(
-      parse_error_future.GetCallback(),
+      parse_status_future.GetCallback(),
       VerificationAction::ContinueAndVerifySignatures(), GetParam());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
 
-  auto parse_error = parse_error_future.Take();
+  auto parse_status = parse_status_future.Take();
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  ASSERT_TRUE(parse_error.has_value());
 
-  auto* error =
-      absl::get_if<web_package::SignedWebBundleSignatureVerifier::Error>(
-          &*parse_error);
-  ASSERT_TRUE(error);
-  EXPECT_EQ(error->message, GetParam().message);
-  EXPECT_EQ(error->type, GetParam().type);
+  auto expected_status = UnusableSwbnFileError(GetParam());
+
+  EXPECT_EQ(parse_status.error(), expected_status);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -365,11 +350,10 @@
 // never triggered.
 TEST_F(SignedWebBundleReaderTest,
        ReadIntegrityBlockAndSkipSignatureVerification) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
   auto reader = CreateReaderAndInitialize(
-      parse_error_future.GetCallback(),
+      parse_status_future.GetCallback(),
       VerificationAction::ContinueAndSkipSignatureVerification(),
       web_package::SignedWebBundleSignatureVerifier::Error::ForInvalidSignature(
           "invalid signature"));
@@ -378,65 +362,60 @@
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 TEST_F(SignedWebBundleReaderTest, ReadMetadataError) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(
       integrity_block_->size, nullptr,
       web_package::mojom::BundleMetadataParseError::New());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_TRUE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  EXPECT_TRUE(
-      absl::holds_alternative<web_package::mojom::BundleMetadataParseErrorPtr>(
-          *parse_error));
+  EXPECT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kMetadataParserInternalError);
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadMetadataWithParserCrash) {
   parser_factory_->SimulateParseMetadataCrash();
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_TRUE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kError);
-  EXPECT_TRUE(
-      absl::holds_alternative<web_package::mojom::BundleMetadataParseErrorPtr>(
-          *parse_error));
-  EXPECT_EQ(
-      absl::get<web_package::mojom::BundleMetadataParseErrorPtr>(*parse_error)
-          ->type,
-      web_package::mojom::BundleParseErrorType::kParserInternalError);
+  EXPECT_EQ(parse_status.error().value(),
+            UnusableSwbnFileError::Error::kMetadataParserInternalError);
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadResponse) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -452,17 +431,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadResponseWithFragment) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -480,17 +460,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadNonExistingResponseWithPath) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -514,17 +495,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadNonExistingResponseWithQuery) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -548,17 +530,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadResponseError) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -576,17 +559,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadResponseWithParserDisconnect) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -623,17 +607,18 @@
 
 TEST_F(SignedWebBundleReaderTest,
        SimulateParserDisconnectWithFileErrorWhenReconnecting) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   SimulateAndWaitForParserDisconnect(*reader.get());
@@ -660,17 +645,18 @@
 
 TEST_F(SignedWebBundleReaderTest, ReadResponseWithParserCrash) {
   parser_factory_->SimulateParseResponseCrash();
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -690,17 +676,18 @@
 }
 
 TEST_F(SignedWebBundleReaderTest, ReadResponseBody) {
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
-  auto reader = CreateReaderAndInitialize(parse_error_future.GetCallback());
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
+  auto reader = CreateReaderAndInitialize(parse_status_future.GetCallback());
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
 
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   network::ResourceRequest resource_request;
@@ -735,19 +722,20 @@
   parser_factory_ = std::make_unique<web_package::MockWebBundleParserFactory>(
       on_create_parser_future.GetCallback());
 
-  base::test::TestFuture<
-      absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>>
-      parse_error_future;
+  base::test::TestFuture<base::expected<void, UnusableSwbnFileError>>
+      parse_status_future;
   auto reader = CreateReaderAndInitialize(
-      parse_error_future.GetCallback(),
+      parse_status_future.GetCallback(),
       VerificationAction::ContinueAndVerifySignatures(), absl::nullopt,
       base_url_);
 
   parser_factory_->RunIntegrityBlockCallback(integrity_block_->Clone());
   parser_factory_->RunMetadataCallback(integrity_block_->size,
                                        metadata_->Clone());
-  auto parse_error = parse_error_future.Take();
-  EXPECT_FALSE(parse_error.has_value());
+  auto parse_status = parse_status_future.Take();
+  EXPECT_TRUE(parse_status.has_value())
+      << "The unexpected error occurred: "
+      << static_cast<int>(parse_status.error().value());
   EXPECT_EQ(reader->GetState(), SignedWebBundleReader::State::kInitialized);
 
   EXPECT_EQ(on_create_parser_future.Take(), base_url_);
diff --git a/chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win_unittest.cc b/chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win_unittest.cc
index 7753383..e605fe1 100644
--- a/chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win_unittest.cc
+++ b/chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
+#include "base/strings/string_util.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/bind.h"
 #include "base/test/test_reg_util_win.h"
@@ -159,8 +160,10 @@
   // See https://docs.microsoft.com/en-us/windows/win32/com/-progid--key.
   const std::wstring prog_id1 = GetProgIdForApp(profile()->GetPath(), app_id1);
   EXPECT_LE(prog_id1.length(), kMaxProgIdLen);
-  for (auto itr = prog_id1.begin(); itr != prog_id1.end(); itr++)
-    EXPECT_TRUE(std::isalnum(*itr) || (*itr == '.' && itr != prog_id1.begin()));
+  for (auto itr = prog_id1.begin(); itr != prog_id1.end(); itr++) {
+    EXPECT_TRUE(base::IsAsciiAlphaNumeric(*itr) ||
+                (*itr == '.' && itr != prog_id1.begin()));
+  }
   // Check that different app ids in the same profile have different prog ids.
   EXPECT_NE(prog_id1, GetProgIdForApp(profile()->GetPath(), app_id2));
 
@@ -180,8 +183,10 @@
   const std::wstring prog_id1 = GetProgIdForAppFileHandler(
       profile()->GetPath(), app_id1, file_extensions1);
   EXPECT_LE(prog_id1.length(), kMaxProgIdLen);
-  for (auto itr = prog_id1.begin(); itr != prog_id1.end(); itr++)
-    EXPECT_TRUE(std::isalnum(*itr) || (*itr == '.' && itr != prog_id1.begin()));
+  for (auto itr = prog_id1.begin(); itr != prog_id1.end(); itr++) {
+    EXPECT_TRUE(base::IsAsciiAlphaNumeric(*itr) ||
+                (*itr == '.' && itr != prog_id1.begin()));
+  }
   // Check that different app ids in the same profile with the same file
   // extensions have different prog ids.
   EXPECT_NE(prog_id1, GetProgIdForAppFileHandler(profile()->GetPath(), app_id2,
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 268fabd..038d72cb 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1683907023-c7a6e41749bbf36ffd244e7181f1a8a411439e8e.profdata
+chrome-chromeos-amd64-generic-main-1684137439-4162bb246047168cb230557593e0526743ceeb85.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 0d65d6c..94b3c29 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1683568773-59f250973d47b83c31e57d616cc535383d1091e9.profdata
+chrome-linux-main-1684087171-f167275cf0752c3218ce0cf4a353d636a8ad577a.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 2cefa8ad..ecee027 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1683914360-1e5c2bc64b4f166fa786bcb8e4933d21e810159b.profdata
+chrome-mac-arm-main-1684144710-7553a06dfd2147aa4dce52eb846e4d338e95f805.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d0b854d..229b6f7 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1683568773-a5d8aa6da29a2ada9329fdd8c4642021945df46d.profdata
+chrome-mac-main-1684130031-a41e6ec918c59e02b2310c2db6692ecf37f70279.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 29fe9b102..254c4f8 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1683903455-59a6336338ddc55af0cbd1a108d49fcbaa95dd82.profdata
+chrome-win32-main-1684130031-6fe259794ddde1832bdbe57f95cccfc3a0888158.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 94572c2..77ec521 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1683914360-1c1f9764dbe340c4b1a45fb624c6d9c4cffd3794.profdata
+chrome-win64-main-1684130031-f175d724425a5a9e2af23dc7ebe86f14918507ac.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index b3a3936c..fcec881f 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -400,6 +400,11 @@
              "EnableWebUsbOnExtensionServiceWorker",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enable extended descriptions for key settings in Chrome settings.
+BASE_FEATURE(kExtendedSettingsDescriptions,
+             "ExtendedSettingsDescriptions",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 #if !BUILDFLAG(IS_ANDROID)
 // Lazy initialize IndividualSettings for extensions from enterprise policy
 // that are not installed.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 0bb35fb..d9c27dd 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -239,6 +239,9 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kEnableWebUsbOnExtensionServiceWorker);
 
+COMPONENT_EXPORT(CHROME_FEATURES)
+BASE_DECLARE_FEATURE(kExtendedSettingsDescriptions);
+
 #if !BUILDFLAG(IS_ANDROID)
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kExtensionDeferredIndividualSettings);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 568625d..4ced775 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1852,9 +1852,6 @@
 const char kDefaultHandlersForFileExtensions[] =
     "filebrowser.default_handlers_for_file_extensions";
 
-// Whether the office files setup flow has ever been completed by the user.
-const char kOfficeSetupComplete[] = "filebrowser.office.setup_complete";
-
 // Whether we should always move office files to Google Drive without prompting
 // the user first.
 const char kOfficeFilesAlwaysMoveToDrive[] =
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 88420b2..ccdb3a40 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -605,7 +605,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kDefaultHandlersForFileExtensions[];
-extern const char kOfficeSetupComplete[];
 extern const char kOfficeFilesAlwaysMoveToDrive[];
 extern const char kOfficeFilesAlwaysMoveToOneDrive[];
 extern const char kOfficeMoveConfirmationShownForDrive[];
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 0acba84..b94eb799 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -418,7 +418,6 @@
 const char kOsUICrashesURL[] = "os://crashes";
 const char kOsUICreditsURL[] = "os://credits";
 const char kOsUIDeviceEmulatorURL[] = "os://device-emulator";
-const char kOsUIDeviceLogURL[] = "os://device-log";
 const char kOsUIDriveInternalsURL[] = "os://drive-internals";
 const char kOsUIEmojiPickerURL[] = "os://emoji-picker";
 const char kOsUIExtensionsInternalsURL[] = "os://extensions-internals";
@@ -504,6 +503,7 @@
 const char kOsUIComponentsURL[] = "os://components";
 const char kOsUIConnectivityDiagnosticsAppURL[] =
     "os://connectivity-diagnostics";
+const char kOsUIDeviceLogURL[] = "os://device-log";
 const char kOsUIDiagnosticsAppURL[] = "os://diagnostics";
 const char kOsUIFirmwareUpdaterAppURL[] = "os://accessory-update";
 const char kOsUIFlagsURL[] = "os://flags";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index a06b689..d8954b5 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -390,7 +390,6 @@
 extern const char kOsUICrashesURL[];
 extern const char kOsUICreditsURL[];
 extern const char kOsUIDeviceEmulatorURL[];
-extern const char kOsUIDeviceLogURL[];
 extern const char kOsUIDriveInternalsURL[];
 extern const char kOsUIEmojiPickerURL[];
 extern const char kOsUIExtensionsInternalsURL[];
@@ -427,6 +426,7 @@
 extern const char kOsUIAboutURL[];
 extern const char kOsUIComponentsURL[];
 extern const char kOsUIConnectivityDiagnosticsAppURL[];
+extern const char kOsUIDeviceLogURL[];
 extern const char kOsUIDiagnosticsAppURL[];
 extern const char kOsUIFirmwareUpdaterAppURL[];
 extern const char kOsUIFlagsURL[];
diff --git a/chrome/install_static/install_modes_unittest.cc b/chrome/install_static/install_modes_unittest.cc
index 47ea1e1..ddc234c 100644
--- a/chrome/install_static/install_modes_unittest.cc
+++ b/chrome/install_static/install_modes_unittest.cc
@@ -7,8 +7,8 @@
 #include <windows.h>
 
 #include <cguid.h>
-#include <ctype.h>
 
+#include "base/strings/string_util.h"
 #include "chrome/install_static/buildflags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -30,10 +30,11 @@
 // alphanumeric nor a period.
 MATCHER(ContainsIllegalProgIdChar, "") {
   const wchar_t* scan = arg;
-  wint_t c;
+  wchar_t c;
   while ((c = *scan++) != 0) {
-    if (!iswalnum(c) && c != L'.')
+    if (!base::IsAsciiAlphaNumeric(c) && c != L'.') {
       return true;
+    }
   }
   return false;
 }
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
index b31588a..5cedf95 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -134,6 +134,19 @@
                                    html_tag);
 }
 
+void SetAXNodeDataDisplay(v8::Isolate* isolate,
+                          gin::Dictionary* v8_dict,
+                          ui::AXNodeData* ax_node_data) {
+  v8::Local<v8::Value> v8_display;
+  v8_dict->Get("display", &v8_display);
+  std::string display;
+  if (!gin::Converter<std::string>::FromV8(isolate, v8_display, &display)) {
+    return;
+  }
+  ax_node_data->AddStringAttribute(ax::mojom::StringAttribute::kDisplay,
+                                   display);
+}
+
 void SetAXNodeDataTextDirection(v8::Isolate* isolate,
                                 gin::Dictionary* v8_dict,
                                 ui::AXNodeData* ax_node_data) {
@@ -290,6 +303,7 @@
     SetAXNodeDataTextDirection(isolate, &v8_node_dict, &ax_node_data);
     SetAXNodeDataTextStyle(isolate, &v8_node_dict, &ax_node_data);
     SetAXNodeDataUrl(isolate, &v8_node_dict, &ax_node_data);
+    SetAXNodeDataDisplay(isolate, &v8_node_dict, &ax_node_data);
     snapshot.nodes.push_back(ax_node_data);
   }
 
diff --git a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
index 0c7f1e3..14b2a47e 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
@@ -320,7 +320,8 @@
   EXPECT_EQ(4, GetChildren(1)[1]);
 }
 
-TEST_F(ReadAnythingAppControllerTest, GetChildren_WithSelection) {
+TEST_F(ReadAnythingAppControllerTest,
+       GetChildren_WithSelection_ContainsNearbyNodes) {
   // Create selection from node 3-4.
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
@@ -332,16 +333,18 @@
   update.tree_data.sel_focus_offset = 0;
   update.tree_data.sel_is_backward = false;
   AccessibilityEventReceived({update});
-  EXPECT_EQ(2u, GetChildren(1).size());
+  EXPECT_EQ(3u, GetChildren(1).size());
   EXPECT_EQ(0u, GetChildren(2).size());
   EXPECT_EQ(0u, GetChildren(3).size());
   EXPECT_EQ(0u, GetChildren(4).size());
 
-  EXPECT_EQ(3, GetChildren(1)[0]);
-  EXPECT_EQ(4, GetChildren(1)[1]);
+  EXPECT_EQ(2, GetChildren(1)[0]);
+  EXPECT_EQ(3, GetChildren(1)[1]);
+  EXPECT_EQ(4, GetChildren(1)[2]);
 }
 
-TEST_F(ReadAnythingAppControllerTest, GetChildren_WithBackwardSelection) {
+TEST_F(ReadAnythingAppControllerTest,
+       GetChildren_WithBackwardSelection_ContainsNearbyNodes) {
   // Create backward selection from node 4-3.
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
@@ -353,13 +356,14 @@
   update.tree_data.sel_focus_offset = 0;
   update.tree_data.sel_is_backward = true;
   AccessibilityEventReceived({update});
-  EXPECT_EQ(2u, GetChildren(1).size());
+  EXPECT_EQ(3u, GetChildren(1).size());
   EXPECT_EQ(0u, GetChildren(2).size());
   EXPECT_EQ(0u, GetChildren(3).size());
   EXPECT_EQ(0u, GetChildren(4).size());
 
-  EXPECT_EQ(3, GetChildren(1)[0]);
-  EXPECT_EQ(4, GetChildren(1)[1]);
+  EXPECT_EQ(2, GetChildren(1)[0]);
+  EXPECT_EQ(3, GetChildren(1)[1]);
+  EXPECT_EQ(4, GetChildren(1)[2]);
 }
 
 TEST_F(ReadAnythingAppControllerTest, GetHtmlTag) {
@@ -537,7 +541,8 @@
   EXPECT_EQ(true, IsNodeIgnoredForReadAnything(4));
 }
 
-TEST_F(ReadAnythingAppControllerTest, SelectionNodeIdsContains_Selection) {
+TEST_F(ReadAnythingAppControllerTest,
+       SelectionNodeIdsContains_SelectionAndNearbyNodes) {
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
   update.has_tree_data = true;
@@ -552,11 +557,11 @@
   EXPECT_TRUE(SelectionNodeIdsContains(1));
   EXPECT_TRUE(SelectionNodeIdsContains(2));
   EXPECT_TRUE(SelectionNodeIdsContains(3));
-  EXPECT_FALSE(SelectionNodeIdsContains(4));
+  EXPECT_TRUE(SelectionNodeIdsContains(4));
 }
 
 TEST_F(ReadAnythingAppControllerTest,
-       SelectionNodeIdsContains_BackwardSelection) {
+       SelectionNodeIdsContains_BackwardSelectionAndNearbyNodes) {
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
   update.has_tree_data = true;
@@ -570,7 +575,7 @@
   EXPECT_TRUE(SelectionNodeIdsContains(1));
   EXPECT_TRUE(SelectionNodeIdsContains(2));
   EXPECT_TRUE(SelectionNodeIdsContains(3));
-  EXPECT_FALSE(SelectionNodeIdsContains(4));
+  EXPECT_TRUE(SelectionNodeIdsContains(4));
 }
 
 TEST_F(ReadAnythingAppControllerTest, DisplayNodeIdsContains_ContentNodes) {
diff --git a/chrome/renderer/accessibility/read_anything_app_model.cc b/chrome/renderer/accessibility/read_anything_app_model.cc
index fa6919f..c7c0c0a 100644
--- a/chrome/renderer/accessibility/read_anything_app_model.cc
+++ b/chrome/renderer/accessibility/read_anything_app_model.cc
@@ -3,8 +3,11 @@
 // found in the LICENSE file.
 
 #include "chrome/renderer/accessibility/read_anything_app_model.h"
+#include <cstddef>
+#include <string>
 
 #include "base/containers/contains.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_serializable_tree.h"
@@ -134,20 +137,63 @@
     }
   }
 
-  // Do a pre-order walk of the tree from the start node to the end node and add
-  // all nodes to the list.
-  // TODO(crbug.com/1266555): Right now, we are going from start node to an
-  // unignored node that is before or equal to the end node. This condition was
-  // changed from next_node != end node because when a paragraph is selected
-  // with a triple click, we sometimes pass the end node, causing a SEGV_ACCERR.
-  // We need to investigate this case in more depth.
-  ui::AXNode* next_node = start_node->GetNextUnignoredInTreeOrder();
-  while (next_node && next_node->CompareTo(*end_node) <= 0) {
-    if (!IsNodeIgnoredForReadAnything(next_node->id())) {
-      InsertSelectionNode(next_node->id());
-    }
-    next_node = next_node->GetNextUnignoredInTreeOrder();
+  // Find the parent of the start and end nodes so we can look at nearby sibling
+  // nodes. Since the start and end nodes might be in different section of the
+  // tree, get the parents for start and end separately. Otherwise, the end
+  // selection might not render.
+  ui::AXNode* start_parent = GetParentForSelection(start_node);
+  ui::AXNode* end_parent = GetParentForSelection(end_node);
+
+  // If either parent is missing, selection is invalid and we should return
+  // early.
+  if (start_parent == nullptr || end_parent == nullptr) {
+    return;
   }
+
+  ui::AXNode* first_sibling_node =
+      start_parent->GetFirstUnignoredChildCrossingTreeBoundary();
+  ui::AXNode* last_sibling_node =
+      end_parent->GetLastUnignoredChildCrossingTreeBoundary();
+
+  // If the last sibling node is null, selection is invalid and we should
+  // return early.
+  if (last_sibling_node == nullptr) {
+    return;
+  }
+
+  // TODO(b/1266555): Consider using ax_position.h here to better manage
+  // selection.
+  // Traverse the tree from and including the first sibling node to the last
+  // last sibling node, inclusive. This ensures that when select-to-distill
+  // is used to distill non-distillable content (such as Gmail), text
+  // outside of the selected portion but on the same line is still
+  // distilled, even if there's special formatting.
+  while (first_sibling_node &&
+         first_sibling_node->CompareTo(*last_sibling_node).value_or(1) <= 0) {
+    if (!IsNodeIgnoredForReadAnything(first_sibling_node->id())) {
+      InsertSelectionNode(first_sibling_node->id());
+    }
+
+    first_sibling_node = first_sibling_node->GetNextUnignoredInTreeOrder();
+  }
+}
+
+ui::AXNode* ReadAnythingAppModel::GetParentForSelection(ui::AXNode* node) {
+  ui::AXNode* parent = node->GetUnignoredParentCrossingTreeBoundary();
+  // For most nodes, the parent is the same as the most direct parent. However,
+  // to handle special types of text formatting such as links and custom spans,
+  // another parent may be needed. e.g. when a link is highlighted, the start
+  // node has an "inline" display but the parent we want would have a "block"
+  // display role, so in order to get the common parent of
+  // all sibling nodes, the grandparent should be used.
+  while (parent && parent->GetUnignoredParentCrossingTreeBoundary() &&
+         parent->HasStringAttribute(ax::mojom::StringAttribute::kDisplay) &&
+         parent->GetStringAttribute(ax::mojom::StringAttribute::kDisplay)
+                 .find("inline") != std::string::npos) {
+    parent = parent->GetUnignoredParentCrossingTreeBoundary();
+  }
+
+  return parent;
 }
 
 void ReadAnythingAppModel::ComputeDisplayNodeIdsForDistilledTree() {
diff --git a/chrome/renderer/accessibility/read_anything_app_model.h b/chrome/renderer/accessibility/read_anything_app_model.h
index d558490..9063c78 100644
--- a/chrome/renderer/accessibility/read_anything_app_model.h
+++ b/chrome/renderer/accessibility/read_anything_app_model.h
@@ -10,6 +10,7 @@
 #include "chrome/common/accessibility/read_anything_constants.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "ui/accessibility/ax_event_generator.h"
+#include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_selection.h"
 
 namespace ui {
@@ -151,6 +152,8 @@
   void ProcessNonGeneratedEvents(const std::vector<ui::AXEvent>& events);
   void ProcessGeneratedEvents(const ui::AXEventGenerator& event_generator);
 
+  ui::AXNode* GetParentForSelection(ui::AXNode* node);
+
   // State.
   // AXTrees of web contents in the browser’s tab strip.
   std::map<ui::AXTreeID, std::unique_ptr<ui::AXSerializableTree>> trees_;
diff --git a/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc
index f421707..d26b3ccc 100644
--- a/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything_app_model_browsertest.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/threading/platform_thread.h"
 #include "chrome/renderer/accessibility/read_anything_app_model.h"
 
 #include "chrome/test/base/chrome_render_view_test.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_serializable_tree.h"
 
 class ReadAnythingAppModelTest : public ChromeRenderViewTest {
@@ -589,7 +591,8 @@
   EXPECT_TRUE(DisplayNodeIdsContains(6));
 }
 
-TEST_F(ReadAnythingAppModelTest, SelectionNodeIdsContains_Selection) {
+TEST_F(ReadAnythingAppModelTest,
+       SelectionNodeIdsContains_SelectionAndNearbyNodes) {
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
   update.tree_data.sel_anchor_object_id = 2;
@@ -603,10 +606,11 @@
   EXPECT_TRUE(SelectionNodeIdsContains(1));
   EXPECT_TRUE(SelectionNodeIdsContains(2));
   EXPECT_TRUE(SelectionNodeIdsContains(3));
-  EXPECT_FALSE(SelectionNodeIdsContains(4));
+  EXPECT_TRUE(SelectionNodeIdsContains(4));
 }
 
-TEST_F(ReadAnythingAppModelTest, SelectionNodeIdsContains_BackwardSelection) {
+TEST_F(ReadAnythingAppModelTest,
+       SelectionNodeIdsContains_BackwardSelectionAndNearbyNodes) {
   ui::AXTreeUpdate update;
   SetUpdateTreeID(&update);
   update.tree_data.sel_anchor_object_id = 3;
@@ -619,7 +623,7 @@
   EXPECT_TRUE(SelectionNodeIdsContains(1));
   EXPECT_TRUE(SelectionNodeIdsContains(2));
   EXPECT_TRUE(SelectionNodeIdsContains(3));
-  EXPECT_FALSE(SelectionNodeIdsContains(4));
+  EXPECT_TRUE(SelectionNodeIdsContains(4));
 }
 
 TEST_F(ReadAnythingAppModelTest, SetTheme_LineAndLetterSpacingCorrect) {
@@ -744,3 +748,169 @@
   ASSERT_EQ(StartNodeId(), 2);
   ASSERT_EQ(EndNodeId(), 3);
 }
+
+TEST_F(ReadAnythingAppModelTest,
+       StartAndEndNodesHaveDifferentParents_SelectionStateCorrect) {
+  ui::AXTreeUpdate update;
+  SetUpdateTreeID(&update);
+  update.nodes.resize(6);
+  update.nodes[0].id = 1;
+  update.nodes[1].id = 2;
+  update.nodes[2].id = 3;
+  update.nodes[3].id = 4;
+  update.nodes[4].id = 5;
+  update.nodes[5].id = 6;
+  update.nodes[0].child_ids = {2, 3, 4};
+  update.nodes[3].child_ids = {5, 6};
+  update.nodes[0].role = ax::mojom::Role::kStaticText;
+  update.nodes[1].role = ax::mojom::Role::kStaticText;
+  update.nodes[2].role = ax::mojom::Role::kStaticText;
+  update.nodes[3].role = ax::mojom::Role::kGenericContainer;
+  update.nodes[4].role = ax::mojom::Role::kStaticText;
+  update.nodes[5].role = ax::mojom::Role::kStaticText;
+  AccessibilityEventReceived({update});
+
+  update.tree_data.sel_anchor_object_id = 2;
+  update.tree_data.sel_focus_object_id = 5;
+  update.tree_data.sel_anchor_offset = 0;
+  update.tree_data.sel_focus_offset = 0;
+  update.tree_data.sel_is_backward = false;
+  AccessibilityEventReceived({update});
+  ProcessSelection();
+
+  ASSERT_TRUE(HasSelection());
+  ASSERT_EQ(StartNodeId(), 2);
+  ASSERT_EQ(EndNodeId(), 5);
+
+  // 1 and 3 are ancestors, so they are included as selection nodes..
+  ASSERT_TRUE(SelectionNodeIdsContains(1));
+  ASSERT_TRUE(SelectionNodeIdsContains(3));
+
+  ASSERT_TRUE(SelectionNodeIdsContains(5));
+  ASSERT_TRUE(SelectionNodeIdsContains(6));
+
+  // Even though 3 is a generic container with more than one child, its sibling
+  // nodes are included in the selection because the start node includes it.
+  ASSERT_TRUE(SelectionNodeIdsContains(2));
+  ASSERT_TRUE(SelectionNodeIdsContains(3));
+}
+
+TEST_F(ReadAnythingAppModelTest,
+       SelectionParentIsLinkAndInlineBlock_SelectionStateCorrect) {
+  ui::AXTreeUpdate update;
+  SetUpdateTreeID(&update);
+  update.nodes.resize(4);
+  update.nodes[0].id = 1;
+  update.nodes[1].id = 2;
+  update.nodes[2].id = 3;
+  update.nodes[3].id = 4;
+  update.nodes[0].child_ids = {2, 3};
+  update.nodes[2].child_ids = {4};
+  update.nodes[0].role = ax::mojom::Role::kStaticText;
+  update.nodes[1].role = ax::mojom::Role::kStaticText;
+  update.nodes[2].role = ax::mojom::Role::kLink;
+  update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kDisplay,
+                                     "block");
+  update.nodes[3].role = ax::mojom::Role::kStaticText;
+  update.nodes[3].AddStringAttribute(ax::mojom::StringAttribute::kDisplay,
+                                     "inline-block");
+  AccessibilityEventReceived({update});
+
+  update.tree_data.sel_anchor_object_id = 4;
+  update.tree_data.sel_focus_object_id = 4;
+  update.tree_data.sel_anchor_offset = 0;
+  update.tree_data.sel_focus_offset = 1;
+  update.tree_data.sel_is_backward = false;
+  AccessibilityEventReceived({update});
+  ProcessSelection();
+
+  ASSERT_TRUE(HasSelection());
+  ASSERT_EQ(StartNodeId(), 4);
+  ASSERT_EQ(EndNodeId(), 4);
+
+  ASSERT_TRUE(SelectionNodeIdsContains(1));
+  ASSERT_FALSE(SelectionNodeIdsContains(2));
+  ASSERT_TRUE(SelectionNodeIdsContains(3));
+  ASSERT_TRUE(SelectionNodeIdsContains(4));
+}
+
+TEST_F(ReadAnythingAppModelTest,
+       SelectionParentIsGenericContainerAndInline_SelectionStateCorrect) {
+  ui::AXTreeUpdate update;
+  SetUpdateTreeID(&update);
+  update.nodes.resize(4);
+  update.nodes[0].id = 1;
+  update.nodes[1].id = 2;
+  update.nodes[2].id = 3;
+  update.nodes[3].id = 4;
+  update.nodes[0].child_ids = {2, 3};
+  update.nodes[2].child_ids = {4};
+  update.nodes[0].role = ax::mojom::Role::kStaticText;
+  update.nodes[1].role = ax::mojom::Role::kStaticText;
+  update.nodes[2].role = ax::mojom::Role::kGenericContainer;
+  update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kDisplay,
+                                     "block");
+  update.nodes[3].role = ax::mojom::Role::kStaticText;
+  update.nodes[3].AddStringAttribute(ax::mojom::StringAttribute::kDisplay,
+                                     "inline");
+  AccessibilityEventReceived({update});
+
+  update.tree_data.sel_anchor_object_id = 4;
+  update.tree_data.sel_focus_object_id = 4;
+  update.tree_data.sel_anchor_offset = 0;
+  update.tree_data.sel_focus_offset = 1;
+  update.tree_data.sel_is_backward = true;
+  AccessibilityEventReceived({update});
+  ProcessSelection();
+
+  ASSERT_TRUE(HasSelection());
+  ASSERT_EQ(StartNodeId(), 4);
+  ASSERT_EQ(EndNodeId(), 4);
+
+  ASSERT_TRUE(SelectionNodeIdsContains(1));
+  ASSERT_FALSE(SelectionNodeIdsContains(2));
+  ASSERT_TRUE(SelectionNodeIdsContains(3));
+  ASSERT_TRUE(SelectionNodeIdsContains(4));
+}
+TEST_F(
+    ReadAnythingAppModelTest,
+    SelectionParentIsGenericContainerWithMultipleChildren_SelectionStateCorrect) {
+  ui::AXTreeUpdate update;
+  SetUpdateTreeID(&update);
+  update.nodes.resize(5);
+  update.nodes[0].id = 1;
+  update.nodes[1].id = 2;
+  update.nodes[2].id = 3;
+  update.nodes[3].id = 4;
+  update.nodes[4].id = 5;
+  update.nodes[0].child_ids = {2, 3};
+  update.nodes[2].child_ids = {4, 5};
+  update.nodes[0].role = ax::mojom::Role::kStaticText;
+  update.nodes[1].role = ax::mojom::Role::kStaticText;
+  update.nodes[2].role = ax::mojom::Role::kGenericContainer;
+  update.nodes[3].role = ax::mojom::Role::kStaticText;
+  update.nodes[4].role = ax::mojom::Role::kStaticText;
+  AccessibilityEventReceived({update});
+
+  update.tree_data.sel_anchor_object_id = 4;
+  update.tree_data.sel_focus_object_id = 5;
+  update.tree_data.sel_anchor_offset = 0;
+  update.tree_data.sel_focus_offset = 0;
+  update.tree_data.sel_is_backward = false;
+  AccessibilityEventReceived({update});
+  ProcessSelection();
+
+  ASSERT_TRUE(HasSelection());
+  ASSERT_EQ(StartNodeId(), 4);
+  ASSERT_EQ(EndNodeId(), 5);
+
+  // 1 and 3 are ancestors, so they are included as selection nodes..
+  ASSERT_TRUE(SelectionNodeIdsContains(1));
+  ASSERT_TRUE(SelectionNodeIdsContains(3));
+  ASSERT_TRUE(SelectionNodeIdsContains(4));
+  ASSERT_TRUE(SelectionNodeIdsContains(5));
+
+  // Since 3 is a generic container with more than one child, its sibling nodes
+  // are not included, so 2 is ignored.
+  ASSERT_FALSE(SelectionNodeIdsContains(2));
+}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 569ca8cc..605a73d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3729,7 +3729,10 @@
         "../browser/ash/crosapi/video_conference_ash_browsertest.cc",
         "../browser/ash/crosapi/vpn_extension_observer_ash_browsertest.cc",
       ]
-      deps += [ "../browser/ash/video_conference" ]
+      deps += [
+        "../browser/ash/video_conference",
+        "//components/global_media_controls:test_support",
+      ]
 
       if (!is_official_build) {
         sources += [ "../browser/ash/crosapi/sharesheet_ash_browsertest.cc" ]
@@ -4118,6 +4121,7 @@
         "../browser/ash/policy/networking/network_policy_application_browsertest.cc",
         "../browser/ash/policy/networking/policy_certs_browsertest.cc",
         "../browser/ash/policy/remote_commands/curtain_mode_chromeos_browsertest.cc",
+        "../browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc",
         "../browser/ash/policy/reporting/metrics_reporting/apps/app_events_observer_browsertest.cc",
         "../browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_sampler_browsertest.cc",
         "../browser/ash/policy/reporting/metrics_reporting/audio/audio_events_observer_browsertest.cc",
@@ -7086,6 +7090,7 @@
       "../browser/ui/autofill/payments/autofill_dialog_models_unittest.cc",
       "../browser/ui/autofill/payments/iban_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc",
+      "../browser/ui/autofill/payments/mandatory_reauth_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/offer_notification_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc",
@@ -9128,6 +9133,7 @@
       "../browser/ui/views/performance_controls/high_efficiency_chip_view_unittest.cc",
       "../browser/ui/views/permissions/permission_chip_unittest.cc",
       "../browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc",
+      "../browser/ui/views/permissions/permission_prompt_bubble_two_origins_view_unittest.cc",
       "../browser/ui/views/qrcode_generator/qrcode_generator_bubble_unittest.cc",
       "../browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc",
       "../browser/ui/views/relaunch_notification/relaunch_required_timer_internal_unittest.cc",
@@ -10032,6 +10038,7 @@
         "../browser/ui/commerce/price_tracking/mock_shopping_list_ui_tab_helper.h",
         "../browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc",
         "../browser/ui/toolbar/app_menu_model_interactive_uitest.cc",
+        "../browser/ui/views/autofill/payments/mandatory_reauth_bubble_view_uitest.cc",
         "../browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc",
         "../browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views_interactive_uitest.cc",
         "../browser/ui/views/autofill/payments/virtual_card_manual_fallback_bubble_views_interactive_uitest.cc",
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.cc b/chrome/test/chromedriver/chrome/stub_web_view.cc
index 2e3a33a..a7928ff8 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.cc
+++ b/chrome/test/chromedriver/chrome/stub_web_view.cc
@@ -97,14 +97,6 @@
   return Status(kOk);
 }
 
-Status StubWebView::CallAsyncFunction(const std::string& frame,
-                                      const std::string& function,
-                                      const base::Value::List& args,
-                                      const base::TimeDelta& timeout,
-                                      std::unique_ptr<base::Value>* result) {
-  return Status(kOk);
-}
-
 Status StubWebView::CallUserAsyncFunction(
     const std::string& frame,
     const std::string& function,
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h
index 5de8d3e..16f0ff4e 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.h
+++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -46,11 +46,6 @@
                       const std::string& function,
                       const base::Value::List& args,
                       std::unique_ptr<base::Value>* result) override;
-  Status CallAsyncFunction(const std::string& frame,
-                           const std::string& function,
-                           const base::Value::List& args,
-                           const base::TimeDelta& timeout,
-                           std::unique_ptr<base::Value>* result) override;
   Status CallUserAsyncFunction(const std::string& frame,
                                const std::string& function,
                                const base::Value::List& args,
diff --git a/chrome/test/chromedriver/chrome/web_view.h b/chrome/test/chromedriver/chrome/web_view.h
index 24145064..19b3e91 100644
--- a/chrome/test/chromedriver/chrome/web_view.h
+++ b/chrome/test/chromedriver/chrome/web_view.h
@@ -118,17 +118,6 @@
                               const base::Value::List& args,
                               std::unique_ptr<base::Value>* result) = 0;
 
-  // Calls a JavaScript function in a specified frame with the given args and
-  // two callbacks. The first may be invoked with a value to return to the user.
-  // The second may be used to report an error. This function waits until
-  // one of the callbacks is invoked or the timeout occurs.
-  // |result| will never be NULL on success.
-  virtual Status CallAsyncFunction(const std::string& frame,
-                                   const std::string& function,
-                                   const base::Value::List& args,
-                                   const base::TimeDelta& timeout,
-                                   std::unique_ptr<base::Value>* result) = 0;
-
   // Same as |CallAsyncFunction|, except no additional error callback is passed
   // to the function. Also, |kJavaScriptError| or |kScriptTimeout| is used
   // as the error code instead of |kUnknownError| in appropriate cases.
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index 3242fa3..c4fd02a 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -840,15 +840,6 @@
                                  result);
 }
 
-Status WebViewImpl::CallAsyncFunction(const std::string& frame,
-                                      const std::string& function,
-                                      const base::Value::List& args,
-                                      const base::TimeDelta& timeout,
-                                      std::unique_ptr<base::Value>* result) {
-  return CallAsyncFunctionInternal(
-      frame, function, args, false, timeout, result);
-}
-
 Status WebViewImpl::CallUserSyncScript(const std::string& frame,
                                        const std::string& script,
                                        const base::Value::List& args,
@@ -879,8 +870,7 @@
     const base::Value::List& args,
     const base::TimeDelta& timeout,
     std::unique_ptr<base::Value>* result) {
-  return CallAsyncFunctionInternal(
-      frame, function, args, true, timeout, result);
+  return CallAsyncFunctionInternal(frame, function, args, timeout, result);
 }
 
 // TODO (crbug.com/chromedriver/4364): Simplify this function
@@ -1573,13 +1563,12 @@
     const std::string& frame,
     const std::string& function,
     const base::Value::List& args,
-    bool is_user_supplied,
     const base::TimeDelta& timeout,
     std::unique_ptr<base::Value>* result) {
   base::Value::List async_args;
   async_args.Append("return (" + function + ").apply(null, arguments);");
   async_args.Append(args.Clone());
-  async_args.Append(is_user_supplied);
+  async_args.Append(/*is_user_supplied=*/true);
   std::unique_ptr<base::Value> tmp;
   Timeout local_timeout(timeout);
   Status status = CallFunctionWithTimeout(frame, kExecuteAsyncScriptScript,
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h
index 7537c097..4ee9bfe5 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.h
+++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -86,11 +86,6 @@
                       const std::string& function,
                       const base::Value::List& args,
                       std::unique_ptr<base::Value>* result) override;
-  Status CallAsyncFunction(const std::string& frame,
-                           const std::string& function,
-                           const base::Value::List& args,
-                           const base::TimeDelta& timeout,
-                           std::unique_ptr<base::Value>* result) override;
   Status CallUserSyncScript(const std::string& frame,
                             const std::string& script,
                             const base::Value::List& args,
@@ -193,7 +188,6 @@
   Status CallAsyncFunctionInternal(const std::string& frame,
                                    const std::string& function,
                                    const base::Value::List& args,
-                                   bool is_user_supplied,
                                    const base::TimeDelta& timeout,
                                    std::unique_ptr<base::Value>* result);
   Status IsNotPendingNavigation(const std::string& frame_id,
diff --git a/chrome/test/chromedriver/docs/run_javascript.md b/chrome/test/chromedriver/docs/run_javascript.md
index 11834e33..824addbff 100644
--- a/chrome/test/chromedriver/docs/run_javascript.md
+++ b/chrome/test/chromedriver/docs/run_javascript.md
@@ -242,10 +242,3 @@
 before passing it to `WebView::CallFunctionWithTimeout`.
 The [`executeAsyncScript`] function is responsible for waiting for the
 async script to finish, as required by the WebDriver standard.
-
-### Use ` WebViewImpl::CallAsyncFunction` Method
-
-This method is similar to `WebView::CallUserAsyncFunction`,
-but is intended for ChromeDriver's own embedded script code.
-This is only used to implement some obsolete features that we expect to
-remove in ChromeDriver version 85 (https://crbug.com/chromedriver/3376).
diff --git a/chrome/test/chromedriver/keycode_text_conversion_mac.mm b/chrome/test/chromedriver/keycode_text_conversion_mac.mm
index cc2bdcd4..14da147 100644
--- a/chrome/test/chromedriver/keycode_text_conversion_mac.mm
+++ b/chrome/test/chromedriver/keycode_text_conversion_mac.mm
@@ -6,9 +6,8 @@
 
 #import <Carbon/Carbon.h>
 
-#include <cctype>
-
 #include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "chrome/test/chromedriver/chrome/ui_events.h"
@@ -54,7 +53,7 @@
   UniChar character =
       GetCharacter(static_cast<UInt16>(mac_key_code), modifier_key_state);
 
-  if (character && !std::iscntrl(character)) {
+  if (character && !base::IsAsciiControl(character)) {
     std::u16string text16;
     text16.push_back(character);
     *text = base::UTF16ToUTF8(text16);
diff --git a/chrome/test/chromedriver/log_replay/devtools_log_reader.cc b/chrome/test/chromedriver/log_replay/devtools_log_reader.cc
index 02a23189..7962de98 100644
--- a/chrome/test/chromedriver/log_replay/devtools_log_reader.cc
+++ b/chrome/test/chromedriver/log_replay/devtools_log_reader.cc
@@ -1,14 +1,15 @@
 // Copyright 2018 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #include "chrome/test/chromedriver/log_replay/devtools_log_reader.h"
 
-#include <cctype>
 #include <iostream>
 #include <string>
 
 #include "base/logging.h"
 #include "base/strings/pattern.h"
+#include "base/strings/string_util.h"
 
 namespace {
 // Parses the word (id=X) and just returns the id number
@@ -29,7 +30,7 @@
 // Parses the word (session_id=X) and just returns the session_id string
 bool GetSessionId(std::istringstream& header_stream, std::string* session_id) {
   std::string spaces;
-  while (std::isspace(header_stream.peek())) {
+  while (base::IsAsciiWhitespace(header_stream.peek())) {
     char ch;
     header_stream.get(ch);
     spaces.push_back(ch);
diff --git a/chrome/test/data/autofill/autofill_creditcard_form_in_iframe.html b/chrome/test/data/autofill/autofill_creditcard_form_in_iframe.html
new file mode 100644
index 0000000..4ee0e3f
--- /dev/null
+++ b/chrome/test/data/autofill/autofill_creditcard_form_in_iframe.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+  <head>
+ <title>Credit Card Form in an Iframe</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ </head>
+ <body>
+  <p>Credit Card Form in an Iframe</p>
+  <iframe src="autofill_creditcard_form.html" width="100%" height="800px"></iframe>
+ </body>
+</html>
+
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_categories.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_categories.ts
index 63aea4a..d8896b75 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_categories.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_categories.ts
@@ -58,7 +58,7 @@
 
     test(
         category + ' category button should be active after clicking at it.',
-        () => {
+        async () => {
           const allCategoryButtons =
               Array
                   .from(findInEmojiPicker('emoji-search')!.shadowRoot!
@@ -69,6 +69,9 @@
           const categoryButton = allCategoryButtons[categoryIndex];
           categoryButton!.click();
           flush();
+          await waitForCondition(
+              () => isCategoryButtonActive(categoryButton),
+              'wait for category button active');
           assertTrue(isCategoryButtonActive(categoryButton));
           allCategoryButtons.forEach((categoryButtonItem, index) => {
             if (index !== categoryIndex) {
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.ts
index 6e27af2..d88f1efdb 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.ts
@@ -43,6 +43,7 @@
     let findInEmojiPicker: (...path: string[]) => HTMLElement | null;
     let findEmojiFirstButton: (...path: string[]) =>
         HTMLElement | null | undefined;
+    let waitUntilFindInEmojiPicker: (...path: string[]) => Promise<HTMLElement>;
     let scrollDown: (height: number) => void;
     let scrollToBottom: () => void;
     let categoryIndex: number;
@@ -52,6 +53,7 @@
       emojiPicker = newPicker.emojiPicker;
       findInEmojiPicker = newPicker.findInEmojiPicker;
       findEmojiFirstButton = newPicker.findEmojiFirstButton;
+      waitUntilFindInEmojiPicker = newPicker.waitUntilFindInEmojiPicker;
       scrollDown = newPicker.scrollDown;
       scrollToBottom = newPicker.scrollToBottom;
       await newPicker.readyPromise;
@@ -100,7 +102,7 @@
     test(
         `history tab button must be disabled when the ${category} history` +
             ' is empty.',
-        () => {
+        async () => {
           // It is assumed that the order of categoryList is the same as
           // buttons.
           const categoryButton =
@@ -110,7 +112,7 @@
           categoryButton!.click();
           flush();
           const historyTab =
-              findInEmojiPicker(
+              await waitUntilFindInEmojiPicker(
                   `#tabs emoji-group-button[data-group="${category}-history"]`,
                   'cr-icon-button') as CrIconButtonElement |
               null;
@@ -202,9 +204,9 @@
               'cr-icon-button');
           gifCategoryButton!.click();
           await flush();
-          const firstGifTabInFirstPage =
-              findInEmojiPicker('.pagination text-group-button', 'cr-button');
-          const firstGifTabInSecondPage = findInEmojiPicker(
+          const firstGifTabInFirstPage = await waitUntilFindInEmojiPicker(
+              '.pagination text-group-button', 'cr-button');
+          const firstGifTabInSecondPage = await waitUntilFindInEmojiPicker(
               '.pagination + .pagination', 'text-group-button', 'cr-button');
           rightChevron!.click();
 
@@ -327,26 +329,26 @@
               () => emojiPicker.activeInfiniteGroupId === TRENDING_GROUP_ID,
               'Wait for trending to be active.');
 
-          const gifResults1 = findInEmojiPicker(subcategoryGroupSelector(
-              category,
-              emojiPicker.activeInfiniteGroupId!,
-              ))!.shadowRoot!.querySelectorAll('emoji-image');
+          const group =
+              await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
+                  category,
+                  emojiPicker.activeInfiniteGroupId!,
+                  ));
+
+          const gifResults1 =
+              group!.shadowRoot!.querySelectorAll('emoji-image');
           assertEquals(gifResults1.length, 6);
 
           scrollToBottom();
 
           await waitForCondition(
-              () => findInEmojiPicker(
-                        subcategoryGroupSelector(
-                            category, emojiPicker.activeInfiniteGroupId!))
-                        ?.shadowRoot?.querySelectorAll('emoji-image')
-                        .length === 12,
+              () =>
+                  group?.shadowRoot?.querySelectorAll('emoji-image').length ===
+                  12,
               'Wait for emoji picker to scroll and render new gifs.');
 
-          const gifResults2 = findInEmojiPicker(subcategoryGroupSelector(
-              category,
-              emojiPicker.activeInfiniteGroupId!,
-              ))!.shadowRoot!.querySelectorAll('emoji-image');
+          const gifResults2 =
+              group!.shadowRoot!.querySelectorAll('emoji-image');
           assertEquals(gifResults2!.length, 12);
         });
 
@@ -363,34 +365,29 @@
           () => emojiPicker.activeInfiniteGroupId === TRENDING_GROUP_ID,
           'Wait for trending to render.');
 
-      const gifResults1 = findInEmojiPicker(subcategoryGroupSelector(
+      const group = await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
           category,
           emojiPicker.activeInfiniteGroupId!,
-          ))!.shadowRoot!.querySelectorAll('emoji-image');
+          ));
+
+      const gifResults1 = group!.shadowRoot!.querySelectorAll('emoji-image');
       assertEquals(gifResults1.length, 6);
 
       scrollToBottom();
 
       // Wait for Emoji Picker to scroll and render new GIFs.
       await waitForCondition(
-          () => findInEmojiPicker(
-                    subcategoryGroupSelector(
-                        category, emojiPicker.activeInfiniteGroupId!))
-                    ?.shadowRoot?.querySelectorAll('emoji-image')
-                    .length === 12,
+          () =>
+              group?.shadowRoot?.querySelectorAll('emoji-image').length === 12,
           'Wait for Emoji Picker to scroll and render new GIFs.');
 
-      const gifResults2 = findInEmojiPicker(subcategoryGroupSelector(
-          category,
-          emojiPicker.activeInfiniteGroupId!,
-          ))!.shadowRoot!.querySelectorAll('emoji-image');
+      const gifResults2 = group!.shadowRoot!.querySelectorAll('emoji-image');
       assertEquals(gifResults2.length, 12);
 
       // Check display is correct.
-      const leftColResults = findInEmojiPicker(subcategoryGroupSelector(
-          category, emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                 .querySelectorAll<HTMLImageElement>(
-                                     'div.left-column > emoji-image');
+      const leftColResults =
+          group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+              'div.left-column > emoji-image');
       assertEquals(leftColResults.length, 6);
       assertEmojiImageAlt(leftColResults[0], 'Trending Left 1');
       assertEmojiImageAlt(leftColResults[1], 'Trending Left 2');
@@ -399,10 +396,9 @@
       assertEmojiImageAlt(leftColResults[4], 'Trending Left 5');
       assertEmojiImageAlt(leftColResults[5], 'Trending Left 6');
 
-      const rightColResults = findInEmojiPicker(subcategoryGroupSelector(
-          category, emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                  .querySelectorAll<HTMLImageElement>(
-                                      'div.right-column > emoji-image');
+      const rightColResults =
+          group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+              'div.right-column > emoji-image');
       assertEquals(rightColResults.length, 6);
       assertEmojiImageAlt(rightColResults[0], 'Trending Right 1');
       assertEmojiImageAlt(rightColResults[1], 'Trending Right 2');
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.ts
index 68f3a59..807c3ee1 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.ts
@@ -22,11 +22,13 @@
 suite('emoji-picker-extension', () => {
   let emojiPicker: EmojiPicker;
   let findInEmojiPicker: (...path: string[]) => HTMLElement | null;
+  let waitUntilFindInEmojiPicker: (...path: string[]) => Promise<HTMLElement>;
 
   setup(async () => {
     const newPicker = initialiseEmojiPickerForTest();
     emojiPicker = newPicker.emojiPicker;
     findInEmojiPicker = newPicker.findInEmojiPicker;
+    waitUntilFindInEmojiPicker = newPicker.waitUntilFindInEmojiPicker;
     await newPicker.readyPromise;
   });
 
@@ -41,9 +43,9 @@
             'cr-icon-button');
         emoticonCategoryButton!.click();
         await flush();
-        const firstEmoticonTabInFirstPage =
-            findInEmojiPicker('.pagination text-group-button', 'cr-button');
-        const firstEmoticonTabInSecondPage = findInEmojiPicker(
+        const firstEmoticonTabInFirstPage = await waitUntilFindInEmojiPicker(
+            '.pagination text-group-button', 'cr-button');
+        const firstEmoticonTabInSecondPage = await waitUntilFindInEmojiPicker(
             '.pagination + .pagination', 'text-group-button', 'cr-button');
         rightChevron!.click();
 
@@ -116,21 +118,29 @@
         const emoticonCategoryButton = findInEmojiPicker(
             'emoji-search', 'emoji-category-button:last-of-type',
             'cr-icon-button');
-        const emojiGroups = findInEmojiPicker('#groups');
+        const emojiGroups = await waitUntilFindInEmojiPicker('#groups');
         emoticonCategoryButton!.click();
         const targetScroll = emojiGroups!.scrollTop;
         emojiCategoryButton!.click();
 
-        (findInEmojiPicker('emoji-search') as unknown as
-         EmojiSearch)!.setSearchQuery('face');
+        const emojiSearch = await waitUntilFindInEmojiPicker('emoji-search');
+        (emojiSearch as unknown as EmojiSearch)!.setSearchQuery('face');
+
         await waitForCondition(
-            () => findInEmojiPicker('emoji-search', 'emoji-group'),
+            () => findInEmojiPicker('emoji-search', 'emoji-group') !== null,
             'Wait for emoji groups to render');
+
         emoticonCategoryButton!.click();
 
         await waitForCondition(
             () => emojiGroups!.scrollTop === targetScroll,
             'Wait for scrolling to complete');
+
+        await waitForCondition(
+            () => (findInEmojiPicker('emoji-search') as EmojiSearch)
+                      .searchNotEmpty() === false,
+            'wait for search results empty');
+
         assertFalse((findInEmojiPicker('emoji-search') as EmojiSearch)
                         .searchNotEmpty());
       });
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test_util.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test_util.ts
index 0539385..15bcce3e 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test_util.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test_util.ts
@@ -168,6 +168,14 @@
   const findInEmojiPicker = (...path: string[]) =>
       deepQuerySelector(emojiPicker, path);
 
+  const waitUntilFindInEmojiPicker = async(...path: string[]):
+      Promise<HTMLElement> => {
+        await waitForCondition(
+            () => findInEmojiPicker(...path) !== null,
+            'element should not be null');
+        return findInEmojiPicker(...path)!;
+      };
+
   const findEmojiFirstButton = (...path: string[]) => {
     const emojiElement = findInEmojiPicker(...path);
     return (emojiElement as EmojiGroupComponent | null)?.firstEmojiButton();
@@ -203,6 +211,7 @@
   return {
     emojiPicker,
     findInEmojiPicker,
+    waitUntilFindInEmojiPicker,
     findEmojiFirstButton,
     readyPromise,
     scrollDown,
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.ts b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.ts
index 4f2ccda8..de74cc8 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.ts
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.ts
@@ -133,6 +133,7 @@
 
   let emojiPicker: EmojiPicker;
   let findInEmojiPicker: (...path: string[]) => HTMLElement | null;
+  let waitUntilFindInEmojiPicker: (...path: string[]) => Promise<HTMLElement>;
   let scrollToBottom: () => void;
   const categoryList = ['emoji', 'symbol', 'emoticon', 'gif'];
   let categoryIndex: number;
@@ -144,6 +145,7 @@
     ]);
     emojiPicker = newPicker.emojiPicker;
     findInEmojiPicker = newPicker.findInEmojiPicker;
+    waitUntilFindInEmojiPicker = newPicker.waitUntilFindInEmojiPicker;
     const readyPromise = newPicker.readyPromise;
     scrollToBottom = newPicker.scrollToBottom;
     await readyPromise;
@@ -195,8 +197,9 @@
         categoryButton.click();
         flush();
 
-        const recentlyUsedEmoji = findInEmojiPicker(historyGroupSelector(
-            'gif'))!.shadowRoot!.querySelectorAll('emoji-image');
+        const recentlyUsedEmoji =
+            (await waitUntilFindInEmojiPicker(historyGroupSelector(
+                'gif')))!.shadowRoot!.querySelectorAll('emoji-image');
 
         assertEquals(3, recentlyUsedEmoji.length);
 
@@ -214,26 +217,26 @@
             () => emojiPicker.activeInfiniteGroupId === trendingId,
             'wait for new group to be active');
 
-        const gifResults1 = findInEmojiPicker(subcategoryGroupSelector(
+        const group = await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
             'gif',
             emojiPicker.activeInfiniteGroupId!,
-            ))!.shadowRoot!.querySelectorAll('emoji-image');
+            ));
+
+        const gifResults1 = group!.shadowRoot!.querySelectorAll('emoji-image');
         assertEquals(gifResults1.length, 6);
 
         // Check display is correct.
-        const leftColResults1 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                    .querySelectorAll<HTMLImageElement>(
-                                        'div.left-column > emoji-image');
+        const leftColResults1 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.left-column > emoji-image');
         assertEquals(leftColResults1.length, 3);
         assertEmojiImageAlt(leftColResults1[0], 'Trending Left 1');
         assertEmojiImageAlt(leftColResults1[1], 'Trending Left 2');
         assertEmojiImageAlt(leftColResults1[2], 'Trending Left 3');
 
-        const rightColResults1 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                     .querySelectorAll<HTMLImageElement>(
-                                         'div.right-column > emoji-image');
+        const rightColResults1 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.right-column > emoji-image');
         assertEquals(rightColResults1.length, 3);
         assertEmojiImageAlt(rightColResults1[0], 'Trending Right 1');
         assertEmojiImageAlt(rightColResults1[1], 'Trending Right 2');
@@ -242,23 +245,17 @@
         scrollToBottom();
 
         await waitForCondition(
-            () => findInEmojiPicker(subcategoryGroupSelector(
-                      'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                      .querySelectorAll('emoji-image')
-                      .length === 12,
+            () => group?.shadowRoot?.querySelectorAll('emoji-image').length ===
+                12,
             'wait for emoji picker to scroll and render new Gifs');
 
-        const gifResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif',
-            emojiPicker.activeInfiniteGroupId!,
-            ))!.shadowRoot!.querySelectorAll('emoji-image');
+        const gifResults2 = group!.shadowRoot!.querySelectorAll('emoji-image');
         assertEquals(gifResults2.length, 12);
 
         // Check display is correct.
-        const leftColResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                    .querySelectorAll<HTMLImageElement>(
-                                        'div.left-column > emoji-image');
+        const leftColResults2 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.left-column > emoji-image');
         assertEquals(leftColResults2.length, 6);
         assertEmojiImageAlt(leftColResults2[0], 'Trending Left 1');
         assertEmojiImageAlt(leftColResults2[1], 'Trending Left 2');
@@ -267,10 +264,9 @@
         assertEmojiImageAlt(leftColResults2[4], 'Trending Left 5');
         assertEmojiImageAlt(leftColResults2[5], 'Trending Left 6');
 
-        const rightColResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                     .querySelectorAll<HTMLImageElement>(
-                                         'div.right-column > emoji-image');
+        const rightColResults2 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.right-column > emoji-image');
         assertEquals(rightColResults2.length, 6);
         assertEmojiImageAlt(rightColResults2[0], 'Trending Right 1');
         assertEmojiImageAlt(rightColResults2[1], 'Trending Right 2');
@@ -294,8 +290,9 @@
         categoryButton!.click();
         flush();
 
-        const recentlyUsedEmoji = findInEmojiPicker(historyGroupSelector(
-            'gif'))!.shadowRoot!.querySelectorAll('emoji-image');
+        const recentlyUsedEmoji =
+            (await waitUntilFindInEmojiPicker(historyGroupSelector(
+                'gif')))!.shadowRoot!.querySelectorAll('emoji-image');
 
         assertEquals(3, recentlyUsedEmoji.length);
 
@@ -304,59 +301,64 @@
                 .find((group: EmojiGroupElement) => group.name === TRENDING)
                 ?.groupId;
 
-        const trendingSubcategoryButton =
-            emojiPicker.shadowRoot!
-                .querySelector(`#tabs text-group-button[data-group="${
-                    trendingId}"]`)!.shadowRoot!.querySelector('cr-button');
+        const trendingSubcategoryButton = (await waitUntilFindInEmojiPicker(
+            `#tabs text-group-button[data-group="${
+                trendingId}"]`))!.shadowRoot!.querySelector('cr-button');
+
         trendingSubcategoryButton!.click();
         await flush();
 
-        const gifResults1 = findInEmojiPicker(subcategoryGroupSelector(
+        await waitForCondition(
+            () => emojiPicker.activeInfiniteGroupId === trendingId,
+            'wait for new group to be active');
+
+        const group = await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
             'gif',
             emojiPicker.activeInfiniteGroupId!,
-            ))!.shadowRoot!.querySelectorAll('emoji-image');
+            ));
+
+        await waitForCondition(
+            () =>
+                group!.shadowRoot!.querySelectorAll('emoji-image').length === 6,
+            'wait for trending GIFs');
+
+        const gifResults1 = group!.shadowRoot!.querySelectorAll('emoji-image');
         assertEquals(gifResults1.length, 6);
 
         // Check display is correct.
-        const leftColResults1 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                    .querySelectorAll<HTMLImageElement>(
-                                        'div.left-column > emoji-image');
+        const leftColResults1 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.left-column > emoji-image');
         assertEquals(leftColResults1.length, 3);
         assertEmojiImageAlt(leftColResults1[0], 'Trending Left 1');
         assertEmojiImageAlt(leftColResults1[1], 'Trending Left 2');
         assertEmojiImageAlt(leftColResults1[2], 'Trending Left 3');
 
-        const rightColResults1 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                     .querySelectorAll<HTMLImageElement>(
-                                         'div.right-column > emoji-image');
+        const rightColResults1 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.right-column > emoji-image');
         assertEquals(rightColResults1.length, 3);
         assertEmojiImageAlt(rightColResults1[0], 'Trending Right 1');
         assertEmojiImageAlt(rightColResults1[1], 'Trending Right 2');
         assertEmojiImageAlt(rightColResults1[2], 'Trending Right 3');
 
+
+
         scrollToBottom();
 
         // Wait for Emoji Picker to scroll and render new GIFs.
         await waitForCondition(
-            () => findInEmojiPicker(subcategoryGroupSelector(
-                      'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                      .querySelectorAll('emoji-image')
-                      .length === 12,
+            () => group!.shadowRoot!.querySelectorAll('emoji-image').length ===
+                12,
             'failed to wait for new GIFs to render');
 
-        const gifResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif',
-            emojiPicker.activeInfiniteGroupId!,
-            ))!.shadowRoot!.querySelectorAll('emoji-image');
+        const gifResults2 = group!.shadowRoot!.querySelectorAll('emoji-image');
         assertEquals(gifResults2.length, 12);
 
         // Check display is correct.
-        const leftColResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                    .querySelectorAll<HTMLImageElement>(
-                                        'div.left-column > emoji-image');
+        const leftColResults2 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.left-column > emoji-image');
         assertEquals(leftColResults2.length, 6);
         assertEmojiImageAlt(leftColResults2[0], 'Trending Left 1');
         assertEmojiImageAlt(leftColResults2[1], 'Trending Left 2');
@@ -365,10 +367,9 @@
         assertEmojiImageAlt(leftColResults2[4], 'Trending Left 5');
         assertEmojiImageAlt(leftColResults2[5], 'Trending Left 6');
 
-        const rightColResults2 = findInEmojiPicker(subcategoryGroupSelector(
-            'gif', emojiPicker.activeInfiniteGroupId!))!.shadowRoot!
-                                     .querySelectorAll<HTMLImageElement>(
-                                         'div.right-column > emoji-image');
+        const rightColResults2 =
+            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
+                'div.right-column > emoji-image');
         assertEquals(rightColResults2.length, 6);
         assertEmojiImageAlt(rightColResults2[0], 'Trending Right 1');
         assertEmojiImageAlt(rightColResults2[1], 'Trending Right 2');
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 3ff584f..7aae1f4 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -180,7 +180,7 @@
     "multidevice_page/multidevice_combined_setup_item_test.ts",
     "multidevice_page/multidevice_feature_item_test.ts",
     "multidevice_page/multidevice_feature_toggle_test.ts",
-    "multidevice_page/multidevice_notification_access_setup_dialog_tests.js",
+    "multidevice_page/multidevice_notification_access_setup_dialog_test.ts",
     "multidevice_page/multidevice_permissions_setup_dialog_tests.js",
     "multidevice_page/multidevice_smartlock_item_test.ts",
     "multidevice_page/multidevice_subpage_tests.js",
diff --git a/chrome/test/data/webui/settings/chromeos/app_management/arc_detail_view_test.js b/chrome/test/data/webui/settings/chromeos/app_management/arc_detail_view_test.js
index 95989a846..7c2bb5c 100644
--- a/chrome/test/data/webui/settings/chromeos/app_management/arc_detail_view_test.js
+++ b/chrome/test/data/webui/settings/chromeos/app_management/arc_detail_view_test.js
@@ -7,10 +7,10 @@
 import {AppManagementStore, updateSelectedAppId} from 'chrome://os-settings/chromeos/os_settings.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {getPermissionValueBool} from 'chrome://resources/cr_components/app_management/util.js';
-import {createBoolPermission} from 'chrome://resources/cr_components/app_management/permission_util.js';
+import {createBoolPermission, createTriStatePermission} from 'chrome://resources/cr_components/app_management/permission_util.js';
 import {setupFakeHandler, replaceStore, replaceBody, isHiddenByDomIf, isHidden, getPermissionItemByType, getPermissionCrToggleByType} from './test_util.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-import {AppType, PermissionType} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
+import {AppType, PermissionType, TriState} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
 import {FakePageHandler} from './fake_page_handler.js';
 
 
@@ -164,7 +164,7 @@
           {'appManagementArcReadOnlyPermissions': false});
     });
 
-    test('Permission display', async () => {
+    test('Boolean permission display', async () => {
       const locationItem =
           getPermissionItemByType(arcPermissionView, 'kLocation');
       assertEquals(
@@ -191,6 +191,48 @@
               .textContent.trim());
     });
 
+    test('Tri-state permission display', async () => {
+      const locationItem =
+          getPermissionItemByType(arcPermissionView, 'kLocation');
+
+      fakeHandler.setPermission(
+          arcPermissionView.app_.id,
+          createTriStatePermission(
+              PermissionType.kLocation, /*value=*/ TriState.kAllow,
+              /*is_managed=*/ false));
+      await flushTasks();
+
+      assertEquals(
+          'Allowed',
+          locationItem.shadowRoot.querySelector('#description')
+              .textContent.trim());
+
+      fakeHandler.setPermission(
+          arcPermissionView.app_.id,
+          createTriStatePermission(
+              PermissionType.kLocation, /*value=*/ TriState.kAsk,
+              /*is_managed=*/ false));
+      await flushTasks();
+
+      assertEquals(
+          'Ask every time',
+          locationItem.shadowRoot.querySelector('#description')
+              .textContent.trim());
+
+      fakeHandler.setPermission(
+          arcPermissionView.app_.id,
+          createTriStatePermission(
+              PermissionType.kLocation, /*value=*/ TriState.kBlock,
+              /*is_managed=*/ false));
+      await flushTasks();
+
+      assertEquals(
+          'Denied',
+          locationItem.shadowRoot.querySelector('#description')
+              .textContent.trim());
+    });
+
+
     test('Permission display with detail', async () => {
       const permission = createBoolPermission(
           PermissionType.kLocation, /*value=*/ true,
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_test.ts b/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_test.ts
new file mode 100644
index 0000000..c691bbb1
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_test.ts
@@ -0,0 +1,223 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://os-settings/chromeos/os_settings.js';
+
+import {MultiDeviceBrowserProxyImpl, NotificationAccessSetupOperationStatus, SettingsMultideviceNotificationAccessSetupDialogElement} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+import {TestMultideviceBrowserProxy} from './test_multidevice_browser_proxy.js';
+
+suite('<settings-multidevice-notification-access-setup-dialog>', () => {
+  let browserProxy: TestMultideviceBrowserProxy;
+  let notificationAccessSetupDialog:
+      SettingsMultideviceNotificationAccessSetupDialogElement;
+  let buttonContainer: HTMLElement;
+
+  function simulateStatusChanged(
+      status: NotificationAccessSetupOperationStatus) {
+    webUIListenerCallback(
+        'settings.onNotificationAccessSetupStatusChanged', status);
+    flush();
+  }
+
+  function isSetupInstructionsShownSeparately(): boolean {
+    return notificationAccessSetupDialog.get(
+        'shouldShowSetupInstructionsSeparately_');
+  }
+
+  function queryCancelButton(): HTMLButtonElement|null {
+    return buttonContainer.querySelector<HTMLButtonElement>('#cancelButton');
+  }
+
+  function queryGetStartedButton(): HTMLButtonElement|null {
+    return buttonContainer.querySelector<HTMLButtonElement>(
+        '#getStartedButton');
+  }
+
+  function queryDoneButton(): HTMLButtonElement|null {
+    return buttonContainer.querySelector<HTMLButtonElement>('#doneButton');
+  }
+
+  function queryTryAgainButton(): HTMLButtonElement|null {
+    return buttonContainer.querySelector<HTMLButtonElement>('#tryAgainButton');
+  }
+
+  function queryCloseButton(): HTMLButtonElement|null {
+    return buttonContainer.querySelector<HTMLButtonElement>('#closeButton');
+  }
+
+  setup(() => {
+    browserProxy = new TestMultideviceBrowserProxy();
+    MultiDeviceBrowserProxyImpl.setInstanceForTesting(browserProxy);
+
+    notificationAccessSetupDialog = document.createElement(
+        'settings-multidevice-notification-access-setup-dialog');
+    document.body.appendChild(notificationAccessSetupDialog);
+    flush();
+    const container =
+        notificationAccessSetupDialog.shadowRoot!.querySelector<HTMLElement>(
+            '#buttonContainer');
+    assertTrue(!!container);
+    buttonContainer = container;
+  });
+
+  test('Test success flow', async () => {
+    assertTrue(isSetupInstructionsShownSeparately());
+    assertTrue(!!queryCancelButton());
+    const getStartedButton = queryGetStartedButton();
+    assertTrue(!!getStartedButton);
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+    getStartedButton.click();
+    assertEquals(1, browserProxy.getCallCount('attemptNotificationSetup'));
+
+    simulateStatusChanged(
+        NotificationAccessSetupOperationStatus.CONNECTION_REQUESTED);
+    assertTrue(isSetupInstructionsShownSeparately());
+    assertTrue(!!queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    simulateStatusChanged(NotificationAccessSetupOperationStatus.CONNECTING);
+    assertTrue(isSetupInstructionsShownSeparately());
+    assertTrue(!!queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    simulateStatusChanged(NotificationAccessSetupOperationStatus
+                              .SENT_MESSAGE_TO_PHONE_AND_WAITING_FOR_RESPONSE);
+    assertTrue(isSetupInstructionsShownSeparately());
+    assertTrue(!!queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    assertEquals(0, browserProxy.getCallCount('setFeatureEnabledState'));
+    simulateStatusChanged(
+        NotificationAccessSetupOperationStatus.COMPLETED_SUCCESSFULLY);
+    assertFalse(isSetupInstructionsShownSeparately());
+    assertEquals(null, queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertTrue(!!queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    // The feature becomes enabled when the status becomes
+    // NotificationAccessSetupOperationStatus.COMPLETED_SUCCESSFULLY.
+    assertEquals(1, browserProxy.getCallCount('setFeatureEnabledState'));
+
+    const dialog = notificationAccessSetupDialog.shadowRoot!
+                       .querySelector<HTMLDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertTrue(dialog.open);
+    const doneButton = queryDoneButton();
+    assertTrue(!!doneButton);
+    doneButton.click();
+    assertFalse(dialog.open);
+  });
+
+  test('Test cancel during connecting flow', async () => {
+    assertTrue(!!queryCancelButton());
+    const getStartedButton = queryGetStartedButton();
+    assertTrue(!!getStartedButton);
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+    getStartedButton.click();
+    assertEquals(1, browserProxy.getCallCount('attemptNotificationSetup'));
+
+    simulateStatusChanged(NotificationAccessSetupOperationStatus.CONNECTING);
+
+    const cancelButton = queryCancelButton();
+    assertTrue(!!cancelButton);
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    cancelButton.click();
+    assertEquals(1, browserProxy.getCallCount('cancelNotificationSetup'));
+
+    const dialog = notificationAccessSetupDialog.shadowRoot!
+                       .querySelector<HTMLDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertFalse(dialog.open);
+  });
+
+  test('Test failure during connecting flow', async () => {
+    assertTrue(!!queryCancelButton());
+    const getStartedButton = queryGetStartedButton();
+    assertTrue(!!getStartedButton);
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+    getStartedButton.click();
+    assertEquals(1, browserProxy.getCallCount('attemptNotificationSetup'));
+
+    simulateStatusChanged(
+        NotificationAccessSetupOperationStatus.TIMED_OUT_CONNECTING);
+
+    assertTrue(!!queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    const tryAgainButton = queryTryAgainButton();
+    assertTrue(!!tryAgainButton);
+
+    tryAgainButton.click();
+    assertEquals(2, browserProxy.getCallCount('attemptNotificationSetup'));
+
+    flush();
+
+    assertTrue(!!queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+
+    simulateStatusChanged(
+        NotificationAccessSetupOperationStatus.CONNECTION_DISCONNECTED);
+
+    const cancelButton = queryCancelButton();
+    assertTrue(!!cancelButton);
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertTrue(!!queryTryAgainButton());
+
+    cancelButton.click();
+    assertEquals(1, browserProxy.getCallCount('cancelNotificationSetup'));
+
+    const dialog = notificationAccessSetupDialog.shadowRoot!
+                       .querySelector<HTMLDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertFalse(dialog.open);
+  });
+
+  test('Test notification access prohibited', async () => {
+    assertTrue(!!queryCancelButton());
+    const getStartedButton = queryGetStartedButton();
+    assertTrue(!!getStartedButton);
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+    assertEquals(null, queryCloseButton());
+    getStartedButton.click();
+    assertEquals(1, browserProxy.getCallCount('attemptNotificationSetup'));
+
+    simulateStatusChanged(
+        NotificationAccessSetupOperationStatus.NOTIFICATION_ACCESS_PROHIBITED);
+
+    assertEquals(null, queryCancelButton());
+    assertEquals(null, queryGetStartedButton());
+    assertEquals(null, queryDoneButton());
+    assertEquals(null, queryTryAgainButton());
+    const closeButton = queryCloseButton();
+    assertTrue(!!closeButton);
+
+    closeButton.click();
+
+    const dialog = notificationAccessSetupDialog.shadowRoot!
+                       .querySelector<HTMLDialogElement>('#dialog');
+    assertTrue(!!dialog);
+    assertFalse(dialog.open);
+  });
+});
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_tests.js
deleted file mode 100644
index f08093e..0000000
--- a/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_notification_access_setup_dialog_tests.js
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {MultiDeviceBrowserProxyImpl, NotificationAccessSetupOperationStatus} from 'chrome://os-settings/chromeos/os_settings.js';
-import {assert} from 'chrome://resources/ash/common/assert.js';
-import {webUIListenerCallback} from 'chrome://resources/ash/common/cr.m.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-import {TestMultideviceBrowserProxy} from './test_multidevice_browser_proxy.js';
-
-/**
- * @fileoverview
- * Suite of tests for multidevice-notification-access-setup-dialog element.
- */
-suite('Multidevice', () => {
-  /** @type {?TestMultideviceBrowserProxy} */
-  let browserProxy;
-
-  /** @type {?MultideviceNotificationsOptInDialog} */
-  let notificationAccessSetupDialog = null;
-
-  /** @type {?HTMLElement} */
-  let buttonContainer = null;
-
-  /**
-   * @param {NotificationAccessSetupOperationStatus} status
-   */
-  function simulateStatusChanged(status) {
-    webUIListenerCallback(
-        'settings.onNotificationAccessSetupStatusChanged', status);
-    flush();
-  }
-
-  /** @return {boolean} */
-  function isSetupInstructionsShownSeparately() {
-    return notificationAccessSetupDialog.shouldShowSetupInstructionsSeparately_;
-  }
-
-  setup(() => {
-    PolymerTest.clearBody();
-    browserProxy = new TestMultideviceBrowserProxy();
-    MultiDeviceBrowserProxyImpl.setInstanceForTesting(browserProxy);
-
-    notificationAccessSetupDialog = document.createElement(
-        'settings-multidevice-notification-access-setup-dialog');
-    document.body.appendChild(notificationAccessSetupDialog);
-    flush();
-    buttonContainer =
-        assert(notificationAccessSetupDialog.shadowRoot.querySelector(
-            '#buttonContainer'));
-  });
-
-  test('Test success flow', async () => {
-    assertTrue(isSetupInstructionsShownSeparately());
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertTrue(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-    buttonContainer.querySelector('#getStartedButton').click();
-    assertEquals(browserProxy.getCallCount('attemptNotificationSetup'), 1);
-
-    simulateStatusChanged(
-        NotificationAccessSetupOperationStatus.CONNECTION_REQUESTED);
-    assertTrue(isSetupInstructionsShownSeparately());
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    simulateStatusChanged(NotificationAccessSetupOperationStatus.CONNECTING);
-    assertTrue(isSetupInstructionsShownSeparately());
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    simulateStatusChanged(NotificationAccessSetupOperationStatus
-                              .SENT_MESSAGE_TO_PHONE_AND_WAITING_FOR_RESPONSE);
-    assertTrue(isSetupInstructionsShownSeparately());
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 0);
-    simulateStatusChanged(
-        NotificationAccessSetupOperationStatus.COMPLETED_SUCCESSFULLY);
-    assertFalse(isSetupInstructionsShownSeparately());
-    assertFalse(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertTrue(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    // The feature becomes enabled when the status becomes
-    // NotificationAccessSetupOperationStatus.COMPLETED_SUCCESSFULLY.
-    assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 1);
-
-    assertTrue(
-        notificationAccessSetupDialog.shadowRoot.querySelector('#dialog').open);
-    buttonContainer.querySelector('#doneButton').click();
-    assertFalse(
-        notificationAccessSetupDialog.shadowRoot.querySelector('#dialog').open);
-  });
-
-  test('Test cancel during connecting flow', async () => {
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertTrue(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-    buttonContainer.querySelector('#getStartedButton').click();
-    assertEquals(browserProxy.getCallCount('attemptNotificationSetup'), 1);
-
-    simulateStatusChanged(NotificationAccessSetupOperationStatus.CONNECTING);
-
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    buttonContainer.querySelector('#cancelButton').click();
-    assertEquals(browserProxy.getCallCount('cancelNotificationSetup'), 1);
-
-    assertFalse(
-        notificationAccessSetupDialog.shadowRoot.querySelector('#dialog').open);
-  });
-
-  test('Test failure during connecting flow', async () => {
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertTrue(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-    buttonContainer.querySelector('#getStartedButton').click();
-    assertEquals(browserProxy.getCallCount('attemptNotificationSetup'), 1);
-
-    simulateStatusChanged(
-        NotificationAccessSetupOperationStatus.TIMED_OUT_CONNECTING);
-
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertTrue(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    buttonContainer.querySelector('#tryAgainButton').click();
-    assertEquals(browserProxy.getCallCount('attemptNotificationSetup'), 2);
-
-    flush();
-
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    simulateStatusChanged(
-        NotificationAccessSetupOperationStatus.CONNECTION_DISCONNECTED);
-
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertTrue(!!buttonContainer.querySelector('#tryAgainButton'));
-
-    buttonContainer.querySelector('#cancelButton').click();
-    assertEquals(browserProxy.getCallCount('cancelNotificationSetup'), 1);
-
-    assertFalse(
-        notificationAccessSetupDialog.shadowRoot.querySelector('#dialog').open);
-  });
-
-  test('Test notification access prohibited', async () => {
-    assertTrue(!!buttonContainer.querySelector('#cancelButton'));
-    assertTrue(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-    assertFalse(!!buttonContainer.querySelector('#closeButton'));
-    buttonContainer.querySelector('#getStartedButton').click();
-    assertEquals(browserProxy.getCallCount('attemptNotificationSetup'), 1);
-
-    simulateStatusChanged(
-        NotificationAccessSetupOperationStatus.NOTIFICATION_ACCESS_PROHIBITED);
-
-    assertFalse(!!buttonContainer.querySelector('#cancelButton'));
-    assertFalse(!!buttonContainer.querySelector('#getStartedButton'));
-    assertFalse(!!buttonContainer.querySelector('#doneButton'));
-    assertFalse(!!buttonContainer.querySelector('#tryAgainButton'));
-    assertTrue(!!buttonContainer.querySelector('#closeButton'));
-
-    buttonContainer.querySelector('#closeButton').click();
-
-    assertFalse(
-        notificationAccessSetupDialog.shadowRoot.querySelector('#dialog').open);
-  });
-});
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page/test_multidevice_browser_proxy.ts b/chrome/test/data/webui/settings/chromeos/multidevice_page/test_multidevice_browser_proxy.ts
index 6a59bead..4dfb833 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_page/test_multidevice_browser_proxy.ts
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_page/test_multidevice_browser_proxy.ts
@@ -67,6 +67,7 @@
       'logPhoneHubPermissionSetUpScreenAction',
       'logPhoneHubPermissionOnboardingSetupMode',
       'logPhoneHubPermissionOnboardingSetupResult',
+      'getSmartLockSignInAllowed',
     ]);
   }
 
@@ -168,6 +169,10 @@
         'logPhoneHubPermissionOnboardingSetupResult', [completedMode]);
   }
 
+  getSmartLockSignInAllowed(): Promise<boolean> {
+    return Promise.resolve(true);
+  }
+
   removeHostDevice(): void {}
 
   retryPendingHostSetup(): void {}
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage_tests.js
index bef0675..368715f 100644
--- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage_tests.js
@@ -916,7 +916,7 @@
     assertFalse(!!bluetoothDeviceDetailPage.getDeviceIdForTest());
   });
 
-  test('Forget button with Fast Pair flag', async function() {
+  test.skip('Forget button with Fast Pair flag', async function() {
     loadTimeData.overrideValues({'enableFastPairFlag': true});
     init();
     bluetoothConfig.setBluetoothEnabledState(/*enabled=*/ true);
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index f99234c..0a6d420b 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -408,7 +408,7 @@
  ],
  [
    'MultidevicePageMultideviceNotificationAccessSetupDialog',
-   'multidevice_page/multidevice_notification_access_setup_dialog_tests.js',
+   'multidevice_page/multidevice_notification_access_setup_dialog_test.js',
  ],
  [
    'MultidevicePageMultidevicePermissionsSetupDialog',
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection.js
index 5f53ad6..3d48fca 100644
--- a/chrome/test/data/webui/side_panel/read_anything/update_content_selection.js
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection.js
@@ -123,7 +123,7 @@
   chrome.readAnything.setContentForTesting(axTree, []);
   // The expected string contains the complete text of each node in the
   // selection.
-  const expected = '<div><p>World</p><p>Friend</p></div>';
+  const expected = '<div><p>World</p><p>Friend!</p></div>';
   assertContainerInnerHTML(expected);
   const selection = readAnythingApp.getSelection();
   assertEquals(selection.anchorNode.textContent, 'World');
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards.js
index 2b28e4da..84cdcc5e 100644
--- a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards.js
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards.js
@@ -123,7 +123,7 @@
   chrome.readAnything.setContentForTesting(axTree, []);
   // The expected string contains the complete text of each node in the
   // selection.
-  const expected = '<div><p>Hello</p><p>World</p><p>Friend</p></div>';
+  const expected = '<div><p>Hello</p><p>World</p><p>Friend!</p></div>';
   assertContainerInnerHTML(expected);
   const selection = readAnythingApp.getSelection();
   assertEquals(selection.anchorNode.textContent, 'Hello');
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards_with_inline_text.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards_with_inline_text.js
new file mode 100644
index 0000000..ee6a1e25
--- /dev/null
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_backwards_with_inline_text.js
@@ -0,0 +1,131 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// out/Debug/browser_tests \
+//    --gtest_filter=ReadAnythingAppTest.UpdateContent_Selection_Backwards
+
+// Do not call the real `onConnected()`. As defined in
+// ReadAnythingAppController, onConnected creates mojo pipes to connect to the
+// rest of the Read Anything feature, which we are not testing here.
+(() => {
+  chrome.readAnything.onConnected = () => {};
+
+  const readAnythingApp =
+      document.querySelector('read-anything-app').shadowRoot;
+  const container = readAnythingApp.getElementById('container');
+  let result = true;
+
+  const assertEquals = (actual, expected) => {
+    const isEqual = actual === expected;
+    if (!isEqual) {
+      console.error(
+          'Expected: ' + JSON.stringify(expected) + ', ' +
+          'Actual: ' + JSON.stringify(actual));
+    }
+    result = result && isEqual;
+    return isEqual;
+  };
+
+  const assertContainerInnerHTML = (expected) => {
+    const actual = container.innerHTML;
+    assertEquals(actual, expected);
+  };
+
+  const setOnSelectionChangeForTest = () => {
+    // This is called by readAnythingApp onselectionchange. It is usually
+    // implemented by ReadAnythingAppController which forwards these
+    // arguments to the browser process in the form of an
+    // AXEventNotificationDetail. Instead, we capture the arguments here and
+    // verify their values. Since onselectionchange is called
+    // asynchronously, the test must wait for this function to be called;
+    // therefore we fire a custom event on-selection-change-for-text here
+    // for the test to await.
+    chrome.readAnything.onSelectionChange =
+        (anchorNodeId, anchorOffset, focusNodeId, focusOffset) => {
+          readAnythingApp.dispatchEvent(
+              new CustomEvent('on-selection-change-for-test', {
+                detail: {
+                  anchorNodeId: anchorNodeId,
+                  anchorOffset: anchorOffset,
+                  focusNodeId: focusNodeId,
+                  focusOffset: focusOffset,
+                },
+              }));
+        };
+  };
+
+  // root htmlTag='#document' id=1
+  // ++paragraph htmlTag='p' id=2
+  // ++++staticText name='Hello' id=3
+  // ++paragraph htmlTag='p' id=4
+  // ++++staticText name='World' id=5
+  // ++++link htmlTag='a' id=6
+  // +++++staticText name='Friend' id=7
+  const axTree = {
+    rootId: 1,
+    nodes: [
+      {
+        id: 1,
+        role: 'rootWebArea',
+        htmlTag: '#document',
+        childIds: [2, 4],
+      },
+      {
+        id: 2,
+        role: 'paragraph',
+        htmlTag: 'p',
+        childIds: [3],
+      },
+      {
+        id: 3,
+        role: 'staticText',
+        name: 'Hello',
+      },
+      {
+        id: 4,
+        role: 'paragraph',
+        htmlTag: 'p',
+        display: 'block',
+        childIds: [5, 6],
+      },
+      {
+        id: 5,
+        role: 'staticText',
+        name: 'World',
+      },
+      {
+        id: 6,
+        role: 'link',
+        htmlTag: 'a',
+        display: 'inline',
+        childIds: [7],
+      },
+      {
+        id: 7,
+        role: 'staticText',
+        name: 'Friend',
+      },
+    ],
+    selection: {
+      anchor_object_id: 7,
+      focus_object_id: 7,
+      anchor_offset: 1,
+      focus_offset: 0,
+      is_backward: true,
+    },
+  };
+  setOnSelectionChangeForTest();
+  chrome.readAnything.setContentForTesting(axTree, []);
+  // The expected string contains the complete text of each node in the
+  // selection.
+  const expected = '<div><p>World<a>Friend</a></p></div>';
+  assertContainerInnerHTML(expected);
+  const selection = readAnythingApp.getSelection();
+  assertEquals(selection.anchorNode.textContent, 'Friend');
+  assertEquals(selection.focusNode.textContent, 'Friend');
+  assertEquals(selection.anchorOffset, 0);
+  assertEquals(selection.focusOffset, 1);
+
+  return result;
+})();
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_outside_distilled_content.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_outside_distilled_content.js
index 0fa5c8d8..547742e 100644
--- a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_outside_distilled_content.js
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_outside_distilled_content.js
@@ -100,7 +100,7 @@
   chrome.readAnything.setContentForTesting(axTree, [2]);
   // The selection is outside the content nodes.The expected string contains
   // the complete text of each node in the selection.
-  const expected = '<div><p>World</p><p>Friend</p></div>';
+  const expected = '<div><p>World</p><p>Friend!</p></div>';
   assertContainerInnerHTML(expected);
 
   return result;
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_partially_outside_distilled_content.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_partially_outside_distilled_content.js
index 4d75e69..86b8deb 100644
--- a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_partially_outside_distilled_content.js
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_partially_outside_distilled_content.js
@@ -100,7 +100,7 @@
   chrome.readAnything.setContentForTesting(axTree, [2, 4]);
   // The selection has content inside and outside the content nodes. The
   // expected string contains the complete text of each node in the selection.
-  const expected = '<div><p>Hello</p><p>World</p><p>Friend</p></div>';
+  const expected = '<div><p>Hello</p><p>World</p><p>Friend!</p></div>';
   assertContainerInnerHTML(expected);
 
   return result;
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_inline_text.js b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_inline_text.js
new file mode 100644
index 0000000..0002a96
--- /dev/null
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_inline_text.js
@@ -0,0 +1,130 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// out/Debug/browser_tests \
+//    --gtest_filter=ReadAnythingAppTest.UpdateContent_Selection
+
+// Do not call the real `onConnected()`. As defined in
+// ReadAnythingAppController, onConnected creates mojo pipes to connect to the
+// rest of the Read Anything feature, which we are not testing here.
+(() => {
+  chrome.readAnything.onConnected = () => {};
+
+  const readAnythingApp =
+      document.querySelector('read-anything-app').shadowRoot;
+  const container = readAnythingApp.getElementById('container');
+  let result = true;
+
+  const assertEquals = (actual, expected) => {
+    const isEqual = actual === expected;
+    if (!isEqual) {
+      console.error(
+          'Expected: ' + JSON.stringify(expected) + ', ' +
+          'Actual: ' + JSON.stringify(actual));
+    }
+    result = result && isEqual;
+    return isEqual;
+  };
+
+  const assertContainerInnerHTML = (expected) => {
+    const actual = container.innerHTML;
+    assertEquals(actual, expected);
+  };
+
+  const setOnSelectionChangeForTest = () => {
+    // This is called by readAnythingApp onselectionchange. It is usually
+    // implemented by ReadAnythingAppController which forwards these
+    // arguments to the browser process in the form of an
+    // AXEventNotificationDetail. Instead, we capture the arguments here and
+    // verify their values. Since onselectionchange is called
+    // asynchronously, the test must wait for this function to be called;
+    // therefore we fire a custom event on-selection-change-for-text here
+    // for the test to await.
+    chrome.readAnything.onSelectionChange =
+        (anchorNodeId, anchorOffset, focusNodeId, focusOffset) => {
+          readAnythingApp.dispatchEvent(
+              new CustomEvent('on-selection-change-for-test', {
+                detail: {
+                  anchorNodeId: anchorNodeId,
+                  anchorOffset: anchorOffset,
+                  focusNodeId: focusNodeId,
+                  focusOffset: focusOffset,
+                },
+              }));
+        };
+  };
+
+  // root htmlTag='#document' id=1
+  // ++paragraph htmlTag='p' id=2
+  // ++++staticText name='Hello' id=3
+  // ++paragraph htmlTag='p' id=4
+  // ++++staticText name='World' id=5
+  // ++++link htmlTag='a' id=6
+  // +++++staticText name='Friend' id=7
+  const axTree = {
+    rootId: 1,
+    nodes: [
+      {
+        id: 1,
+        role: 'rootWebArea',
+        htmlTag: '#document',
+        childIds: [2, 4],
+      },
+      {
+        id: 2,
+        role: 'paragraph',
+        htmlTag: 'p',
+        childIds: [3],
+      },
+      {
+        id: 3,
+        role: 'staticText',
+        name: 'Hello',
+      },
+      {
+        id: 4,
+        role: 'paragraph',
+        htmlTag: 'p',
+        childIds: [5, 6],
+      },
+      {
+        id: 5,
+        role: 'staticText',
+        name: 'World',
+      },
+      {
+        id: 6,
+        role: 'link',
+        htmlTag: 'a',
+        display: 'inline',
+        childIds: [7],
+      },
+      {
+        id: 7,
+        role: 'staticText',
+        name: 'Friend',
+      },
+    ],
+    selection: {
+      anchor_object_id: 7,
+      focus_object_id: 7,
+      anchor_offset: 0,
+      focus_offset: 1,
+      is_backward: false,
+    },
+  };
+  setOnSelectionChangeForTest();
+  chrome.readAnything.setContentForTesting(axTree, []);
+  // The expected string contains the complete text of each node in the
+  // selection.
+  const expected = '<div><p>World<a>Friend</a></p></div>';
+  assertContainerInnerHTML(expected);
+  const selection = readAnythingApp.getSelection();
+  assertEquals(selection.anchorNode.textContent, 'Friend');
+  assertEquals(selection.focusNode.textContent, 'Friend');
+  assertEquals(selection.anchorOffset, 0);
+  assertEquals(selection.focusOffset, 1);
+
+  return result;
+})();
diff --git a/chrome/test/webapps/coverage/coverage_cros.tsv b/chrome/test/webapps/coverage/coverage_cros.tsv
index 467049c..72d347b 100644
--- a/chrome/test/webapps/coverage/coverage_cros.tsv
+++ b/chrome/test/webapps/coverage/coverage_cros.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 55%, with partial coverage: 74%
+# Full coverage: 56%, with partial coverage: 81%
 create_shortcut_Standalone_Windowed🌕	launch_from_menu_option_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_launch_icon_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_chrome_apps_Standalone🌓	check_app_title_Standalone_StandaloneOriginal🌑
@@ -1142,3 +1142,467 @@
 install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓	add_file_handling_policy_approval_FileHandler🌑	remove_file_handling_policy_approval_FileHandler🌑	launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑
 install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓	add_file_handling_policy_approval_FileHandler🌑	remove_file_handling_policy_approval_FileHandler🌑	launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑
 install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓	add_file_handling_policy_approval_FileHandler🌑	remove_file_handling_policy_approval_FileHandler🌑	launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_app_in_list_windowed_SubApp1🌓	check_has_sub_app_HasSubApps_SubApp1🌕	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_list_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_menu_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_os_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_app_settings_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_list_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_menu_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_os_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_app_settings_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_list_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_menu_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_os_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_app_settings_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_list_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_menu_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_os_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_from_app_settings_HasSubApps🌑	check_app_not_in_list_SubApp1🌑	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	uninstall_policy_app_HasSubApps🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	install_sub_app_HasSubApps_SubApp2_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕	check_has_sub_app_HasSubApps_SubApp2🌕
+create_shortcut_HasSubApps_Windowed🌕	check_no_sub_apps_HasSubApps🌕
+create_shortcut_HasSubApps_Browser🌕	check_no_sub_apps_HasSubApps🌕
+install_omnibox_icon_HasSubApps🌕	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_no_sub_apps_HasSubApps🌕
+install_menu_option_HasSubApps🌕	check_no_sub_apps_HasSubApps🌕
+create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_app_not_in_list_SubApp1🌓	check_platform_shortcut_not_exists_SubApp1🌑	check_no_sub_apps_HasSubApps🌑
+create_shortcut_SubApp1_Windowed🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	check_not_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_menu_option_HasSubApps🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Browser🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_omnibox_icon_SubApp1🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+install_menu_option_SubApp1🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	check_has_sub_app_HasSubApps_SubApp1🌕
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Windowed🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_omnibox_icon_SubApp1🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Windowed_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_menu_option_SubApp1🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_windowed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+create_shortcut_SubApp1_Browser🌕	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_WithShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Windowed🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	create_shortcut_HasSubApps_Browser🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Windowed_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_WithShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_policy_app_HasSubApps_NoShortcut_Browser_WebApp🌓	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
+install_policy_app_SubApp1_NoShortcut_Browser_WebApp🌓	install_menu_option_HasSubApps🌕	install_sub_app_HasSubApps_SubApp1_UserAllow🌕	remove_sub_app_HasSubApps_SubApp1🌕	check_not_has_sub_app_HasSubApps_SubApp1🌕	check_app_in_list_tabbed_SubApp1🌓	check_platform_shortcut_and_icon_SubApp1🌓
diff --git a/chrome/test/webapps/data/actions.md b/chrome/test/webapps/data/actions.md
index 07c57ed3..e16f0598 100644
--- a/chrome/test/webapps/data/actions.md
+++ b/chrome/test/webapps/data/actions.md
@@ -53,7 +53,7 @@
 | |
 | # Install |
 | install_omnibox_icon | InstallableSite |  | 31 | Implemented |  |  |
-| install_policy_app | Site, ShortcutOptions, WindowOptions, InstallMode |  | 32 | Implemented | Add a force-installed enterprise policy site to the user profile (must be managed profile). |  |
+| install_policy_app | Site, ShortcutOptions, WindowOptions, InstallMode |  | 32 | Implemented | Add a force-installed enterprise policy site to the user profile (must be managed profile). This installation action also opens the target site in a tab to match the expectation of installs opening the app first for some CUJs.|  |
 | install_menu_option | InstallableSite |  | 47 | Implemented |  |  |
 | install_no_shortcut | Site | install_policy_app($1, NoShortcut, WindowOptions::All, WebApp) | 56 | Parameterized |  |  |
 | install_tabbed_no_shortcut | Site | install_policy_app($1, NoShortcut, Browser, WebApp) | 129 | Parameterized | All installation methods that result in a tabbed webapp without shortcut. |  |
@@ -165,9 +165,9 @@
 | #Subapps |
 | install_sub_app | Site, Site, SubAppInstallDialogOptions |  | 138 | WIP | Navigate to the first site, call subApps.add() to install the second site. |  |
 | remove_sub_app | Site, Site |  | 139 | Implemented | Navigate to the first site, call subApps.remove() to uninstall the second site. |  |
-| check_has_sub_app | Site |  | 140 | Implemented | Assuming we have the active browser window on the (potential) parent site, call subApps.list() and check if the given site is listed. |  |
-| check_not_has_sub_app | Site |  | 141 | Implemented | Assuming we have the active browser window on the (potential) parent site, call subApps.list() and check if the given site is not listed. |  |
-| check_no_sub_apps |  |  | 142 | Implemented | Assuming we navigated to the (potential) parent site, call subApps.list() and check if the list is empty. |  |
+| check_has_sub_app | Site, Site |  | 140 | Implemented | Assuming we have some tab or browser window on the (potential) parent site, call subApps.list() and check if the given site is listed. |  |
+| check_not_has_sub_app | Site, Site |  | 141 | Implemented | Assuming we have some tab or browser window on the (potential) parent site, call subApps.list() and check if the given site is not listed. |  |
+| check_no_sub_apps | Site |  | 142 | Implemented | Assuming we have some tab or browser window on the (potential) parent site, call subApps.list() and check if the list is empty. |  |
 
 ### App Home
 Actions that the user can take by going to chrome://apps and either left clicking an app or right clicking an app and then taking actions from the context menu that opens.
diff --git a/chrome/test/webapps/data/critical_user_journeys.md b/chrome/test/webapps/data/critical_user_journeys.md
index e9e8b3f..473c77a 100644
--- a/chrome/test/webapps/data/critical_user_journeys.md
+++ b/chrome/test/webapps/data/critical_user_journeys.md
@@ -404,15 +404,16 @@
 
 | #Platforms | Test -> | | | | | | | | | | | | | | | | |
 | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
-| #WMLC | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | check_app_in_list_windowed(SubApp1) | check_has_sub_app(SubApp1) | check_has_shortcuts(SubApp1) |
-| #WMLC | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserDeny) | check_app_is not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
-| #WMLC | install_or_shortcut_by_user(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | uninstall_by_user(HasSubApps) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
-| #WMLC | install_or_shortcut_by_policy(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | uninstall_by_policy(HasSubApps) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
-| #WMLC | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | install_sub_app(HasSubApps, SubApp2, UserAllow) | check_has_sub_app(SubApp1) | check_has_sub_app(SubApp2) |
-| #WMLC | install_or_shortcut(HasSubApps) | check_no_sub_apps() |
-| #WMLC | install_or_shortcut_by_user(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) | check_no_sub_apps() |
-| #WMLC | install_or_shortcut_by_policy(HasSubApps) | launch(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) | check_no_sub_apps() |
-| #WMLC | install_or_shortcut(SubApp1) | check_app_in_list(SubApp1) | check_has_shortcut(SubApp1)
-| #WMLC | install_or_shortcut(HasSubApps) | install_or_shortcut(SubApp1) | check_not_has_sub_app(SubApp1)
-| #WMLC | install_or_shortcut(HasSubApps) | install_or_shortcut(SubApp1) | install_sub_app(HasSubApps, SubApp1, UserAllow) | check_has_sub_app(SubApp1)
-| #WMLC | install_or_shortcut(HasSubApps) | install_or_shortcut(SubApp1) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_not_has_sub_app(SubApp1) | check_app_in_list_windowed(SubApp1) | check_has_shortcut(SubApp1)
+| C | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | check_app_in_list_windowed(SubApp1) | check_has_sub_app(HasSubApps, SubApp1) | check_platform_shortcut_and_icon(SubApp1) |
+| #C | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserDeny) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
+| C | install_or_shortcut_by_user(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | uninstall_by_user(HasSubApps) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
+| C | install_policy_app(HasSubApps, ShortcutOptions::All, WindowOptions::All, WebApp) | install_sub_app(HasSubApps, SubApp1, UserAllow) | uninstall_policy_app(HasSubApps) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) |
+| C | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | install_sub_app(HasSubApps, SubApp2, UserAllow) | check_has_sub_app(HasSubApps, SubApp1) | check_has_sub_app(HasSubApps, SubApp2) |
+| C | install_or_shortcut(HasSubApps) | check_no_sub_apps(HasSubApps) |
+| C | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_app_not_in_list(SubApp1) | check_platform_shortcut_not_exists(SubApp1) | check_no_sub_apps(HasSubApps) |
+| C | install_or_shortcut_windowed(SubApp1) | check_app_in_list_windowed(SubApp1) | check_platform_shortcut_and_icon(SubApp1)
+| C | install_or_shortcut_tabbed(SubApp1) | check_app_in_list_tabbed(SubApp1) | check_platform_shortcut_and_icon(SubApp1)
+| C | install_or_shortcut(SubApp1) | install_or_shortcut(HasSubApps) | check_not_has_sub_app(HasSubApps, SubApp1)
+| C | install_or_shortcut(SubApp1) | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | check_has_sub_app(HasSubApps, SubApp1)
+| C | install_or_shortcut_windowed(SubApp1) | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_not_has_sub_app(HasSubApps, SubApp1) | check_app_in_list_windowed(SubApp1) | check_platform_shortcut_and_icon(SubApp1)
+| C | install_or_shortcut_tabbed(SubApp1) | install_or_shortcut(HasSubApps) | install_sub_app(HasSubApps, SubApp1, UserAllow) | remove_sub_app(HasSubApps, SubApp1) | check_not_has_sub_app(HasSubApps, SubApp1) | check_app_in_list_tabbed(SubApp1) | check_platform_shortcut_and_icon(SubApp1)
diff --git a/chrome/test/webapps/data/framework_supported_actions.csv b/chrome/test/webapps/data/framework_supported_actions.csv
index ab86fc4..e114575 100644
--- a/chrome/test/webapps/data/framework_supported_actions.csv
+++ b/chrome/test/webapps/data/framework_supported_actions.csv
@@ -91,3 +91,8 @@
 await_manifest_update,                                 🌕, 🌕,  🌕,   🌕,
 enable_file_handling,                                  🌕, 🌕,  🌕,   🌑,
 disable_file_handling,                                 🌕, 🌕,  🌕,   🌑,
+install_sub_app,                                       🌑, 🌑,  🌑,   🌕,
+remove_sub_app,                                        🌑, 🌑,  🌑,   🌕,
+check_has_sub_app,                                     🌑, 🌑,  🌑,   🌕,
+check_not_has_sub_app,                                 🌑, 🌑,  🌑,   🌕,
+check_no_sub_apps,                                     🌑, 🌑,  🌑,   🌕,
diff --git a/chrome/test/webapps/file_reading.py b/chrome/test/webapps/file_reading.py
index f06bde6..ecf1371 100755
--- a/chrome/test/webapps/file_reading.py
+++ b/chrome/test/webapps/file_reading.py
@@ -156,9 +156,10 @@
         human_friendly_action_name += "_" + action_base_name_to_default_args[
             human_friendly_action_name]
     elif '(' in human_friendly_action_name:
-        # Handle arguments being specified.
+        # Handle arguments being specified. Also strip trailing _, which appears
+        # if the action is "action_name()" without arguments.
         human_friendly_action_name = human_friendly_action_name.replace(
-            "(", "_").replace(", ", "_").rstrip(")")
+            "(", "_").replace(", ", "_").rstrip(")_")
     return human_friendly_action_name
 
 
@@ -407,7 +408,7 @@
     unused_supported_actions = set(
         supported_platform_actions.keys()).difference(action_base_names)
     if unused_supported_actions:
-        raise ValueError(f"Actions specified as suppored that are not in "
+        raise ValueError(f"Actions specified as supported that are not in "
                          f"the actions list: {unused_supported_actions}.")
 
     # Resolve the output actions
diff --git a/chrome/updater/device_management/dm_storage.h b/chrome/updater/device_management/dm_storage.h
index fb93e5de..f6f21f3e 100644
--- a/chrome/updater/device_management/dm_storage.h
+++ b/chrome/updater/device_management/dm_storage.h
@@ -145,6 +145,9 @@
       ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto>
   GetOmahaPolicySettings() const;
 
+  // Returns the folder that caches the downloaded policies.
+  base::FilePath policy_cache_folder() const { return policy_cache_root_; }
+
  private:
   friend class base::RefCountedThreadSafe<DMStorage>;
   ~DMStorage();
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 48f9f94..ec10730 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -292,9 +292,7 @@
 
     EXPECT_EQ(task_info.trigger_types,
               TaskScheduler::TriggerType::TRIGGER_TYPE_HOURLY |
-                  (IsSystemInstall(scope)
-                       ? TaskScheduler::TriggerType::TRIGGER_TYPE_LOGON
-                       : 0));
+                  TaskScheduler::TriggerType::TRIGGER_TYPE_LOGON);
   } else {
     task_scheduler->ForEachTaskWithPrefix(
         base::ASCIIToWide(PRODUCT_FULLNAME_STRING),
diff --git a/chrome/updater/tools/BUILD.gn b/chrome/updater/tools/BUILD.gn
index f626aa2..288abf86 100644
--- a/chrome/updater/tools/BUILD.gn
+++ b/chrome/updater/tools/BUILD.gn
@@ -58,6 +58,18 @@
   }
 }
 
+executable("dm_policy_dump") {
+  sources = [ "dm_policy_dump.cc" ]
+  deps = [
+    "//base",
+    "//chrome/updater:base",
+    "//chrome/updater:constants_prod",
+    "//chrome/updater:external_constants",
+    "//chrome/updater/protos:omaha_proto",
+    "//components/policy/proto",
+  ]
+}
+
 source_set("unittest") {
   testonly = true
 
diff --git a/chrome/updater/tools/dm_policy_dump.cc b/chrome/updater/tools/dm_policy_dump.cc
new file mode 100644
index 0000000..9ab8e40
--- /dev/null
+++ b/chrome/updater/tools/dm_policy_dump.cc
@@ -0,0 +1,204 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+#include <memory>
+#include <string>
+#
+
+#include "base/base64.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/updater/device_management/dm_cached_policy_info.h"
+#include "chrome/updater/device_management/dm_storage.h"
+#include "chrome/updater/protos/omaha_settings.pb.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+
+namespace updater {
+namespace {
+
+std::string UpdateValueAsString(
+    ::wireless_android_enterprise_devicemanagement::UpdateValue value) {
+  switch (value) {
+    case ::wireless_android_enterprise_devicemanagement::UPDATES_DISABLED:
+      return "Disabled";
+    case ::wireless_android_enterprise_devicemanagement::MANUAL_UPDATES_ONLY:
+      return "Manual Updates Only";
+    case ::wireless_android_enterprise_devicemanagement::AUTOMATIC_UPDATES_ONLY:
+      return "Automatic Updates Only";
+    case ::wireless_android_enterprise_devicemanagement::UPDATES_ENABLED:
+    default:
+      return "Enabled";
+  }
+}
+
+std::string InstallValueAsString(
+    ::wireless_android_enterprise_devicemanagement::InstallValue value) {
+  switch (value) {
+    case ::wireless_android_enterprise_devicemanagement::INSTALL_DISABLED:
+      return "Disabled";
+    case ::wireless_android_enterprise_devicemanagement::INSTALL_ENABLED:
+    default:
+      return "Enabled";
+  }
+}
+
+void PrintPolicies() {
+  scoped_refptr<DMStorage> storage = GetDefaultDMStorage();
+  if (!storage) {
+    std::cerr << "Failed to instantiate DM storage instance." << std::endl;
+    return;
+  }
+
+  std::cout << "-------------------------------------------------" << std::endl;
+  std::cout << "Device ID: " << storage->GetDeviceID() << std::endl;
+  std::cout << "Enrollment token: " << storage->GetEnrollmentToken()
+            << std::endl;
+  std::cout << "DM token: " << storage->GetDmToken() << std::endl;
+  std::cout << "-------------------------------------------------" << std::endl;
+
+  std::unique_ptr<CachedPolicyInfo> cached_info =
+      storage->GetCachedPolicyInfo();
+  if (cached_info) {
+    std::cout << "Cached policy info (for subsequent policy fetch):"
+              << std::endl;
+    if (cached_info->has_key_version()) {
+      std::cout << "  Key version: " << cached_info->key_version() << std::endl;
+      std::cout << "  Key size: " << cached_info->public_key().size()
+                << std::endl;
+    }
+    std::cout << "  Timestamp: " << cached_info->timestamp() << std::endl;
+  }
+  std::cout << "-------------------------------------------------" << std::endl;
+
+  std::unique_ptr<
+      ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto>
+      omaha_settings = storage->GetOmahaPolicySettings();
+  if (omaha_settings) {
+    bool has_global_policy = false;
+    std::cout << "Global policies:" << std::endl;
+    if (omaha_settings->has_install_default()) {
+      std::cout << "  InstallDefault: "
+                << InstallValueAsString(omaha_settings->install_default())
+                << "(" << omaha_settings->install_default() << ")" << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_update_default()) {
+      std::cout << "  UpdateDefault: "
+                << UpdateValueAsString(omaha_settings->update_default()) << "("
+                << omaha_settings->update_default() << ")" << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_auto_update_check_period_minutes()) {
+      std::cout << "  Auto-update check period minutes: "
+                << omaha_settings->auto_update_check_period_minutes()
+                << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_updates_suppressed()) {
+      std::cout << "  Update suppressed: " << std::endl
+                << "      Start Hour: "
+                << omaha_settings->updates_suppressed().start_hour()
+                << std::endl
+                << "      Start Minute: "
+                << omaha_settings->updates_suppressed().start_minute()
+                << std::endl
+                << "      Durantion Minute: "
+                << omaha_settings->updates_suppressed().duration_min()
+                << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_proxy_mode()) {
+      std::cout << "  Proxy Mode: " << omaha_settings->proxy_mode()
+                << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_proxy_pac_url()) {
+      std::cout << "  Proxy PacURL: " << omaha_settings->proxy_pac_url()
+                << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_proxy_server()) {
+      std::cout << "  Proxy Server: " << omaha_settings->proxy_server()
+                << std::endl;
+      has_global_policy = true;
+    }
+    if (omaha_settings->has_download_preference()) {
+      std::cout << "  DownloadPreference: "
+                << omaha_settings->download_preference() << std::endl;
+      has_global_policy = true;
+    }
+    if (!has_global_policy) {
+      std::cout << "  (No policy)" << std::endl;
+    }
+
+    for (const auto& app_settings : omaha_settings->application_settings()) {
+      bool has_policy = false;
+      if (app_settings.has_app_guid()) {
+        std::cout << "App : " << app_settings.app_guid();
+        if (app_settings.has_bundle_identifier()) {
+          std::cout << "(" << app_settings.bundle_identifier() << ")";
+        }
+        std::cout << std::endl;
+      }
+      if (app_settings.has_install()) {
+        std::cout << "  Install : "
+                  << InstallValueAsString(app_settings.install()) << "("
+                  << app_settings.install() << ")" << std::endl;
+        has_policy = true;
+      }
+      if (app_settings.has_update()) {
+        std::cout << "  Update : " << UpdateValueAsString(app_settings.update())
+                  << "(" << app_settings.update() << ")" << std::endl;
+        has_policy = true;
+      }
+      if (app_settings.has_rollback_to_target_version()) {
+        std::cout << "  RollbackToTargetVersionAllowed : "
+                  << app_settings.rollback_to_target_version() << std::endl;
+        has_policy = true;
+      }
+      if (app_settings.has_target_version_prefix()) {
+        std::cout << "  TargetVersionPrefix : "
+                  << app_settings.target_version_prefix() << std::endl;
+        has_policy = true;
+      }
+      if (app_settings.has_target_channel()) {
+        std::cout << "  TargetChannel : " << app_settings.target_channel()
+                  << std::endl;
+        has_policy = true;
+      }
+      if (app_settings.has_gcpw_application_settings()) {
+        std::cout << "  DomainsAllowedToLogin: ";
+        for (const auto& domain : app_settings.gcpw_application_settings()
+                                      .domains_allowed_to_login()) {
+          std::cout << domain << ", ";
+          has_policy = true;
+        }
+        std::cout << std::endl;
+      }
+      if (!has_policy) {
+        std::cout << "  (No policy)" << std::endl;
+      }
+    }
+  }
+  std::cout << "-------------------------------------------------" << std::endl;
+  base::FileEnumerator e(storage->policy_cache_folder(), false,
+                         base::FileEnumerator::DIRECTORIES);
+  std::cout << "Downloaded policy types:" << std::endl;
+  for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) {
+    std::string policy_type;
+    if (base::Base64Decode(name.BaseName().MaybeAsASCII(), &policy_type)) {
+      std::cout << "  " << policy_type << std::endl;
+    }
+  }
+  std::cout << std::endl;
+}
+
+}  // namespace
+}  // namespace updater
+
+int main(int argc, char* argv[]) {
+  updater::PrintPolicies();
+}
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc
index a57f09e7..469372fe 100644
--- a/chrome/updater/win/setup/setup_util.cc
+++ b/chrome/updater/win/setup/setup_util.cc
@@ -520,9 +520,7 @@
   if (!task_scheduler->RegisterTask(
           task_name.c_str(), GetTaskDisplayName(scope_).c_str(), run_command_,
           TaskScheduler::TriggerType::TRIGGER_TYPE_HOURLY |
-              (IsSystemInstall(scope_)
-                   ? TaskScheduler::TriggerType::TRIGGER_TYPE_LOGON
-                   : 0),
+              TaskScheduler::TriggerType::TRIGGER_TYPE_LOGON,
           true)) {
     return false;
   }
diff --git a/chrome/updater/win/task_scheduler.cc b/chrome/updater/win/task_scheduler.cc
index c53de0be..468566f 100644
--- a/chrome/updater/win/task_scheduler.cc
+++ b/chrome/updater/win/task_scheduler.cc
@@ -637,6 +637,14 @@
                       << hr;
           return false;
         }
+
+        if (!is_system) {
+          hr = logon_trigger->put_UserId(user_name.Get());
+          if (FAILED(hr)) {
+            PLOG(ERROR) << "Can't put 'UserId'. " << std::hex << hr;
+            return false;
+          }
+        }
       }
     }
 
diff --git a/chrome/updater/win/task_scheduler.h b/chrome/updater/win/task_scheduler.h
index 55201c4..c43d734 100644
--- a/chrome/updater/win/task_scheduler.h
+++ b/chrome/updater/win/task_scheduler.h
@@ -33,10 +33,19 @@
   // The types of trigger to register for this task. Multiple triggers types can
   // be combined using the bitwise OR operator.
   enum TriggerType {
-    TRIGGER_TYPE_LOGON = 1 << 0,   // Run when any user logs on.
-    TRIGGER_TYPE_NOW = 1 << 1,     // Run right now (mainly for tests).
-    TRIGGER_TYPE_HOURLY = 1 << 2,  // Run every hour.
+    // Run when the current user logs on (for user installs). Or when any user
+    // logs on (for system installs).
+    TRIGGER_TYPE_LOGON = 1 << 0,
+
+    // Run right now (mainly for tests).
+    TRIGGER_TYPE_NOW = 1 << 1,
+
+    // Run every hour.
+    TRIGGER_TYPE_HOURLY = 1 << 2,
+
+    // Run every five hours.
     TRIGGER_TYPE_EVERY_FIVE_HOURS = 1 << 3,
+
     TRIGGER_TYPE_MAX = 1 << 4,
   };
 
diff --git a/chrome/updater/win/task_scheduler_unittest.cc b/chrome/updater/win/task_scheduler_unittest.cc
index 1644131..1be25d9 100644
--- a/chrome/updater/win/task_scheduler_unittest.cc
+++ b/chrome/updater/win/task_scheduler_unittest.cc
@@ -462,18 +462,12 @@
            TaskScheduler::TRIGGER_TYPE_HOURLY,
            TaskScheduler::TRIGGER_TYPE_EVERY_FIVE_HOURS,
        }) {
-    if (expected_trigger_type == TaskScheduler::TRIGGER_TYPE_LOGON &&
-        !::IsUserAnAdmin()) {
-      continue;
-    }
-
     RunGetTaskInfoTriggerTypesTest(expected_trigger_type);
   }
 
-  RunGetTaskInfoTriggerTypesTest(
-      (::IsUserAnAdmin() ? TaskScheduler::TRIGGER_TYPE_LOGON : 0) |
-      TaskScheduler::TRIGGER_TYPE_HOURLY |
-      TaskScheduler::TRIGGER_TYPE_EVERY_FIVE_HOURS);
+  RunGetTaskInfoTriggerTypesTest(TaskScheduler::TRIGGER_TYPE_LOGON |
+                                 TaskScheduler::TRIGGER_TYPE_HOURLY |
+                                 TaskScheduler::TRIGGER_TYPE_EVERY_FIVE_HOURS);
 }
 
 TEST(TaskSchedulerTest, NoSubfolders) {
diff --git a/chromecast/media/cma/backend/proxy/OWNERS b/chromecast/media/cma/backend/proxy/OWNERS
index 0ea3949..e69de29 100644
--- a/chromecast/media/cma/backend/proxy/OWNERS
+++ b/chromecast/media/cma/backend/proxy/OWNERS
@@ -1 +0,0 @@
-rwkeane@google.com
diff --git a/chromeos/ash/components/dbus/concierge/concierge_client.cc b/chromeos/ash/components/dbus/concierge/concierge_client.cc
index 8f21db3e..26ec8056 100644
--- a/chromeos/ash/components/dbus/concierge/concierge_client.cc
+++ b/chromeos/ash/components/dbus/concierge/concierge_client.cc
@@ -295,6 +295,14 @@
                      std::move(callback));
   }
 
+  void AggressiveBalloon(
+      const vm_tools::concierge::AggressiveBalloonRequest& request,
+      chromeos::DBusMethodCallback<
+          vm_tools::concierge::AggressiveBalloonResponse> callback) override {
+    CallMethod(concierge::kAggressiveBalloonMethod, request,
+               std::move(callback));
+  }
+
   void Init(dbus::Bus* bus) override {
     concierge_proxy_ = bus->GetObjectProxy(
         concierge::kVmConciergeServiceName,
diff --git a/chromeos/ash/components/dbus/concierge/concierge_client.h b/chromeos/ash/components/dbus/concierge/concierge_client.h
index 98063063..1d8ddf02 100644
--- a/chromeos/ash/components/dbus/concierge/concierge_client.h
+++ b/chromeos/ash/components/dbus/concierge/concierge_client.h
@@ -299,6 +299,13 @@
       chromeos::DBusMethodCallback<vm_tools::concierge::InstallPflashResponse>
           callback) = 0;
 
+  // Enables or disables aggressive balloon.
+  // |callback| is called after the method call finishes.
+  virtual void AggressiveBalloon(
+      const vm_tools::concierge::AggressiveBalloonRequest& request,
+      chromeos::DBusMethodCallback<
+          vm_tools::concierge::AggressiveBalloonResponse> callback) = 0;
+
   // Creates and initializes the global instance. |bus| must not be null.
   static void Initialize(dbus::Bus* bus);
 
diff --git a/chromeos/ash/components/dbus/concierge/fake_concierge_client.cc b/chromeos/ash/components/dbus/concierge/fake_concierge_client.cc
index 7236fc2..2fff8d1 100644
--- a/chromeos/ash/components/dbus/concierge/fake_concierge_client.cc
+++ b/chromeos/ash/components/dbus/concierge/fake_concierge_client.cc
@@ -8,6 +8,7 @@
 
 #include "base/check_op.h"
 #include "base/functional/bind.h"
+#include "base/location.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h"
 
@@ -412,6 +413,15 @@
       FROM_HERE, base::BindOnce(std::move(callback), install_pflash_response_));
 }
 
+void FakeConciergeClient::AggressiveBalloon(
+    const vm_tools::concierge::AggressiveBalloonRequest& request,
+    chromeos::DBusMethodCallback<vm_tools::concierge::AggressiveBalloonResponse>
+        callback) {
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), aggressive_balloon_response_));
+}
+
 void FakeConciergeClient::NotifyVmStarted(
     const vm_tools::concierge::VmStartedSignal& signal) {
   // Now GetVmInfo can return success.
diff --git a/chromeos/ash/components/dbus/concierge/fake_concierge_client.h b/chromeos/ash/components/dbus/concierge/fake_concierge_client.h
index 04770f0..4668b16 100644
--- a/chromeos/ash/components/dbus/concierge/fake_concierge_client.h
+++ b/chromeos/ash/components/dbus/concierge/fake_concierge_client.h
@@ -161,6 +161,11 @@
       chromeos::DBusMethodCallback<vm_tools::concierge::InstallPflashResponse>
           callback) override;
 
+  void AggressiveBalloon(
+      const vm_tools::concierge::AggressiveBalloonRequest& request,
+      chromeos::DBusMethodCallback<
+          vm_tools::concierge::AggressiveBalloonResponse> callback) override;
+
   const base::ObserverList<Observer>& observer_list() const {
     return observer_list_;
   }
@@ -331,6 +336,11 @@
           install_pflash_response) {
     install_pflash_response_ = install_pflash_response;
   }
+  void set_aggressive_balloon_response(
+      absl::optional<vm_tools::concierge::AggressiveBalloonResponse>
+          aggressive_balloon_response) {
+    aggressive_balloon_response_ = aggressive_balloon_response;
+  }
 
   void set_send_create_disk_image_response_delay(base::TimeDelta delay) {
     send_create_disk_image_response_delay_ = delay;
@@ -437,6 +447,8 @@
   absl::optional<vm_tools::concierge::SwapVmResponse> swap_vm_response_;
   absl::optional<vm_tools::concierge::InstallPflashResponse>
       install_pflash_response_;
+  absl::optional<vm_tools::concierge::AggressiveBalloonResponse>
+      aggressive_balloon_response_;
 
   base::TimeDelta send_create_disk_image_response_delay_;
   base::TimeDelta send_start_vm_response_delay_;
diff --git a/chromeos/ash/components/dbus/swap_management/BUILD.gn b/chromeos/ash/components/dbus/swap_management/BUILD.gn
new file mode 100644
index 0000000..15bc577
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos/ash")
+
+component("swap_management") {
+  defines = [ "IS_SWAP_MANAGEMENT_IMPL" ]
+
+  deps = [
+    "//base",
+    "//chromeos/dbus/common",
+    "//dbus",
+  ]
+
+  sources = [
+    "fake_swap_management_client.cc",
+    "fake_swap_management_client.h",
+    "swap_management_client.cc",
+    "swap_management_client.h",
+  ]
+}
diff --git a/chromeos/ash/components/dbus/swap_management/OWNERS b/chromeos/ash/components/dbus/swap_management/OWNERS
new file mode 100644
index 0000000..bcb34fc
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/OWNERS
@@ -0,0 +1,5 @@
+# Primary Owners
+ctshao@google.com
+
+# Backup OWNERS
+bgeffon@chromium.org
diff --git a/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.cc b/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.cc
new file mode 100644
index 0000000..80d8c02
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.cc
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/dbus/swap_management/fake_swap_management_client.h"
+
+namespace {}  // namespace
+
+namespace ash {
+
+FakeSwapManagementClient::FakeSwapManagementClient() = default;
+
+FakeSwapManagementClient::~FakeSwapManagementClient() = default;
+
+void FakeSwapManagementClient::Init(dbus::Bus* bus) {}
+
+void FakeSwapManagementClient::SwapZramEnableWriteback(
+    uint32_t size,
+    chromeos::VoidDBusMethodCallback callback) {
+  std::move(callback).Run(true);
+}
+
+}  // namespace ash
diff --git a/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.h b/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.h
new file mode 100644
index 0000000..81fb199c
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/fake_swap_management_client.h
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_FAKE_SWAP_MANAGEMENT_CLIENT_H_
+#define CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_FAKE_SWAP_MANAGEMENT_CLIENT_H_
+
+#include "chromeos/ash/components/dbus/swap_management/swap_management_client.h"
+
+namespace ash {
+
+// The SwapManagementClient implementation used on Linux desktop,
+// which does nothing.
+class COMPONENT_EXPORT(SWAP_MANAGEMENT) FakeSwapManagementClient
+    : public SwapManagementClient {
+ public:
+  FakeSwapManagementClient();
+
+  FakeSwapManagementClient(const FakeSwapManagementClient&) = delete;
+  FakeSwapManagementClient& operator=(const FakeSwapManagementClient&) = delete;
+
+  ~FakeSwapManagementClient() override;
+
+  void Init(dbus::Bus* bus) override;
+
+  void SwapZramEnableWriteback(
+      uint32_t size,
+      chromeos::VoidDBusMethodCallback callback) override;
+};
+
+}  // namespace ash
+
+#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_FAKE_SWAP_MANAGEMENT_CLIENT_H_
diff --git a/chromeos/ash/components/dbus/swap_management/swap_management_client.cc b/chromeos/ash/components/dbus/swap_management/swap_management_client.cc
new file mode 100644
index 0000000..148d7f038
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/swap_management_client.cc
@@ -0,0 +1,91 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/dbus/swap_management/swap_management_client.h"
+
+#include "chromeos/ash/components/dbus/swap_management/fake_swap_management_client.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+
+namespace ash {
+
+namespace {
+
+SwapManagementClient* g_instance = nullptr;
+
+// The SwapManagementClient implementation used in production.
+class SwapManagementClientImpl : public SwapManagementClient {
+ public:
+  SwapManagementClientImpl() = default;
+
+  SwapManagementClientImpl(const SwapManagementClientImpl&) = delete;
+  SwapManagementClientImpl& operator=(const SwapManagementClientImpl&) = delete;
+
+  ~SwapManagementClientImpl() override = default;
+
+  void Init(dbus::Bus* bus) override {
+    swap_management_proxy_ = bus->GetObjectProxy(
+        swap_management::kSwapManagementServiceName,
+        dbus::ObjectPath(swap_management::kSwapManagementServicePath));
+  }
+
+  void SwapZramEnableWriteback(
+      uint32_t size,
+      chromeos::VoidDBusMethodCallback callback) override {
+    dbus::MethodCall method_call(swap_management::kSwapManagementInterface,
+                                 swap_management::kSwapZramEnableWriteback);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendUint32(size);
+    swap_management_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&SwapManagementClientImpl::OnResponse,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+ private:
+  void OnResponse(chromeos::VoidDBusMethodCallback callback,
+                  dbus::Response* response) {
+    std::move(callback).Run(response != nullptr);
+  }
+
+  dbus::ObjectProxy* swap_management_proxy_ = nullptr;
+  base::WeakPtrFactory<SwapManagementClientImpl> weak_ptr_factory_{this};
+};
+
+}  // namespace
+
+// static
+SwapManagementClient* SwapManagementClient::Get() {
+  return g_instance;
+}
+
+// static
+void SwapManagementClient::Initialize(dbus::Bus* bus) {
+  CHECK(bus);
+  CHECK(!g_instance);
+  g_instance = new SwapManagementClientImpl();
+  g_instance->Init(bus);
+}
+
+// static
+void SwapManagementClient::InitializeFake() {
+  CHECK(!g_instance);
+  g_instance = new FakeSwapManagementClient();
+  g_instance->Init(nullptr);
+}
+
+// static
+void SwapManagementClient::Shutdown() {
+  CHECK(g_instance);
+  delete g_instance;
+  g_instance = nullptr;
+}
+
+SwapManagementClient::SwapManagementClient() = default;
+
+SwapManagementClient::~SwapManagementClient() = default;
+
+}  // namespace ash
diff --git a/chromeos/ash/components/dbus/swap_management/swap_management_client.h b/chromeos/ash/components/dbus/swap_management/swap_management_client.h
new file mode 100644
index 0000000..ea4b013
--- /dev/null
+++ b/chromeos/ash/components/dbus/swap_management/swap_management_client.h
@@ -0,0 +1,48 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_SWAP_MANAGEMENT_CLIENT_H_
+#define CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_SWAP_MANAGEMENT_CLIENT_H_
+
+#include "chromeos/dbus/common/dbus_client.h"
+#include "chromeos/dbus/common/dbus_method_call_status.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace ash {
+
+// SwapManagementClient is used to communicate with the swap_management.
+class COMPONENT_EXPORT(SWAP_MANAGEMENT) SwapManagementClient
+    : public chromeos::DBusClient {
+ public:
+  // Returns the global instance if initialized. May return null.
+  static SwapManagementClient* Get();
+
+  // Creates and initializes the global instance. |bus| must not be null.
+  static void Initialize(dbus::Bus* bus);
+
+  // Creates and initializes a fake global instance.
+  static void InitializeFake();
+
+  // Destroys the global instance if it has been initialized.
+  static void Shutdown();
+
+  SwapManagementClient(const SwapManagementClient&) = delete;
+  SwapManagementClient& operator=(const SwapManagementClient&) = delete;
+
+  ~SwapManagementClient() override;
+
+  // Send dbus message to swap_management for enabling zram writeback, targeted
+  // on |size| MiB.
+  virtual void SwapZramEnableWriteback(
+      uint32_t size,
+      chromeos::VoidDBusMethodCallback callback) = 0;
+
+ protected:
+  // Initialize() should be used instead.
+  SwapManagementClient();
+};
+
+}  // namespace ash
+
+#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_SWAP_MANAGEMENT_SWAP_MANAGEMENT_CLIENT_H_
diff --git a/chromeos/ash/components/language/language_packs/BUILD.gn b/chromeos/ash/components/language/language_packs/BUILD.gn
index 8498d6f..8c1763fca 100644
--- a/chromeos/ash/components/language/language_packs/BUILD.gn
+++ b/chromeos/ash/components/language/language_packs/BUILD.gn
@@ -12,6 +12,8 @@
     "language_pack_manager.h",
     "language_packs_impl.cc",
     "language_packs_impl.h",
+    "language_packs_util.cc",
+    "language_packs_util.h",
   ]
   deps = [
     "//base",
@@ -25,6 +27,7 @@
   testonly = true
   sources = [
     "language_pack_manager_unittest.cc",
+    "language_packs_util_unittest.cc",
     "metrics_unittest.cc",
   ]
   deps = [
diff --git a/chromeos/ash/components/language/language_packs/language_pack_manager.cc b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
index b2e250e..b1ec5d0 100644
--- a/chromeos/ash/components/language/language_packs/language_pack_manager.cc
+++ b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
@@ -15,6 +15,7 @@
 #include "base/no_destructor.h"
 #include "chromeos/ash/components/dbus/dlcservice/dlcservice.pb.h"
 #include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
+#include "chromeos/ash/components/language/language_packs/language_packs_util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
 
@@ -147,100 +148,6 @@
   return *all_dlc_ids;
 }
 
-// This function returns the enum value of a feature ID that matches the
-// corresponding value in the UMA Histogram enum.
-FeatureIdsEnum GetFeatureIdValueForUma(const std::string& feature_id) {
-  if (feature_id == kHandwritingFeatureId) {
-    return FeatureIdsEnum::kHandwriting;
-  }
-  if (feature_id == kTtsFeatureId) {
-    return FeatureIdsEnum::kTts;
-  }
-
-  // Default value of unknown.
-  return FeatureIdsEnum::kUnknown;
-}
-
-// This function returns the enum value of a success or failure for a given
-// Feature ID. These values match the corresponding UMA histogram enum
-// "LanguagePackFeatureSuccess".
-FeatureSuccessEnum GetSuccessValueForUma(const std::string& feature_id,
-                                         const bool success) {
-  if (feature_id == kHandwritingFeatureId) {
-    if (success) {
-      return FeatureSuccessEnum::kHandwritingSuccess;
-    } else {
-      return FeatureSuccessEnum::kHandwritingFailure;
-    }
-  }
-  if (feature_id == kTtsFeatureId) {
-    if (success) {
-      return FeatureSuccessEnum::kTtsSuccess;
-    } else {
-      return FeatureSuccessEnum::kTtsFailure;
-    }
-  }
-
-  // Default value of unknown.
-  if (success) {
-    return FeatureSuccessEnum::kUnknownSuccess;
-  } else {
-    return FeatureSuccessEnum::kUnknownFailure;
-  }
-}
-
-DlcErrorTypeEnum GetDlcErrorTypeForUma(const std::string& error_str) {
-  if (error_str == dlcservice::kErrorNone) {
-    return DlcErrorTypeEnum::kErrorNone;
-  } else if (error_str == dlcservice::kErrorInternal) {
-    return DlcErrorTypeEnum::kErrorInternal;
-  } else if (error_str == dlcservice::kErrorBusy) {
-    return DlcErrorTypeEnum::kErrorBusy;
-  } else if (error_str == dlcservice::kErrorNeedReboot) {
-    return DlcErrorTypeEnum::kErrorNeedReboot;
-  } else if (error_str == dlcservice::kErrorInvalidDlc) {
-    return DlcErrorTypeEnum::kErrorInvalidDlc;
-  } else if (error_str == dlcservice::kErrorAllocation) {
-    return DlcErrorTypeEnum::kErrorAllocation;
-  } else if (error_str == dlcservice::kErrorNoImageFound) {
-    return DlcErrorTypeEnum::kErrorNoImageFound;
-  }
-
-  // Return unknown if we can't recognize the error.
-  LOG(ERROR) << "Wrong error message received from DLC Service";
-  return DlcErrorTypeEnum::kErrorUnknown;
-}
-
-// PackResult that is returned by an invalid feature ID is specified.
-PackResult CreateInvalidDlcPackResult() {
-  return {
-      .operation_error = dlcservice::kErrorInvalidDlc,
-      .pack_state = PackResult::WRONG_ID,
-  };
-}
-
-PackResult ConvertDlcStateToPackResult(const dlcservice::DlcState& dlc_state) {
-  PackResult result;
-
-  switch (dlc_state.state()) {
-    case dlcservice::DlcState_State_INSTALLED:
-      result.pack_state = PackResult::INSTALLED;
-      result.path = dlc_state.root_path();
-      break;
-    case dlcservice::DlcState_State_INSTALLING:
-      result.pack_state = PackResult::IN_PROGRESS;
-      break;
-    case dlcservice::DlcState_State_NOT_INSTALLED:
-      result.pack_state = PackResult::NOT_INSTALLED;
-      break;
-    default:
-      result.pack_state = PackResult::UNKNOWN;
-      break;
-  }
-
-  return result;
-}
-
 // Finds the ID of the DLC corresponding to the given spec.
 // Returns the DLC ID if the DLC exists or absl::nullopt otherwise.
 absl::optional<std::string> GetDlcIdForLanguagePack(
diff --git a/chromeos/ash/components/language/language_packs/language_packs_util.cc b/chromeos/ash/components/language/language_packs/language_packs_util.cc
new file mode 100644
index 0000000..c114ae0
--- /dev/null
+++ b/chromeos/ash/components/language/language_packs/language_packs_util.cc
@@ -0,0 +1,100 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/language/language_packs/language_packs_util.h"
+
+#include "base/logging.h"
+#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
+
+namespace ash::language_packs {
+
+FeatureIdsEnum GetFeatureIdValueForUma(const std::string& feature_id) {
+  if (feature_id == kHandwritingFeatureId) {
+    return FeatureIdsEnum::kHandwriting;
+  }
+  if (feature_id == kTtsFeatureId) {
+    return FeatureIdsEnum::kTts;
+  }
+
+  // Default value of unknown.
+  return FeatureIdsEnum::kUnknown;
+}
+
+FeatureSuccessEnum GetSuccessValueForUma(const std::string& feature_id,
+                                         const bool success) {
+  if (feature_id == kHandwritingFeatureId) {
+    if (success) {
+      return FeatureSuccessEnum::kHandwritingSuccess;
+    } else {
+      return FeatureSuccessEnum::kHandwritingFailure;
+    }
+  }
+  if (feature_id == kTtsFeatureId) {
+    if (success) {
+      return FeatureSuccessEnum::kTtsSuccess;
+    } else {
+      return FeatureSuccessEnum::kTtsFailure;
+    }
+  }
+
+  // Default value of unknown.
+  if (success) {
+    return FeatureSuccessEnum::kUnknownSuccess;
+  } else {
+    return FeatureSuccessEnum::kUnknownFailure;
+  }
+}
+
+DlcErrorTypeEnum GetDlcErrorTypeForUma(const std::string& error_str) {
+  if (error_str == dlcservice::kErrorNone) {
+    return DlcErrorTypeEnum::kErrorNone;
+  } else if (error_str == dlcservice::kErrorInternal) {
+    return DlcErrorTypeEnum::kErrorInternal;
+  } else if (error_str == dlcservice::kErrorBusy) {
+    return DlcErrorTypeEnum::kErrorBusy;
+  } else if (error_str == dlcservice::kErrorNeedReboot) {
+    return DlcErrorTypeEnum::kErrorNeedReboot;
+  } else if (error_str == dlcservice::kErrorInvalidDlc) {
+    return DlcErrorTypeEnum::kErrorInvalidDlc;
+  } else if (error_str == dlcservice::kErrorAllocation) {
+    return DlcErrorTypeEnum::kErrorAllocation;
+  } else if (error_str == dlcservice::kErrorNoImageFound) {
+    return DlcErrorTypeEnum::kErrorNoImageFound;
+  }
+
+  // Return unknown if we can't recognize the error.
+  LOG(ERROR) << "Wrong error message received from DLC Service";
+  return DlcErrorTypeEnum::kErrorUnknown;
+}
+
+PackResult CreateInvalidDlcPackResult() {
+  return {
+      .operation_error = dlcservice::kErrorInvalidDlc,
+      .pack_state = PackResult::WRONG_ID,
+  };
+}
+
+PackResult ConvertDlcStateToPackResult(const dlcservice::DlcState& dlc_state) {
+  PackResult result;
+
+  switch (dlc_state.state()) {
+    case dlcservice::DlcState_State_INSTALLED:
+      result.pack_state = PackResult::INSTALLED;
+      result.path = dlc_state.root_path();
+      break;
+    case dlcservice::DlcState_State_INSTALLING:
+      result.pack_state = PackResult::IN_PROGRESS;
+      break;
+    case dlcservice::DlcState_State_NOT_INSTALLED:
+      result.pack_state = PackResult::NOT_INSTALLED;
+      break;
+    default:
+      result.pack_state = PackResult::UNKNOWN;
+      break;
+  }
+
+  return result;
+}
+
+}  // namespace ash::language_packs
diff --git a/chromeos/ash/components/language/language_packs/language_packs_util.h b/chromeos/ash/components/language/language_packs/language_packs_util.h
new file mode 100644
index 0000000..dfb5bce6
--- /dev/null
+++ b/chromeos/ash/components/language/language_packs/language_packs_util.h
@@ -0,0 +1,36 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_UTIL_H_
+#define CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_UTIL_H_
+
+#include <string>
+
+#include "chromeos/ash/components/dbus/dlcservice/dlcservice.pb.h"
+#include "chromeos/ash/components/language/language_packs/language_pack_manager.h"
+
+namespace ash::language_packs {
+
+// Returns the enum value of a feature ID that matches the corresponding value
+// in the UMA Histogram enum.
+FeatureIdsEnum GetFeatureIdValueForUma(const std::string& feature_id);
+
+// Returns the enum value of a success or failure for a given Feature ID.
+// These values match the corresponding UMA histogram enum
+// "LanguagePackFeatureSuccess".
+FeatureSuccessEnum GetSuccessValueForUma(const std::string& feature_id,
+                                         const bool success);
+
+// Returns the enum value of a error type received from DLC Service.
+DlcErrorTypeEnum GetDlcErrorTypeForUma(const std::string& error_str);
+
+// PackResult that is returned by an invalid feature ID is specified.
+PackResult CreateInvalidDlcPackResult();
+
+// Converts the state defined by the DLC Service into our own PackResult proto.
+PackResult ConvertDlcStateToPackResult(const dlcservice::DlcState& dlc_state);
+
+}  // namespace ash::language_packs
+
+#endif  // CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_UTIL_H_
diff --git a/chromeos/ash/components/language/language_packs/language_packs_util_unittest.cc b/chromeos/ash/components/language/language_packs/language_packs_util_unittest.cc
new file mode 100644
index 0000000..bc46daf
--- /dev/null
+++ b/chromeos/ash/components/language/language_packs/language_packs_util_unittest.cc
@@ -0,0 +1,74 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/language/language_packs/language_packs_util.h"
+
+#include "chromeos/ash/components/language/language_packs/language_pack_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
+
+namespace ash::language_packs {
+
+TEST(LanguagePacksUtil, ConvertDlcState_EmptyInput) {
+  dlcservice::DlcState input;
+  PackResult output = ConvertDlcStateToPackResult(input);
+
+  // The default value in the input is 'NOT_INSTALLED'.
+  EXPECT_EQ(output.pack_state, PackResult::NOT_INSTALLED);
+}
+
+TEST(LanguagePacksUtil, ConvertDlcState_NotInstalled) {
+  dlcservice::DlcState input;
+  input.set_state(dlcservice::DlcState_State_NOT_INSTALLED);
+  PackResult output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::NOT_INSTALLED);
+
+  // Even if the path is set (by mistake) in the input, we should not return it.
+  input.set_root_path("/var/somepath");
+  output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::NOT_INSTALLED);
+  EXPECT_TRUE(output.path.empty());
+}
+
+TEST(LanguagePacksUtil, ConvertDlcState_Installing) {
+  dlcservice::DlcState input;
+  input.set_state(dlcservice::DlcState_State_INSTALLING);
+  PackResult output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::IN_PROGRESS);
+
+  // Even if the path is set (by mistake) in the input, we should not return it.
+  input.set_root_path("/var/somepath");
+  output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::IN_PROGRESS);
+  EXPECT_TRUE(output.path.empty());
+}
+
+TEST(LanguagePacksUtil, ConvertDlcState_Installed) {
+  dlcservice::DlcState input;
+  input.set_state(dlcservice::DlcState_State_INSTALLED);
+  input.set_root_path("/var/somepath");
+  PackResult output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::INSTALLED);
+  EXPECT_EQ(output.path, "/var/somepath");
+}
+
+// Tests the behaviour in case the state received from the input in not a valid
+// value. This could happen for example if the proto changes without notice.
+TEST(LanguagePacksUtil, ConvertDlcState_MalformedProto) {
+  dlcservice::DlcState input;
+  // Enum value '3' is beyond currently defined values.
+  input.set_state(static_cast<dlcservice::DlcState_State>(3));
+  input.set_root_path("/var/somepath");
+  PackResult output = ConvertDlcStateToPackResult(input);
+
+  EXPECT_EQ(output.pack_state, PackResult::UNKNOWN);
+  EXPECT_TRUE(output.path.empty());
+}
+
+}  // namespace ash::language_packs
diff --git a/chromeos/ash/components/memory/BUILD.gn b/chromeos/ash/components/memory/BUILD.gn
index 2533ae9f0..d4c19d71 100644
--- a/chromeos/ash/components/memory/BUILD.gn
+++ b/chromeos/ash/components/memory/BUILD.gn
@@ -15,6 +15,7 @@
     "//chromeos/ash/components/dbus",
     "//chromeos/ash/components/dbus/debug_daemon",
     "//chromeos/ash/components/dbus/resourced:resourced",
+    "//chromeos/ash/components/dbus/swap_management",
     "//chromeos/dbus/constants",
     "//components/memory_pressure",
     "//crypto",
diff --git a/chromeos/ash/components/memory/DEPS b/chromeos/ash/components/memory/DEPS
index 095cf1c..f5a7000 100644
--- a/chromeos/ash/components/memory/DEPS
+++ b/chromeos/ash/components/memory/DEPS
@@ -5,6 +5,7 @@
   "+services/resource_coordinator",
   "+chromeos/ash/components/dbus/debug_daemon",
   "+chromeos/ash/components/dbus/resourced",
+  "+chromeos/ash/components/dbus/swap_management",
   "+components/memory_pressure",
   "+content/public/child",
 ]
diff --git a/chromeos/ash/components/memory/zram_writeback_backend.cc b/chromeos/ash/components/memory/zram_writeback_backend.cc
index 30a49b4..efe28268 100644
--- a/chromeos/ash/components/memory/zram_writeback_backend.cc
+++ b/chromeos/ash/components/memory/zram_writeback_backend.cc
@@ -12,11 +12,14 @@
 #include "base/memory/page_size.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
+#include "chromeos/ash/components/dbus/swap_management/swap_management_client.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/re2/src/re2/re2.h"
 
@@ -24,22 +27,27 @@
 
 namespace {
 
-constexpr char kSavedWritebackSizeFile[] = "/tmp/saved-writeback-size";
 constexpr char kZramDev[] = "/sys/block/zram0";
 constexpr char kZramBackingDevFile[] = "backing_dev";
 constexpr char kZramDiskSize[] = "disksize";
 constexpr char kZramWritebackLimitFile[] = "writeback_limit";
 
-int64_t ReadFileAsInt64(const base::FilePath& path) {
+std::string ReadFileAsString(const base::FilePath& path) {
   std::string str;
   if (!base::ReadFileToStringNonBlocking(path, &str)) {
-    return std::numeric_limits<int64_t>::min();
+    return std::string();
   }
 
   if (!str.empty() && str.back() == '\n') {
     str.resize(str.size() - 1);
   }
 
+  return str;
+}
+
+int64_t ReadFileAsInt64(const base::FilePath& path) {
+  std::string str = ReadFileAsString(path);
+
   int64_t val;
   if (!base::StringToInt64(str, &val)) {
     return std::numeric_limits<int64_t>::min();
@@ -48,19 +56,21 @@
   return val;
 }
 
-void SaveWritebackSize(uint64_t size_mb) {
-  const base::FilePath file_path(kSavedWritebackSizeFile);
-  DCHECK(!base::PathExists(file_path));
-  if (base::WriteFile(file_path, base::NumberToString(size_mb))) {
-    base::SetPosixFilePermissions(
-        file_path, base::FilePermissionBits::FILE_PERMISSION_READ_BY_USER);
-  }
-}
-
 void ReadWritebackSize(int64_t* v) {
   DCHECK(v);
-  const base::FilePath file_path(kSavedWritebackSizeFile);
-  *v = ReadFileAsInt64(file_path);
+  std::string backing_dev =
+      ReadFileAsString(base::FilePath(kZramDev).Append(kZramBackingDevFile));
+  // Since swap_management minijail would be time out and terminated, the read
+  // |backing_dev| could be "/dev/<device_name>" or "/<device_name>". We should
+  // only take the device name after the last slash.
+  backing_dev = base::SplitString(backing_dev, "/", base::TRIM_WHITESPACE,
+                                  base::SPLIT_WANT_NONEMPTY)
+                    .back();
+  base::FilePath size_file =
+      base::FilePath("/sys/class/block").Append(backing_dev).Append("size");
+  // The unit of the content in |size_file| is number of sectors. Convert it to
+  // MiB.
+  *v = ReadFileAsInt64(size_file) * 512 / 1024 / 1024;
 }
 
 // The backend is responsible for the "how" things happens.
@@ -68,52 +78,26 @@
  public:
   ~ZramWritebackBackendImpl() override = default;
 
-  void OnEnableWritebackResponse(IntCallback cb,
-                                 int64_t size_mb,
-                                 absl::optional<std::string> res) {
+  void OnEnableWriteback(IntCallback cb, bool res) {
     if (!res) {
-      // If we did not receive a response, it's likely that debugd is not up
-      // yet. Let's try again in 30 seconds.
-      base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-          FROM_HERE,
-          base::BindOnce(&ZramWritebackBackendImpl::EnableWriteback,
-                         weak_factory_.GetWeakPtr(), size_mb, std::move(cb)),
-          base::Seconds(30));
+      LOG(ERROR) << "Error enabling zram writeback.";
       return;
     }
 
-    /* let's parse the response */
-    std::string resp = *res;
-    int size;
-    if (RE2::PartialMatch(resp, "SUCCESS: Enabled writeback with size (\\d+)MB",
-                          &size)) {
-      base::ThreadPool::PostTask(FROM_HERE, {base::MayBlock()},
-                                 base::BindOnce(&SaveWritebackSize, size));
-
-      std::move(cb).Run(true, size);
-      return;
-    } else {
-      if (resp.find("ERROR") != std::string::npos) {
-        LOG(ERROR) << "Error configuring zram writeback: " << resp;
-      } else {
-        LOG(WARNING) << "Unexpected response from debugd: " << resp;
-      }
-    }
-
-    std::move(cb).Run(false, 0);
+    // Read actual writeback device size and run callback.
+    GetCurrentBackingDevSize(std::move(cb));
   }
 
-  void EnableWriteback(uint64_t size_mb, IntCallback cb) override {
-    DebugDaemonClient* debugd_client = DebugDaemonClient::Get();
-    CHECK(debugd_client);
+  void EnableWriteback(uint64_t size, IntCallback cb) override {
+    SwapManagementClient* swap_management_client = SwapManagementClient::Get();
+    CHECK(swap_management_client);
 
-    debugd_client->SwapZramEnableWriteback(
-        size_mb,
-        base::BindOnce(&ZramWritebackBackendImpl::OnEnableWritebackResponse,
-                       weak_factory_.GetWeakPtr(), std::move(cb), size_mb));
+    swap_management_client->SwapZramEnableWriteback(
+        size, base::BindOnce(&ZramWritebackBackendImpl::OnEnableWriteback,
+                             weak_factory_.GetWeakPtr(), std::move(cb)));
   }
 
-  void OnMarkIdle(Callback cb, absl::optional<std::string> resp) {
+  void OnMarkIdle(BoolCallback cb, absl::optional<std::string> resp) {
     if (!resp) {
       std::move(cb).Run(false);
       return;
@@ -128,7 +112,7 @@
     std::move(cb).Run(true);
   }
 
-  void MarkIdle(base::TimeDelta age, Callback cb) override {
+  void MarkIdle(base::TimeDelta age, BoolCallback cb) override {
     DebugDaemonClient* debugd_client = DebugDaemonClient::Get();
     CHECK(debugd_client);
 
@@ -146,7 +130,7 @@
     return ReadFileAsInt64(kZramPath.Append(kZramWritebackLimitFile));
   }
 
-  void OnSetWritebackLimitResponse(IntCallback cb,
+  void OnSetWritebackLimitResponse(BoolIntCallback cb,
                                    absl::optional<std::string> resp) {
     if (!resp) {
       std::move(cb).Run(false, 0);
@@ -162,7 +146,7 @@
     std::move(cb).Run(true, GetCurrentWritebackLimitPages());
   }
 
-  void SetWritebackLimit(uint64_t size_pages, IntCallback cb) override {
+  void SetWritebackLimit(uint64_t size_pages, BoolIntCallback cb) override {
     DebugDaemonClient* debugd_client = DebugDaemonClient::Get();
     CHECK(debugd_client);
 
@@ -172,7 +156,7 @@
                        weak_factory_.GetWeakPtr(), std::move(cb)));
   }
 
-  void OnInitiateWritebackResponse(Callback cb,
+  void OnInitiateWritebackResponse(BoolCallback cb,
                                    absl::optional<std::string> resp) {
     if (!resp) {
       std::move(cb).Run(false);
@@ -193,7 +177,7 @@
     std::move(cb).Run(true);
   }
 
-  void InitiateWriteback(ZramWritebackMode mode, Callback cb) override {
+  void InitiateWriteback(ZramWritebackMode mode, BoolCallback cb) override {
     DebugDaemonClient* debugd_client = DebugDaemonClient::Get();
     CHECK(debugd_client);
 
@@ -210,8 +194,9 @@
       const std::string kNone("none");
       // For whatever reason the backing file in zram will tack on a \n, let's
       // remove it.
-      if (!contents.empty() && contents.at(contents.length() - 1) == '\n')
+      if (!contents.empty() && contents.at(contents.length() - 1) == '\n') {
         contents = contents.substr(0, contents.length() - 1);
+      }
       if (contents != kNone) {
         return true;
       }
@@ -227,7 +212,11 @@
         FROM_HERE, {base::MayBlock()}, base::BindOnce(&ReadWritebackSize, val),
         base::BindOnce(
             [](decltype(cb) cb, decltype(val) v) {
-              std::move(cb).Run(*v != std::numeric_limits<int64_t>::min(), *v);
+              if (*v == std::numeric_limits<int64_t>::min()) {
+                LOG(ERROR) << "Unable to read zram writeback device size.";
+              } else {
+                std::move(cb).Run(*v);
+              }
             },
             std::move(cb), base::Owned(val)));
   }
diff --git a/chromeos/ash/components/memory/zram_writeback_backend.h b/chromeos/ash/components/memory/zram_writeback_backend.h
index b0828cb..f6ed467b 100644
--- a/chromeos/ash/components/memory/zram_writeback_backend.h
+++ b/chromeos/ash/components/memory/zram_writeback_backend.h
@@ -28,13 +28,15 @@
  public:
   virtual ~ZramWritebackBackend() = default;
 
-  using IntCallback = base::OnceCallback<void(bool, int64_t)>;
+  using IntCallback = base::OnceCallback<void(int64_t)>;
   virtual void EnableWriteback(uint64_t size_mb, IntCallback cb) = 0;
-  virtual void SetWritebackLimit(uint64_t size_pages, IntCallback cb) = 0;
 
-  using Callback = base::OnceCallback<void(bool)>;
-  virtual void InitiateWriteback(ZramWritebackMode mode, Callback cb) = 0;
-  virtual void MarkIdle(base::TimeDelta age, Callback cb) = 0;
+  using BoolIntCallback = base::OnceCallback<void(bool, int64_t)>;
+  virtual void SetWritebackLimit(uint64_t size_pages, BoolIntCallback cb) = 0;
+
+  using BoolCallback = base::OnceCallback<void(bool)>;
+  virtual void InitiateWriteback(ZramWritebackMode mode, BoolCallback cb) = 0;
+  virtual void MarkIdle(base::TimeDelta age, BoolCallback cb) = 0;
   virtual bool WritebackAlreadyEnabled() = 0;
 
   // If and only if writeback already enabled returns true, then
diff --git a/chromeos/ash/components/memory/zram_writeback_controller.cc b/chromeos/ash/components/memory/zram_writeback_controller.cc
index 649609ab..8f652bc1 100644
--- a/chromeos/ash/components/memory/zram_writeback_controller.cc
+++ b/chromeos/ash/components/memory/zram_writeback_controller.cc
@@ -65,14 +65,9 @@
 
 ZramWritebackController::~ZramWritebackController() = default;
 
-void ZramWritebackController::OnEnableWriteback(bool result, int64_t size_mb) {
-  if (!result) {
-    LOG(ERROR) << "Unable to enable zram writeback";
-    return;
-  }
-
+void ZramWritebackController::OnEnableWriteback(int64_t size) {
   // Finally we can complete the policy initialization.
-  CompleteInitialization(backend_->GetZramDiskSizeBytes() >> 20, size_mb);
+  CompleteInitialization(backend_->GetZramDiskSizeBytes() >> 20, size);
 }
 
 void ZramWritebackController::ResetCurrentlyWritingBack() {
@@ -81,10 +76,9 @@
   current_writeback_limit_ = 0;
 }
 
-void ZramWritebackController::CompleteInitialization(
-    uint64_t zram_size_mb,
-    uint64_t writeback_size_mb) {
-  policy_->Initialize(zram_size_mb, writeback_size_mb);
+void ZramWritebackController::CompleteInitialization(uint64_t zram_size,
+                                                     uint64_t writeback_size) {
+  policy_->Initialize(zram_size, writeback_size);
   timer_.Start(FROM_HERE, policy_->GetWritebackTimerInterval(),
                base::BindRepeating(&ZramWritebackController::PeriodicWriteback,
                                    weak_factory_.GetWeakPtr()));
@@ -134,11 +128,11 @@
 
   // Move on to the next writeback phase.
   if (current_writeback_mode_ == ZramWritebackMode::kModeHugeIdle &&
-      policy_->CanWritebackIdle())
+      policy_->CanWritebackIdle()) {
     current_writeback_mode_ = ZramWritebackMode::kModeIdle;
-  else if ((current_writeback_mode_ == ZramWritebackMode::kModeIdle ||
-            current_writeback_mode_ == ZramWritebackMode::kModeHugeIdle) &&
-           policy_->CanWritebackHuge()) {
+  } else if ((current_writeback_mode_ == ZramWritebackMode::kModeIdle ||
+              current_writeback_mode_ == ZramWritebackMode::kModeHugeIdle) &&
+             policy_->CanWritebackHuge()) {
     current_writeback_mode_ = ZramWritebackMode::kModeHuge;
   } else {
     // We're done.
diff --git a/chromeos/ash/components/memory/zram_writeback_controller.h b/chromeos/ash/components/memory/zram_writeback_controller.h
index 3617dfd4..df89ad04 100644
--- a/chromeos/ash/components/memory/zram_writeback_controller.h
+++ b/chromeos/ash/components/memory/zram_writeback_controller.h
@@ -41,7 +41,7 @@
 
   void PeriodicWriteback();
   void ReadyToWriteback();
-  void OnEnableWriteback(bool result, int64_t writeback_size_mb);
+  void OnEnableWriteback(int64_t writeback_size_mb);
   void OnSetWritebackLimit(bool result, int64_t num_pages);
   void CompleteInitialization(uint64_t zram_size_mb,
                               uint64_t writeback_size_mb);
diff --git a/chromeos/ash/components/memory/zram_writeback_controller_unittest.cc b/chromeos/ash/components/memory/zram_writeback_controller_unittest.cc
index fed3d38..6dddf35 100644
--- a/chromeos/ash/components/memory/zram_writeback_controller_unittest.cc
+++ b/chromeos/ash/components/memory/zram_writeback_controller_unittest.cc
@@ -36,9 +36,11 @@
   ~MockZramWritebackBackend() override = default;
 
   MOCK_METHOD2(EnableWriteback, void(uint64_t size_mb, IntCallback cb));
-  MOCK_METHOD2(SetWritebackLimit, void(uint64_t size_pages, IntCallback cb));
-  MOCK_METHOD2(InitiateWriteback, void(ZramWritebackMode mode, Callback cb));
-  MOCK_METHOD2(MarkIdle, void(base::TimeDelta age, Callback cb));
+  MOCK_METHOD2(SetWritebackLimit,
+               void(uint64_t size_pages, BoolIntCallback cb));
+  MOCK_METHOD2(InitiateWriteback,
+               void(ZramWritebackMode mode, BoolCallback cb));
+  MOCK_METHOD2(MarkIdle, void(base::TimeDelta age, BoolCallback cb));
   MOCK_METHOD0(WritebackAlreadyEnabled, bool());
 
   MOCK_METHOD1(GetCurrentBackingDevSize, void(IntCallback cb));
@@ -94,8 +96,9 @@
   }
 
  protected:
-  using Callback = MockZramWritebackBackend::Callback;
+  using BoolCallback = MockZramWritebackBackend::BoolCallback;
   using IntCallback = MockZramWritebackBackend::IntCallback;
+  using BoolIntCallback = MockZramWritebackBackend::BoolIntCallback;
 
   MockZramWritebackPolicy* policy() { return policy_; }
   MockZramWritebackBackend* backend() { return backend_; }
@@ -119,9 +122,8 @@
   constexpr uint64_t kZramSizeMb = 1000;
   EXPECT_CALL(*backend(), WritebackAlreadyEnabled()).WillOnce(Return(false));
   EXPECT_CALL(*backend(), EnableWriteback(_, _))
-      .WillOnce(Invoke([](uint64_t size, IntCallback cb) {
-        std::move(cb).Run(true, kWbSize);
-      }));
+      .WillOnce(Invoke(
+          [](uint64_t size, IntCallback cb) { std::move(cb).Run(kWbSize); }));
   EXPECT_CALL(*backend(), GetZramDiskSizeBytes())
       .WillRepeatedly(Return(kZramSizeMb << kMbShift));
   EXPECT_CALL(*policy(), Initialize(kZramSizeMb, kWbSize)).Times(1);
@@ -135,8 +137,7 @@
   EXPECT_CALL(*backend(), WritebackAlreadyEnabled()).WillOnce(Return(true));
   EXPECT_CALL(*backend(), EnableWriteback(_, _)).Times(0);
   EXPECT_CALL(*backend(), GetCurrentBackingDevSize(_))
-      .WillOnce(
-          Invoke([](IntCallback cb) { std::move(cb).Run(true, kWbSize); }));
+      .WillOnce(Invoke([](IntCallback cb) { std::move(cb).Run(kWbSize); }));
 
   EXPECT_CALL(*backend(), GetZramDiskSizeBytes())
       .WillRepeatedly(Return(kZramSizeMb << kMbShift));
@@ -159,9 +160,8 @@
     // Do a basic setup with standard values.
     EXPECT_CALL(*backend(), WritebackAlreadyEnabled()).WillOnce(Return(false));
     EXPECT_CALL(*backend(), EnableWriteback(_, _))
-        .WillOnce(Invoke([](uint64_t size, IntCallback cb) {
-          std::move(cb).Run(true, kWbSize);
-        }));
+        .WillOnce(Invoke(
+            [](uint64_t size, IntCallback cb) { std::move(cb).Run(kWbSize); }));
     EXPECT_CALL(*backend(), GetZramDiskSizeBytes())
         .WillRepeatedly(Return(kZramSizeMb << kMbShift));
     EXPECT_CALL(*policy(), Initialize(kZramSizeMb, kWbSize)).Times(1);
@@ -212,8 +212,9 @@
   // backend.
   EXPECT_CALL(*backend(), SetWritebackLimit(_, _))
       .Times(1)
-      .WillRepeatedly(Invoke(
-          [](uint64_t limit, IntCallback cb) { std::move(cb).Run(false, 1); }));
+      .WillRepeatedly(Invoke([](uint64_t limit, BoolIntCallback cb) {
+        std::move(cb).Run(false, 1);
+      }));
   // We invoked the SetWritebackLimit callback with false (failed), so no
   // further methods should be called, we're a strict mock so that's how we
   // confirm this.
@@ -266,7 +267,7 @@
 
   EXPECT_CALL(*backend(), SetWritebackLimit(_, _))
       .Times(times_)
-      .WillRepeatedly(Invoke([](uint64_t limit, IntCallback cb) {
+      .WillRepeatedly(Invoke([](uint64_t limit, BoolIntCallback cb) {
         std::move(cb).Run(true, kPageLimit);
       }));
   EXPECT_CALL(*policy(), CanWritebackIdle()).WillOnce(Return(true));
@@ -282,12 +283,13 @@
 
   // We expect to do an idle sweep of 60s.
   EXPECT_CALL(*backend(), MarkIdle(base::Seconds(60), _))
-      .WillOnce(Invoke(
-          [](base::TimeDelta age, Callback cb) { std::move(cb).Run(true); }));
+      .WillOnce(Invoke([](base::TimeDelta age, BoolCallback cb) {
+        std::move(cb).Run(true);
+      }));
 
   // We expect to now initiate a writeback for idle.
   EXPECT_CALL(*backend(), InitiateWriteback(ZramWritebackMode::kModeIdle, _))
-      .WillOnce(Invoke([](ZramWritebackMode mode, Callback cb) {
+      .WillOnce(Invoke([](ZramWritebackMode mode, BoolCallback cb) {
         std::move(cb).Run(true);
       }));
 
diff --git a/chromeos/ash/components/settings/cros_settings_provider.h b/chromeos/ash/components/settings/cros_settings_provider.h
index 39e0607..559f572d6 100644
--- a/chromeos/ash/components/settings/cros_settings_provider.h
+++ b/chromeos/ash/components/settings/cros_settings_provider.h
@@ -9,6 +9,7 @@
 
 #include "base/component_export.h"
 #include "base/functional/callback.h"
+#include "base/strings/string_piece.h"
 
 namespace base {
 class Value;
@@ -43,7 +44,7 @@
   virtual ~CrosSettingsProvider();
 
   // Gets settings value of given |path| to |out_value|.
-  virtual const base::Value* Get(const std::string& path) const = 0;
+  virtual const base::Value* Get(base::StringPiece path) const = 0;
 
   // Requests the provider to fetch its values from a trusted store, if it
   // hasn't done so yet. Returns TRUSTED if the values returned by this provider
@@ -55,7 +56,7 @@
   virtual TrustedStatus PrepareTrustedValues(base::OnceClosure* callback) = 0;
 
   // Gets the namespace prefix provided by this provider.
-  virtual bool HandlesSetting(const std::string& path) const = 0;
+  virtual bool HandlesSetting(base::StringPiece path) const = 0;
 
   void SetNotifyObserversCallback(const NotifyObserversCallback& notify_cb);
 
diff --git a/chromeos/ash/components/settings/system_settings_provider.cc b/chromeos/ash/components/settings/system_settings_provider.cc
index 63f17a7..253dbc10 100644
--- a/chromeos/ash/components/settings/system_settings_provider.cc
+++ b/chromeos/ash/components/settings/system_settings_provider.cc
@@ -5,7 +5,6 @@
 #include "chromeos/ash/components/settings/system_settings_provider.h"
 
 #include <memory>
-#include <string>
 
 #include "ash/constants/ash_switches.h"
 #include "base/command_line.h"
@@ -60,7 +59,7 @@
       std::make_unique<base::Value>(FineGrainedTimeZoneDetectionEnabled());
 }
 
-const base::Value* SystemSettingsProvider::Get(const std::string& path) const {
+const base::Value* SystemSettingsProvider::Get(base::StringPiece path) const {
   if (path == kSystemTimezone)
     return timezone_value_.get();
 
@@ -79,7 +78,7 @@
   return TRUSTED;
 }
 
-bool SystemSettingsProvider::HandlesSetting(const std::string& path) const {
+bool SystemSettingsProvider::HandlesSetting(base::StringPiece path) const {
   return path == kSystemTimezone || path == kPerUserTimezoneEnabled ||
          path == kFineGrainedTimeZoneResolveEnabled;
 }
diff --git a/chromeos/ash/components/settings/system_settings_provider.h b/chromeos/ash/components/settings/system_settings_provider.h
index 0fa5c12..b694ceb 100644
--- a/chromeos/ash/components/settings/system_settings_provider.h
+++ b/chromeos/ash/components/settings/system_settings_provider.h
@@ -6,10 +6,10 @@
 #define CHROMEOS_ASH_COMPONENTS_SETTINGS_SYSTEM_SETTINGS_PROVIDER_H_
 
 #include <memory>
-#include <string>
 
 #include "base/component_export.h"
 #include "base/functional/callback.h"
+#include "base/strings/string_piece.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
 #include "chromeos/ash/components/settings/timezone_settings.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
@@ -33,9 +33,9 @@
   ~SystemSettingsProvider() override;
 
   // CrosSettingsProvider implementation.
-  const base::Value* Get(const std::string& path) const override;
+  const base::Value* Get(base::StringPiece path) const override;
   TrustedStatus PrepareTrustedValues(base::OnceClosure* callback) override;
-  bool HandlesSetting(const std::string& path) const override;
+  bool HandlesSetting(base::StringPiece path) const override;
 
   // TimezoneSettings::Observer implementation.
   void TimezoneChanged(const icu::TimeZone& timezone) override;
diff --git a/chromeos/ash/services/ime/ime_service_unittest.cc b/chromeos/ash/services/ime/ime_service_unittest.cc
index 1a65f68..f2e36c7 100644
--- a/chromeos/ash/services/ime/ime_service_unittest.cc
+++ b/chromeos/ash/services/ime/ime_service_unittest.cc
@@ -156,7 +156,8 @@
   void RequestSuggestions(mojom::SuggestionsRequestPtr request,
                           RequestSuggestionsCallback callback) override {}
   void DisplaySuggestions(
-      const std::vector<AssistiveSuggestion>& suggestions) override {}
+      const std::vector<AssistiveSuggestion>& suggestions,
+      const absl::optional<SuggestionsTextContext>& context) override {}
   void UpdateCandidatesWindow(mojom::CandidatesWindowPtr window) override {}
   void RecordUkm(mojom::UkmEntryPtr entry) override {}
   void ReportKoreanAction(mojom::KoreanAction action) override {}
@@ -209,7 +210,8 @@
   void RequestSuggestions(mojom::SuggestionsRequestPtr request,
                           RequestSuggestionsCallback callback) override {}
   void DisplaySuggestions(
-      const std::vector<AssistiveSuggestion>& suggestions) override {}
+      const std::vector<AssistiveSuggestion>& suggestions,
+      const absl::optional<SuggestionsTextContext>& context) override {}
   void UpdateCandidatesWindow(mojom::CandidatesWindowPtr window) override {}
   void RecordUkm(mojom::UkmEntryPtr entry) override {}
   void ReportKoreanAction(mojom::KoreanAction action) override {}
diff --git a/chromeos/ash/services/ime/public/cpp/assistive_suggestions.h b/chromeos/ash/services/ime/public/cpp/assistive_suggestions.h
index bcf267b..18a8446 100644
--- a/chromeos/ash/services/ime/public/cpp/assistive_suggestions.h
+++ b/chromeos/ash/services/ime/public/cpp/assistive_suggestions.h
@@ -43,6 +43,14 @@
   }
 };
 
+// Holds the surrounding text context used to generate some suggestions.
+struct SuggestionsTextContext {
+  // The last N chars found in the surrounding text.
+  std::string last_n_chars;
+  // The full surrounding text length.
+  size_t surrounding_text_length;
+};
+
 // Encapsulates a completion candidate emitted by a decoder.
 struct DecoderCompletionCandidate {
   std::string text;
diff --git a/chromeos/ash/services/ime/public/mojom/BUILD.gn b/chromeos/ash/services/ime/public/mojom/BUILD.gn
index a495e88..123cf34 100644
--- a/chromeos/ash/services/ime/public/mojom/BUILD.gn
+++ b/chromeos/ash/services/ime/public/mojom/BUILD.gn
@@ -43,6 +43,10 @@
           cpp = "::ash::ime::AssistiveSuggestion"
         },
         {
+          mojom = "ash.ime.mojom.SuggestionsTextContext"
+          cpp = "::ash::ime::SuggestionsTextContext"
+        },
+        {
           mojom = "ash.ime.mojom.TextRange"
           cpp = "::gfx::Range"
         },
diff --git a/chromeos/ash/services/ime/public/mojom/input_method_host.mojom b/chromeos/ash/services/ime/public/mojom/input_method_host.mojom
index 0cbb4e5..b830ac78 100644
--- a/chromeos/ash/services/ime/public/mojom/input_method_host.mojom
+++ b/chromeos/ash/services/ime/public/mojom/input_method_host.mojom
@@ -6,7 +6,7 @@
 // the Chromium repo. This file should be updated first, before syncing in the
 // other repos.
 
-// Next MinVersion: 10
+// Next MinVersion: 11
 
 module ash.ime.mojom;
 
@@ -107,6 +107,16 @@
   array<SuggestionCandidate> candidates@0;
 };
 
+// Next ordinal: 1
+[Stable]
+struct SuggestionsTextContext {
+  // The last N chars from the text used to produce the suggestions.
+  string last_n_chars;
+
+  // The total length of the surrounding text used to produce suggestions.
+  uint32 surrounding_text_length;
+};
+
 // A URL-Keyed Metric (UKM) entry.
 [Stable]
 union UkmEntry {
@@ -273,8 +283,13 @@
   // This method does not modify the input field text.
   HandleAutocorrect@5(AutocorrectSpan autocorrect_span);
 
-  // Asks the system to display the given suggestions to the user.
-  DisplaySuggestions@6(array<SuggestionCandidate> suggestions);
+  // Asks the system to display the given suggestions to the user. The
+  // surrounding text given with the call was the text used to generate the
+  // suggestions. Listeners to this call can use this text to decide what they
+  // want to do with the suggestions given.
+  DisplaySuggestions@6(
+    array<SuggestionCandidate> suggestions,
+    [MinVersion=10] SuggestionsTextContext? context);
 
   // Asks the system to update the current candidates window state.
   // If `window` is null, then the candidates window is hidden.
diff --git a/chromeos/ash/services/ime/public/mojom/mojom_traits.cc b/chromeos/ash/services/ime/public/mojom/mojom_traits.cc
index 402d90a4..df5f73bd 100644
--- a/chromeos/ash/services/ime/public/mojom/mojom_traits.cc
+++ b/chromeos/ash/services/ime/public/mojom/mojom_traits.cc
@@ -18,6 +18,9 @@
 using AssistiveSuggestionMode = ash::ime::AssistiveSuggestionMode;
 using SuggestionMode = ash::ime::mojom::SuggestionMode;
 using SuggestionType = ash::ime::mojom::SuggestionType;
+using SuggestionsTextContextDataView =
+    ash::ime::mojom::SuggestionsTextContextDataView;
+using SuggestionsTextContext = ash::ime::SuggestionsTextContext;
 using SuggestionCandidateDataView =
     ash::ime::mojom::SuggestionCandidateDataView;
 using DecoderCompletionCandidate = ash::ime::DecoderCompletionCandidate;
@@ -115,6 +118,16 @@
   return true;
 }
 
+bool StructTraits<SuggestionsTextContextDataView, SuggestionsTextContext>::Read(
+    SuggestionsTextContextDataView input,
+    SuggestionsTextContext* output) {
+  if (!input.ReadLastNChars(&output->last_n_chars)) {
+    return false;
+  }
+  output->surrounding_text_length = input.surrounding_text_length();
+  return true;
+}
+
 bool StructTraits<CompletionCandidateDataView, DecoderCompletionCandidate>::
     Read(CompletionCandidateDataView input,
          DecoderCompletionCandidate* output) {
diff --git a/chromeos/ash/services/ime/public/mojom/mojom_traits.h b/chromeos/ash/services/ime/public/mojom/mojom_traits.h
index 8bcfd15..96b147a 100644
--- a/chromeos/ash/services/ime/public/mojom/mojom_traits.h
+++ b/chromeos/ash/services/ime/public/mojom/mojom_traits.h
@@ -61,6 +61,26 @@
 };
 
 template <>
+struct StructTraits<ash::ime::mojom::SuggestionsTextContextDataView,
+                    ash::ime::SuggestionsTextContext> {
+  using SuggestionsTextContextDataView =
+      ::ash::ime::mojom::SuggestionsTextContextDataView;
+  using SuggestionsTextContext = ::ash::ime::SuggestionsTextContext;
+
+  static const std::string& last_n_chars(
+      const SuggestionsTextContext& context) {
+    return context.last_n_chars;
+  }
+
+  static size_t surrounding_text_length(const SuggestionsTextContext& context) {
+    return context.surrounding_text_length;
+  }
+
+  static bool Read(SuggestionsTextContextDataView input,
+                   SuggestionsTextContext* output);
+};
+
+template <>
 struct StructTraits<ash::ime::mojom::CompletionCandidateDataView,
                     ash::ime::DecoderCompletionCandidate> {
   using CompletionCandidateDataView =
diff --git a/chromeos/components/kcer/kcer_impl.cc b/chromeos/components/kcer/kcer_impl.cc
index 8c574894..90fffee 100644
--- a/chromeos/components/kcer/kcer_impl.cc
+++ b/chromeos/components/kcer/kcer_impl.cc
@@ -242,7 +242,15 @@
 }
 
 void KcerImpl::GetTokenInfo(Token token, GetTokenInfoCallback callback) {
-  // TODO(244408716): Implement.
+  const base::WeakPtr<KcerToken>& kcer_token = GetToken(token);
+  if (!kcer_token.MaybeValid()) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kTokenIsNotAvailable));
+  }
+  token_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&KcerToken::GetTokenInfo, kcer_token,
+                     base::BindPostTaskToCurrentDefault(std::move(callback))));
 }
 
 void KcerImpl::GetKeyInfo(PrivateKeyHandle key, GetKeyInfoCallback callback) {
@@ -253,8 +261,7 @@
   auto on_find_key_done =
       base::BindOnce(&KcerImpl::GetKeyInfoWithToken, weak_factory_.GetWeakPtr(),
                      std::move(callback));
-  return PopulateTokenForKey(
-      /*key=*/std::move(key), std::move(on_find_key_done));
+  return PopulateTokenForKey(std::move(key), std::move(on_find_key_done));
 }
 
 void KcerImpl::GetKeyInfoWithToken(
@@ -316,13 +323,73 @@
 void KcerImpl::SetKeyPermissions(PrivateKeyHandle key,
                                  chaps::KeyPermissions key_permissions,
                                  StatusCallback callback) {
-  // TODO(244408716): Implement.
+  if (key.GetTokenInternal().has_value()) {
+    return SetKeyPermissionsWithToken(std::move(key_permissions),
+                                      std::move(callback), std::move(key));
+  }
+
+  auto on_find_key_done = base::BindOnce(
+      &KcerImpl::SetKeyPermissionsWithToken, weak_factory_.GetWeakPtr(),
+      std::move(key_permissions), std::move(callback));
+  return PopulateTokenForKey(std::move(key), std::move(on_find_key_done));
+}
+
+void KcerImpl::SetKeyPermissionsWithToken(
+    chaps::KeyPermissions key_permissions,
+    StatusCallback callback,
+    base::expected<PrivateKeyHandle, Error> key_or_error) {
+  if (!key_or_error.has_value()) {
+    return std::move(callback).Run(base::unexpected(key_or_error.error()));
+  }
+  PrivateKeyHandle key = std::move(key_or_error).value();
+
+  const base::WeakPtr<KcerToken>& kcer_token =
+      GetToken(key.GetTokenInternal().value());
+  if (!kcer_token.MaybeValid()) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kTokenIsNotAvailable));
+  }
+  token_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&KcerToken::SetKeyPermissions, kcer_token, std::move(key),
+                     std::move(key_permissions),
+                     base::BindPostTaskToCurrentDefault(std::move(callback))));
 }
 
 void KcerImpl::SetCertProvisioningProfileId(PrivateKeyHandle key,
                                             std::string profile_id,
                                             StatusCallback callback) {
-  // TODO(244408716): Implement.
+  if (key.GetTokenInternal().has_value()) {
+    return SetCertProvisioningProfileIdWithToken(
+        std::move(profile_id), std::move(callback), std::move(key));
+  }
+
+  auto on_find_key_done = base::BindOnce(
+      &KcerImpl::SetCertProvisioningProfileIdWithToken,
+      weak_factory_.GetWeakPtr(), std::move(profile_id), std::move(callback));
+  return PopulateTokenForKey(std::move(key), std::move(on_find_key_done));
+}
+
+void KcerImpl::SetCertProvisioningProfileIdWithToken(
+    std::string profile_id,
+    StatusCallback callback,
+    base::expected<PrivateKeyHandle, Error> key_or_error) {
+  if (!key_or_error.has_value()) {
+    return std::move(callback).Run(base::unexpected(key_or_error.error()));
+  }
+  PrivateKeyHandle key = std::move(key_or_error).value();
+
+  const base::WeakPtr<KcerToken>& kcer_token =
+      GetToken(key.GetTokenInternal().value());
+  if (!kcer_token.MaybeValid()) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kTokenIsNotAvailable));
+  }
+  token_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&KcerToken::SetCertProvisioningProfileId, kcer_token,
+                     std::move(key), std::move(profile_id),
+                     base::BindPostTaskToCurrentDefault(std::move(callback))));
 }
 
 base::WeakPtr<internal::KcerToken>& KcerImpl::GetToken(Token token) {
diff --git a/chromeos/components/kcer/kcer_impl.h b/chromeos/components/kcer/kcer_impl.h
index 8a0cbd3..8a90e4e 100644
--- a/chromeos/components/kcer/kcer_impl.h
+++ b/chromeos/components/kcer/kcer_impl.h
@@ -127,6 +127,16 @@
       StatusCallback callback,
       base::expected<PrivateKeyHandle, Error> key_or_error);
 
+  void SetKeyPermissionsWithToken(
+      chaps::KeyPermissions key_permissions,
+      StatusCallback callback,
+      base::expected<PrivateKeyHandle, Error> key_or_error);
+
+  void SetCertProvisioningProfileIdWithToken(
+      std::string profile_id,
+      StatusCallback callback,
+      base::expected<PrivateKeyHandle, Error> key_or_error);
+
   // Task runner for the tokens. Can be nullptr if no tokens are available
   // to the current Kcer instance.
   scoped_refptr<base::TaskRunner> token_task_runner_;
diff --git a/chromeos/crosapi/mojom/account_manager.mojom b/chromeos/crosapi/mojom/account_manager.mojom
index fa8de1e..71ac011a 100644
--- a/chromeos/crosapi/mojom/account_manager.mojom
+++ b/chromeos/crosapi/mojom/account_manager.mojom
@@ -7,7 +7,7 @@
 // versioning. Bump this value before making a change to any of the following
 // interfaces / enums.
 //
-// Next MinVersion: 13
+// Next MinVersion: 14
 
 module crosapi.mojom;
 
@@ -236,9 +236,11 @@
     [MinVersion=8] AccountAdditionOptions? add_account_options) =>
     (AccountUpsertionResult result);
 
-  // Launches account reauthentication dialog for provided `email`.
+  // Launches account reauthentication dialog for provided `email` and returns
+  // `result` with the reauthenticated/added account.
   [MinVersion = 3]
-  ShowReauthAccountDialog@4(string email) => ();
+  ShowReauthAccountDialog@4(string email) =>
+    ([MinVersion=13]AccountUpsertionResult? result);
 
   // Launches OS Settings > Accounts.
   [MinVersion = 4]
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt
index 07e1c59..035db59 100644
--- a/chromeos/profiles/arm-exp.afdo.newest.txt
+++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5762.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5771.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 07e1c59..035db59 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5762.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5771.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 17dadbd..0d818b1 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-115-5735.12-1683543901-benchmark-115.0.5762.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-115-5735.12-1683543901-benchmark-115.0.5770.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index e7076b45..cc79c65 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-115-5735.12-1683542912-benchmark-115.0.5762.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-115-5735.12-1683542912-benchmark-115.0.5770.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index ffb3ee7..80b22af 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-115-5735.12-1683543901-benchmark-115.0.5758.0-r1.orderfile.xz
+chromeos-chrome-orderfile-field-115-5735.12-1683543901-benchmark-115.0.5769.0-r1.orderfile.xz
diff --git a/chromeos/strings/chromeos_strings_af.xtb b/chromeos/strings/chromeos_strings_af.xtb
index 396a640..a5731133 100644
--- a/chromeos/strings/chromeos_strings_af.xtb
+++ b/chromeos/strings/chromeos_strings_af.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">Toegangspuntnaam (APN)</translation>
 <translation id="7131634559772719176">Bevestig voorafstelling</translation>
 <translation id="7134436342991564651">{0,plural, =1{Naambediener}other{Naambedieners}}</translation>
+<translation id="7135814714616751706">Soek kortpaaie</translation>
 <translation id="7143207342074048698">Koppel tans</translation>
 <translation id="7144878232160441200">Probeer weer</translation>
 <translation id="714876143603641390">LAN-konnektiwiteit</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Druk Search plus spasiebalk om resultaat in Google Search te sien.</translation>
 <translation id="7343649194310845056">Netwerktoestelle</translation>
+<translation id="7353413232959255829">Soekresultaat <ph name="LIST_POSITION" /> van <ph name="LIST_SIZE" />: <ph name="SEARCH_RESULT_TEXT" />. Druk Enter om na kortpad te gaan.</translation>
 <translation id="7359657277149375382">Lêertipe</translation>
 <translation id="73631062356239394">Deel diagnostiese data</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_am.xtb b/chromeos/strings/chromeos_strings_am.xtb
index 66b8c8d..6c9c65f2 100644
--- a/chromeos/strings/chromeos_strings_am.xtb
+++ b/chromeos/strings/chromeos_strings_am.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">የመድረሻ ነጥብ ስም (ኤፒኤን)</translation>
 <translation id="7131634559772719176">ቅድመ-ቅምጥን ያረጋግጡ</translation>
 <translation id="7134436342991564651">{0,plural, =1{የስም አገልጋይ}one{የስም አገልጋዩች}other{የስም አገልጋዩች}}</translation>
+<translation id="7135814714616751706">የፍለጋ አቋራጮች</translation>
 <translation id="7143207342074048698">በመያያዝ ላይ</translation>
 <translation id="7144878232160441200">እንደገና ሞክር</translation>
 <translation id="714876143603641390">የላን ተገናኝነት</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; በGoogle ፍለጋ ውስጥ ውጤትን ለማየት ፍለጋን እና ክፍተትን ይጫኑ።</translation>
 <translation id="7343649194310845056">የአውታረ መረብ መሣሪያዎች</translation>
+<translation id="7353413232959255829">የፍለጋ ውጤት <ph name="LIST_POSITION" /> ከ<ph name="LIST_SIZE" />፦ <ph name="SEARCH_RESULT_TEXT" />። ወደ አቋራጭ ለማሰስ አስገባን ይጫኑ።</translation>
 <translation id="7359657277149375382">የፋይል ዓይነት</translation>
 <translation id="73631062356239394">የምርመራ ውሂብን ያጋሩ</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_bg.xtb b/chromeos/strings/chromeos_strings_bg.xtb
index c9f77f2..89a3fbf 100644
--- a/chromeos/strings/chromeos_strings_bg.xtb
+++ b/chromeos/strings/chromeos_strings_bg.xtb
@@ -426,6 +426,7 @@
 <translation id="455835558791489930">Батерия с капацитет от <ph name="CHARGE_VALUE" /> мАч</translation>
 <translation id="4561801978359312462">SIM картата е отключена</translation>
 <translation id="4562494484721939086">Няма покритие</translation>
+<translation id="4573777384450697571">Неуспешно– сертификатът е изтекъл</translation>
 <translation id="458794348635939462">Името на нито един хост не бе преобразувано</translation>
 <translation id="4593212453765072419">Изисква се удостоверяване в прокси сървъра</translation>
 <translation id="4609350030397390689">Намаляване на яркостта на клавиатурата</translation>
diff --git a/chromeos/strings/chromeos_strings_da.xtb b/chromeos/strings/chromeos_strings_da.xtb
index b41b0ab..a7b9be61 100644
--- a/chromeos/strings/chromeos_strings_da.xtb
+++ b/chromeos/strings/chromeos_strings_da.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">Adgangspunkt (APN)</translation>
 <translation id="7131634559772719176">Bekræft forudindstilling</translation>
 <translation id="7134436342991564651">{0,plural, =1{Navneserver}one{Navneserver}other{Navneservere}}</translation>
+<translation id="7135814714616751706">Søg efter genveje</translation>
 <translation id="7143207342074048698">Tilslutter</translation>
 <translation id="7144878232160441200">Prøv igen</translation>
 <translation id="714876143603641390">LAN-forbindelse</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Tryk på søgetasten og mellemrumstasten for at se resultater i Google Søgning.</translation>
 <translation id="7343649194310845056">Netværksenheder</translation>
+<translation id="7353413232959255829">Søgeresultat <ph name="LIST_POSITION" /> af <ph name="LIST_SIZE" />: <ph name="SEARCH_RESULT_TEXT" />. Tryk på Enter for at gå til genvejen.</translation>
 <translation id="7359657277149375382">Filtype</translation>
 <translation id="73631062356239394">Del diagnosticeringsdata</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_lo.xtb b/chromeos/strings/chromeos_strings_lo.xtb
index d5feffb..7a0d1c9 100644
--- a/chromeos/strings/chromeos_strings_lo.xtb
+++ b/chromeos/strings/chromeos_strings_lo.xtb
@@ -217,6 +217,7 @@
 <translation id="2638662041295312666">ຮູບການເຂົ້າສູ່ລະບົບ</translation>
 <translation id="2640549051766135490">ເລືອກອະລະບໍ້າ <ph name="TITLE" /> <ph name="DESC" /> ແລ້ວ</translation>
 <translation id="267442004702508783">ຣີເຟຣັຊ</translation>
+<translation id="268270014981824665">ຫຼີ່ແສງແປ້ນພິມ</translation>
 <translation id="2712812801627182647">ກະແຈການພິສູດຢືນຢັນ TLS</translation>
 <translation id="2713444072780614174">ສີ​ຂາວ</translation>
 <translation id="2717139507051041123">ເປີດການນຳໃຊ້ໂໝດສີມືດ</translation>
@@ -224,6 +225,7 @@
 <translation id="2744221223678373668">ແຊຣ໌ແລ້ວ</translation>
 <translation id="2751739896257479635">ການຮັບຮອງຄວາມຖືກຕ້ອງ EAP ໄລຍະທີ 2</translation>
 <translation id="2783010256799387990">ຜ່ານແລ້ວ</translation>
+<translation id="2787435249130282949">ແປ້ນພິມແຈ້ງຂຶ້ນ</translation>
 <translation id="2789486458103222910">ຕົກລົງ</translation>
 <translation id="2805756323405976993">ແອັບ</translation>
 <translation id="28232023175184696">ບໍ່ສາມາດເຊື່ອມຕໍ່ກັບອິນເຕີເນັດໄດ້. ຄລິກເພື່ອລອງໃໝ່.</translation>
@@ -327,11 +329,13 @@
 <translation id="3749289110408117711">ຊື່​ໄຟລ​໌</translation>
 <translation id="3771294271822695279">ໄຟລ​໌​ວິ​ດີ​ໂອ</translation>
 <translation id="3784455785234192852">ລັອກ</translation>
+<translation id="380097101658023925">ການຄວບຄຸມ RGB</translation>
 <translation id="38114475217616659">ລຶບລ້າງປະຫວັດທັງໝົດ</translation>
 <translation id="3820172043799983114">PIN ບໍ່ຖືກຕ້ອງ.</translation>
 <translation id="3824259034819781947">ແນບໄຟລ໌</translation>
 <translation id="3838338534323494292">ລະຫັດຜ່ານໃໝ່</translation>
 <translation id="3845880861638660475">ກົດປຸ່ມ <ph name="ALT_SHORTCUT_START" />Alt<ph name="ALT_SHORTCUT_END" /> + <ph name="ESC_SHORTCUT_START" />Esc<ph name="ESC_SHORTCUT_END" /> ເພື່ອປິດກ່ອງໂຕ້ຕອບ.</translation>
+<translation id="3848280697030027394">ແປ້ນພິມມືດ</translation>
 <translation id="385051799172605136">ກັບ​ຄືນ​</translation>
 <translation id="3858860766373142691">ຊື່</translation>
 <translation id="3862598938296403232">ຕ້ອງລະບຸຄຳອະທິບາຍ</translation>
@@ -403,6 +407,7 @@
 <translation id="4382484599443659549">PDF</translation>
 <translation id="4394049700291259645">ປິດ​ໃຊ້ງານ</translation>
 <translation id="439429847087949098">ກຳລັງຣີສະຕາດ <ph name="DEVICE_NAME" /></translation>
+<translation id="4395835743215824109">ປັບແຕ່ງແປ້ນພິມ</translation>
 <translation id="4415951057168511744">ຮູບແທນຕົວປັດຈຸບັນ</translation>
 <translation id="4422041425070339732">ລູກສອນລົງ</translation>
 <translation id="4425149324548788773">My Drive</translation>
@@ -442,6 +447,7 @@
 <translation id="4731797938093519117">ສິດເຂົ້າເຖິງຂອງພໍ່ແມ່</translation>
 <translation id="473775607612524610">ອັບເດດ</translation>
 <translation id="4744944742468440486">ຂໍ້ມູນທີ່ກ່ຽວຂ້ອງກັບການເລືອກຂອງທ່ານ</translation>
+<translation id="4771607256327216405">ແປ້ນພິມແຈ້ງ</translation>
 <translation id="4773299976671772492">ຢຸດ​ແລ້ວ</translation>
 <translation id="4782311465517282004">ຮັບຄຳນິຍາມ, ການແປພາສາ ຫຼື ການປ່ຽນແປງຫົວໜ່ວຍເມື່ອທ່ານຄລິກຂວາ ຫຼື ແຕະໃສ່ຂໍ້ຄວາມຄ້າງໄວ້</translation>
 <translation id="4791000909649665275"><ph name="NUMBER" /> ຮູບ</translation>
@@ -490,6 +496,7 @@
 <translation id="500920857929044050">ຢຸດການທົດສອບ</translation>
 <translation id="5017508259293544172">LEAP</translation>
 <translation id="5019310272469539976">ເມື່ອໜ້າຈໍຂອງທ່ານຢູ່ລ້າໆ, ໃຫ້ສະແດງຮູບພາບ, ເວລາ, ສະພາບອາກາດ ແລະ ຂໍ້ມູນມີເດຍ.</translation>
+<translation id="5038292761217083259">ແປນພິມຫຼາກສີ</translation>
 <translation id="5039804452771397117">ອະ​ນຸ​ຍາດ​</translation>
 <translation id="5049856988445523908">ລັອກຊິມແລ້ວ (<ph name="LOCK_TYPE" />)</translation>
 <translation id="5050042263972837708">ຊື່​ກຸ່ມ​</translation>
@@ -639,6 +646,7 @@
 <translation id="6280912520669706465">ARC</translation>
 <translation id="6284632978374966585">ເປີດໃຊ້ຮູບແບບສີສັນມືດ</translation>
 <translation id="6285899124799306373">ເປີດຕົວເປີດໃຊ້</translation>
+<translation id="629550705077076970">ການຫຼຸດແສງແປ້ນພິມ</translation>
 <translation id="6302401976930124515">ຍົກເລີກການທົດສອບ <ph name="TEST_NAME" /> ແລ້ວ</translation>
 <translation id="631063167932043783">ແອັບ Explore</translation>
 <translation id="6319207335391420837">ອັບເດດເຟີມແວຢູ່ <ph name="DEVICE_NAME" /></translation>
@@ -657,6 +665,7 @@
 <translation id="6401427872449207797">ການຊອກຫາດ້ວຍໂປຣແກຣມທ່ອງເວັບ</translation>
 <translation id="6410257289063177456">ໄຟລ​໌​ຮູບ​</translation>
 <translation id="641081527798843608">ຫົວຂໍ້ກົງກັນ</translation>
+<translation id="6411934471898487866">ຄວາມແຈ້ງຂອງແປ້ນພິມ</translation>
 <translation id="6412715219990689313">ແປ້ນພິມໃນຕົວ</translation>
 <translation id="6417265370957905582">ຜູ້ຊ່ວຍ Google</translation>
 <translation id="6423239382391657905">ເປີດVPN</translation>
@@ -741,6 +750,7 @@
 <translation id="7130438335435247835">ຊື່ຈຸດການເຂົ້າເຖິງ (APN)</translation>
 <translation id="7131634559772719176">ຢືນຢັນການພຣີເຊັດ</translation>
 <translation id="7134436342991564651">{0,plural, =1{Name server}other{Name servers}}</translation>
+<translation id="7135814714616751706">ຊອກຫາທາງລັດ</translation>
 <translation id="7143207342074048698">ກຳ​ລັງ​ເຊື່ອມ​ຕໍ່</translation>
 <translation id="7144878232160441200">ລອງໃໝ່ອີກ</translation>
 <translation id="714876143603641390">ການເຊື່ອມຕໍ່ LAN</translation>
@@ -771,6 +781,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; ກົດຊອກຫາພ້ອມກັບຍະຫວ່າງເພື່ອເບິ່ງຜົນການຊອກຫາໃນ Google ຊອກຫາ.</translation>
 <translation id="7343649194310845056">ອຸປະກອນເຄືອຂ່າຍ</translation>
+<translation id="7353413232959255829">ຜົນການຊອກຫາ <ph name="LIST_POSITION" /> ຈາກ <ph name="LIST_SIZE" /> ລາຍການ: <ph name="SEARCH_RESULT_TEXT" />. ກົດ Enter ເພື່ອໄປທາງລັດ.</translation>
 <translation id="7359657277149375382">ປະເພດໄຟລ໌</translation>
 <translation id="73631062356239394">ແບ່ງປັນຂໍ້ມູນການວິນິໄສ</translation>
 <translation id="7375053625150546623">EAP</translation>
@@ -807,10 +818,12 @@
 <translation id="7656388927906093505">ອຸປະກອນແມ່ນເມົ້າ.</translation>
 <translation id="7658239707568436148">ຍົກ​ເລີກ​</translation>
 <translation id="7665800271478495366">ປ່ຽນຮູບແທນຕົວ</translation>
+<translation id="7683228889864052081">ສີແປ້ນພິມ</translation>
 <translation id="7690294790491645610">ຢືນຢັນລະຫັດຜ່ານໃໝ່</translation>
 <translation id="7701040980221191251">ບໍ່​ມີ​</translation>
 <translation id="7705524343798198388">VPN</translation>
 <translation id="7716280709122323042">WPA3</translation>
+<translation id="7718231387947923843">ແສງແປ້ນພິມ</translation>
 <translation id="773153675489693198">ຈຳນວນຮອບ</translation>
 <translation id="7747039790905080783">ລະຫັດທີ່ແບ່ງປັນລ່ວງໜ້າ</translation>
 <translation id="7762130827864645708">ປ່ຽນລະຫັດຜ່ານຂອງທ່ານສຳເລັດແລ້ວ. ກະລຸນາໃຊ້ລະຫັດຜ່ານໃໝ່ນັບຈາກນີ້ໄປ.</translation>
@@ -854,6 +867,7 @@
 <translation id="8075838845814659848">ການສາກທີ່ເຫຼືອ</translation>
 <translation id="8076492880354921740">ແຖບ</translation>
 <translation id="8082366717211101304">ບໍ່ສາມາດລະບຸ DNS ຈາກແອັບ Android ໄດ້</translation>
+<translation id="8082644724189923105">ໂຊນແປ້ນພິມ</translation>
 <translation id="808894953321890993">ປ່ຽນລະຫັດຜ່ານ</translation>
 <translation id="8094062939584182041">ອະນຸຍາດໃຫ້ Google ສົ່ງອີເມວຫາທ່ານກ່ຽວກັບບັນຫານີ້</translation>
 <translation id="8104083085214006426">ທ່ານກຳລັງໃຊ້ເຄືອຂ່າຍເປີດ ແລະ ບໍ່ປອດໄພຢູ່</translation>
@@ -902,6 +916,7 @@
 <translation id="8456761643544401578">ໂໝດມືດອັດຕະໂນມັດ</translation>
 <translation id="8461329675984532579">ຊື່ຜູ້ໃຫ້ບໍລິການ Home</translation>
 <translation id="8475690821716466388">ເຄືອຂ່າຍ WiFi ມີການຮັກສາຄວາມປອດໄພດ້ວຍໂປຣໂຕຄໍ WEP PSK ທີ່ບໍ່ຮັດກຸມ</translation>
+<translation id="8476242415522716722">ແປ້ນພິມເຮືອງແສງ</translation>
 <translation id="8477551185774834963">ເວລາໃນການຕອບສະໜອງ DNS ສູງກວ່າເກນທີ່ຍອມຮັບໄດ້ເລັກນ້ອຍ</translation>
 <translation id="8483248364096924578">ທີ່ຢູ່ IP</translation>
 <translation id="8491311378305535241">ບໍ່ສາມາດເຊື່ອມຕໍ່ຜ່ານ firewall ຫາເວັບໄຊ HTTP ຈາກແອັບ Android ໄດ້</translation>
@@ -945,6 +960,7 @@
 <translation id="8845001906332463065">ຂໍການຊ່ວຍເຫຼືອ</translation>
 <translation id="8855781559874488009">ບໍ່ສາມາດເຊື່ອມຕໍ່ຜ່ານ firewall ຫາເວັບໄຊ HTTP ໄດ້</translation>
 <translation id="885701979325669005">ການເກັບຂໍ້ມູນ</translation>
+<translation id="885704831271383379">ແປ້ນພິມເຂັ້ມຂຶ້ນ</translation>
 <translation id="8863170912498892583">ເປີດການນຳໃຊ້ຮູບແບບສີສັນມືດ</translation>
 <translation id="8863888432376731307">ຮັບ <ph name="INTENT" /> ສຳລັບ "<ph name="QUERY" />" ແລະ ອື່ນໆ</translation>
 <translation id="8864415976656252616">ບໍ່ມີເນື້ອຫາທີ່ແນະນຳ. ເບິ່ງເນື້ອຫາຊ່ວຍເຫຼືອຍອດນິຍົມ.</translation>
diff --git a/chromeos/strings/chromeos_strings_ne.xtb b/chromeos/strings/chromeos_strings_ne.xtb
index 3aa1cf2..eb68f7e0 100644
--- a/chromeos/strings/chromeos_strings_ne.xtb
+++ b/chromeos/strings/chromeos_strings_ne.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">एक्सेस पोइन्टको नाम (APN)</translation>
 <translation id="7131634559772719176">प्रिसेट पुष्टि गर्नुहोस्</translation>
 <translation id="7134436342991564651">{0,plural, =1{नेम सर्भर}other{नेम सेभरहरू}}</translation>
+<translation id="7135814714616751706">सर्टकटहरू खोज्नुहोस्</translation>
 <translation id="7143207342074048698">जडान गर्दै...</translation>
 <translation id="7144878232160441200">पुन: प्रयास गर्नुहोस्</translation>
 <translation id="714876143603641390">Lan कनेक्टिभिटी</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Google Search मा परिणाम हेर्न Search र Space बटन एकै चोटि थिच्नुहोस्।</translation>
 <translation id="7343649194310845056">नेटवर्कसम्बन्धी यन्त्रहरू</translation>
+<translation id="7353413232959255829"><ph name="LIST_SIZE" /> मध्ये <ph name="LIST_POSITION" /> औँ खोज परिणाम: <ph name="SEARCH_RESULT_TEXT" />। सर्टकटमा जान इन्टर की थिच्नुहोस्।</translation>
 <translation id="7359657277149375382">फाइलको प्रकार</translation>
 <translation id="73631062356239394">डाइग्नोस्टिक्स डेटा सेयर गर्नुहोस्</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_te.xtb b/chromeos/strings/chromeos_strings_te.xtb
index 2571c51..1bec177 100644
--- a/chromeos/strings/chromeos_strings_te.xtb
+++ b/chromeos/strings/chromeos_strings_te.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">యాక్సెస్ స్థానం పేరు (APN)</translation>
 <translation id="7131634559772719176">ప్రీసెట్‌ను నిర్ధారించండి</translation>
 <translation id="7134436342991564651">{0,plural, =1{సర్వర్ పేరు}other{సర్వర్‌ల పేరు}}</translation>
+<translation id="7135814714616751706">షార్ట్‌కట్‌ల కోసం సెర్చ్ చేయండి</translation>
 <translation id="7143207342074048698">కనెక్ట్ అవుతో.</translation>
 <translation id="7144878232160441200">మళ్ళీ ప్రయత్నించు</translation>
 <translation id="714876143603641390">LAN కనెక్టివిటీ</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Google Searchలో ఫలితాన్ని చూడటానికి 'Search + Space'ను నొక్కండి.</translation>
 <translation id="7343649194310845056">నెట్‌వర్క్ పరికరాలు</translation>
+<translation id="7353413232959255829"><ph name="LIST_SIZE" />లోని <ph name="LIST_POSITION" />లో ఉన్న సెర్చ్ ఫలితం: <ph name="SEARCH_RESULT_TEXT" />. షార్ట్‌కట్‌కు నావిగేట్ అవ్వడానికి 'Enter'ను నొక్కండి.</translation>
 <translation id="7359657277149375382">ఫైల్ రకం</translation>
 <translation id="73631062356239394">సమస్య విశ్లేషణ డేటాను షేర్ చేయండి</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_uz.xtb b/chromeos/strings/chromeos_strings_uz.xtb
index 41dc38f9..fa136d40 100644
--- a/chromeos/strings/chromeos_strings_uz.xtb
+++ b/chromeos/strings/chromeos_strings_uz.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">Ulanish nuqtasi nomi (APN)</translation>
 <translation id="7131634559772719176">Andozani tasdiqlang</translation>
 <translation id="7134436342991564651">{0,plural, =1{Nom serveri}other{Nom serverlari}}</translation>
+<translation id="7135814714616751706">Tezkor tugmalar qidiruvi</translation>
 <translation id="7143207342074048698">Ulanmoqda</translation>
 <translation id="7144878232160441200">Qayta urinish</translation>
 <translation id="714876143603641390">LAN aloqasi</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Natijalarni Google Qidiruvida chiqarish uchun Qidiruv + Boʻshliq tugmalarini bosing.</translation>
 <translation id="7343649194310845056">Tarmoq qurilmalari</translation>
+<translation id="7353413232959255829"><ph name="LIST_POSITION" />/<ph name="LIST_SIZE" /> ta natija: <ph name="SEARCH_RESULT_TEXT" />. Tezkor tugmani ochish uchun Enter tugmasini bosing.</translation>
 <translation id="7359657277149375382">Fayl turi</translation>
 <translation id="73631062356239394">Diagnostika axborotini ulashish</translation>
 <translation id="7375053625150546623">EAP</translation>
diff --git a/chromeos/strings/chromeos_strings_zh-HK.xtb b/chromeos/strings/chromeos_strings_zh-HK.xtb
index d495f11..71994d7f 100644
--- a/chromeos/strings/chromeos_strings_zh-HK.xtb
+++ b/chromeos/strings/chromeos_strings_zh-HK.xtb
@@ -426,6 +426,7 @@
 <translation id="455835558791489930"><ph name="CHARGE_VALUE" /> mAh 電池</translation>
 <translation id="4561801978359312462">SIM 卡已解鎖</translation>
 <translation id="4562494484721939086">不提供服務</translation>
+<translation id="4573777384450697571">失敗 - 憑證已過期</translation>
 <translation id="458794348635939462">無法解析所有主機</translation>
 <translation id="4593212453765072419">需要 Proxy 驗證</translation>
 <translation id="4609350030397390689">鍵盤校暗亮度</translation>
diff --git a/chromeos/strings/chromeos_strings_zu.xtb b/chromeos/strings/chromeos_strings_zu.xtb
index 59035eb..ea539b89 100644
--- a/chromeos/strings/chromeos_strings_zu.xtb
+++ b/chromeos/strings/chromeos_strings_zu.xtb
@@ -740,6 +740,7 @@
 <translation id="7130438335435247835">Igama lephoyinti lokufinyelela (APN)</translation>
 <translation id="7131634559772719176">Qinisekisa ukusetha ngaphambilini</translation>
 <translation id="7134436342991564651">{0,plural, =1{Igama leseva}one{Igama lamaseva}other{Igama lamaseva}}</translation>
+<translation id="7135814714616751706">Sesha izinqamuleli</translation>
 <translation id="7143207342074048698">Iyaxhuma</translation>
 <translation id="7144878232160441200">Zama futhi</translation>
 <translation id="714876143603641390">Ukuxhumana kwe-LAN</translation>
@@ -770,6 +771,7 @@
 <translation id="7319430975418800333">A3</translation>
 <translation id="7343581795491695942"><ph name="QUERY_TEXT" />; <ph name="RESULT_TEXT" />; Cindezela okuthi Sesha ne-Space ukuze ubone umphumela ku-Google Search.</translation>
 <translation id="7343649194310845056">Amadivayisi Enethiwekhi</translation>
+<translation id="7353413232959255829">Imiphumela yosesho engu-<ph name="LIST_POSITION" /> kwengu-<ph name="LIST_SIZE" />: <ph name="SEARCH_RESULT_TEXT" />. Cindezela u-Enter ukuze uzulele kusinqamuleli.</translation>
 <translation id="7359657277149375382">Uhlobo lwefayela</translation>
 <translation id="73631062356239394">Yabelana ngedatha yokuxilonga</translation>
 <translation id="7375053625150546623">I-EAP</translation>
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 29da333..5f8f4c0 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -326,6 +326,9 @@
   # b/279351324: Until crrev.com/c/4475024 upreved.
   "a11y.LiveCaption.lacros",
 
+  # b/281983222
+  "inputs.InputMethodShelfInputs",
+
   # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
 ]
 
diff --git a/chromeos/ui/base/file_icon_util.cc b/chromeos/ui/base/file_icon_util.cc
index a3136257..0ec25a4f 100644
--- a/chromeos/ui/base/file_icon_util.cc
+++ b/chromeos/ui/base/file_icon_util.cc
@@ -306,6 +306,7 @@
           {".PPT", IconType::kPpt},
           {".PPTX", IconType::kPpt},
           {".XLS", IconType::kExcel},
+          {".XLSM", IconType::kExcel},
           {".XLSX", IconType::kExcel},
           {".TINI", IconType::kTini},
       });
diff --git a/components/OWNERS b/components/OWNERS
index 576a50c..6df4596 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -1,6 +1,7 @@
 set noparent
 blundell@chromium.org
 caitkp@chromium.org
+sdefresne@chromium.org
 tedchoc@chromium.org
 
 # For build configuration things and simple changes.
diff --git a/components/account_manager_core/account_manager_facade.h b/components/account_manager_core/account_manager_facade.h
index 5f489d9..b36ad31 100644
--- a/components/account_manager_core/account_manager_facade.h
+++ b/components/account_manager_core/account_manager_facade.h
@@ -134,9 +134,13 @@
           callback) = 0;
 
   // Launches account reauthentication dialog for provided `email`.
-  virtual void ShowReauthAccountDialog(AccountAdditionSource source,
-                                       const std::string& email,
-                                       base::OnceClosure callback) = 0;
+  // Note: the added/reauthenticated account may not match the account provided
+  // in the `email` field if user decided to edit the email inside the dialog.
+  virtual void ShowReauthAccountDialog(
+      AccountAdditionSource source,
+      const std::string& email,
+      base::OnceCallback<void(const AccountUpsertionResult& result)>
+          callback) = 0;
 
   // Launches OS Settings > Accounts.
   virtual void ShowManageAccountsSettings() = 0;
diff --git a/components/account_manager_core/account_manager_facade_impl.cc b/components/account_manager_core/account_manager_facade_impl.cc
index 1a64b8b..c85814c 100644
--- a/components/account_manager_core/account_manager_facade_impl.cc
+++ b/components/account_manager_core/account_manager_facade_impl.cc
@@ -381,7 +381,7 @@
         void(const account_manager::AccountUpsertionResult& result)> callback) {
   if (!account_manager_remote_) {
     LOG(WARNING) << "Account Manager remote disconnected";
-    FinishAddAccount(
+    FinishUpsertAccount(
         std::move(callback),
         AccountUpsertionResult::FromStatus(
             AccountUpsertionResult::Status::kMojoRemoteDisconnected));
@@ -392,7 +392,7 @@
     LOG(WARNING) << "Found remote at: " << remote_version_ << ", expected: "
                  << RemoteMinVersions::kShowAddAccountDialogMinVersion
                  << " for ShowAddAccountDialog.";
-    FinishAddAccount(
+    FinishUpsertAccount(
         std::move(callback),
         AccountUpsertionResult::FromStatus(
             AccountUpsertionResult::Status::kIncompatibleMojoVersions));
@@ -409,27 +409,41 @@
 
   account_manager_remote_->ShowAddAccountDialog(
       std::move(options),
-      base::BindOnce(&AccountManagerFacadeImpl::OnShowAddAccountDialogFinished,
+      base::BindOnce(&AccountManagerFacadeImpl::OnSigninDialogActionFinished,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void AccountManagerFacadeImpl::ShowReauthAccountDialog(
     AccountAdditionSource source,
     const std::string& email,
-    base::OnceClosure callback) {
-  if (!account_manager_remote_ ||
-      remote_version_ < RemoteMinVersions::kShowReauthAccountDialogMinVersion) {
+    base::OnceCallback<
+        void(const account_manager::AccountUpsertionResult& result)> callback) {
+  if (!account_manager_remote_) {
+    LOG(WARNING) << "Account Manager remote disconnected";
+    FinishUpsertAccount(
+        std::move(callback),
+        AccountUpsertionResult::FromStatus(
+            AccountUpsertionResult::Status::kMojoRemoteDisconnected));
+    return;
+  }
+
+  if (remote_version_ < RemoteMinVersions::kShowReauthAccountDialogMinVersion) {
     LOG(WARNING) << "Found remote at: " << remote_version_ << ", expected: "
                  << RemoteMinVersions::kShowReauthAccountDialogMinVersion
                  << " for ShowReauthAccountDialog.";
-    if (callback)
-      std::move(callback).Run();
+    FinishUpsertAccount(
+        std::move(callback),
+        AccountUpsertionResult::FromStatus(
+            AccountUpsertionResult::Status::kIncompatibleMojoVersions));
     return;
   }
 
   base::UmaHistogramEnumeration(kAccountAdditionSource, source);
 
-  account_manager_remote_->ShowReauthAccountDialog(email, std::move(callback));
+  account_manager_remote_->ShowReauthAccountDialog(
+      email,
+      base::BindOnce(&AccountManagerFacadeImpl::OnSigninDialogActionFinished,
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void AccountManagerFacadeImpl::ShowManageAccountsSettings() {
@@ -521,22 +535,23 @@
   FinishInitSequenceIfNotAlreadyFinished();
 }
 
-void AccountManagerFacadeImpl::OnShowAddAccountDialogFinished(
+void AccountManagerFacadeImpl::OnSigninDialogActionFinished(
     base::OnceCallback<
         void(const account_manager::AccountUpsertionResult& result)> callback,
     crosapi::mojom::AccountUpsertionResultPtr mojo_result) {
   absl::optional<account_manager::AccountUpsertionResult> result =
       account_manager::FromMojoAccountUpsertionResult(mojo_result);
   if (!result.has_value()) {
-    FinishAddAccount(std::move(callback),
-                     AccountUpsertionResult::FromStatus(
-                         AccountUpsertionResult::Status::kUnexpectedResponse));
+    FinishUpsertAccount(
+        std::move(callback),
+        AccountUpsertionResult::FromStatus(
+            AccountUpsertionResult::Status::kUnexpectedResponse));
     return;
   }
-  FinishAddAccount(std::move(callback), result.value());
+  FinishUpsertAccount(std::move(callback), result.value());
 }
 
-void AccountManagerFacadeImpl::FinishAddAccount(
+void AccountManagerFacadeImpl::FinishUpsertAccount(
     base::OnceCallback<
         void(const account_manager::AccountUpsertionResult& result)> callback,
     const account_manager::AccountUpsertionResult& result) {
diff --git a/components/account_manager_core/account_manager_facade_impl.h b/components/account_manager_core/account_manager_facade_impl.h
index 2f9f4c7..0c74145b 100644
--- a/components/account_manager_core/account_manager_facade_impl.h
+++ b/components/account_manager_core/account_manager_facade_impl.h
@@ -62,9 +62,11 @@
       AccountAdditionSource source,
       base::OnceCallback<void(const account_manager::AccountUpsertionResult&
                                   result)> callback) override;
-  void ShowReauthAccountDialog(AccountAdditionSource source,
-                               const std::string& email,
-                               base::OnceClosure callback) override;
+  void ShowReauthAccountDialog(
+      AccountAdditionSource source,
+      const std::string& email,
+      base::OnceCallback<void(const account_manager::AccountUpsertionResult&
+                                  result)> callback) override;
   void ShowManageAccountsSettings() override;
   std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
       const AccountKey& account,
@@ -142,11 +144,11 @@
   void OnReceiverReceived(
       mojo::PendingReceiver<AccountManagerObserver> receiver);
   // Callback for `crosapi::mojom::AccountManager::ShowAddAccountDialog`.
-  void OnShowAddAccountDialogFinished(
+  void OnSigninDialogActionFinished(
       base::OnceCallback<
           void(const account_manager::AccountUpsertionResult& result)> callback,
       crosapi::mojom::AccountUpsertionResultPtr mojo_result);
-  void FinishAddAccount(
+  void FinishUpsertAccount(
       base::OnceCallback<
           void(const account_manager::AccountUpsertionResult& result)> callback,
       const account_manager::AccountUpsertionResult& result);
diff --git a/components/account_manager_core/account_manager_facade_impl_unittest.cc b/components/account_manager_core/account_manager_facade_impl_unittest.cc
index 5b54073..97295d1f 100644
--- a/components/account_manager_core/account_manager_facade_impl_unittest.cc
+++ b/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -179,10 +179,12 @@
         account_manager::ToMojoAccountUpsertionResult(*upsertion_result_));
   }
 
-  void ShowReauthAccountDialog(const std::string& email,
-                               base::OnceClosure closure) override {
+  void ShowReauthAccountDialog(
+      const std::string& email,
+      ShowReauthAccountDialogCallback callback) override {
     show_reauth_account_dialog_calls_++;
-    std::move(closure).Run();
+    std::move(callback).Run(
+        account_manager::ToMojoAccountUpsertionResult(*upsertion_result_));
   }
 
   void ShowManageAccountsSettings() override {
@@ -605,11 +607,16 @@
 TEST_F(AccountManagerFacadeImplTest, ShowReauthAccountDialogCallsMojo) {
   std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
       CreateFacade();
+
+  account_manager().SetAccountUpsertionResult(
+      account_manager::AccountUpsertionResult::FromStatus(
+          account_manager::AccountUpsertionResult::Status::
+              kUnexpectedResponse));
   EXPECT_EQ(0, account_manager().show_reauth_account_dialog_calls());
   account_manager_facade->ShowReauthAccountDialog(
       account_manager::AccountManagerFacade::AccountAdditionSource::
-          kSettingsAddAccountButton,
-      kTestAccountEmail, base::OnceClosure());
+          kContentAreaReauth,
+      kTestAccountEmail, base::DoNothing());
   account_manager_facade->FlushMojoForTesting();
   EXPECT_EQ(1, account_manager().show_reauth_account_dialog_calls());
 }
@@ -618,10 +625,14 @@
   base::HistogramTester tester;
   std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
       CreateFacade();
+
+  auto result = account_manager::AccountUpsertionResult::FromStatus(
+      account_manager::AccountUpsertionResult::Status::kAlreadyInProgress);
+  account_manager().SetAccountUpsertionResult(result);
   auto source = AccountManagerFacade::AccountAdditionSource::kContentAreaReauth;
 
   account_manager_facade->ShowReauthAccountDialog(source, kTestAccountEmail,
-                                                  base::OnceClosure());
+                                                  base::DoNothing());
   account_manager_facade->FlushMojoForTesting();
 
   // Check that UMA stats were sent.
diff --git a/components/account_manager_core/account_upsertion_result.h b/components/account_manager_core/account_upsertion_result.h
index e5fe202..56027fd 100644
--- a/components/account_manager_core/account_upsertion_result.h
+++ b/components/account_manager_core/account_upsertion_result.h
@@ -49,6 +49,8 @@
   // error state must not be NONE.
   static AccountUpsertionResult FromError(const GoogleServiceAuthError& error);
 
+  // If `status` is `kSuccess`, the reauthenticated/added account will be
+  // returned from `account`. Otherwise `account` will be `absl::nullopt`.
   Status status() const { return status_; }
 
   // The account that was added. Set iff `status` is set to `kSuccess`.
diff --git a/components/account_manager_core/chromeos/account_manager_mojo_service.cc b/components/account_manager_core/chromeos/account_manager_mojo_service.cc
index 6b7ad9e..3d7280f 100644
--- a/components/account_manager_core/chromeos/account_manager_mojo_service.cc
+++ b/components/account_manager_core/chromeos/account_manager_mojo_service.cc
@@ -58,7 +58,7 @@
 AccountManagerMojoService::AccountManagerMojoService(
     account_manager::AccountManager* account_manager)
     : account_manager_(account_manager) {
-  DCHECK(account_manager_);
+  CHECK(account_manager_);
   account_manager_->AddObserver(this);
 }
 
@@ -76,9 +76,9 @@
   account_manager_ui_ = std::move(account_manager_ui);
 }
 
-void AccountManagerMojoService::OnAccountAdditionFinishedForTesting(
+void AccountManagerMojoService::OnAccountUpsertionFinishedForTesting(
     const account_manager::AccountUpsertionResult& result) {
-  OnAccountAdditionFinished(result);
+  OnAccountUpsertionFinished(result);
 }
 
 void AccountManagerMojoService::IsInitialized(IsInitializedCallback callback) {
@@ -114,7 +114,7 @@
 void AccountManagerMojoService::ShowAddAccountDialog(
     crosapi::mojom::AccountAdditionOptionsPtr options,
     ShowAddAccountDialogCallback callback) {
-  DCHECK(account_manager_ui_);
+  CHECK(account_manager_ui_);
   if (account_manager_ui_->IsDialogShown()) {
     std::move(callback).Run(ToMojoAccountUpsertionResult(
         account_manager::AccountUpsertionResult::FromStatus(
@@ -123,35 +123,36 @@
     return;
   }
 
-  DCHECK(!account_addition_in_progress_);
-  account_addition_in_progress_ = true;
+  DCHECK(!account_signin_in_progress_);
+  account_signin_in_progress_ = true;
+  is_reauth_ = false;
   account_addition_callback_ = std::move(callback);
   auto maybe_options = account_manager::FromMojoAccountAdditionOptions(options);
   account_manager_ui_->ShowAddAccountDialog(
       maybe_options.value_or(account_manager::AccountAdditionOptions{}),
-      base::BindOnce(&AccountManagerMojoService::OnAddAccountDialogClosed,
+      base::BindOnce(&AccountManagerMojoService::OnSigninDialogClosed,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AccountManagerMojoService::ShowReauthAccountDialog(
     const std::string& email,
-    base::OnceClosure closure) {
-  DCHECK(account_manager_ui_);
-  if (account_manager_ui_->IsDialogShown())
+    ShowReauthAccountDialogCallback callback) {
+  CHECK(account_manager_ui_);
+  if (account_manager_ui_->IsDialogShown()) {
+    std::move(callback).Run(ToMojoAccountUpsertionResult(
+        account_manager::AccountUpsertionResult::FromStatus(
+            account_manager::AccountUpsertionResult::Status::
+                kAlreadyInProgress)));
     return;
+  }
 
-  // `closure` is used by the entity which launched the account
-  // re-authentication flow in the first place to know about the completion of
-  // the flow. The notification that we are going to chain here will inform all
-  // observers of `AccountManagerFacade` (see
-  // `AccountManagerFacade::Observer::OnSigninDialogClosed()`), that the signin
-  // dialog was closed.
-  // As of this writing, this notification is used by `AccountReconcilor` to
-  // force mint cookies.
+  DCHECK(!account_signin_in_progress_);
+  account_signin_in_progress_ = true;
+  is_reauth_ = true;
+  account_reauth_callback_ = std::move(callback);
   account_manager_ui_->ShowReauthAccountDialog(
-      email, std::move(closure).Then(base::BindOnce(
-                 &AccountManagerMojoService::NotifySigninDialogClosed,
-                 weak_ptr_factory_.GetWeakPtr())));
+      email, base::BindOnce(&AccountManagerMojoService::OnSigninDialogClosed,
+                            weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AccountManagerMojoService::ShowManageAccountsSettings() {
@@ -225,31 +226,44 @@
     observer->OnAccountRemoved(ToMojoAccount(account));
 }
 
-void AccountManagerMojoService::OnAccountAdditionFinished(
+void AccountManagerMojoService::OnAccountUpsertionFinished(
     const account_manager::AccountUpsertionResult& result) {
-  if (!account_addition_in_progress_)
+  if (!account_signin_in_progress_) {
     return;
+  }
 
-  FinishAddAccount(result);
+  FinishUpsertAccount(result);
 }
 
-void AccountManagerMojoService::OnAddAccountDialogClosed() {
-  if (!account_addition_in_progress_)
+void AccountManagerMojoService::OnSigninDialogClosed() {
+  if (!account_signin_in_progress_) {
     return;
+  }
 
   // Account addition is still in progress. It means that user didn't complete
   // the account addition flow and closed the dialog.
-  FinishAddAccount(account_manager::AccountUpsertionResult::FromStatus(
+  FinishUpsertAccount(account_manager::AccountUpsertionResult::FromStatus(
       account_manager::AccountUpsertionResult::Status::kCancelledByUser));
 }
 
-void AccountManagerMojoService::FinishAddAccount(
+void AccountManagerMojoService::FinishUpsertAccount(
     const account_manager::AccountUpsertionResult& result) {
-  account_addition_in_progress_ = false;
+  if (!account_signin_in_progress_) {
+    return;
+  }
 
-  DCHECK(!account_addition_callback_.is_null());
-  std::move(account_addition_callback_)
-      .Run(ToMojoAccountUpsertionResult(result));
+  if (is_reauth_) {
+    CHECK(account_reauth_callback_);
+    std::move(account_reauth_callback_)
+        .Run(ToMojoAccountUpsertionResult(result));
+  } else {
+    CHECK(account_addition_callback_);
+    std::move(account_addition_callback_)
+        .Run(ToMojoAccountUpsertionResult(result));
+  }
+
+  account_signin_in_progress_ = false;
+  is_reauth_ = false;
   NotifySigninDialogClosed();
 }
 
diff --git a/components/account_manager_core/chromeos/account_manager_mojo_service.h b/components/account_manager_core/chromeos/account_manager_mojo_service.h
index cfeaea9..04b1367 100644
--- a/components/account_manager_core/chromeos/account_manager_mojo_service.h
+++ b/components/account_manager_core/chromeos/account_manager_mojo_service.h
@@ -45,7 +45,7 @@
   void SetAccountManagerUI(
       std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui);
 
-  void OnAccountAdditionFinishedForTesting(
+  void OnAccountUpsertionFinishedForTesting(
       const account_manager::AccountUpsertionResult& result);
 
   // crosapi::mojom::AccountManager:
@@ -57,8 +57,9 @@
       GetPersistentErrorForAccountCallback callback) override;
   void ShowAddAccountDialog(mojom::AccountAdditionOptionsPtr options,
                             ShowAddAccountDialogCallback callback) override;
-  void ShowReauthAccountDialog(const std::string& email,
-                               base::OnceClosure closure) override;
+  void ShowReauthAccountDialog(
+      const std::string& email,
+      ShowReauthAccountDialogCallback callback) override;
   void ShowManageAccountsSettings() override;
   void CreateAccessTokenFetcher(
       mojom::AccountKeyPtr mojo_account_key,
@@ -79,11 +80,12 @@
 
   // This method is called by `ash::SigninHelper` which passes `AccountKey`
   // of account that was added.
-  void OnAccountAdditionFinished(
+  void OnAccountUpsertionFinished(
       const account_manager::AccountUpsertionResult& result);
   // A callback for `AccountManagerUI::ShowAccountAdditionDialog`.
-  void OnAddAccountDialogClosed();
-  void FinishAddAccount(const account_manager::AccountUpsertionResult& result);
+  void OnSigninDialogClosed();
+  void FinishUpsertAccount(
+      const account_manager::AccountUpsertionResult& result);
   // Deletes `request` from `pending_access_token_requests_`, if present.
   void DeletePendingAccessTokenFetchRequest(AccessTokenFetcher* request);
 
@@ -103,7 +105,9 @@
   int GetNumPendingAccessTokenRequests() const;
 
   ShowAddAccountDialogCallback account_addition_callback_;
-  bool account_addition_in_progress_ = false;
+  ShowReauthAccountDialogCallback account_reauth_callback_;
+  bool account_signin_in_progress_ = false;
+  bool is_reauth_ = false;
   const raw_ptr<account_manager::AccountManager> account_manager_;
   std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui_;
   std::vector<std::unique_ptr<AccessTokenFetcher>>
diff --git a/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc b/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
index aeb6257..b1559c2c 100644
--- a/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
+++ b/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
@@ -212,32 +212,23 @@
         account_manager_mojo_service_->account_manager_ui_.get());
   }
 
-  mojom::AccountUpsertionResultPtr ShowAddAccountDialog(
-      base::OnceClosure quit_closure) {
-    auto upsertion_result = mojom::AccountUpsertionResult::New();
-    account_manager_mojo_service_->ShowAddAccountDialog(
-        crosapi::mojom::AccountAdditionOptions::New(),
-        base::BindOnce(
-            [](base::OnceClosure quit_closure,
-               mojom::AccountUpsertionResultPtr* upsertion_result,
-               mojom::AccountUpsertionResultPtr result) {
-              (*upsertion_result)->status = result->status;
-              (*upsertion_result)->account = std::move(result->account);
-              std::move(quit_closure).Run();
-            },
-            std::move(quit_closure), &upsertion_result));
-    return upsertion_result;
+  void ShowAddAccountDialog(
+      crosapi::mojom::AccountAdditionOptionsPtr options,
+      AccountManagerMojoService::ShowAddAccountDialogCallback callback) {
+    account_manager_mojo_service_->ShowAddAccountDialog(std::move(options),
+                                                        std::move(callback));
   }
 
-  void ShowReauthAccountDialog(const std::string& email,
-                               base::OnceClosure close_dialog_closure) {
-    account_manager_mojo_service_->ShowReauthAccountDialog(
-        email, std::move(close_dialog_closure));
+  void ShowReauthAccountDialog(
+      const std::string& email,
+      AccountManagerMojoService::ShowReauthAccountDialogCallback callback) {
+    account_manager_mojo_service_->ShowReauthAccountDialog(email,
+                                                           std::move(callback));
   }
 
-  void CallAccountAdditionFinished(
+  void CallAccountUpsertionFinished(
       const account_manager::AccountUpsertionResult& result) {
-    account_manager_mojo_service_->OnAccountAdditionFinished(result);
+    account_manager_mojo_service_->OnAccountUpsertionFinished(result);
     GetFakeAccountManagerUI()->CloseDialog();
   }
 
@@ -416,20 +407,39 @@
 }
 
 TEST_F(AccountManagerMojoServiceTest,
+       ShowReauthAccountDialogReturnsInProgressIfDialogIsOpen) {
+  EXPECT_EQ(
+      0,
+      GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
+  GetFakeAccountManagerUI()->SetIsDialogShown(true);
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowReauthAccountDialog(kFakeEmail, future.GetCallback());
+  auto result = future.Take();
+
+  // Check status.
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kAlreadyInProgress,
+            result->status);
+  // Check that dialog was not called.
+  EXPECT_EQ(
+      0,
+      GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
+}
+
+TEST_F(AccountManagerMojoServiceTest,
        ShowAddAccountDialogReturnsCancelledAfterDialogIsClosed) {
   EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
 
-  base::test::TestFuture<void> future;
-  mojom::AccountUpsertionResultPtr account_upsertion_result =
-      ShowAddAccountDialog(future.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future.GetCallback());
+
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
-
+  auto result = future.Take();
   // Check status.
   EXPECT_EQ(mojom::AccountUpsertionResult::Status::kCancelledByUser,
-            account_upsertion_result->status);
+            result->status);
   // Check that dialog was called once.
   EXPECT_EQ(1, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
 }
@@ -439,22 +449,21 @@
   EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
 
-  base::test::TestFuture<void> future;
-  mojom::AccountUpsertionResultPtr account_upsertion_result =
-      ShowAddAccountDialog(future.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future.GetCallback());
   // Simulate account addition.
-  CallAccountAdditionFinished(
+  CallAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
+  auto result = future.Take();
 
   // Check status.
-  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess,
-            account_upsertion_result->status);
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess, result->status);
   // Check account.
   absl::optional<account_manager::Account> account =
-      account_manager::FromMojoAccount(account_upsertion_result->account);
+      account_manager::FromMojoAccount(result->account);
   EXPECT_TRUE(account.has_value());
   EXPECT_EQ(kFakeAccount.key, account.value().key);
   EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
@@ -463,34 +472,63 @@
 }
 
 TEST_F(AccountManagerMojoServiceTest,
+       ShowReauthAccountDialogReturnsSuccessAfterAccountIsAdded) {
+  EXPECT_EQ(
+      0,
+      GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
+  GetFakeAccountManagerUI()->SetIsDialogShown(false);
+
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowReauthAccountDialog(kFakeEmail, future.GetCallback());
+  // Simulate account reauth.
+  CallAccountUpsertionFinished(
+      account_manager::AccountUpsertionResult::FromAccount(kFakeAccount));
+  // Simulate closing the dialog.
+  GetFakeAccountManagerUI()->CloseDialog();
+  auto result = future.Take();
+
+  // Check status.
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess, result->status);
+  // Check account.
+  absl::optional<account_manager::Account> account =
+      account_manager::FromMojoAccount(result->account);
+  EXPECT_TRUE(account.has_value());
+  EXPECT_EQ(kFakeAccount.key, account.value().key);
+  EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
+  // Check that dialog was called once.
+  EXPECT_EQ(
+      1,
+      GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
+}
+
+TEST_F(AccountManagerMojoServiceTest,
        ShowAddAccountDialogCanHandleMultipleCalls) {
   EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
 
-  base::test::TestFuture<void> future;
-  mojom::AccountUpsertionResultPtr account_upsertion_result =
-      ShowAddAccountDialog(future.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future.GetCallback());
 
-  base::test::TestFuture<void> future_2;
-  mojom::AccountUpsertionResultPtr account_upsertion_result_2 =
-      ShowAddAccountDialog(future_2.GetCallback());
-  EXPECT_TRUE(future_2.Wait());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future_2;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future_2.GetCallback());
+  auto result_2 = future_2.Take();
   // The second call gets 'kAlreadyInProgress' reply.
   EXPECT_EQ(mojom::AccountUpsertionResult::Status::kAlreadyInProgress,
-            account_upsertion_result_2->status);
+            result_2->status);
 
   // Simulate account addition.
-  CallAccountAdditionFinished(
+  CallAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
+  auto result = future.Take();
 
-  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess,
-            account_upsertion_result->status);
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess, result->status);
   // Check account.
   absl::optional<account_manager::Account> account =
-      account_manager::FromMojoAccount(account_upsertion_result->account);
+      account_manager::FromMojoAccount(result->account);
   EXPECT_TRUE(account.has_value());
   EXPECT_EQ(kFakeAccount.key, account.value().key);
   EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
@@ -503,38 +541,36 @@
   EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
 
-  base::test::TestFuture<void> future;
-  mojom::AccountUpsertionResultPtr account_upsertion_result =
-      ShowAddAccountDialog(future.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future.GetCallback());
   // Simulate account addition.
-  CallAccountAdditionFinished(
+  CallAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
-  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess,
-            account_upsertion_result->status);
+  auto result = future.Take();
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess, result->status);
   // Check account.
   absl::optional<account_manager::Account> account =
-      account_manager::FromMojoAccount(account_upsertion_result->account);
+      account_manager::FromMojoAccount(result->account);
   EXPECT_TRUE(account.has_value());
   EXPECT_EQ(kFakeAccount.key, account.value().key);
   EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
 
-  base::test::TestFuture<void> future_2;
-  mojom::AccountUpsertionResultPtr account_upsertion_result_2 =
-      ShowAddAccountDialog(future_2.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future_2;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future_2.GetCallback());
   // Simulate account addition.
-  CallAccountAdditionFinished(
+  CallAccountUpsertionFinished(
       account_manager::AccountUpsertionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future_2.Wait());
-  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess,
-            account_upsertion_result_2->status);
+  auto result_2 = future_2.Take();
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kSuccess, result_2->status);
   // Check account.
   absl::optional<account_manager::Account> account_2 =
-      account_manager::FromMojoAccount(account_upsertion_result_2->account);
+      account_manager::FromMojoAccount(result_2->account);
   EXPECT_TRUE(account_2.has_value());
   EXPECT_EQ(kFakeAccount.key, account_2.value().key);
   EXPECT_EQ(kFakeAccount.raw_email, account_2.value().raw_email);
@@ -549,7 +585,7 @@
       0,
       GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(true);
-  base::test::TestFuture<void> future;
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
   // Simulate account re-authentication.
   ShowReauthAccountDialog(kFakeEmail, future.GetCallback());
   // Simulate closing the dialog.
@@ -566,12 +602,17 @@
       0,
       GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
-  base::test::TestFuture<void> future;
+
   // Simulate account reauthentication.
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
   ShowReauthAccountDialog(kFakeEmail, future.GetCallback());
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
+  auto result = future.Take();
 
+  // Check status.
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kCancelledByUser,
+            result->status);
   // Check that dialog was called once.
   EXPECT_EQ(
       1,
@@ -758,12 +799,14 @@
 
   EXPECT_EQ(0, observer.GetNumSigninDialogClosedNotifications());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
-  base::test::TestFuture<void> future;
-  mojom::AccountUpsertionResultPtr account_upsertion_result =
-      ShowAddAccountDialog(future.GetCallback());
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
+  ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptions::New(),
+                       future.GetCallback());
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
+  auto result = future.Take();
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kCancelledByUser,
+            result->status);
   FlushMojoForTesting();
   EXPECT_EQ(1, observer.GetNumSigninDialogClosedNotifications());
 }
@@ -776,11 +819,13 @@
 
   EXPECT_EQ(0, observer.GetNumSigninDialogClosedNotifications());
   GetFakeAccountManagerUI()->SetIsDialogShown(false);
-  base::test::TestFuture<void> future;
+  base::test::TestFuture<mojom::AccountUpsertionResultPtr> future;
   ShowReauthAccountDialog(kFakeEmail, future.GetCallback());
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
-  EXPECT_TRUE(future.Wait());
+  auto result = future.Take();
+  EXPECT_EQ(mojom::AccountUpsertionResult::Status::kCancelledByUser,
+            result->status);
   FlushMojoForTesting();
   EXPECT_EQ(1, observer.GetNumSigninDialogClosedNotifications());
 }
diff --git a/components/account_manager_core/mock_account_manager_facade.h b/components/account_manager_core/mock_account_manager_facade.h
index 75e8c25..1b8c524 100644
--- a/components/account_manager_core/mock_account_manager_facade.h
+++ b/components/account_manager_core/mock_account_manager_facade.h
@@ -57,7 +57,9 @@
               (override));
   MOCK_METHOD(void,
               ShowReauthAccountDialog,
-              (AccountAdditionSource, const std::string&, base::OnceClosure),
+              (AccountAdditionSource,
+               const std::string&,
+               base::OnceCallback<void(const AccountUpsertionResult& result)>),
               (override));
   MOCK_METHOD(void, ShowManageAccountsSettings, (), (override));
   MOCK_METHOD(void,
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 639212e4..8176f0a05 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -1031,6 +1031,12 @@
           weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+std::vector<blink::WebAutofillClient::FormIssue>
+AutofillAgent::ProccessFormsAndReturnIssues() {
+  ProcessForms();
+  return {};
+}
+
 void AutofillAgent::ProcessForms() {
   FormCache::UpdateFormCacheResult cache =
       form_cache_.UpdateFormCache(field_data_manager_.get());
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 450911e..0b20b0f 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -259,6 +259,8 @@
       const blink::WebFormControlElement& element) override;
   void FormElementReset(const blink::WebFormElement& form) override;
   void PasswordFieldReset(const blink::WebInputElement& element) override;
+  std::vector<blink::WebAutofillClient::FormIssue>
+  ProccessFormsAndReturnIssues() override;
 
   void HandleFocusChangeComplete();
   void SendFocusedInputChangedNotificationToBrowser(
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc
index 2d3148a..ab30a52 100644
--- a/components/autofill/core/browser/autofill_client.cc
+++ b/components/autofill/core/browser/autofill_client.cc
@@ -124,6 +124,11 @@
   // ChromeAutofillClient (Chrome Desktop and Clank) implements this.
 }
 
+void AutofillClient::ShowMandatoryReauthOptInPrompt(
+    base::OnceClosure accept_mandatory_reauth_callback,
+    base::OnceClosure cancel_mandatory_reauth_callback,
+    base::RepeatingClosure close_mandatory_reauth_callback) {}
+
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 void AutofillClient::HideVirtualCardEnrollBubbleAndIconIfVisible() {
   // This is overridden by platform subclasses. Currently only
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index e5ff6db..69af57e 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -507,6 +507,14 @@
       base::OnceClosure accept_virtual_card_callback,
       base::OnceClosure decline_virtual_card_callback);
 
+  // Prompt the user to enable mandatory reauthentication for payment method
+  // autofill. When enabled, the user will be asked to authenticate using
+  // biometrics or device unlock before filling in payment method information.
+  virtual void ShowMandatoryReauthOptInPrompt(
+      base::OnceClosure accept_mandatory_reauth_callback,
+      base::OnceClosure cancel_mandatory_reauth_callback,
+      base::RepeatingClosure close_mandatory_reauth_callback);
+
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
   // Hides the virtual card enroll bubble and icon if it is visible.
   virtual void HideVirtualCardEnrollBubbleAndIconIfVisible();
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index 7cf59be..4dc9168 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -92,6 +92,7 @@
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
@@ -127,6 +128,96 @@
 const std::u16string kArbitraryNickname16 = u"Grocery Card";
 const std::string kAddressEntryIcon = "accountIcon";
 
+struct TestAddressFillData {
+  TestAddressFillData(const char* first,
+                      const char* middle,
+                      const char* last,
+                      const char* address1,
+                      const char* address2,
+                      const char* city,
+                      const char* state,
+                      const char* postal_code,
+                      const char* country,
+                      const char* country_short,
+                      const char* phone,
+                      const char* email,
+                      const char* company)
+      : first(first),
+        middle(middle),
+        last(last),
+        address1(address1),
+        address2(address2),
+        city(city),
+        state(state),
+        postal_code(postal_code),
+        country(country),
+        country_short(country_short),
+        phone(phone),
+        email(email),
+        company(company) {}
+
+  const char* first;
+  const char* middle;
+  const char* last;
+  const char* address1;
+  const char* address2;
+  const char* city;
+  const char* state;
+  const char* postal_code;
+  const char* country;
+  const char* country_short;
+  const char* phone;
+  const char* email;
+  const char* company;
+};
+
+struct TestCardFillData {
+  TestCardFillData(const char* name_on_card,
+                   const char* card_number,
+                   const char* expiration_month,
+                   const char* expiration_year,
+                   bool use_month_type)
+      : name_on_card(name_on_card),
+        card_number(card_number),
+        expiration_month(expiration_month),
+        expiration_year(expiration_year),
+        use_month_type(use_month_type) {}
+  const char* name_on_card;
+  const char* card_number;
+  const char* expiration_month;
+  const char* expiration_year;
+  bool use_month_type;
+};
+
+const TestAddressFillData
+    kEmptyAddressFillData("", "", "", "", "", "", "", "", "", "", "", "", "");
+
+const TestAddressFillData kElvisAddressFillData("Elvis",
+                                                "Aaron",
+                                                "Presley",
+                                                "3734 Elvis Presley Blvd.",
+                                                "Apt. 10",
+                                                "Memphis",
+                                                "Tennessee",
+                                                "38116",
+                                                "United States",
+                                                "US",
+                                                "12345678901",
+                                                "theking@gmail.com",
+                                                "RCA");
+
+const TestCardFillData kEmptyCardFillData("",
+                                          "",
+                                          "",
+                                          "",
+                                          /*use_month_type=*/false);
+
+const TestCardFillData kElvisCardFillData("Elvis Presley",
+                                          "4234567890123456",
+                                          "04",
+                                          "2999",
+                                          /*use_month_type*/ false);
+
 class MockAutofillClient : public TestAutofillClient {
  public:
   MockAutofillClient() {
@@ -261,6 +352,22 @@
   MOCK_METHOD(void, HideFastCheckout, (bool), (override));
 };
 
+AutofillProfile FillDataToAutofillProfile(const TestAddressFillData& data) {
+  AutofillProfile profile;
+  test::SetProfileInfo(&profile, data.first, data.middle, data.last, data.email,
+                       data.company, data.address1, data.address2, data.city,
+                       data.state, data.postal_code, data.country_short,
+                       data.phone);
+  return profile;
+}
+
+CreditCard FillDataToCreditCardInfo(const TestCardFillData& data) {
+  CreditCard card;
+  test::SetCreditCardInfo(&card, data.name_on_card, data.card_number,
+                          data.expiration_month, data.expiration_year, "1");
+  return card;
+}
+
 void ExpectFilledField(const char* expected_label,
                        const char* expected_name,
                        const char* expected_value,
@@ -277,71 +384,65 @@
 // Verifies address fields if |has_address_fields| is true, and verifies
 // credit card fields if |has_credit_card_fields| is true. Verifies both if both
 // are true. |use_month_type| is used for credit card input month type.
-void ExpectFilledForm(const FormData& filled_form,
-                      const char* first,
-                      const char* middle,
-                      const char* last,
-                      const char* address1,
-                      const char* address2,
-                      const char* city,
-                      const char* state,
-                      const char* postal_code,
-                      const char* country,
-                      const char* phone,
-                      const char* email,
-                      const char* name_on_card,
-                      const char* card_number,
-                      const char* expiration_month,
-                      const char* expiration_year,
-                      bool has_address_fields,
-                      bool has_credit_card_fields,
-                      bool use_month_type) {
+void ExpectFilledForm(
+    const FormData& filled_form,
+    const absl::optional<TestAddressFillData>& address_fill_data,
+    const absl::optional<TestCardFillData>& card_fill_data) {
   // The number of fields in the address and credit card forms created above.
   const size_t kAddressFormSize = 11;
-  const size_t kCreditCardFormSize = use_month_type ? 4 : 5;
+  const size_t kCreditCardFormSizeMonthType = 4;
+  const size_t kCreditCardFormSizeNotMonthType = 5;
 
   EXPECT_EQ(u"MyForm", filled_form.name);
   EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.url);
   EXPECT_EQ(GURL("https://myform.com/submit.html"), filled_form.action);
 
   size_t form_size = 0;
-  if (has_address_fields)
+  if (address_fill_data) {
     form_size += kAddressFormSize;
-  if (has_credit_card_fields)
-    form_size += kCreditCardFormSize;
+  }
+  if (card_fill_data) {
+    form_size += card_fill_data->use_month_type
+                     ? kCreditCardFormSizeMonthType
+                     : kCreditCardFormSizeNotMonthType;
+  }
   ASSERT_EQ(form_size, filled_form.fields.size());
 
-  if (has_address_fields) {
-    ExpectFilledField("First Name", "firstname", first, "text",
-                      filled_form.fields[0]);
-    ExpectFilledField("Middle Name", "middlename", middle, "text",
-                      filled_form.fields[1]);
-    ExpectFilledField("Last Name", "lastname", last, "text",
+  if (address_fill_data) {
+    ExpectFilledField("First Name", "firstname", address_fill_data->first,
+                      "text", filled_form.fields[0]);
+    ExpectFilledField("Middle Name", "middlename", address_fill_data->middle,
+                      "text", filled_form.fields[1]);
+    ExpectFilledField("Last Name", "lastname", address_fill_data->last, "text",
                       filled_form.fields[2]);
-    ExpectFilledField("Address Line 1", "addr1", address1, "text",
-                      filled_form.fields[3]);
-    ExpectFilledField("Address Line 2", "addr2", address2, "text",
-                      filled_form.fields[4]);
-    ExpectFilledField("City", "city", city, "text", filled_form.fields[5]);
-    ExpectFilledField("State", "state", state, "text", filled_form.fields[6]);
-    ExpectFilledField("Postal Code", "zipcode", postal_code, "text",
-                      filled_form.fields[7]);
-    ExpectFilledField("Country", "country", country, "text",
+    ExpectFilledField("Address Line 1", "addr1", address_fill_data->address1,
+                      "text", filled_form.fields[3]);
+    ExpectFilledField("Address Line 2", "addr2", address_fill_data->address2,
+                      "text", filled_form.fields[4]);
+    ExpectFilledField("City", "city", address_fill_data->city, "text",
+                      filled_form.fields[5]);
+    ExpectFilledField("State", "state", address_fill_data->state, "text",
+                      filled_form.fields[6]);
+    ExpectFilledField("Postal Code", "zipcode", address_fill_data->postal_code,
+                      "text", filled_form.fields[7]);
+    ExpectFilledField("Country", "country", address_fill_data->country, "text",
                       filled_form.fields[8]);
-    ExpectFilledField("Phone Number", "phonenumber", phone, "tel",
-                      filled_form.fields[9]);
-    ExpectFilledField("Email", "email", email, "email", filled_form.fields[10]);
+    ExpectFilledField("Phone Number", "phonenumber", address_fill_data->phone,
+                      "tel", filled_form.fields[9]);
+    ExpectFilledField("Email", "email", address_fill_data->email, "email",
+                      filled_form.fields[10]);
   }
 
-  if (has_credit_card_fields) {
-    size_t offset = has_address_fields ? kAddressFormSize : 0;
-    ExpectFilledField("Name on Card", "nameoncard", name_on_card, "text",
+  if (card_fill_data) {
+    size_t offset = address_fill_data ? kAddressFormSize : 0;
+    ExpectFilledField("Name on Card", "nameoncard",
+                      card_fill_data->name_on_card, "text",
                       filled_form.fields[offset + 0]);
-    ExpectFilledField("Card Number", "cardnumber", card_number, "text",
-                      filled_form.fields[offset + 1]);
-    if (use_month_type) {
-      std::string exp_year = expiration_year;
-      std::string exp_month = expiration_month;
+    ExpectFilledField("Card Number", "cardnumber", card_fill_data->card_number,
+                      "text", filled_form.fields[offset + 1]);
+    if (card_fill_data->use_month_type) {
+      std::string exp_year = card_fill_data->expiration_year;
+      std::string exp_month = card_fill_data->expiration_month;
       std::string date;
       if (!exp_year.empty() && !exp_month.empty())
         date = exp_year + "-" + exp_month;
@@ -349,9 +450,10 @@
       ExpectFilledField("Expiration Date", "ccmonth", date.c_str(), "month",
                         filled_form.fields[offset + 2]);
     } else {
-      ExpectFilledField("Expiration Date", "ccmonth", expiration_month, "text",
+      ExpectFilledField("Expiration Date", "ccmonth",
+                        card_fill_data->expiration_month, "text",
                         filled_form.fields[offset + 2]);
-      ExpectFilledField("", "ccyear", expiration_year, "text",
+      ExpectFilledField("", "ccyear", card_fill_data->expiration_year, "text",
                         filled_form.fields[offset + 3]);
     }
   }
@@ -359,27 +461,20 @@
 
 void ExpectFilledAddressFormElvis(const FormData& filled_form,
                                   bool has_credit_card_fields) {
-  ExpectFilledForm(filled_form, "Elvis", "Aaron", "Presley",
-                   "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                   "Tennessee", "38116", "United States", "12345678901",
-                   "theking@gmail.com", "", "", "", "", true,
-                   has_credit_card_fields, false);
+  absl::optional<TestCardFillData> expected_card_fill_data;
+  if (has_credit_card_fields) {
+    expected_card_fill_data = kEmptyCardFillData;
+  }
+  ExpectFilledForm(filled_form, kElvisAddressFillData, expected_card_fill_data);
 }
 
 void ExpectFilledCreditCardFormElvis(const FormData& filled_form,
                                      bool has_address_fields) {
-  ExpectFilledForm(filled_form, "", "", "", "", "", "", "", "", "", "", "",
-                   "Elvis Presley", "4234567890123456", "04", "2999",
-                   has_address_fields, true, false);
-}
-
-void ExpectFilledCreditCardYearMonthWithYearMonth(const FormData& filled_form,
-                                                  bool has_address_fields,
-                                                  const char* year,
-                                                  const char* month) {
-  ExpectFilledForm(filled_form, "", "", "", "", "", "", "", "", "", "", "",
-                   "Miku Hatsune", "4234567890654321", month, year,
-                   has_address_fields, true, true);
+  absl::optional<TestAddressFillData> expected_address_fill_data;
+  if (has_address_fields) {
+    expected_address_fill_data = kEmptyAddressFillData;
+  }
+  ExpectFilledForm(filled_form, expected_address_fill_data, kElvisCardFillData);
 }
 
 void CheckThatOnlyFieldByIndexHasThisPossibleType(
@@ -1051,11 +1146,7 @@
   }
 
   void CreateTestAutofillProfiles() {
-    AutofillProfile profile1;
-    test::SetProfileInfo(&profile1, "Elvis", "Aaron", "Presley",
-                         "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                         "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                         "12345678901");
+    AutofillProfile profile1 = FillDataToAutofillProfile(kElvisAddressFillData);
     profile1.set_guid("00000000-0000-0000-0000-000000000001");
     personal_data().AddProfile(profile1);
 
@@ -2687,8 +2778,8 @@
   section1.fields.erase(section1.fields.begin() + mid, section1.fields.end());
   section2.fields.erase(section2.fields.begin(), section2.fields.end() - mid);
   // First section should be empty, second should be filled.
-  ExpectFilledForm(section1, "", "", "", "", "", "", "", "", "", "", "", "", "",
-                   "", "", true, false, false);
+  ExpectFilledForm(section1, kEmptyAddressFillData,
+                   /*card_fill_data=*/absl::nullopt);
   ExpectFilledAddressFormElvis(section2, false);
 }
 
@@ -3547,7 +3638,7 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardFormElvis(response_data, false);
+  ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
 
 // Test that whitespace is stripped from the credit card number.
@@ -3571,7 +3662,7 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardFormElvis(response_data, false);
+  ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
 
 // Test that separator characters are stripped from the credit card number.
@@ -3596,17 +3687,20 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardFormElvis(response_data, false);
+  ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
 
 // Test that we correctly fill a credit card form with month input type.
 // Test 1 of 4: Empty month, empty year
 TEST_F(BrowserAutofillManagerTest, FillCreditCardForm_NoYearNoMonth) {
   personal_data().ClearCreditCards();
-  CreditCard credit_card;
-  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
-                          "4234567890654321",  // Visa
-                          "", "", "1");
+
+  TestCardFillData card_fill_data = kElvisCardFillData;
+  card_fill_data.expiration_month = "";
+  card_fill_data.expiration_year = "";
+  card_fill_data.use_month_type = true;
+  CreditCard credit_card = FillDataToCreditCardInfo(card_fill_data);
+
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
   personal_data().AddCreditCard(credit_card);
   // Set up our form data.
@@ -3618,17 +3712,20 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardYearMonthWithYearMonth(response_data, false, "", "");
+  ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
+                   card_fill_data);
 }
 
 // Test that we correctly fill a credit card form with month input type.
 // Test 2 of 4: Non-empty month, empty year
 TEST_F(BrowserAutofillManagerTest, FillCreditCardForm_NoYearMonth) {
   personal_data().ClearCreditCards();
-  CreditCard credit_card;
-  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
-                          "4234567890654321",  // Visa
-                          "04", "", "1");
+  TestCardFillData card_fill_data = kElvisCardFillData;
+  card_fill_data.expiration_month = "04";
+  card_fill_data.expiration_year = "";
+  card_fill_data.use_month_type = true;
+  CreditCard credit_card = FillDataToCreditCardInfo(card_fill_data);
+
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
   personal_data().AddCreditCard(credit_card);
   // Set up our form data.
@@ -3640,7 +3737,8 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardYearMonthWithYearMonth(response_data, false, "", "04");
+  ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
+                   card_fill_data);
 }
 
 // Test that we correctly fill a credit card form with month input type.
@@ -3649,10 +3747,11 @@
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
   personal_data().ClearCreditCards();
-  CreditCard credit_card;
-  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
-                          "4234567890654321",  // Visa
-                          "", "2999", "1");
+  TestCardFillData card_fill_data = kElvisCardFillData;
+  card_fill_data.expiration_month = "";
+  card_fill_data.expiration_year = "2999";
+  card_fill_data.use_month_type = true;
+  CreditCard credit_card = FillDataToCreditCardInfo(card_fill_data);
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
   personal_data().AddCreditCard(credit_card);
   // Set up our form data.
@@ -3664,18 +3763,19 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardYearMonthWithYearMonth(response_data, false, "2999",
-                                               "");
+  ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
+                   card_fill_data);
 }
 
 // Test that we correctly fill a credit card form with month input type.
 // Test 4 of 4: Non-empty month, non-empty year
 TEST_F(BrowserAutofillManagerTest, FillCreditCardForm_YearMonth) {
   personal_data().ClearCreditCards();
-  CreditCard credit_card;
-  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
-                          "4234567890654321",  // Visa
-                          "04", "2999", "1");
+  TestCardFillData card_fill_data = kElvisCardFillData;
+  card_fill_data.expiration_month = "04";
+  card_fill_data.expiration_year = "2999";
+  card_fill_data.use_month_type = true;
+  CreditCard credit_card = FillDataToCreditCardInfo(card_fill_data);
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
   personal_data().AddCreditCard(credit_card);
   // Set up our form data.
@@ -3687,8 +3787,8 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardYearMonthWithYearMonth(response_data, false, "2999",
-                                               "04");
+  ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
+                   card_fill_data);
 }
 
 // Test that only the first 16 credit card number fields are filled.
@@ -3935,12 +4035,10 @@
 
   FormsSeen({form});
 
-  AutofillProfile profile;
   const char guid[] = "00000000-0000-0000-0000-000000000123";
-  test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
-                       "theking@gmail.com", "1987", "3734 Elvis Presley Blvd.",
-                       "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                       "12345678901");
+  TestAddressFillData profile_info_data = kElvisAddressFillData;
+  profile_info_data.company = "1987";
+  AutofillProfile profile = FillDataToAutofillProfile(profile_info_data);
   profile.set_guid(guid);
   personal_data().AddProfile(profile);
 
@@ -4008,7 +4106,7 @@
         form, form.fields.back(), MakeFrontendId({.credit_card_id = guid2}),
         &response_data);
     SCOPED_TRACE("Credit card");
-    ExpectFilledCreditCardFormElvis(response_data, true);
+    ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/true);
   }
 }
 
@@ -4167,7 +4265,7 @@
                                      &response_data);
 
   // All fields should be filled.
-  ExpectFilledCreditCardFormElvis(response_data, false);
+  ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
 
 // Test that selecting an expired credit card fills everything except the
@@ -4567,8 +4665,10 @@
                                      &response_data);
   {
     SCOPED_TRACE("Address");
-    ExpectFilledForm(response_data, "Elvis", "", "", "", "", "", "", "", "", "",
-                     "", "", "", "", "", true, true, false);
+    TestAddressFillData expected_address_fill_data = kEmptyAddressFillData;
+    expected_address_fill_data.first = "Elvis";
+    ExpectFilledForm(response_data, expected_address_fill_data,
+                     kEmptyCardFillData);
   }
 
   // Now fill the credit card data.
@@ -4578,7 +4678,7 @@
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
-    ExpectFilledCreditCardFormElvis(response_data, true);
+    ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/true);
   }
 
   // Now set the credit card fields to also be auto-filled, and try again to
@@ -4592,8 +4692,10 @@
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 2");
-    ExpectFilledForm(response_data, "", "", "", "", "", "", "", "", "", "", "",
-                     "", "", "", "2999", true, true, false);
+    TestCardFillData expected_card_fill_data = kEmptyCardFillData;
+    expected_card_fill_data.expiration_year = "2999";
+    ExpectFilledForm(response_data, kEmptyAddressFillData,
+                     expected_card_fill_data);
   }
 }
 
@@ -4620,9 +4722,16 @@
                                      &response_data);
   {
     SCOPED_TRACE("Address");
-    ExpectFilledForm(response_data, "Elvis", "Aaron", "Presley", "", "", "", "",
-                     "38116", "United States", "12345678901", "", "", "", "",
-                     "", true, true, false);
+    TestAddressFillData expected_address_fill_data = kEmptyAddressFillData;
+    expected_address_fill_data.first = "Elvis";
+    expected_address_fill_data.middle = "Aaron";
+    expected_address_fill_data.last = "Presley";
+    expected_address_fill_data.postal_code = "38116";
+    expected_address_fill_data.country = "United States";
+    expected_address_fill_data.phone = "12345678901";
+
+    ExpectFilledForm(response_data, expected_address_fill_data,
+                     kEmptyCardFillData);
   }
 
   // Now fill the credit card data.
@@ -4632,7 +4741,7 @@
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
-    ExpectFilledCreditCardFormElvis(response_data, true);
+    ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/true);
   }
 }
 
@@ -4664,10 +4773,10 @@
                                      &response_data);
   {
     SCOPED_TRACE("Address");
-    ExpectFilledForm(response_data, "Elvis", "Aaron", "Jackson",
-                     "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                     "Tennessee", "38116", "United States", "12345678901",
-                     "theking@gmail.com", "", "", "", "", true, true, false);
+    TestAddressFillData expected_address_fill_data = kElvisAddressFillData;
+    expected_address_fill_data.last = "Jackson";
+    ExpectFilledForm(response_data, expected_address_fill_data,
+                     kEmptyCardFillData);
   }
 
   // Now fill the credit card data.
@@ -4677,9 +4786,11 @@
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
-    ExpectFilledForm(response_data, "Michael", "", "Jackson", "", "", "", "",
-                     "", "", "", "", "Elvis Presley", "4234567890123456", "04",
-                     "2999", true, true, false);
+    TestAddressFillData expected_address_fill_data = kEmptyAddressFillData;
+    expected_address_fill_data.first = "Michael";
+    expected_address_fill_data.last = "Jackson";
+    ExpectFilledForm(response_data, expected_address_fill_data,
+                     kElvisCardFillData);
   }
 }
 
@@ -5642,22 +5753,23 @@
   form.fields[2].properties_mask |= kUserTyped;
 
   // Fill the address data.
-  AutofillProfile profile1;
   const char guid[] = "00000000-0000-0000-0000-000000000100";
+  TestAddressFillData address_fill_data(
+      "Buddy", "Aaron", "Holly", "3734 Elvis Presley Blvd.", "Apt. 10",
+      "Memphis", "Tennessee", "38116", "United States", "US", /*phone=*/"",
+      /*email=*/"", "RCA");
+  AutofillProfile profile1 = FillDataToAutofillProfile(address_fill_data);
   profile1.set_guid(guid);
-  test::SetProfileInfo(&profile1, "Buddy", "Aaron", "Holly", "", "RCA",
-                       "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                       "Tennessee", "38116", "US", "");
   personal_data().AddProfile(profile1);
   FormData response_data;
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.profile_id = guid}),
                                      &response_data);
 
-  ExpectFilledForm(response_data, "Buddy", "Aaron", "Jackson",
-                   "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                   "Tennessee", "38116", "United States", "", "", "", "", "",
-                   "", true, false, false);
+  TestAddressFillData expected_address_fill_data = address_fill_data;
+  expected_address_fill_data.last = "Jackson";
+  ExpectFilledForm(response_data, expected_address_fill_data,
+                   /*card_fill_data=*/absl::nullopt);
 
   FormStructure* form_structure = nullptr;
   AutofillField* autofill_field = nullptr;
@@ -5740,22 +5852,22 @@
   FormsSeen(forms);
 
   // First fill the address data which does not have email and phone number.
-  AutofillProfile profile1;
   const char guid[] = "00000000-0000-0000-0000-000000000100";
+  TestAddressFillData address_fill_data(
+      "Buddy", "Aaron", "Holly", "3734 Elvis Presley Blvd.", "Apt. 10",
+      "Memphis", "Tennessee", "38116", "United States", "US", /*phone=*/"",
+      /*email=*/"", "RCA");
+  AutofillProfile profile1 = FillDataToAutofillProfile(address_fill_data);
   profile1.set_guid(guid);
-  test::SetProfileInfo(&profile1, "Buddy", "Aaron", "Holly", "", "RCA",
-                       "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                       "Tennessee", "38116", "US", "");
   personal_data().AddProfile(profile1);
   FormData response_data;
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.profile_id = guid}),
                                      &response_data);
 
-  ExpectFilledForm(response_data, "Buddy", "Aaron", "Holly",
-                   "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                   "Tennessee", "38116", "United States", "", "", "", "", "",
-                   "", true, false, false);
+  TestAddressFillData expected_address_fill_data = address_fill_data;
+  ExpectFilledForm(response_data, expected_address_fill_data,
+                   /*card_fill_data=*/absl::nullopt);
 
   // Refill the address data with all the field values.
   const char guid2[] = "00000000-0000-0000-0000-000000000001";
@@ -5763,10 +5875,11 @@
       response_data, *response_data.fields.begin(),
       MakeFrontendId({.profile_id = guid2}), &response_data);
 
-  ExpectFilledForm(response_data, "Elvis", "Aaron", "Holly",
-                   "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                   "Tennessee", "38116", "United States", "12345678901",
-                   "theking@gmail.com", "", "", "", "", true, false, false);
+  expected_address_fill_data.first = "Elvis";
+  expected_address_fill_data.phone = "12345678901";
+  expected_address_fill_data.email = "theking@gmail.com";
+  ExpectFilledForm(response_data, expected_address_fill_data,
+                   /*card_fill_data=*/absl::nullopt);
 
   FormStructure* form_structure = nullptr;
   AutofillField* autofill_field = nullptr;
@@ -5864,11 +5977,6 @@
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
-  ExpectFilledForm(response_data, "Elvis", "Aaron", "Presley",
-                   "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
-                   "Tennessee", "38116", "United States", "12345678901",
-                   "theking@gmail.com", "", "", "", "", true, false, false);
-
   FormFieldData field = form.fields[0];
   // Simulate editing the first field.
   field.value = u"Michael";
@@ -5952,7 +6060,7 @@
   FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
                                      MakeFrontendId({.credit_card_id = guid}),
                                      &response_data);
-  ExpectFilledCreditCardFormElvis(response_data, false);
+  ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 
   // Simulate form submission.
   FormSubmitted(response_data);
@@ -7002,10 +7110,10 @@
   // Set up the test profiles.
   std::vector<AutofillProfile> profiles;
   profiles.resize(3);
-  test::SetProfileInfo(&profiles[0], "Elvis", "Aaron", "Presley",
-                       "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                       "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                       "+1 (234) 567-8901");
+  TestAddressFillData profile_info_data = kElvisAddressFillData;
+  profile_info_data.phone = "+1 (234) 567-8901";
+  profiles[0] = FillDataToAutofillProfile(profile_info_data);
+
   profiles[0].set_guid("00000000-0000-0000-0000-000000000001");
 
   test::SetProfileInfo(&profiles[1], "Charles", "", "Holley", "buddy@gmail.com",
@@ -7071,10 +7179,9 @@
 
   // Set up a profile and no credit cards.
   std::vector<AutofillProfile> profiles(1);
-  test::SetProfileInfo(&profiles[0], "Elvis", "Aaron", "Presley",
-                       "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                       "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                       "+1 (234) 567-8901");
+  TestAddressFillData profile_info_data = kElvisAddressFillData;
+  profile_info_data.phone = "+1 (234) 567-8901";
+  profiles[0] = FillDataToAutofillProfile(profile_info_data);
   profiles[0].set_guid("00000000-0000-0000-0000-000000000001");
   std::vector<CreditCard> credit_cards;
 
@@ -7182,11 +7289,11 @@
 TEST_F(BrowserAutofillManagerTest, DisambiguateUploadTypes) {
   // Set up the test profile.
   std::vector<AutofillProfile> profiles;
-  AutofillProfile profile;
-  test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
-                       "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                       "", "Memphis", "Tennessee", "38116", "US",
-                       "(234) 567-8901");
+  TestAddressFillData profile_info_data = kElvisAddressFillData;
+  profile_info_data.address2 = "";
+  profile_info_data.phone = "(234) 567-8901";
+  AutofillProfile profile = FillDataToAutofillProfile(profile_info_data);
+
   profile.set_guid("00000000-0000-0000-0000-000000000001");
   profiles.push_back(profile);
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 85259177..110ebc8 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -377,6 +377,7 @@
   IdentifySections(/*ignore_autocomplete=*/false);
 
   FormStructureRationalizer rationalizer(&fields_, form_signature_);
+  rationalizer.RationalizeAutocompleteAttributes(log_manager);
   if (base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection)) {
     rationalizer.RationalizeRepeatedFields(form_interactions_ukm_logger,
                                            log_manager);
@@ -700,6 +701,7 @@
     form->UpdateAutofillCount();
     FormStructureRationalizer rationalizer(&(form->fields_),
                                            form->form_signature_);
+    rationalizer.RationalizeAutocompleteAttributes(log_manager);
     rationalizer.RationalizeRepeatedFields(form_interactions_ukm_logger,
                                            log_manager);
     rationalizer.RationalizeFieldTypePredictions(log_manager);
diff --git a/components/autofill/core/browser/form_structure_rationalizer.cc b/components/autofill/core/browser/form_structure_rationalizer.cc
index e94211e..cd2b87f 100644
--- a/components/autofill/core/browser/form_structure_rationalizer.cc
+++ b/components/autofill/core/browser/form_structure_rationalizer.cc
@@ -95,6 +95,38 @@
     : fields_(*fields), form_signature_(form_signature) {}
 FormStructureRationalizer::~FormStructureRationalizer() = default;
 
+void FormStructureRationalizer::RationalizeAutocompleteAttributes(
+    LogManager* log_manager) {
+  for (const auto& field : *fields_) {
+    auto set_html_type = [&field](HtmlFieldType type) {
+      field->SetHtmlType(type, field->html_mode());
+    };
+    switch (field->html_type()) {
+      case HtmlFieldType::kAdditionalName:
+        if (field->max_length == 1) {
+          set_html_type(HtmlFieldType::kAdditionalNameInitial);
+        }
+        break;
+      case HtmlFieldType::kCreditCardExp:
+        if (field->max_length == 5) {
+          set_html_type(HtmlFieldType::kCreditCardExpDate2DigitYear);
+        } else if (field->max_length == 7) {
+          set_html_type(HtmlFieldType::kCreditCardExpDate4DigitYear);
+        }
+        break;
+      case HtmlFieldType::kCreditCardExpYear:
+        if (field->max_length == 2) {
+          set_html_type(HtmlFieldType::kCreditCardExp2DigitYear);
+        } else if (field->max_length == 4) {
+          set_html_type(HtmlFieldType::kCreditCardExp4DigitYear);
+        }
+        break;
+      default:
+        break;
+    }
+  }
+}
+
 void FormStructureRationalizer::RationalizeCreditCardFieldPredictions(
     LogManager* log_manager) {
   bool cc_first_name_found = false;
diff --git a/components/autofill/core/browser/form_structure_rationalizer.h b/components/autofill/core/browser/form_structure_rationalizer.h
index ee898ab..f5e943f6 100644
--- a/components/autofill/core/browser/form_structure_rationalizer.h
+++ b/components/autofill/core/browser/form_structure_rationalizer.h
@@ -32,6 +32,11 @@
   FormStructureRationalizer& operator=(const FormStructureRationalizer&) =
       delete;
 
+  // Rationalizes autocomplete attributes like turning a generic
+  // autocomplete="cc-exp-year" into a 2 digit or 4 digit year if there are
+  // hints like max-length=4.
+  void RationalizeAutocompleteAttributes(LogManager* log_manager);
+
   // Tunes the fields with identical predictions.
   void RationalizeRepeatedFields(AutofillMetrics::FormInteractionsUkmLogger*,
                                  LogManager* log_manager);
diff --git a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
index 5fa4bce..63626f0 100644
--- a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
+++ b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
@@ -44,10 +44,11 @@
   base::StringPiece name;
   // This is a field type we assume the autofill server would provide for
   // the given field.
-  ServerFieldType field_type;
+  ServerFieldType field_type = UNKNOWN_TYPE;
   // Section name of a field.
   base::StringPiece section = "";
   base::StringPiece form_control_type = "text";
+  absl::optional<AutocompleteParsingResult> parsed_autocomplete = absl::nullopt;
   bool is_focusable = true;
   size_t max_length = std::numeric_limits<int>::max();
   FormFieldData::RoleAttribute role = FormFieldData::RoleAttribute::kOther;
@@ -90,6 +91,7 @@
     field.form_control_type = std::string(field_template.form_control_type);
     field.is_focusable = field_template.is_focusable;
     field.max_length = field_template.max_length;
+    field.parsed_autocomplete = field_template.parsed_autocomplete;
     field.role = field_template.role;
     field.host_frame = field_template.host_form.frame_token;
     field.host_form_id = field_template.host_form.renderer_id;
@@ -883,6 +885,73 @@
                         HasTypeAndOffset(CREDIT_CARD_NUMBER, 0)));
 }
 
+struct RationalizeAutocompleteTestParam {
+  std::vector<FieldTemplate> fields;
+  std::vector<ServerFieldType> final_types;
+};
+class RationalizeAutocompleteTest
+    : public testing::Test,
+      public testing::WithParamInterface<RationalizeAutocompleteTestParam> {
+  test::AutofillUnitTestEnvironment autofill_test_environment_;
+};
+INSTANTIATE_TEST_SUITE_P(
+    RationalizeAutocompleteTest,
+    RationalizeAutocompleteTest,
+    testing::Values(
+        // <input autocomplete="additional-name" max-length=1> becomes a middle
+        // initial.
+        RationalizeAutocompleteTestParam{
+            .fields = {{.parsed_autocomplete =
+                            AutocompleteParsingResult{
+                                .field_type = HtmlFieldType::kAdditionalName},
+                        .max_length = 1}},
+            .final_types = {NAME_MIDDLE_INITIAL}},
+        // <input autocomplete="cc-exp" max-length=5> becomes a MM/YY field.
+        RationalizeAutocompleteTestParam{
+            .fields = {{.parsed_autocomplete =
+                            AutocompleteParsingResult{
+                                .field_type = HtmlFieldType::kCreditCardExp},
+                        .max_length = 5}},
+            .final_types = {CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR}},
+        // <input autocomplete="cc-exp" max-length=7> becomes a MM/YYYY field.
+        RationalizeAutocompleteTestParam{
+            .fields = {{.parsed_autocomplete =
+                            AutocompleteParsingResult{
+                                .field_type = HtmlFieldType::kCreditCardExp},
+                        .max_length = 7}},
+            .final_types = {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+        // <input autocomplete="cc-exp-year" max-length=4> becomes a YYYY field.
+        RationalizeAutocompleteTestParam{
+            .fields =
+                {{.parsed_autocomplete =
+                      AutocompleteParsingResult{
+                          .field_type = HtmlFieldType::kCreditCardExpMonth}},
+                 {.parsed_autocomplete =
+                      AutocompleteParsingResult{
+                          .field_type = HtmlFieldType::kCreditCardExpYear},
+                  .max_length = 4}},
+            .final_types = {CREDIT_CARD_EXP_MONTH,
+                            CREDIT_CARD_EXP_4_DIGIT_YEAR}},
+        // <input autocomplete="cc-exp-year" max-length=2> becomes a YY field.
+        RationalizeAutocompleteTestParam{
+            .fields =
+                {{.parsed_autocomplete =
+                      AutocompleteParsingResult{
+                          .field_type = HtmlFieldType::kCreditCardExpMonth}},
+                 {.parsed_autocomplete =
+                      AutocompleteParsingResult{
+                          .field_type = HtmlFieldType::kCreditCardExpYear},
+                  .max_length = 2}},
+            .final_types = {CREDIT_CARD_EXP_MONTH,
+                            CREDIT_CARD_EXP_2_DIGIT_YEAR}}));
+
+TEST_P(RationalizeAutocompleteTest, RationalizeAutocompleteAttribute) {
+  std::unique_ptr<FormStructure> form_structure =
+      BuildFormStructure(CreateFormAndServerClassification(GetParam().fields),
+                         /*run_heuristics=*/false);
+  EXPECT_THAT(GetTypes(*form_structure), GetParam().final_types);
+}
+
 struct RationalizationTypeRelationshipsTestParams {
   ServerFieldType server_type;
   ServerFieldType required_type;
diff --git a/components/autofill/core/browser/logging/text_log_receiver.cc b/components/autofill/core/browser/logging/text_log_receiver.cc
index 429bd02..1f0998e5 100644
--- a/components/autofill/core/browser/logging/text_log_receiver.cc
+++ b/components/autofill/core/browser/logging/text_log_receiver.cc
@@ -105,11 +105,7 @@
 }
 
 void TextLogReceiver::LogEntry(const base::Value::Dict& entry) {
-  // This is a cheap workaround because the presubmit scripts don't want us
-  // to log to INFO. Given that this is gated by a Finch feature, it should
-  // be fine.
-#define DESTINATION INFO
-  LOG(DESTINATION) << LogEntryToText(entry);
+  LOG(ERROR) << LogEntryToText(entry);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/manual_testing_import.cc b/components/autofill/core/browser/manual_testing_import.cc
index 4936d0f6..fed01dcd 100644
--- a/components/autofill/core/browser/manual_testing_import.cc
+++ b/components/autofill/core/browser/manual_testing_import.cc
@@ -75,7 +75,9 @@
 bool IsFullyStructuredProfile(const AutofillProfile& profile) {
   AutofillProfile finalized_profile = profile;
   finalized_profile.FinalizeAfterImport();
-  return profile == finalized_profile;
+  // TODO(1445454): Re-enable this check.
+  // return profile == finalized_profile;
+  return true;
 }
 
 // Extracts the `kKeySource` value of the `dict` and translates it into an
diff --git a/components/autofill/core/browser/manual_testing_import_unittest.cc b/components/autofill/core/browser/manual_testing_import_unittest.cc
index d305b2e..9af67b7 100644
--- a/components/autofill/core/browser/manual_testing_import_unittest.cc
+++ b/components/autofill/core/browser/manual_testing_import_unittest.cc
@@ -106,9 +106,7 @@
   expected_card2.SetRawInfoWithVerificationStatus(
       CREDIT_CARD_VERIFICATION_CODE, u"321", VerificationStatus::kUserVerified);
 
-  absl::optional<std::vector<CreditCard>> loaded_cards =
-      LoadCreditCardsFromFile(file_path);
-  EXPECT_THAT(loaded_cards,
+  EXPECT_THAT(LoadCreditCardsFromFile(file_path),
               testing::Optional(testing::Pointwise(
                   DataModelsCompareEqual(), {expected_card1, expected_card2})));
 }
@@ -295,9 +293,10 @@
   EXPECT_FALSE(LoadProfilesFromFile(file_path2).has_value());
 }
 
+// TODO(1445454): Re-enable this test.
 // Tests that the conversion fails for non-fully structured profiles.
 TEST_F(ManualTestingImportTest,
-       LoadProfilesFromFile_Invalid_NotFullyStructured) {
+       DISABLED_LoadProfilesFromFile_Invalid_NotFullyStructured) {
   base::FilePath file_path = GetFilePath();
   base::WriteFile(file_path, R"({
     "profiles" : [
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 57d0c70..8d10448 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1868,7 +1868,7 @@
 
 bool PersonalDataManager::IsSyncEnabledFor(
     syncer::UserSelectableType data_type) const {
-  return sync_service_ != nullptr && sync_service_->CanSyncFeatureStart() &&
+  return sync_service_ != nullptr && sync_service_->IsSyncFeatureEnabled() &&
          sync_service_->GetUserSettings()->GetSelectedTypes().Has(data_type);
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 40cc960..6d5fac76 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -2874,45 +2874,12 @@
 
 bool AutofillTable::RemoveOriginURLsModifiedBetween(
     const base::Time& delete_begin,
-    const base::Time& delete_end,
-    std::vector<std::unique_ptr<AutofillProfile>>* profiles) {
+    const base::Time& delete_end) {
   DCHECK(delete_end.is_null() || delete_begin < delete_end);
 
   time_t delete_begin_t = delete_begin.ToTimeT();
   time_t delete_end_t = GetEndTime(delete_end);
 
-  // Remember Autofill profiles with URL origins in the time range.
-  sql::Statement s_profiles_get;
-  SelectBetween(db_, s_profiles_get, kAutofillProfilesTable, {kGuid, kOrigin},
-                kDateModified, delete_begin_t, delete_end_t);
-
-  std::vector<std::string> profile_guids;
-  while (s_profiles_get.Step()) {
-    std::string guid = s_profiles_get.ColumnString(0);
-    std::string origin = s_profiles_get.ColumnString(1);
-    if (GURL(origin).is_valid())
-      profile_guids.push_back(guid);
-  }
-  if (!s_profiles_get.Succeeded())
-    return false;
-
-  // Clear out the origins for the found Autofill profiles.
-  for (const std::string& guid : profile_guids) {
-    sql::Statement s_profile;
-    UpdateBuilder(db_, s_profile, kAutofillProfilesTable, {kOrigin}, "guid=?");
-    s_profile.BindString(0, "");
-    s_profile.BindString(1, guid);
-    if (!s_profile.Run())
-      return false;
-
-    std::unique_ptr<AutofillProfile> profile =
-        GetAutofillProfile(guid, AutofillProfile::Source::kLocalOrSyncable);
-    if (!profile)
-      return false;
-
-    profiles->push_back(std::move(profile));
-  }
-
   // Remember Autofill credit cards with URL origins in the time range.
   sql::Statement s_credit_cards_get;
   SelectBetween(db_, s_credit_cards_get, kCreditCardsTable, {kGuid, kOrigin},
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index 9ba3279..264bd3d1 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -756,18 +756,11 @@
       std::vector<std::unique_ptr<AutofillProfile>>* profiles,
       std::vector<std::unique_ptr<CreditCard>>* credit_cards);
 
-  // Removes origin URLs from the autofill_profiles and credit_cards tables if
-  // they were written on or after `delete_begin` and strictly before
-  // `delete_end`. Returns the list of modified profiles in `profiles`. Return
-  // value is true if all rows were successfully updated. Returns false on
-  // database error. In that case, the output vector state is undefined, and
-  // may be partially filled.
-  // Profiles from the `contact_info` table are not considered, as they don't
-  // store an origin.
-  bool RemoveOriginURLsModifiedBetween(
-      const base::Time& delete_begin,
-      const base::Time& delete_end,
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles);
+  // Removes origin URLs from the credit_cards tables if they were written on or
+  // after `delete_begin` and strictly before `delete_end`. Returns true if all
+  // rows were successfully updated and false on a database error.
+  bool RemoveOriginURLsModifiedBetween(const base::Time& delete_begin,
+                                       const base::Time& delete_end);
 
   // Clear all profiles.
   bool ClearAutofillProfiles();
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index 9107708b..0ecd08f5 100644
--- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1665,15 +1665,8 @@
 }
 
 TEST_F(AutofillTableTest, RemoveOriginURLsModifiedBetween) {
-  // Populate the autofill_profiles and credit_cards tables.
+  // Populate the credit_cards table.
   ASSERT_TRUE(db_->GetSQLConnection()->Execute(
-      "INSERT INTO autofill_profiles (guid, origin, date_modified) "
-      "VALUES('00000000-0000-0000-0000-000000000000', '', 11);"
-      "INSERT INTO autofill_profiles (guid, origin, date_modified) "
-      "VALUES('00000000-0000-0000-0000-000000000001', "
-      "       'https://www.example.com/', 21);"
-      "INSERT INTO autofill_profiles (guid, origin, date_modified) "
-      "VALUES('00000000-0000-0000-0000-000000000002', 'Chrome settings', 31);"
       "INSERT INTO credit_cards (guid, origin, date_modified) "
       "VALUES('00000000-0000-0000-0000-000000000003', '', 17);"
       "INSERT INTO credit_cards (guid, origin, date_modified) "
@@ -1684,24 +1677,8 @@
       "       37);"));
 
   // Remove all origin URLs set in the bounded time range [21,27).
-  std::vector<std::unique_ptr<AutofillProfile>> profiles;
   table_->RemoveOriginURLsModifiedBetween(Time::FromTimeT(21),
-                                          Time::FromTimeT(27), &profiles);
-  ASSERT_EQ(1UL, profiles.size());
-  EXPECT_EQ("00000000-0000-0000-0000-000000000001", profiles[0]->guid());
-  sql::Statement s_autofill_profiles_bounded(
-      db_->GetSQLConnection()->GetUniqueStatement(
-          "SELECT date_modified, origin FROM autofill_profiles"));
-  ASSERT_TRUE(s_autofill_profiles_bounded.is_valid());
-  ASSERT_TRUE(s_autofill_profiles_bounded.Step());
-  EXPECT_EQ(11, s_autofill_profiles_bounded.ColumnInt64(0));
-  EXPECT_EQ(std::string(), s_autofill_profiles_bounded.ColumnString(1));
-  ASSERT_TRUE(s_autofill_profiles_bounded.Step());
-  EXPECT_EQ(21, s_autofill_profiles_bounded.ColumnInt64(0));
-  EXPECT_EQ(std::string(), s_autofill_profiles_bounded.ColumnString(1));
-  ASSERT_TRUE(s_autofill_profiles_bounded.Step());
-  EXPECT_EQ(31, s_autofill_profiles_bounded.ColumnInt64(0));
-  EXPECT_EQ(kSettingsOrigin, s_autofill_profiles_bounded.ColumnString(1));
+                                          Time::FromTimeT(27));
   sql::Statement s_credit_cards_bounded(
       db_->GetSQLConnection()->GetUniqueStatement(
           "SELECT date_modified, origin FROM credit_cards"));
@@ -1717,22 +1694,7 @@
   EXPECT_EQ(kSettingsOrigin, s_credit_cards_bounded.ColumnString(1));
 
   // Remove all origin URLS.
-  profiles.clear();
-  table_->RemoveOriginURLsModifiedBetween(Time(), Time(), &profiles);
-  EXPECT_EQ(0UL, profiles.size());
-  sql::Statement s_autofill_profiles_all(
-      db_->GetSQLConnection()->GetUniqueStatement(
-          "SELECT date_modified, origin FROM autofill_profiles"));
-  ASSERT_TRUE(s_autofill_profiles_all.is_valid());
-  ASSERT_TRUE(s_autofill_profiles_all.Step());
-  EXPECT_EQ(11, s_autofill_profiles_all.ColumnInt64(0));
-  EXPECT_EQ(std::string(), s_autofill_profiles_all.ColumnString(1));
-  ASSERT_TRUE(s_autofill_profiles_all.Step());
-  EXPECT_EQ(21, s_autofill_profiles_all.ColumnInt64(0));
-  EXPECT_EQ(std::string(), s_autofill_profiles_all.ColumnString(1));
-  ASSERT_TRUE(s_autofill_profiles_all.Step());
-  EXPECT_EQ(31, s_autofill_profiles_all.ColumnInt64(0));
-  EXPECT_EQ(kSettingsOrigin, s_autofill_profiles_all.ColumnString(1));
+  table_->RemoveOriginURLsModifiedBetween(Time(), Time());
   sql::Statement s_credit_cards_all(db_->GetSQLConnection()->GetUniqueStatement(
       "SELECT date_modified, origin FROM credit_cards"));
   ASSERT_TRUE(s_credit_cards_all.is_valid());
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 79bcc8b..d42c52b 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -725,18 +725,10 @@
     const base::Time& delete_end,
     WebDatabase* db) {
   DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
-  std::vector<std::unique_ptr<AutofillProfile>> profiles;
   if (!AutofillTable::FromWebDatabase(db)->RemoveOriginURLsModifiedBetween(
-          delete_begin, delete_end, &profiles)) {
+          delete_begin, delete_end)) {
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
-
-  for (const auto& profile : profiles) {
-    AutofillProfileChange change(AutofillProfileChange::UPDATE, profile->guid(),
-                                 profile.get());
-    for (auto& db_observer : db_observer_list_)
-      db_observer.AutofillProfileChanged(change);
-  }
   // Note: It is the caller's responsibility to post notifications for any
   // changes, e.g. by calling the Refresh() method of PersonalDataManager.
   return WebDatabase::COMMIT_NEEDED;
diff --git a/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index e010d31..394b5dd 100644
--- a/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -48,29 +48,30 @@
 namespace {
 
 template <class T>
-class AutofillWebDataServiceConsumer : public WebDataServiceConsumer {
+class AutofillWebDataServiceWaiter : public WebDataServiceConsumer {
  public:
-  AutofillWebDataServiceConsumer() : handle_(0) {}
+  AutofillWebDataServiceWaiter() = default;
 
-  AutofillWebDataServiceConsumer(const AutofillWebDataServiceConsumer&) =
+  AutofillWebDataServiceWaiter(const AutofillWebDataServiceWaiter&) = delete;
+  AutofillWebDataServiceWaiter& operator=(const AutofillWebDataServiceWaiter&) =
       delete;
-  AutofillWebDataServiceConsumer& operator=(
-      const AutofillWebDataServiceConsumer&) = delete;
 
-  virtual ~AutofillWebDataServiceConsumer() {}
-
-  virtual void OnWebDataServiceRequestDone(
-      WebDataServiceBase::Handle handle,
-      std::unique_ptr<WDTypedResult> result) {
-    handle_ = handle;
-    result_ = std::move(static_cast<WDResult<T>*>(result.get())->GetValue());
+  WebDataServiceBase::Handle WaitForHandle() {
+    run_loop_.Run();
+    return handle_;
   }
-
-  WebDataServiceBase::Handle handle() { return handle_; }
   T& result() { return result_; }
 
  private:
-  WebDataServiceBase::Handle handle_;
+  void OnWebDataServiceRequestDone(
+      WebDataServiceBase::Handle handle,
+      std::unique_ptr<WDTypedResult> result) final {
+    handle_ = handle;
+    result_ = std::move(static_cast<WDResult<T>*>(result.get())->GetValue());
+    run_loop_.Quit();
+  }
+  WebDataServiceBase::Handle handle_ = 0;
+  base::RunLoop run_loop_;
   T result_;
 };
 
@@ -100,7 +101,13 @@
 class WebDataServiceTest : public testing::Test {
  public:
   WebDataServiceTest()
-      : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {}
+      : task_environment_(base::test::TaskEnvironment::MainThreadType::UI),
+        // TODO(pkasting): http://crbug.com/740773 This should likely be
+        // sequenced, not single-threaded; it's also possible the various uses
+        // of this below should each use their own sequences instead of sharing
+        // this one.
+        db_task_runner_(base::ThreadPool::CreateSingleThreadTaskRunner(
+            {base::MayBlock()})) {}
 
  protected:
   void SetUp() override {
@@ -108,36 +115,34 @@
     // OSCrypt is used for encryption of credit card data in this test.
     OSCryptMocker::SetUp();
 
-    // TODO(pkasting): http://crbug.com/740773 This should likely be sequenced,
-    // not single-threaded; it's also possible the various uses of this below
-    // should each use their own sequences instead of sharing this one.
-    auto db_task_runner =
-        base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()});
     wdbs_ = new WebDatabaseService(
         path, base::SingleThreadTaskRunner::GetCurrentDefault(),
-        db_task_runner);
+        db_task_runner_);
     wdbs_->AddTable(std::make_unique<AutofillTable>());
     wdbs_->LoadDatabase();
 
     wds_ = new AutofillWebDataService(
         wdbs_, base::SingleThreadTaskRunner::GetCurrentDefault(),
-        db_task_runner);
+        db_task_runner_);
     wds_->Init(base::NullCallback());
   }
 
   void TearDown() override {
     wds_->ShutdownOnUISequence();
     wdbs_->ShutdownDatabase();
-    wds_ = nullptr;
-    wdbs_ = nullptr;
-    task_environment_.RunUntilIdle();
+    base::RunLoop run_loop;
+    // Drain the db_task_runner.
+    db_task_runner_->PostTaskAndReply(FROM_HERE, base::BindOnce([]() {}),
+                                      run_loop.QuitClosure());
+    run_loop.Run();
     OSCryptMocker::TearDown();
   }
 
   base::test::TaskEnvironment task_environment_;
   base::FilePath profile_dir_;
-  scoped_refptr<AutofillWebDataService> wds_;
+  scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
   scoped_refptr<WebDatabaseService> wdbs_;
+  scoped_refptr<AutofillWebDataService> wds_;
 };
 
 class WebDataServiceAutofillTest : public WebDataServiceTest {
@@ -213,13 +218,12 @@
   // The event will be signaled when the mock observer is notified.
   done_event_.TimedWait(test_timeout_);
 
-  AutofillWebDataServiceConsumer<std::vector<AutofillEntry>> consumer;
+  AutofillWebDataServiceWaiter<std::vector<AutofillEntry>> consumer;
   WebDataServiceBase::Handle handle;
   static const int limit = 10;
   handle = wds_->GetFormValuesForElementName(name1_, std::u16string(), limit,
                                              &consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(1U, consumer.result().size());
   EXPECT_EQ(value1_, consumer.result()[0].key().value());
 }
@@ -290,12 +294,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(1U, consumer.result().size());
   EXPECT_EQ(profile, *consumer.result()[0]);
 }
@@ -310,12 +313,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(1U, consumer.result().size());
   EXPECT_EQ(profile, *consumer.result()[0]);
 
@@ -331,12 +333,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that it was removed.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       consumer2;
   WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, consumer2.handle());
+  EXPECT_EQ(handle2, consumer2.WaitForHandle());
   ASSERT_EQ(0U, consumer2.result().size());
 }
 
@@ -359,12 +360,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that they were added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(2U, consumer.result().size());
   EXPECT_EQ(profile2, *consumer.result()[0]);
   EXPECT_EQ(profile1, *consumer.result()[1]);
@@ -382,12 +382,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that the updates were made.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       consumer2;
   WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, consumer2.handle());
+  EXPECT_EQ(handle2, consumer2.WaitForHandle());
   ASSERT_EQ(2U, consumer2.result().size());
   EXPECT_EQ(profile2_changed, *consumer2.result()[0]);
   EXPECT_NE(profile2, *consumer2.result()[0]);
@@ -399,11 +398,10 @@
   wds_->AddCreditCard(card);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(1U, consumer.result().size());
   EXPECT_EQ(card, *consumer.result()[0]);
 }
@@ -415,11 +413,10 @@
   wds_->AddCreditCard(credit_card);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(1U, consumer.result().size());
   EXPECT_EQ(credit_card, *consumer.result()[0]);
 
@@ -427,11 +424,10 @@
   wds_->RemoveCreditCard(credit_card.guid());
 
   // Check that it was removed.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       consumer2;
   WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, consumer2.handle());
+  EXPECT_EQ(handle2, consumer2.WaitForHandle());
   ASSERT_EQ(0U, consumer2.result().size());
 }
 
@@ -445,11 +441,10 @@
   wds_->AddCreditCard(card2);
 
   // Check that they got added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       consumer;
   WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, consumer.handle());
+  EXPECT_EQ(handle, consumer.WaitForHandle());
   ASSERT_EQ(2U, consumer.result().size());
   EXPECT_EQ(card2, *consumer.result()[0]);
   EXPECT_EQ(card1, *consumer.result()[1]);
@@ -460,11 +455,10 @@
   wds_->UpdateCreditCard(card2_changed);
 
   // Check that the updates were made.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       consumer2;
   WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, consumer2.handle());
+  EXPECT_EQ(handle2, consumer2.WaitForHandle());
   ASSERT_EQ(2U, consumer2.result().size());
   EXPECT_NE(card2, *consumer2.result()[0]);
   EXPECT_EQ(card2_changed, *consumer2.result()[0]);
@@ -480,12 +474,11 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       profile_consumer;
   WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &profile_consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, profile_consumer.handle());
+  EXPECT_EQ(handle, profile_consumer.WaitForHandle());
   ASSERT_EQ(1U, profile_consumer.result().size());
   EXPECT_EQ(profile, *profile_consumer.result()[0]);
 
@@ -494,11 +487,10 @@
   wds_->AddCreditCard(credit_card);
 
   // Check that it was added.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       card_consumer;
   handle = wds_->GetCreditCards(&card_consumer);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle, card_consumer.handle());
+  EXPECT_EQ(handle, card_consumer.WaitForHandle());
   ASSERT_EQ(1U, card_consumer.result().size());
   EXPECT_EQ(credit_card, *card_consumer.result()[0]);
 
@@ -513,20 +505,18 @@
   done_event_.TimedWait(test_timeout_);
 
   // Check that the profile was removed.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<AutofillProfile>>>
       profile_consumer2;
   WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(
       AutofillProfile::Source::kLocalOrSyncable, &profile_consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, profile_consumer2.handle());
+  EXPECT_EQ(handle2, profile_consumer2.WaitForHandle());
   ASSERT_EQ(0U, profile_consumer2.result().size());
 
   // Check that the credit card was removed.
-  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
+  AutofillWebDataServiceWaiter<std::vector<std::unique_ptr<CreditCard>>>
       card_consumer2;
   handle2 = wds_->GetCreditCards(&card_consumer2);
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(handle2, card_consumer2.handle());
+  EXPECT_EQ(handle2, card_consumer2.WaitForHandle());
   ASSERT_EQ(0U, card_consumer2.result().size());
 }
 
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index ae49684..108b20a 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -566,6 +566,23 @@
     Manage payment methods
   </message>
 
+  <!-- Mandatory Reauth related strings - start -->
+  <message name="IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_NO_THANKS" desc="Text for the cancel button in the mandatory reauth opt-in prompt. If the user clicks this button, mandatory reauth will not be enabled. Mandatory reauth requires the user to unlock their device or pass a biometric auth when autofilling payment method information.">
+    No Thanks
+  </message>
+  <message name="IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_ACCEPT" desc="Text for the accept button in the mandatory reauth opt-in prompt. If the user clicks this button, mandatory reauth will be enabled. Mandatory reauth requires the user to unlock their device or pass a biometric auth when autofilling payment method information.">
+    Yes
+  </message>
+  <message name="IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_TITLE" desc="Title text for the mandatory reauth opt-in prompt that is displayed to the user after filling in payment method information. Mandatory reauth requires the user to unlock their device or pass a biometric auth when autofilling payment method information.">
+    Always verify?
+  </message>
+  <message name="IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_EXPLANATION" desc="Explanation text for the mandatory reauth opt-in prompt that is displayed to the user after filling in payment method information. Mandatory reauth requires the user to unlock their device or pass a biometric auth when autofilling payment method information.">
+    For added security on shared devices, turn on verification every time you pay using autofill.
+  </message>
+  <message name="IDS_AUTOFILL_MANDATORY_REAUTH_ICON_TOOLTIP" desc="The tooltip message for the omnibox icon for the mandatory reauth opt-in bubble on Desktop. This bubble prompts users if they would like to enroll in mandatory reauth. Mandatory reauth requires the user to unlock their device or pass a biometric auth when autofilling payment method information.">
+    Enable mandatory re-authentication
+  </message>
+
   <!-- virtual cards related strings - start -->
   <if expr="not is_ios and not is_android">
     <message name="IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL" desc="Text shown in the button in the Autofill dropdown menu when a credit card form field is queried, to offer the option to use a virtual card.">
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_ICON_TOOLTIP.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_ICON_TOOLTIP.png.sha1
new file mode 100644
index 0000000..c5a2bc8
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_ICON_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+93c07e78eb26dde8c8af464dfaf4b70931a5ffab
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_ACCEPT.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_ACCEPT.png.sha1
new file mode 100644
index 0000000..13333fb
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_ACCEPT.png.sha1
@@ -0,0 +1 @@
+49b48998884871826cb354584d396116f9125491
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_EXPLANATION.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_EXPLANATION.png.sha1
new file mode 100644
index 0000000..13333fb
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+49b48998884871826cb354584d396116f9125491
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_NO_THANKS.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_NO_THANKS.png.sha1
new file mode 100644
index 0000000..13333fb
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_NO_THANKS.png.sha1
@@ -0,0 +1 @@
+49b48998884871826cb354584d396116f9125491
\ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_TITLE.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_TITLE.png.sha1
new file mode 100644
index 0000000..13333fb
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_MANDATORY_REAUTH_OPT_IN_TITLE.png.sha1
@@ -0,0 +1 @@
+49b48998884871826cb354584d396116f9125491
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
index 8c4865aa..6353ea21 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">Beskermde inhoud</translation>
 <translation id="662080504995468778">Bly</translation>
 <translation id="6643016212128521049">Vee uit</translation>
+<translation id="6653342741369270081">Druk die terugknoppie om volskerm te verlaat.</translation>
 <translation id="6689172468748959065">Profielfoto's</translation>
 <translation id="6697925417670533197">Aktiewe aflaaie</translation>
 <translation id="6722828510648505498">Blokkeer aanmeldporboodskappe van identiteitsdienste af.</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
index 787b919..2234bcb 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">ጥበቃ የሚደረግለት ይዘት</translation>
 <translation id="662080504995468778">ቆይ</translation>
 <translation id="6643016212128521049">አጽዳ</translation>
+<translation id="6653342741369270081">ከሙሉ ማያ ገጽ ለመውጣት የተመለስ አዝራሩን ይጫኑ።</translation>
 <translation id="6689172468748959065">የመገለጫ ፎቶዎች</translation>
 <translation id="6697925417670533197">ንቁ ውርዶች</translation>
 <translation id="6722828510648505498">የመግቢያ መጠይቆችን ከማንነት አገልግሎቶች ያግዱ።</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
index 00f5f5d..26e6b037 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
@@ -12,7 +12,7 @@
 <translation id="1272079795634619415">Stop</translation>
 <translation id="1289742167380433257">Billederne på denne side er blevet optimeret af Google, så du sparer data.</translation>
 <translation id="129382876167171263">Filer, der gemmes af websites, vises her</translation>
-<translation id="131112695174432497">Data, der påvirker personlig annoncetilpasning, slettes</translation>
+<translation id="131112695174432497">Data, der påvirker personlig tilpasning af annoncer, slettes</translation>
 <translation id="1317194122196776028">Glem dette website</translation>
 <translation id="1343356790768851700">Dette website foretager en vurdering af, hvad du kan lide, og foreslår derefter annoncer til andre websites</translation>
 <translation id="1369915414381695676">Websitet <ph name="SITE_NAME" /> blev tilføjet</translation>
@@ -187,7 +187,7 @@
 <translation id="4338831206024587507">Alle websites på <ph name="DOMAIN" /></translation>
 <translation id="4402755511846832236">Bloker websites fra at vide, hvornår du aktivt bruger denne enhed</translation>
 <translation id="4412992751769744546">Tillad tredjepartscookies</translation>
-<translation id="4428065317363009941">Annoncetilpasning</translation>
+<translation id="4428065317363009941">Personlig tilpasning af annoncer</translation>
 <translation id="4434045419905280838">Pop op-vinduer og omdirigeringer</translation>
 <translation id="4440642537584213025">Udvid <ph name="TARGET_DESCRIPTION" /></translation>
 <translation id="4468959413250150279">Slå lyden fra for et bestemt website.</translation>
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">Beskyttet indhold</translation>
 <translation id="662080504995468778">Bliv her</translation>
 <translation id="6643016212128521049">Ryd</translation>
+<translation id="6653342741369270081">Tryk på knappen Tilbage for at afslutte fuld skærm.</translation>
 <translation id="6689172468748959065">Profilbilleder</translation>
 <translation id="6697925417670533197">Aktive downloads</translation>
 <translation id="6722828510648505498">Bloker loginmeddelelser fra identitetstjenester</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
index b54ba1c..55e0eb2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">ເນື້ອ​ໃນ​ທີ່ຖືກ​ປົກ​ປ້ອງ</translation>
 <translation id="662080504995468778">ຢູ່ຕໍ່</translation>
 <translation id="6643016212128521049">ລຶບ</translation>
+<translation id="6653342741369270081">ກົດປຸ່ມກັບຄືນເພື່ອອອກຈາກໂໝດເຕັມຈໍ.</translation>
 <translation id="6689172468748959065">ຮູບໂປຣໄຟລ໌</translation>
 <translation id="6697925417670533197">ການດາວໂຫຼດທີ່ດຳເນີນຢູ່</translation>
 <translation id="6722828510648505498">ບລັອກຂໍ້ຄວາມການເຂົ້າສູ່ລະບົບຈາກບໍລິການຕົວຕົນຕ່າງໆ.</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
index 16bf77e..0685ba6 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">संरक्षित सामग्री</translation>
 <translation id="662080504995468778">यहीँ रहनुहोस्</translation>
 <translation id="6643016212128521049">खालि गर्नुहोस्</translation>
+<translation id="6653342741369270081">फुल स्क्रिनबाट बाहिरिन "पछाडि जानुहोस्" बटन थिच्नुहोस्।</translation>
 <translation id="6689172468748959065">प्रोफाइल तस्बिरहरू</translation>
 <translation id="6697925417670533197">जारी डाउनलोडहरू</translation>
 <translation id="6722828510648505498">पहिचान सेवा प्रदायकहरूबाट प्राप्त साइन इन गर्ने प्रम्प्टहरू ब्लक गरियोस्।</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
index e08fc2ee..151e9a46 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">రక్షిత కంటెంట్</translation>
 <translation id="662080504995468778">ఇందులోనే ఉంచు</translation>
 <translation id="6643016212128521049">క్లియర్ చేయండి</translation>
+<translation id="6653342741369270081">ఫుల్ స్క్రీన్ నుండి నిష్క్రమించడానికి వెనుకకు బటన్‌ను నొక్కండి.</translation>
 <translation id="6689172468748959065">ప్రొఫైల్ ఫోటోలు</translation>
 <translation id="6697925417670533197">యాక్టివ్‌గా ఉన్న డౌన్‌లోడ్‌లు</translation>
 <translation id="6722828510648505498">గుర్తింపు సర్వీస్‌ల నుండి సైన్-ఇన్ ప్రాంప్ట్‌లను బ్లాక్ చేయండి.</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
index f3df61fe..f831e4cd 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">Himoyalangan kontent</translation>
 <translation id="662080504995468778">Qolaman</translation>
 <translation id="6643016212128521049">Tozalash</translation>
+<translation id="6653342741369270081">To‘liq ekran rejimidan chiqish uchun orqaga tugmasini bosing.</translation>
 <translation id="6689172468748959065">Profil rasmlari</translation>
 <translation id="6697925417670533197">Faol yuklanmalar</translation>
 <translation id="6722828510648505498">Shaxsni tasdiqlash xizmatlariga kirish oynalarini bloklash</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
index a4e059c..fbac21c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
@@ -311,6 +311,7 @@
 <translation id="6612358246767739896">Okuqukethwe okuvikelekile</translation>
 <translation id="662080504995468778">Hlala</translation>
 <translation id="6643016212128521049">Sula</translation>
+<translation id="6653342741369270081">Cindezela inkinobho yokubuyela emuva ukuze uphume kusikrini esigcwele.</translation>
 <translation id="6689172468748959065">Izithombe zephrofayela</translation>
 <translation id="6697925417670533197">Ukulanda okusebenzayo</translation>
 <translation id="6722828510648505498">Vimba imiyalo yokungena ngemvume evela kumasevisi kamazisi.</translation>
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index a68f338..513520c 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "20.67",
-  "log_list_timestamp": "2023-05-09T12:54:01Z",
+  "version": "20.72",
+  "log_list_timestamp": "2023-05-14T12:55:17Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/cloud_devices/common/description_items.h b/components/cloud_devices/common/description_items.h
index d7be62e4..1b0393a 100644
--- a/components/cloud_devices/common/description_items.h
+++ b/components/cloud_devices/common/description_items.h
@@ -71,11 +71,13 @@
 
   void AddOption(Option&& option) { options_.emplace_back(std::move(option)); }
 
-  OptionVector::iterator begin() { return options_.begin(); }
-  OptionVector::const_iterator begin() const { return options_.begin(); }
+  typename OptionVector::iterator begin() { return options_.begin(); }
+  typename OptionVector::const_iterator begin() const {
+    return options_.begin();
+  }
 
-  OptionVector::iterator end() { return options_.end(); }
-  OptionVector::const_iterator end() const { return options_.end(); }
+  typename OptionVector::iterator end() { return options_.end(); }
+  typename OptionVector::const_iterator end() const { return options_.end(); }
 
   // Returns JSON path for this item relative to the root of the CDD.
   virtual std::string GetPath() const;
diff --git a/components/commerce/core/flag_descriptions.cc b/components/commerce/core/flag_descriptions.cc
index af3b9563..a3d947a 100644
--- a/components/commerce/core/flag_descriptions.cc
+++ b/components/commerce/core/flag_descriptions.cc
@@ -23,6 +23,9 @@
 const char kChromeCartDomBasedHeuristicsDescription[] =
     "Enable DOM-based heuristics for ChromeCart.";
 
+const char kPriceInsightsName[] = "Price Insights";
+const char kPriceInsightsDescription[] = "Enable price insights experiment.";
+
 const char kPriceTrackingChipExperimentName[] =
     "Price Tracking Chip Experiment";
 const char kPriceTrackingChipExperimentDescription[] =
diff --git a/components/commerce/core/flag_descriptions.h b/components/commerce/core/flag_descriptions.h
index d461e402..6ce3561 100644
--- a/components/commerce/core/flag_descriptions.h
+++ b/components/commerce/core/flag_descriptions.h
@@ -22,6 +22,9 @@
 extern const char kChromeCartDomBasedHeuristicsName[];
 extern const char kChromeCartDomBasedHeuristicsDescription[];
 
+extern const char kPriceInsightsName[];
+extern const char kPriceInsightsDescription[];
+
 extern const char kPriceTrackingChipExperimentName[];
 extern const char kPriceTrackingChipExperimentDescription[];
 
diff --git a/components/content_settings/core/browser/content_settings_default_provider.cc b/components/content_settings/core/browser/content_settings_default_provider.cc
index 33772c4..219ba4f 100644
--- a/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -93,11 +93,12 @@
 
   bool HasNext() const override { return !is_done_; }
 
-  Rule Next() override {
+  std::unique_ptr<Rule> Next() override {
     DCHECK(HasNext());
     is_done_ = true;
-    return Rule(ContentSettingsPattern::Wildcard(),
-                ContentSettingsPattern::Wildcard(), std::move(value_), {});
+    return std::make_unique<OwnedRule>(ContentSettingsPattern::Wildcard(),
+                                       ContentSettingsPattern::Wildcard(),
+                                       std::move(value_), RuleMetaData{});
   }
 
  private:
diff --git a/components/content_settings/core/browser/content_settings_global_value_map.cc b/components/content_settings/core/browser/content_settings_global_value_map.cc
index 0590e02..0abb5c39 100644
--- a/components/content_settings/core/browser/content_settings_global_value_map.cc
+++ b/components/content_settings/core/browser/content_settings_global_value_map.cc
@@ -24,11 +24,12 @@
 
   bool HasNext() const override { return !is_done_; }
 
-  Rule Next() override {
+  std::unique_ptr<Rule> Next() override {
     DCHECK(HasNext());
     is_done_ = true;
-    return Rule(ContentSettingsPattern::Wildcard(),
-                ContentSettingsPattern::Wildcard(), base::Value(setting_), {});
+    return std::make_unique<OwnedRule>(ContentSettingsPattern::Wildcard(),
+                                       ContentSettingsPattern::Wildcard(),
+                                       base::Value(setting_), RuleMetaData{});
   }
 
  private:
diff --git a/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc b/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
index ebff3d79..c7e7835 100644
--- a/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
+++ b/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
@@ -10,6 +10,7 @@
 #include "base/auto_reset.h"
 #include "base/check_op.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/synchronization/lock.h"
 #include "base/values.h"
 #include "components/content_settings/core/browser/content_settings_rule.h"
@@ -27,7 +28,7 @@
   RuleIteratorImpl(
       const OriginIdentifierValueMap::Rules::const_iterator& current_rule,
       const OriginIdentifierValueMap::Rules::const_iterator& rule_end,
-      std::unique_ptr<base::AutoLock> auto_lock,
+      scoped_refptr<RefCountedAutoLock> auto_lock,
       base::AutoReset<bool> iterating)
       : current_rule_(current_rule),
         rule_end_(rule_end),
@@ -37,12 +38,12 @@
 
   bool HasNext() const override { return (current_rule_ != rule_end_); }
 
-  Rule Next() override {
+  std::unique_ptr<Rule> Next() override {
     DCHECK(HasNext());
-    Rule to_return(current_rule_->first.primary_pattern,
-                   current_rule_->first.secondary_pattern,
-                   current_rule_->second.value.Clone(),
-                   current_rule_->second.metadata);
+    auto to_return = std::make_unique<UnownedRule>(
+        current_rule_->first.primary_pattern,
+        current_rule_->first.secondary_pattern, &current_rule_->second.value,
+        auto_lock_, current_rule_->second.metadata);
     ++current_rule_;
     return to_return;
   }
@@ -50,7 +51,7 @@
  private:
   OriginIdentifierValueMap::Rules::const_iterator current_rule_;
   OriginIdentifierValueMap::Rules::const_iterator rule_end_;
-  std::unique_ptr<base::AutoLock> auto_lock_;
+  scoped_refptr<RefCountedAutoLock> auto_lock_;
   base::AutoReset<bool> iterating_;
 };
 
@@ -80,8 +81,8 @@
   // must be passed to the |RuleIteratorImpl| in a locked state, so that nobody
   // can access |entries_| after |find()| but before the |RuleIteratorImpl| is
   // created.
-  std::unique_ptr<base::AutoLock> auto_lock =
-      std::make_unique<base::AutoLock>(lock_);
+  scoped_refptr<RefCountedAutoLock> auto_lock =
+      MakeRefCounted<RefCountedAutoLock>(lock_);
   auto it = entries_.find(content_type);
   if (it == entries_.end()) {
     return nullptr;
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc
index 498240d..fa92ce58 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -251,19 +251,26 @@
     return false;
   }
 
-  Rule rule;
   while (it->HasNext()) {
-    rule = it->Next();
-    if (rule.primary_pattern == primary_pattern &&
-        rule.secondary_pattern == secondary_pattern) {
+    std::unique_ptr<Rule> rule = it->Next();
+    if (rule->primary_pattern == primary_pattern &&
+        rule->secondary_pattern == secondary_pattern) {
       // This should only be updated for settings that are already tracked.
-      DCHECK(rule.metadata.last_visited != base::Time());
-      // Reset iterator to release lock before updating setting.
+      DCHECK(rule->metadata.last_visited != base::Time());
+
+      ContentSettingsPattern primary = std::move(rule->primary_pattern);
+      ContentSettingsPattern secondary = std::move(rule->secondary_pattern);
+      base::Value value = rule->TakeValue();
+      RuleMetaData metadata = std::move(rule->metadata);
+      metadata.last_visited = time;
+
+      // Reset iterator and Rule to release lock before updating setting.
       it.reset();
-      rule.metadata.last_visited = time;
+      rule.reset();
+
       GetPref(content_type)
-          ->SetWebsiteSetting(rule.primary_pattern, rule.secondary_pattern,
-                              std::move(rule.value), std::move(rule.metadata));
+          ->SetWebsiteSetting(std::move(primary), std::move(secondary),
+                              std::move(value), std::move(metadata));
       return true;
     }
   }
diff --git a/components/content_settings/core/browser/content_settings_pref_unittest.cc b/components/content_settings/core/browser/content_settings_pref_unittest.cc
index 0f0131cd..65b7601 100644
--- a/components/content_settings/core/browser/content_settings_pref_unittest.cc
+++ b/components/content_settings/core/browser/content_settings_pref_unittest.cc
@@ -143,8 +143,8 @@
   while (rule_iterator->HasNext()) {
     auto rule = rule_iterator->Next();
     patterns_to_tags_in_memory.emplace_back(
-        CreatePatternString(rule.primary_pattern, rule.secondary_pattern),
-        GetTagFromDummyContentSetting(rule.value.GetDict()));
+        CreatePatternString(rule->primary_pattern, rule->secondary_pattern),
+        GetTagFromDummyContentSetting(rule->value().GetDict()));
   }
 
   EXPECT_THAT(patterns_to_tags_in_memory,
@@ -211,8 +211,8 @@
   while (rule_iterator->HasNext()) {
     auto rule = rule_iterator->Next();
     patterns_to_tags_in_memory.emplace_back(
-        CreatePatternString(rule.primary_pattern, rule.secondary_pattern),
-        GetTagFromDummyContentSetting(rule.value.GetDict()));
+        CreatePatternString(rule->primary_pattern, rule->secondary_pattern),
+        GetTagFromDummyContentSetting(rule->value().GetDict()));
   }
 
   EXPECT_THAT(patterns_to_tags_in_memory,
@@ -268,7 +268,7 @@
   // still parsed correctly.
   EXPECT_EQ(content_settings_pref.GetNumExceptions(), 1u);
   auto it = content_settings_pref.GetRuleIterator(false);
-  base::Time retrieved_last_modified = it->Next().metadata.last_modified;
+  base::Time retrieved_last_modified = it->Next()->metadata.last_modified;
   EXPECT_EQ(last_modified, retrieved_last_modified);
 }
 
diff --git a/components/content_settings/core/browser/content_settings_rule.cc b/components/content_settings/core/browser/content_settings_rule.cc
index 09f1eaa..b13e2294 100644
--- a/components/content_settings/core/browser/content_settings_rule.cc
+++ b/components/content_settings/core/browser/content_settings_rule.cc
@@ -10,23 +10,54 @@
 
 namespace content_settings {
 
-Rule::Rule() = default;
+RefCountedAutoLock::RefCountedAutoLock(base::Lock& lock) : auto_lock_(lock) {}
+RefCountedAutoLock::~RefCountedAutoLock() = default;
 
 Rule::Rule(const ContentSettingsPattern& primary_pattern,
            const ContentSettingsPattern& secondary_pattern,
-           base::Value value,
            const RuleMetaData& metadata)
     : primary_pattern(primary_pattern),
       secondary_pattern(secondary_pattern),
-      value(std::move(value)),
       metadata(metadata) {}
 
-Rule::Rule(Rule&& other) = default;
-
-Rule& Rule::operator=(Rule&& other) = default;
-
 Rule::~Rule() = default;
 
+UnownedRule::UnownedRule(const ContentSettingsPattern& primary_pattern,
+                         const ContentSettingsPattern& secondary_pattern,
+                         const base::Value* unowned_value,
+                         scoped_refptr<RefCountedAutoLock> value_lock,
+                         const RuleMetaData& metadata)
+    : Rule(primary_pattern, secondary_pattern, metadata),
+      unowned_value(unowned_value),
+      value_lock(value_lock) {}
+
+UnownedRule::~UnownedRule() = default;
+
+const base::Value& UnownedRule::value() const {
+  return *unowned_value;
+}
+
+base::Value UnownedRule::TakeValue() {
+  return unowned_value->Clone();
+}
+
+OwnedRule::OwnedRule(const ContentSettingsPattern& primary_pattern,
+                     const ContentSettingsPattern& secondary_pattern,
+                     base::Value owned_value,
+                     const RuleMetaData& metadata)
+    : Rule(primary_pattern, secondary_pattern, metadata),
+      owned_value(std::move(owned_value)) {}
+
+OwnedRule::~OwnedRule() = default;
+
+const base::Value& OwnedRule::value() const {
+  return owned_value;
+}
+
+base::Value OwnedRule::TakeValue() {
+  return std::move(owned_value);
+}
+
 RuleIterator::~RuleIterator() = default;
 
 ConcatenationIterator::ConcatenationIterator(
@@ -47,16 +78,15 @@
   return !iterators_.empty();
 }
 
-Rule ConcatenationIterator::Next() {
+std::unique_ptr<Rule> ConcatenationIterator::Next() {
   auto current_iterator = iterators_.begin();
   DCHECK(current_iterator != iterators_.end());
   DCHECK((*current_iterator)->HasNext());
-  const Rule& next_rule = (*current_iterator)->Next();
-  Rule to_return(next_rule.primary_pattern, next_rule.secondary_pattern,
-                 next_rule.value.Clone(), next_rule.metadata);
-  if (!(*current_iterator)->HasNext())
+  std::unique_ptr<Rule> next_rule = (*current_iterator)->Next();
+  if (!(*current_iterator)->HasNext()) {
     iterators_.erase(current_iterator);
-  return to_return;
+  }
+  return next_rule;
 }
 
 }  // namespace content_settings
diff --git a/components/content_settings/core/browser/content_settings_rule.h b/components/content_settings/core/browser/content_settings_rule.h
index d4cc99a3..846e36b0 100644
--- a/components/content_settings/core/browser/content_settings_rule.h
+++ b/components/content_settings/core/browser/content_settings_rule.h
@@ -11,6 +11,8 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -20,32 +22,84 @@
 
 namespace content_settings {
 
+class SCOPED_LOCKABLE RefCountedAutoLock
+    : public base::RefCounted<RefCountedAutoLock> {
+ public:
+  explicit RefCountedAutoLock(base::Lock& lock);
+
+ protected:
+  virtual ~RefCountedAutoLock();
+
+ private:
+  friend class base::RefCounted<RefCountedAutoLock>;
+
+  base::AutoLock auto_lock_;
+};
+
+// Note that Rules and their iterators must be destroyed before modifying the
+// map that their values come from, as some types of rules hold locks on the map
+// that owns their value. See UnownedRule and OriginIdentifierValueMap.
 struct Rule {
-  Rule();
   Rule(const ContentSettingsPattern& primary_pattern,
        const ContentSettingsPattern& secondary_pattern,
-       base::Value value,
        const RuleMetaData& metadata);
 
   Rule(const Rule&) = delete;
   Rule& operator=(const Rule&) = delete;
 
-  Rule(Rule&& other);
-  Rule& operator=(Rule&& other);
+  Rule(Rule&& other) = delete;
+  Rule& operator=(Rule&& other) = delete;
 
-  ~Rule();
+  virtual ~Rule();
+
+  virtual const base::Value& value() const = 0;
+  virtual base::Value TakeValue() = 0;
 
   ContentSettingsPattern primary_pattern;
   ContentSettingsPattern secondary_pattern;
-  base::Value value;
   RuleMetaData metadata;
 };
 
+// Note that this Rule doesn't actually own its value, it's usually just a
+// pointer to the OriginIdentifierValueMap that created it.
+struct UnownedRule : public Rule {
+  UnownedRule(const ContentSettingsPattern& primary_pattern,
+              const ContentSettingsPattern& secondary_pattern,
+              const base::Value* unowned_value,
+              scoped_refptr<RefCountedAutoLock> value_lock,
+              const RuleMetaData& metadata);
+
+  ~UnownedRule() override;
+
+  const base::Value& value() const override;
+  base::Value TakeValue() override;
+
+  // Owned by the creator of the Rule, usually an OriginIdentifierValueMap.
+  raw_ptr<const base::Value> unowned_value;
+  // A lock held to ensure |unowned_value| is not modified/destroyed before
+  // this Rule is.
+  scoped_refptr<RefCountedAutoLock> value_lock;
+};
+
+struct OwnedRule : public Rule {
+  OwnedRule(const ContentSettingsPattern& primary_pattern,
+            const ContentSettingsPattern& secondary_pattern,
+            base::Value unowned_value,
+            const RuleMetaData& metadata);
+
+  ~OwnedRule() override;
+
+  const base::Value& value() const override;
+  base::Value TakeValue() override;
+
+  base::Value owned_value;
+};
+
 class RuleIterator {
  public:
   virtual ~RuleIterator();
   virtual bool HasNext() const = 0;
-  virtual Rule Next() = 0;
+  virtual std::unique_ptr<Rule> Next() = 0;
 };
 
 class ConcatenationIterator : public RuleIterator {
@@ -54,7 +108,7 @@
       std::vector<std::unique_ptr<RuleIterator>> iterators);
   ~ConcatenationIterator() override;
   bool HasNext() const override;
-  Rule Next() override;
+  std::unique_ptr<Rule> Next() override;
 
  private:
   std::vector<std::unique_ptr<RuleIterator>> iterators_;
diff --git a/components/content_settings/core/browser/content_settings_rule_unittest.cc b/components/content_settings/core/browser/content_settings_rule_unittest.cc
index fcb4a4e..5cb45192 100644
--- a/components/content_settings/core/browser/content_settings_rule_unittest.cc
+++ b/components/content_settings/core/browser/content_settings_rule_unittest.cc
@@ -17,21 +17,22 @@
 
 class ListIterator : public RuleIterator {
  public:
-  explicit ListIterator(std::list<Rule> rules) : rules_(std::move(rules)) {}
+  explicit ListIterator(std::list<std::unique_ptr<Rule>> rules)
+      : rules_(std::move(rules)) {}
 
   ~ListIterator() override = default;
 
   bool HasNext() const override { return !rules_.empty(); }
 
-  Rule Next() override {
+  std::unique_ptr<Rule> Next() override {
     EXPECT_FALSE(rules_.empty());
-    Rule rule = std::move(rules_.front());
+    std::unique_ptr<Rule> rule = std::move(rules_.front());
     rules_.pop_front();
     return rule;
   }
 
  private:
-  std::list<Rule> rules_;
+  std::list<std::unique_ptr<Rule>> rules_;
 };
 
 }  // namespace
@@ -40,53 +41,55 @@
   base::Time expiredTime = base::Time::Now() - base::Seconds(101);
   base::Time validTime = base::Time::Now() - base::Seconds(101);
 
-  std::list<Rule> rules1;
-  rules1.push_back(Rule(ContentSettingsPattern::FromString("a"),
-                        ContentSettingsPattern::Wildcard(), base::Value(0),
-                        {}));
-  rules1.push_back(Rule(
+  std::list<std::unique_ptr<Rule>> rules1;
+  rules1.push_back(std::make_unique<OwnedRule>(
+      ContentSettingsPattern::FromString("a"),
+      ContentSettingsPattern::Wildcard(), base::Value(0), RuleMetaData{}));
+  rules1.push_back(std::make_unique<OwnedRule>(
       ContentSettingsPattern::FromString("b"),
       ContentSettingsPattern::Wildcard(), base::Value(0),
-      {.expiration = expiredTime, .session_model = SessionModel::UserSession}));
-  std::list<Rule> rules2;
-  rules2.push_back(
-      Rule(ContentSettingsPattern::FromString("c"),
-           ContentSettingsPattern::Wildcard(), base::Value(0),
-           {.expiration = validTime, .session_model = SessionModel::Durable}));
-  rules2.push_back(Rule(ContentSettingsPattern::FromString("d"),
-                        ContentSettingsPattern::Wildcard(), base::Value(0),
-                        {.expiration = base::Time(),
-                         .session_model = SessionModel::UserSession}));
+      RuleMetaData{.expiration = expiredTime,
+                   .session_model = SessionModel::UserSession}));
+  std::list<std::unique_ptr<Rule>> rules2;
+  rules2.push_back(std::make_unique<OwnedRule>(
+      ContentSettingsPattern::FromString("c"),
+      ContentSettingsPattern::Wildcard(), base::Value(0),
+      RuleMetaData{.expiration = validTime,
+                   .session_model = SessionModel::Durable}));
+  rules2.push_back(std::make_unique<OwnedRule>(
+      ContentSettingsPattern::FromString("d"),
+      ContentSettingsPattern::Wildcard(), base::Value(0),
+      RuleMetaData{.expiration = base::Time(),
+                   .session_model = SessionModel::UserSession}));
 
   std::vector<std::unique_ptr<RuleIterator>> iterators;
   iterators.push_back(std::make_unique<ListIterator>(std::move(rules1)));
   iterators.push_back(std::make_unique<ListIterator>(std::move(rules2)));
   ConcatenationIterator concatenation_iterator(std::move(iterators));
 
-  Rule rule;
   ASSERT_TRUE(concatenation_iterator.HasNext());
-  rule = concatenation_iterator.Next();
-  EXPECT_EQ(rule.primary_pattern, ContentSettingsPattern::FromString("a"));
-  EXPECT_EQ(rule.metadata.expiration, base::Time());
-  EXPECT_EQ(rule.metadata.session_model, SessionModel::Durable);
+  std::unique_ptr<Rule> rule = concatenation_iterator.Next();
+  EXPECT_EQ(rule->primary_pattern, ContentSettingsPattern::FromString("a"));
+  EXPECT_EQ(rule->metadata.expiration, base::Time());
+  EXPECT_EQ(rule->metadata.session_model, SessionModel::Durable);
 
   ASSERT_TRUE(concatenation_iterator.HasNext());
   rule = concatenation_iterator.Next();
-  EXPECT_EQ(rule.primary_pattern, ContentSettingsPattern::FromString("b"));
-  EXPECT_EQ(rule.metadata.expiration, expiredTime);
-  EXPECT_EQ(rule.metadata.session_model, SessionModel::UserSession);
+  EXPECT_EQ(rule->primary_pattern, ContentSettingsPattern::FromString("b"));
+  EXPECT_EQ(rule->metadata.expiration, expiredTime);
+  EXPECT_EQ(rule->metadata.session_model, SessionModel::UserSession);
 
   ASSERT_TRUE(concatenation_iterator.HasNext());
   rule = concatenation_iterator.Next();
-  EXPECT_EQ(rule.primary_pattern, ContentSettingsPattern::FromString("c"));
-  EXPECT_EQ(rule.metadata.expiration, validTime);
-  EXPECT_EQ(rule.metadata.session_model, SessionModel::Durable);
+  EXPECT_EQ(rule->primary_pattern, ContentSettingsPattern::FromString("c"));
+  EXPECT_EQ(rule->metadata.expiration, validTime);
+  EXPECT_EQ(rule->metadata.session_model, SessionModel::Durable);
 
   ASSERT_TRUE(concatenation_iterator.HasNext());
   rule = concatenation_iterator.Next();
-  EXPECT_EQ(rule.primary_pattern, ContentSettingsPattern::FromString("d"));
-  EXPECT_EQ(rule.metadata.expiration, base::Time());
-  EXPECT_EQ(rule.metadata.session_model, SessionModel::UserSession);
+  EXPECT_EQ(rule->primary_pattern, ContentSettingsPattern::FromString("d"));
+  EXPECT_EQ(rule->metadata.expiration, base::Time());
+  EXPECT_EQ(rule->metadata.session_model, SessionModel::UserSession);
 
   EXPECT_FALSE(concatenation_iterator.HasNext());
 }
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index b695900..f193a98 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -332,10 +332,10 @@
   if (rule_iterator) {
     ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
     while (rule_iterator->HasNext()) {
-      content_settings::Rule rule = rule_iterator->Next();
-      if (rule.primary_pattern == wildcard &&
-          rule.secondary_pattern == wildcard) {
-        return content_settings::ValueToContentSetting(rule.value);
+      std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+      if (rule->primary_pattern == wildcard &&
+          rule->secondary_pattern == wildcard) {
+        return content_settings::ValueToContentSetting(rule->value());
       }
     }
   }
@@ -533,7 +533,7 @@
   // the permission for the given permission |type|. Then test whether the
   // existing rule is more specific than the rule we are about to create. If
   // the existing rule is more specific, than change the existing rule instead
-  // of creating a new rule that would be hidden behind the existing rule.
+  // of creating a new rule that would be hidden behind the existing rule->
   content_settings::SettingInfo info;
   GetWebsiteSettingInternal(primary_url, secondary_url, type, kFirstProvider,
                             &info);
@@ -785,15 +785,15 @@
     return;
 
   while (rule_iterator->HasNext()) {
-    content_settings::Rule rule = rule_iterator->Next();
-    base::Value value = std::move(rule.value);
+    std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+    base::Value value = rule->TakeValue();
 
     // We may be adding settings for only specific rule types. If that's the
     // case and this setting isn't a match, don't add it. We will also avoid
     // adding any expired rules since they are no longer valid.
-    if ((!rule.metadata.expiration.is_null() &&
-         (rule.metadata.expiration < clock_->Now())) ||
-        (session_model && (session_model != rule.metadata.session_model))) {
+    if ((!rule->metadata.expiration.is_null() &&
+         (rule->metadata.expiration < clock_->Now())) ||
+        (session_model && (session_model != rule->metadata.session_model))) {
       continue;
     }
 
@@ -802,15 +802,16 @@
     if (!incognito && is_off_the_record_) {
       base::Value inherit_value =
           ProcessIncognitoInheritanceBehavior(content_type, std::move(value));
-      if (!inherit_value.is_none())
+      if (!inherit_value.is_none()) {
         value = std::move(inherit_value);
-      else
+      } else {
         continue;
+      }
     }
-    settings->emplace_back(rule.primary_pattern, rule.secondary_pattern,
+    settings->emplace_back(rule->primary_pattern, rule->secondary_pattern,
                            std::move(value),
                            kProviderNamesSourceMap[provider_type].provider_name,
-                           incognito, rule.metadata);
+                           incognito, rule->metadata);
   }
 }
 
@@ -968,18 +969,18 @@
     base::Clock* clock) {
   if (rule_iterator) {
     while (rule_iterator->HasNext()) {
-      const content_settings::Rule& rule = rule_iterator->Next();
-      if (rule.primary_pattern.Matches(primary_url) &&
-          rule.secondary_pattern.Matches(secondary_url) &&
-          (rule.metadata.expiration.is_null() ||
-           (rule.metadata.expiration > clock->Now()))) {
+      std::unique_ptr<content_settings::Rule> rule = rule_iterator->Next();
+      if (rule->primary_pattern.Matches(primary_url) &&
+          rule->secondary_pattern.Matches(secondary_url) &&
+          (rule->metadata.expiration.is_null() ||
+           (rule->metadata.expiration > clock->Now()))) {
         if (primary_pattern)
-          *primary_pattern = rule.primary_pattern;
+          *primary_pattern = rule->primary_pattern;
         if (secondary_pattern)
-          *secondary_pattern = rule.secondary_pattern;
+          *secondary_pattern = rule->secondary_pattern;
         if (metadata)
-          *metadata = rule.metadata;
-        return rule.value.Clone();
+          *metadata = rule->metadata;
+        return rule->TakeValue();
       }
     }
   }
diff --git a/components/crash/content/tools/dmp2minidump.py b/components/crash/content/tools/dmp2minidump.py
index bcba2a8e..5d3cfd39 100755
--- a/components/crash/content/tools/dmp2minidump.py
+++ b/components/crash/content/tools/dmp2minidump.py
@@ -33,8 +33,8 @@
     print('Could not find minidump file in dump.')
     return
 
-  f = open(minidump_file, 'w')
-  f.write("\r\n".join(data['upload_file_minidump']))
+  f = open(minidump_file, 'wb')
+  f.write(b"\r\n".join(data['upload_file_minidump']))
   f.close()
 
 
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 742dd6f..9aa4974 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1005,6 +1005,7 @@
            "//build/android:build_java",
            "//third_party/android_sdk:android_test_base_java",
            "//third_party/androidx:androidx_annotation_annotation_java",
+           "//third_party/google-truth:google_truth_java",
            "//third_party/junit",
          ] + cronet_tests_androidx_common_srcs
 }
@@ -1103,6 +1104,7 @@
     ":cronet_api_java",
     ":cronet_impl_all_java",
     ":cronet_urlconnection_impl_java",
+    "//third_party/android_deps:guava_android_java",
     "//third_party/android_sdk:android_test_base_java",
     "//third_party/androidx:androidx_test_ext_junit_java",
     "//third_party/androidx:androidx_test_runner_java",
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index 263c2c24..ac2def31 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -308,13 +310,12 @@
         assertTrue(stream.isDone());
         // Server terminated on us, so the stream must fail.
         // QUIC reports this as ERR_QUIC_PROTOCOL_ERROR. Sometimes we get ERR_CONNECTION_REFUSED.
-        assertNotNull(callback.mError);
-        assertTrue(callback.mError instanceof NetworkException);
+        assertThat(callback.mError).isInstanceOf(NetworkException.class);
         NetworkException networkError = (NetworkException) callback.mError;
         assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == networkError.getCronetInternalErrorCode()
                 || NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode());
         if (NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode()) return;
-        assertTrue(callback.mError instanceof QuicException);
+        assertThat(callback.mError).isInstanceOf(QuicException.class);
     }
 
     @Test
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
index 4b137ad..6ed2253 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -90,7 +92,7 @@
         assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode());
         assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText());
         assertFalse(responseInfo.wasCached());
-        assertTrue(responseInfo.toString().length() > 0);
+        assertThat(responseInfo.toString()).isNotEmpty();
     }
 
     private static String createLongString(String base, int repetition) {
@@ -1298,8 +1300,8 @@
             // connect timing metrics.
             MetricsTestUtil.checkTimingMetrics(metrics, startTime, endTime);
             MetricsTestUtil.checkHasConnectTiming(metrics, startTime, endTime, true);
-            assertTrue(metrics.getSentByteCount() > 0);
-            assertTrue(metrics.getReceivedByteCount() > 0);
+            assertThat(metrics.getSentByteCount()).isGreaterThan(0L);
+            assertThat(metrics.getReceivedByteCount()).isGreaterThan(0L);
         } else if (failureStep == ResponseStep.ON_STREAM_READY) {
             assertNotNull(metrics.getRequestStart());
             MetricsTestUtil.assertAfter(metrics.getRequestStart(), startTime);
@@ -1597,7 +1599,7 @@
                 .build()
                 .start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test explicit tagging.
         tag = 0x12345678;
@@ -1609,7 +1611,7 @@
         assertEquals(builder.setTrafficStatsTag(tag), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test a different tag value to make sure reused connections are retagged.
         tag = 0x87654321;
@@ -1621,7 +1623,7 @@
         assertEquals(builder.setTrafficStatsTag(tag), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test tagging with our UID.
         tag = 0;
@@ -1633,6 +1635,6 @@
         assertEquals(builder.setTrafficStatsUid(Process.myUid()), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
     }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 6c66e819..965591b5 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -953,7 +955,7 @@
         urlRequestBuilder.allowDirectExecutor();
         urlRequestBuilder.build().start();
         callback.blockForDone();
-        assertTrue(thrown.get() instanceof RuntimeException);
+        assertThat(thrown.get()).isInstanceOf(RuntimeException.class);
         cronetEngine.shutdown();
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
index a86d36b..f2c6301 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -114,7 +116,7 @@
         assertEquals(expectedHttpStatusCode, responseInfo.getHttpStatusCode());
         assertEquals(expectedHttpStatusText, responseInfo.getHttpStatusText());
         assertFalse(responseInfo.wasCached());
-        assertTrue(responseInfo.toString().length() > 0);
+        assertThat(responseInfo.toString()).isNotEmpty();
     }
 
     private void checkResponseInfoHeader(
@@ -2128,13 +2130,11 @@
                 startAndWaitForComplete(MockUrlRequestJobFactory.getMockUrlWithFailure(
                         FailurePhase.START, NetError.ERR_QUIC_PROTOCOL_ERROR));
         assertNull(callback.mResponseInfo);
-        assertNotNull(callback.mError);
-        assertEquals(NetworkException.ERROR_QUIC_PROTOCOL_FAILED,
-                ((NetworkException) callback.mError).getErrorCode());
-        assertTrue(callback.mError instanceof QuicException);
+        assertThat(callback.mError).isInstanceOf(QuicException.class);
         QuicException quicException = (QuicException) callback.mError;
         // 1 is QUIC_INTERNAL_ERROR
         assertEquals(1, quicException.getQuicDetailedErrorCode());
+        assertEquals(NetworkException.ERROR_QUIC_PROTOCOL_FAILED, quicException.getErrorCode());
     }
 
     @Test
@@ -2145,15 +2145,13 @@
                 startAndWaitForComplete(MockUrlRequestJobFactory.getMockUrlWithFailure(
                         FailurePhase.START, NetError.ERR_NETWORK_CHANGED));
         assertNull(callback.mResponseInfo);
-        assertNotNull(callback.mError);
-        assertEquals(NetworkException.ERROR_NETWORK_CHANGED,
-                ((NetworkException) callback.mError).getErrorCode());
-        assertTrue(callback.mError instanceof QuicException);
+        assertThat(callback.mError).isInstanceOf(QuicException.class);
         QuicException quicException = (QuicException) callback.mError;
         // QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK(83) is set in
         // URLRequestFailedJob::PopulateNetErrorDetails for this test.
         final int quicErrorCode = 83;
         assertEquals(quicErrorCode, quicException.getQuicDetailedErrorCode());
+        assertEquals(NetworkException.ERROR_NETWORK_CHANGED, quicException.getErrorCode());
     }
 
     /**
@@ -2196,7 +2194,7 @@
 
             @Override
             public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
-                assertTrue(error instanceof NetworkException);
+                assertThat(error).isInstanceOf(NetworkException.class);
                 assertEquals(netError, ((NetworkException) error).getCronetInternalErrorCode());
                 failedExpectation.set(
                         ((NetworkException) error).getCronetInternalErrorCode() != netError);
@@ -2342,7 +2340,7 @@
                 url, callback, callback.getExecutor());
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test explicit tagging.
         tag = 0x12345678;
@@ -2353,7 +2351,7 @@
         assertEquals(builder.setTrafficStatsTag(tag), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test a different tag value to make sure reused connections are retagged.
         tag = 0x87654321;
@@ -2364,7 +2362,7 @@
         assertEquals(builder.setTrafficStatsTag(tag), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test tagging with our UID.
         tag = 0;
@@ -2375,7 +2373,7 @@
         assertEquals(builder.setTrafficStatsUid(Process.myUid()), builder);
         builder.build().start();
         callback.blockForDone();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
     }
 
     @Test
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java
index d2844c3b..62c8fab3c 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -15,6 +17,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.google.common.collect.Range;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -100,10 +104,8 @@
         urlRequest.getStatus(statusListener1);
         statusListener1.waitUntilOnStatusCalled();
         assertTrue(statusListener1.mOnStatusCalled);
-        assertTrue("Status is :" + statusListener1.mStatus, statusListener1.mStatus >= Status.IDLE);
-        assertTrue("Status is :" + statusListener1.mStatus,
-                statusListener1.mStatus <= Status.READING_RESPONSE);
-
+        assertThat(statusListener1.mStatus)
+                .isIn(Range.closed(Status.IDLE, Status.READING_RESPONSE));
         callback.waitForNextStep();
         assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
         callback.startNextRead(urlRequest);
@@ -113,8 +115,8 @@
         urlRequest.getStatus(statusListener2);
         statusListener2.waitUntilOnStatusCalled();
         assertTrue(statusListener2.mOnStatusCalled);
-        assertTrue(statusListener1.mStatus >= Status.IDLE);
-        assertTrue(statusListener1.mStatus <= Status.READING_RESPONSE);
+        assertThat(statusListener1.mStatus)
+                .isIn(Range.closed(Status.IDLE, Status.READING_RESPONSE));
 
         callback.waitForNextStep();
         assertEquals(ResponseStep.ON_READ_COMPLETED, callback.mResponseStep);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/MetricsTestUtil.java b/components/cronet/android/test/javatests/src/org/chromium/net/MetricsTestUtil.java
index 2cbbe76..4ce784c 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/MetricsTestUtil.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/MetricsTestUtil.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -120,14 +122,14 @@
         RequestFinishedInfo.Metrics metrics = info.getMetrics();
         assertNotNull("RequestFinishedInfo.getMetrics() must not be null", metrics);
         // Check old (deprecated) timing metrics
-        assertTrue(metrics.getTotalTimeMs() >= 0);
-        assertTrue(metrics.getTotalTimeMs() >= metrics.getTtfbMs());
+        assertThat(metrics.getTotalTimeMs()).isAtLeast(0L);
+        assertThat(metrics.getTotalTimeMs()).isAtLeast(metrics.getTtfbMs());
         // Check new timing metrics
         checkTimingMetrics(metrics, startTime, endTime);
         assertNull(metrics.getPushStart());
         assertNull(metrics.getPushEnd());
         // Check data use metrics
-        assertTrue(metrics.getSentByteCount() > 0);
-        assertTrue(metrics.getReceivedByteCount() > 0);
+        assertThat(metrics.getSentByteCount()).isGreaterThan(0L);
+        assertThat(metrics.getReceivedByteCount()).isGreaterThan(0L);
     }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
index 1b6c8164c..32e83611 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -176,7 +178,7 @@
                                          .build();
         ExperimentalCronetEngine.Builder cronetEngineBuilder =
                 new ExperimentalCronetEngine.Builder(getContext());
-        assertTrue(RttThroughputValues.INVALID_RTT_THROUGHPUT < 0);
+        assertThat(RttThroughputValues.INVALID_RTT_THROUGHPUT).isLessThan(0);
         Executor listenersExecutor = Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
         TestNetworkQualityRttListener rttListener =
                 new TestNetworkQualityRttListener(listenersExecutor);
@@ -215,20 +217,20 @@
         // Wait for RTT observation (at the URL request layer) to be posted.
         rttListener.waitUntilFirstUrlRequestRTTReceived();
 
-        assertTrue(throughputListener.throughputObservationCount() > 0);
+        assertThat(throughputListener.throughputObservationCount()).isGreaterThan(0);
 
         // Prefs must be read at startup.
         readCountHistogram.assertExpected();
 
         // Check RTT observation count after throughput observation has been received. This ensures
         // that executor has finished posting the RTT observation to the RTT listeners.
-        assertTrue(rttListener.rttObservationCount() > 0);
+        assertThat(rttListener.rttObservationCount()).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST
-        assertTrue(rttListener.rttObservationCount(0) > 0);
+        assertThat(rttListener.rttObservationCount(0)).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_TCP
-        assertTrue(rttListener.rttObservationCount(1) > 0);
+        assertThat(rttListener.rttObservationCount(1)).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC
         assertEquals(0, rttListener.rttObservationCount(2));
@@ -244,9 +246,9 @@
 
         // Verify that the HTTP RTT, transport RTT and downstream throughput
         // estimates are available.
-        assertTrue(cronetEngine.getHttpRttMs() >= 0);
-        assertTrue(cronetEngine.getTransportRttMs() >= 0);
-        assertTrue(cronetEngine.getDownstreamThroughputKbps() >= 0);
+        assertThat(cronetEngine.getHttpRttMs()).isAtLeast(0);
+        assertThat(cronetEngine.getTransportRttMs()).isAtLeast(0);
+        assertThat(cronetEngine.getDownstreamThroughputKbps()).isAtLeast(0);
 
         // Verify that the cached estimates were written to the prefs.
         while (true) {
@@ -307,7 +309,7 @@
 
             ExperimentalCronetEngine.Builder cronetEngineBuilder =
                     new ExperimentalCronetEngine.Builder(getContext());
-            assertTrue(RttThroughputValues.INVALID_RTT_THROUGHPUT < 0);
+            assertThat(RttThroughputValues.INVALID_RTT_THROUGHPUT).isLessThan(0);
             Executor listenersExecutor =
                     Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
             TestNetworkQualityRttListener rttListener =
@@ -348,7 +350,7 @@
             // Check RTT observation count after throughput observation has been received. This
             // ensures
             // that executor has finished posting the RTT observation to the RTT listeners.
-            assertTrue(rttListener.rttObservationCount() > 0);
+            assertThat(rttListener.rttObservationCount()).isGreaterThan(0);
 
             // Verify that effective connection type callback is received and
             // effective connection type is correctly set.
@@ -413,17 +415,17 @@
         // Wait for RTT observation (at the URL request layer) to be posted.
         rttListener.waitUntilFirstUrlRequestRTTReceived();
 
-        assertTrue(throughputListener.throughputObservationCount() > 0);
+        assertThat(throughputListener.throughputObservationCount()).isGreaterThan(0);
 
         // Check RTT observation count after throughput observation has been received. This ensures
         // that executor has finished posting the RTT observation to the RTT listeners.
-        assertTrue(rttListener.rttObservationCount() > 0);
+        assertThat(rttListener.rttObservationCount()).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST
-        assertTrue(rttListener.rttObservationCount(0) > 0);
+        assertThat(rttListener.rttObservationCount(0)).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_TCP
-        assertTrue(rttListener.rttObservationCount(1) > 0);
+        assertThat(rttListener.rttObservationCount(1)).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC
         assertEquals(0, rttListener.rttObservationCount(2));
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
index 472ba25..781cd47 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -106,7 +108,8 @@
         assertIsQuic(callback.mResponseInfo);
         // The total received bytes should be larger than the content length, to account for
         // headers.
-        assertTrue(callback.mResponseInfo.getReceivedByteCount() > expectedContent.length());
+        assertThat(callback.mResponseInfo.getReceivedByteCount())
+                .isGreaterThan((long) expectedContent.length());
         // This test takes a long time, since the update will only be scheduled
         // after kUpdatePrefsDelayMs in http_server_properties_manager.cc.
         while (true) {
@@ -147,7 +150,8 @@
         assertIsQuic(callback.mResponseInfo);
         // The total received bytes should be larger than the content length, to account for
         // headers.
-        assertTrue(callback2.mResponseInfo.getReceivedByteCount() > expectedContent.length());
+        assertThat(callback2.mResponseInfo.getReceivedByteCount())
+                .isGreaterThan((long) expectedContent.length());
         cronetEngine.shutdown();
     }
 
@@ -205,15 +209,15 @@
         // Wait for RTT observation (at the URL request layer) to be posted.
         rttListener.waitUntilFirstUrlRequestRTTReceived();
 
-        assertTrue(throughputListener.throughputObservationCount() > 0);
+        assertThat(throughputListener.throughputObservationCount()).isGreaterThan(0);
 
         // Check RTT observation count after throughput observation has been received. This ensures
         // that executor has finished posting the RTT observation to the RTT listeners.
         // NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST
-        assertTrue(rttListener.rttObservationCount(0) > 0);
+        assertThat(rttListener.rttObservationCount(0)).isGreaterThan(0);
 
         // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC
-        assertTrue(rttListener.rttObservationCount(2) > 0);
+        assertThat(rttListener.rttObservationCount(2)).isGreaterThan(0);
 
         // Verify that effective connection type callback is received and
         // effective connection type is correctly set.
@@ -222,9 +226,9 @@
 
         // Verify that the HTTP RTT, transport RTT and downstream throughput
         // estimates are available.
-        assertTrue(cronetEngine.getHttpRttMs() >= 0);
-        assertTrue(cronetEngine.getTransportRttMs() >= 0);
-        assertTrue(cronetEngine.getDownstreamThroughputKbps() >= 0);
+        assertThat(cronetEngine.getHttpRttMs()).isAtLeast(0);
+        assertThat(cronetEngine.getTransportRttMs()).isAtLeast(0);
+        assertThat(cronetEngine.getDownstreamThroughputKbps()).isAtLeast(0);
 
         // Verify that the cached estimates were written to the prefs.
         while (true) {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java b/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java
index 8fb27d0..bdca7a2 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/TestUrlRequestCallback.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -298,10 +300,10 @@
         assertFalse(mOnCanceledCalled);
         assertNull(mError);
         if (mCallbackExceptionThrown) {
-            assertTrue(error instanceof CallbackException);
+            assertThat(error).isInstanceOf(CallbackException.class);
             assertContains("Exception received from UrlRequest.Callback", error.getMessage());
             assertNotNull(error.getCause());
-            assertTrue(error.getCause() instanceof IllegalStateException);
+            assertThat(error).hasCauseThat().isInstanceOf(IllegalStateException.class);
             assertContains("Listener Exception.", error.getCause().getMessage());
         }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/apihelpers/UploadDataProvidersTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/apihelpers/UploadDataProvidersTest.java
index a77d3c4..602e6441 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/apihelpers/UploadDataProvidersTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/apihelpers/UploadDataProvidersTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net.apihelpers;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -117,7 +119,7 @@
             builder.build().start();
             callback.blockForDone();
 
-            assertTrue(callback.mError.getCause() instanceof IllegalArgumentException);
+            assertThat(callback.mError).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
         } finally {
             pipe[1].close();
         }
@@ -241,7 +243,7 @@
         first.block();
         callback.blockForDone();
         assertFalse(callback.mOnCanceledCalled);
-        assertTrue(callback.mError instanceof CallbackException);
+        assertThat(callback.mError).isInstanceOf(CallbackException.class);
         assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
         assertContains(exceptionMessage, callback.mError.getCause().getMessage());
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
index 8a76b21..511f747 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.net.urlconnection;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -763,7 +765,7 @@
                 numBytesToRead = actualOutput.length - totalBytesRead;
             }
             int bytesRead = in.read(actualOutput, totalBytesRead, numBytesToRead);
-            assertTrue(bytesRead <= numBytesToRead);
+            assertThat(bytesRead).isAtMost(numBytesToRead);
             totalBytesRead += bytesRead;
             numBytesToRead++;
         }
@@ -1343,7 +1345,7 @@
         CronetHttpURLConnection urlConnection = (CronetHttpURLConnection) url.openConnection();
         assertEquals(200, urlConnection.getResponseCode());
         urlConnection.disconnect();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test explicit tagging.
         tag = 0x12345678;
@@ -1352,7 +1354,7 @@
         urlConnection.setTrafficStatsTag(tag);
         assertEquals(200, urlConnection.getResponseCode());
         urlConnection.disconnect();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test a different tag value.
         tag = 0x87654321;
@@ -1361,7 +1363,7 @@
         urlConnection.setTrafficStatsTag(tag);
         assertEquals(200, urlConnection.getResponseCode());
         urlConnection.disconnect();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test tagging with TrafficStats.
         tag = 0x12348765;
@@ -1370,7 +1372,7 @@
         TrafficStats.setThreadStatsTag(tag);
         assertEquals(200, urlConnection.getResponseCode());
         urlConnection.disconnect();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // Test tagging with our UID.
         // NOTE(pauljensen): Explicitly setting the UID to the current UID isn't a particularly
@@ -1387,7 +1389,7 @@
         urlConnection.setTrafficStatsUid(Process.myUid());
         assertEquals(200, urlConnection.getResponseCode());
         urlConnection.disconnect();
-        assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+        assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
 
         // TrafficStats.getThreadStatsUid() which is required for this feature is added in API level
         // 28.
@@ -1400,7 +1402,7 @@
             TrafficStats.setThreadStatsUid(Process.myUid());
             assertEquals(200, urlConnection.getResponseCode());
             urlConnection.disconnect();
-            assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
+            assertThat(CronetTestUtil.nativeGetTaggedBytes(tag)).isGreaterThan(priorBytes);
         }
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandlerTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandlerTest.java
index 9e70030..b63f3d88 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandlerTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandlerTest.java
@@ -20,6 +20,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.net.CronetTestRule;
 import org.chromium.net.CronetTestRule.CronetTestFramework;
 import org.chromium.net.NativeTestServer;
@@ -32,6 +33,7 @@
 /**
  * Tests for CronetHttpURLStreamHandler class.
  */
+@Batch(Batch.UNIT_TESTS)
 @RunWith(AndroidJUnit4.class)
 public class CronetHttpURLStreamHandlerTest {
     @Rule
@@ -47,6 +49,7 @@
 
     @After
     public void tearDown() throws Exception {
+        mTestFramework.shutdownEngine();
         NativeTestServer.shutdownNativeTestServer();
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetInputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetInputStreamTest.java
index 55cde38..9d44a2a 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetInputStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetInputStreamTest.java
@@ -13,6 +13,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.net.CronetTestRule;
 
 import java.io.IOException;
@@ -20,6 +21,7 @@
 import java.util.concurrent.Callable;
 
 /** Test for {@link CronetInputStream}. */
+@Batch(Batch.UNIT_TESTS)
 @RunWith(AndroidJUnit4.class)
 public class CronetInputStreamTest {
     @Rule
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactoryTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactoryTest.java
index 74d277e..ff8cc47e 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactoryTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactoryTest.java
@@ -10,25 +10,40 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.net.CronetTestRule;
+import org.chromium.net.CronetTestRule.CronetTestFramework;
 
 /**
  * Test for CronetURLStreamHandlerFactory.
  */
+@Batch(Batch.UNIT_TESTS)
 @RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
 public class CronetURLStreamHandlerFactoryTest {
     @Rule
     public final CronetTestRule mTestRule = new CronetTestRule();
 
+    private CronetTestFramework mTestFramework;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestFramework = mTestRule.startCronetTestFramework();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestFramework.shutdownEngine();
+    }
+
     @Test
     @SmallTest
     public void testRequireConfig() throws Exception {
-        mTestRule.startCronetTestFramework();
         try {
             new CronetURLStreamHandlerFactory(null);
             fail();
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
index 195d439..26c42be 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
@@ -15,6 +15,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.net.CronetTestRule;
 
 import java.io.IOException;
@@ -28,6 +29,7 @@
 /**
  * Tests the MessageLoop implementation.
  */
+@Batch(Batch.UNIT_TESTS)
 @RunWith(AndroidJUnit4.class)
 public class MessageLoopTest {
     @Rule
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/QuicUploadTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/QuicUploadTest.java
index fc93a9e..9a2e632 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/QuicUploadTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/QuicUploadTest.java
@@ -12,11 +12,13 @@
 import androidx.test.filters.SmallTest;
 
 import org.json.JSONObject;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.net.CronetEngine;
 import org.chromium.net.CronetTestRule;
 import org.chromium.net.CronetTestRule.OnlyRunNativeCronet;
@@ -32,19 +34,19 @@
 /**
  * Tests HttpURLConnection upload using QUIC.
  */
+@Batch(Batch.UNIT_TESTS)
 @RunWith(AndroidJUnit4.class)
 public class QuicUploadTest {
     @Rule
     public final CronetTestRule mTestRule = new CronetTestRule();
 
+    private CronetTestRule.CronetTestFramework mTestFramework;
     private CronetEngine mCronetEngine;
 
     @Before
     public void setUp() throws Exception {
-        // Load library first to create MockCertVerifier.
-        System.loadLibrary("cronet_tests");
-        ExperimentalCronetEngine.Builder builder =
-                new ExperimentalCronetEngine.Builder(getContext());
+        mTestFramework = mTestRule.buildCronetTestFramework();
+        ExperimentalCronetEngine.Builder builder = mTestFramework.mBuilder;
 
         QuicTestServer.startQuicTestServer(getContext());
 
@@ -60,7 +62,13 @@
         CronetTestUtil.setMockCertVerifierForTesting(
                 builder, QuicTestServer.createMockCertVerifier());
 
-        mCronetEngine = builder.build();
+        mCronetEngine = mTestFramework.startEngine();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestFramework.shutdownEngine();
+        QuicTestServer.shutdownQuicTestServer();
     }
 
     @Test
diff --git a/components/dom_distiller/content/browser/test/distilled_page_js_browsertest.cc b/components/dom_distiller/content/browser/test/distilled_page_js_browsertest.cc
index a802987..ad8a4fd9 100644
--- a/components/dom_distiller/content/browser/test/distilled_page_js_browsertest.cc
+++ b/components/dom_distiller/content/browser/test/distilled_page_js_browsertest.cc
@@ -40,8 +40,8 @@
   void LoadAndExecuteTestScript(const std::string& file) {
     distilled_page_->AppendScriptFile(file);
     distilled_page_->Load(embedded_test_server(), shell()->web_contents());
-    EXPECT_EQ(true, content::EvalJs(shell()->web_contents(), "mocha.run()",
-                                    content::EXECUTE_SCRIPT_USE_MANUAL_REPLY));
+    EXPECT_TRUE(content::ExecJs(shell()->web_contents(),
+                                "mocha.run(); window.completePromise"));
   }
 
   std::unique_ptr<FakeDistilledPage> distilled_page_;
diff --git a/components/error_page_strings.grdp b/components/error_page_strings.grdp
index 86860b93..637dccd 100644
--- a/components/error_page_strings.grdp
+++ b/components/error_page_strings.grdp
@@ -121,9 +121,15 @@
   <message name="IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED" desc="Heading of the error page when the network connection failed.">
     No internet
   </message>
-  <message name="IDS_ERRORPAGES_HEADING_YOU_ARE_OFFLINE" desc="Heading of the error page for when a PWA/TWA is offline.">
+  <message name="IDS_ERRORPAGES_HEADING_YOU_ARE_OFFLINE" desc="Message of the error page for when a PWA/TWA/IWA is offline.">
     You're offline
   </message>
+  <message name="IDS_ERRORPAGES_MESSAGE_IWA_INVALID_WEB_BUNDLE" desc="Message of the error page for when an IWA has invalid web bundle.">
+    This application is missing or damaged
+  </message>
+  <message name="IDS_ERRORPAGES_MESSAGE_IWA_CONNECTION_REFUSED" desc="Message of the error page for when an IWA can't connect to dev server.">
+    The development server for this application cannot be reached
+  </message>
   <message name="IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE" desc="Heading in the error page when we encountered an error reading from the cache.  Generally this happens when the disk cache is corrupted from improper shutdown.">
     This site can’t be loaded from the cache
   </message>
diff --git a/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_CONNECTION_REFUSED.png.sha1 b/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_CONNECTION_REFUSED.png.sha1
new file mode 100644
index 0000000..435b75b
--- /dev/null
+++ b/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_CONNECTION_REFUSED.png.sha1
@@ -0,0 +1 @@
+5e919be262e1920d893485342e27d392b3588346
\ No newline at end of file
diff --git a/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_INVALID_WEB_BUNDLE.png.sha1 b/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_INVALID_WEB_BUNDLE.png.sha1
new file mode 100644
index 0000000..8852869
--- /dev/null
+++ b/components/error_page_strings_grdp/IDS_ERRORPAGES_MESSAGE_IWA_INVALID_WEB_BUNDLE.png.sha1
@@ -0,0 +1 @@
+f0c6449ce31f37d3c7a88315868cf6807d65f9c4
\ No newline at end of file
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 9fc2ce6..5f496cd 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -447,9 +447,6 @@
 BASE_FEATURE(kIPHFollowWhileBrowsingFeature,
              "IPH_FollowWhileBrowsing",
              base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kIPHOverflowMenuTipFeature,
-             "IPH_OverflowMenuTip",
-             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHPriceNotificationsWhileBrowsingFeature,
              "IPH_PriceNotificationsWhileBrowsing",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index 8e0ac25e..9a5debc 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -183,7 +183,6 @@
 BASE_DECLARE_FEATURE(kIPHDiscoverFeedHeaderFeature);
 BASE_DECLARE_FEATURE(kIPHDefaultSiteViewFeature);
 BASE_DECLARE_FEATURE(kIPHFollowWhileBrowsingFeature);
-BASE_DECLARE_FEATURE(kIPHOverflowMenuTipFeature);
 BASE_DECLARE_FEATURE(kIPHPriceNotificationsWhileBrowsingFeature);
 BASE_DECLARE_FEATURE(kIPHiOSDefaultBrowserBadgeEligibilityFeature);
 BASE_DECLARE_FEATURE(kIPHiOSDefaultBrowserOverflowMenuBadgeFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 7ee2198..948300a 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -121,7 +121,6 @@
     &kIPHDiscoverFeedHeaderFeature,
     &kIPHDefaultSiteViewFeature,
     &kIPHFollowWhileBrowsingFeature,
-    &kIPHOverflowMenuTipFeature,
     &kIPHPriceNotificationsWhileBrowsingFeature,
     &kIPHiOSDefaultBrowserBadgeEligibilityFeature,
     &kIPHiOSDefaultBrowserOverflowMenuBadgeFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index 9a65e60..29940055 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -225,7 +225,6 @@
 DEFINE_VARIATION_PARAM(kIPHDefaultSiteViewFeature, "IPH_DefaultSiteView");
 DEFINE_VARIATION_PARAM(kIPHFollowWhileBrowsingFeature,
                        "IPH_FollowWhileBrowsing");
-DEFINE_VARIATION_PARAM(kIPHOverflowMenuTipFeature, "IPH_OverflowMenuTip");
 DEFINE_VARIATION_PARAM(kIPHPriceNotificationsWhileBrowsingFeature,
                        "IPHPriceNotificationsWhileBrowsing");
 DEFINE_VARIATION_PARAM(kIPHiOSDefaultBrowserBadgeEligibilityFeature,
@@ -434,7 +433,6 @@
         VARIATION_ENTRY(kIPHDiscoverFeedHeaderFeature),
         VARIATION_ENTRY(kIPHDefaultSiteViewFeature),
         VARIATION_ENTRY(kIPHFollowWhileBrowsingFeature),
-        VARIATION_ENTRY(kIPHOverflowMenuTipFeature),
         VARIATION_ENTRY(kIPHPriceNotificationsWhileBrowsingFeature),
         VARIATION_ENTRY(kIPHiOSDefaultBrowserBadgeEligibilityFeature),
         VARIATION_ENTRY(kIPHiOSDefaultBrowserOverflowMenuBadgeFeature),
diff --git a/components/global_media_controls/BUILD.gn b/components/global_media_controls/BUILD.gn
index b05d0081..047428ef 100644
--- a/components/global_media_controls/BUILD.gn
+++ b/components/global_media_controls/BUILD.gn
@@ -89,6 +89,8 @@
   testonly = true
 
   sources = [
+    "public/test/mock_device_service.cc",
+    "public/test/mock_device_service.h",
     "public/test/mock_media_dialog_delegate.cc",
     "public/test/mock_media_dialog_delegate.h",
     "public/test/mock_media_item_manager.cc",
@@ -109,6 +111,7 @@
 
   deps = [
     ":global_media_controls",
+    "public/mojom:device_service",
     "//components/media_message_center:test_support",
     "//skia",
     "//testing/gmock",
diff --git a/components/global_media_controls/media_item_manager_impl.cc b/components/global_media_controls/media_item_manager_impl.cc
index 230a5648..a512b1f 100644
--- a/components/global_media_controls/media_item_manager_impl.cc
+++ b/components/global_media_controls/media_item_manager_impl.cc
@@ -56,31 +56,33 @@
 }
 
 void MediaItemManagerImpl::RefreshItem(const std::string& id) {
-  if (!dialog_delegate_)
+  if (!dialog_delegate_) {
     return;
-
+  }
   dialog_delegate_->RefreshMediaItem(id, GetItem(id));
 }
 
 void MediaItemManagerImpl::OnItemsChanged() {
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.OnItemListChanged();
+  }
 }
 
 void MediaItemManagerImpl::SetDialogDelegate(MediaDialogDelegate* delegate) {
   dialog_opened_for_single_item_ = false;
   SetDialogDelegateCommon(delegate);
-  if (!dialog_delegate_)
+  if (!dialog_delegate_) {
     return;
-
+  }
   auto item_ids = GetActiveItemIds();
   for (const std::string& id : item_ids) {
     base::WeakPtr<media_message_center::MediaNotificationItem> item =
         GetItem(id);
     MediaItemUI* item_ui = dialog_delegate_->ShowMediaItem(id, item);
     auto* item_producer = GetItemProducer(id);
-    if (item_producer)
+    if (item_producer) {
       item_producer->OnItemShown(id, item_ui);
+    }
   }
 
   media_message_center::RecordConcurrentNotificationCount(item_ids.size());
@@ -92,31 +94,33 @@
 
 void MediaItemManagerImpl::SetDialogDelegateForId(MediaDialogDelegate* delegate,
                                                   const std::string& id) {
-  dialog_opened_for_single_item_ = true;
   SetDialogDelegateCommon(delegate);
-  if (!dialog_delegate_)
+  if (!dialog_delegate_) {
     return;
-
+  }
   auto* producer = GetItemProducer(id);
-  if (!producer)
+  if (!producer) {
     return;
-
+  }
   auto item = producer->GetMediaItem(id);
-  if (!item)
+  if (!item) {
     return;
-
+  }
+  dialog_opened_for_single_item_ = true;
   auto* item_ui = dialog_delegate_->ShowMediaItem(id, item);
   producer->OnItemShown(id, item_ui);
 }
 
 void MediaItemManagerImpl::FocusDialog() {
-  if (dialog_delegate_)
+  if (dialog_delegate_) {
     dialog_delegate_->Focus();
+  }
 }
 
 void MediaItemManagerImpl::HideDialog() {
-  if (dialog_delegate_)
+  if (dialog_delegate_) {
     dialog_delegate_->HideMediaDialog();
+  }
 }
 
 bool MediaItemManagerImpl::HasActiveItems() {
@@ -125,8 +129,9 @@
 
 bool MediaItemManagerImpl::HasFrozenItems() {
   for (auto* item_producer : item_producers_) {
-    if (item_producer->HasFrozenItems())
+    if (item_producer->HasFrozenItems()) {
       return true;
+    }
   }
   return false;
 }
@@ -161,22 +166,24 @@
 
 void MediaItemManagerImpl::ShowAndObserveItem(const std::string& id) {
   OnItemsChanged();
-  if (!dialog_delegate_)
+  if (!dialog_delegate_) {
     return;
-
+  }
   auto item = GetItem(id);
   auto* item_ui = dialog_delegate_->ShowMediaItem(id, item);
   auto* producer = GetItemProducer(id);
-  if (producer)
+  if (producer) {
     producer->OnItemShown(id, item_ui);
+  }
 }
 
 base::WeakPtr<media_message_center::MediaNotificationItem>
 MediaItemManagerImpl::GetItem(const std::string& id) {
   for (auto* producer : item_producers_) {
     auto item = producer->GetMediaItem(id);
-    if (item)
+    if (item) {
       return item;
+    }
   }
   return nullptr;
 }
@@ -184,8 +191,9 @@
 MediaItemProducer* MediaItemManagerImpl::GetItemProducer(
     const std::string& item_id) {
   for (auto* producer : item_producers_) {
-    if (producer->GetMediaItem(item_id))
+    if (producer->GetMediaItem(item_id)) {
       return producer;
+    }
   }
   return nullptr;
 }
@@ -196,11 +204,13 @@
   dialog_delegate_ = delegate;
 
   if (dialog_delegate_) {
-    for (auto& observer : observers_)
+    for (auto& observer : observers_) {
       observer.OnMediaDialogOpened();
+    }
   } else {
-    for (auto& observer : observers_)
+    for (auto& observer : observers_) {
       observer.OnMediaDialogClosed();
+    }
   }
 }
 
diff --git a/components/global_media_controls/public/test/mock_device_service.cc b/components/global_media_controls/public/test/mock_device_service.cc
new file mode 100644
index 0000000..5596357
--- /dev/null
+++ b/components/global_media_controls/public/test/mock_device_service.cc
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/global_media_controls/public/test/mock_device_service.h"
+
+namespace global_media_controls::test {
+
+MockDeviceService::MockDeviceService() = default;
+MockDeviceService::~MockDeviceService() = default;
+
+mojo::PendingRemote<mojom::DeviceService> MockDeviceService::PassRemote() {
+  return receiver_.BindNewPipeAndPassRemote();
+}
+
+void MockDeviceService::ResetReceiver() {
+  receiver_.reset();
+}
+
+void MockDeviceService::FlushForTesting() {
+  receiver_.FlushForTesting();
+}
+
+}  // namespace global_media_controls::test
diff --git a/components/global_media_controls/public/test/mock_device_service.h b/components/global_media_controls/public/test/mock_device_service.h
new file mode 100644
index 0000000..bca768b
--- /dev/null
+++ b/components/global_media_controls/public/test/mock_device_service.h
@@ -0,0 +1,50 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_TEST_MOCK_DEVICE_SERVICE_H_
+#define COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_TEST_MOCK_DEVICE_SERVICE_H_
+
+#include "components/global_media_controls/public/mojom/device_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace global_media_controls::test {
+
+class MockDeviceService : public mojom::DeviceService {
+ public:
+  MockDeviceService();
+  ~MockDeviceService() override;
+
+  // Returns a remote bound to `this`.
+  mojo::PendingRemote<mojom::DeviceService> PassRemote();
+
+  // Resets the Mojo receiver bound to `this`.
+  void ResetReceiver();
+
+  // Flushes the Mojo receiver bound to `this`.
+  void FlushForTesting();
+
+  MOCK_METHOD(void,
+              GetDeviceListHostForSession,
+              (const std::string& session_id,
+               mojo::PendingReceiver<mojom::DeviceListHost> host_receiver,
+               mojo::PendingRemote<mojom::DeviceListClient> client_remote));
+  MOCK_METHOD(void,
+              GetDeviceListHostForPresentation,
+              (mojo::PendingReceiver<mojom::DeviceListHost> host_receiver,
+               mojo::PendingRemote<mojom::DeviceListClient> client_remote));
+  MOCK_METHOD(
+      void,
+      SetDevicePickerProvider,
+      (mojo::PendingRemote<mojom::DevicePickerProvider> provider_remote));
+
+ private:
+  mojo::Receiver<mojom::DeviceService> receiver_{this};
+};
+
+}  // namespace global_media_controls::test
+
+#endif  // COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MOCK_DEVICE_SERVICE_H_
diff --git a/components/history_clusters/core/history_clusters_debug_jsons.cc b/components/history_clusters/core/history_clusters_debug_jsons.cc
index 166a8e6..007748e 100644
--- a/components/history_clusters/core/history_clusters_debug_jsons.cc
+++ b/components/history_clusters/core/history_clusters_debug_jsons.cc
@@ -87,6 +87,10 @@
   debug_visit.Set("visibility",
                   visit.content_annotations.model_annotations.visibility_score);
   debug_visit.Set("searchTerms", visit.content_annotations.search_terms);
+  if (!visit.content_annotations.search_terms.empty()) {
+    debug_visit.Set("hasRelatedSearches",
+                    !visit.content_annotations.related_searches.empty());
+  }
   debug_visit.Set("hasUrlKeyedImage",
                   visit.content_annotations.has_url_keyed_image);
   return debug_visit;
diff --git a/components/metrics/content/content_stability_metrics_provider.cc b/components/metrics/content/content_stability_metrics_provider.cc
index b238068..80ee176 100644
--- a/components/metrics/content/content_stability_metrics_provider.cc
+++ b/components/metrics/content/content_stability_metrics_provider.cc
@@ -80,6 +80,13 @@
       extensions_helper_ && extensions_helper_->IsExtensionProcess(host);
   helper_.LogRendererCrash(was_extension_process, info.status, info.exit_code);
 #endif  // !BUILDFLAG(IS_ANDROID)
+}
+
+void ContentStabilityMetricsProvider::RenderProcessHostDestroyed(
+    content::RenderProcessHost* host) {
+  // In single-process mode, RenderProcessExited isn't called, so we ensure
+  // we remove observations here rather than there, to avoid later use-after-
+  // frees in single process mode.
   host_observation_.RemoveObservation(host);
 }
 
diff --git a/components/metrics/content/content_stability_metrics_provider.h b/components/metrics/content/content_stability_metrics_provider.h
index 398547e..cebbc3b 100644
--- a/components/metrics/content/content_stability_metrics_provider.h
+++ b/components/metrics/content/content_stability_metrics_provider.h
@@ -82,6 +82,7 @@
   void RenderProcessExited(
       content::RenderProcessHost* host,
       const content::ChildProcessTerminationInfo& info) override;
+  void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
 
   // content::NotificationObserver:
   void Observe(int type,
diff --git a/components/metrics/demographics/demographic_metrics_provider_unittest.cc b/components/metrics/demographics/demographic_metrics_provider_unittest.cc
index 9025007..d633a1f 100644
--- a/components/metrics/demographics/demographic_metrics_provider_unittest.cc
+++ b/components/metrics/demographics/demographic_metrics_provider_unittest.cc
@@ -88,8 +88,7 @@
 
       case SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD:
         sync_service_ = std::make_unique<syncer::TestSyncService>();
-        sync_service_->SetDisableReasons(
-            {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
+        sync_service_->SetSyncFeatureDisabledViaDashboard(true);
 
         // On ChromeOS Ash, IsInitialSyncFeatureSetupComplete gets cleared
         // temporarily but immediately afterwards, it gets set again with
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 7c5a98b..4e23115 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -240,6 +240,14 @@
       return;
     }
     case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY: {
+      // Map `ACMatchType::SEARCH_SUGGEST_ENTITY` back to
+      // `omnibox::TYPE_CATEGORICAL_QUERY` depending on the original suggestion
+      // type.
+      if (match.suggest_type == omnibox::TYPE_CATEGORICAL_QUERY &&
+          base::FeatureList::IsEnabled(omnibox::kCategoricalSuggestions)) {
+        *type = omnibox::TYPE_CATEGORICAL_QUERY;
+        return;
+      }
       *type = omnibox::TYPE_ENTITY;
       return;
     }
diff --git a/components/omnibox/browser/autocomplete_provider_unittest.cc b/components/omnibox/browser/autocomplete_provider_unittest.cc
index 7e6c844d..023c4baa 100644
--- a/components/omnibox/browser/autocomplete_provider_unittest.cc
+++ b/components/omnibox/browser/autocomplete_provider_unittest.cc
@@ -1014,6 +1014,9 @@
 TEST_F(AutocompleteProviderTest, UpdateAssistedQueryStats) {
   ResetControllerWithTestProviders(false, nullptr, nullptr);
 
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(omnibox::kCategoricalSuggestions);
+
   {
     omnibox::metrics::ChromeSearchboxStats searchbox_stats;
     AssistedQueryStatsTestData test_data[] = {
@@ -1084,7 +1087,7 @@
     available_suggestion->add_subtypes(omnibox::SUBTYPE_TRENDS);
     available_suggestion = searchbox_stats.add_available_suggestions();
     available_suggestion->set_index(2);
-    available_suggestion->set_type(omnibox::TYPE_ENTITY);
+    available_suggestion->set_type(omnibox::TYPE_CATEGORICAL_QUERY);
     available_suggestion->add_subtypes(omnibox::SUBTYPE_PERSONAL);
     available_suggestion->add_subtypes(omnibox::SUBTYPE_TRENDS);
     available_suggestion = searchbox_stats.add_available_suggestions();
@@ -1128,7 +1131,7 @@
     // properly handled and reported as the same suggestion type.
     AssistedQueryStatsTestData test_data[] = {
         {AutocompleteMatchType::SEARCH_SUGGEST,
-         "chrome.0.0i39i143i362j46i39i143l2j46i39i143i362j46i39i143",
+         "chrome.0.0i39i143i362j46i39i143j185i39i143j46i39i143i362j46i39i143",
          searchbox_stats_0,
          omnibox::TYPE_QUERY,
          {omnibox::SUBTYPE_PERSONAL, omnibox::SUBTYPE_TRENDS,
@@ -1136,20 +1139,20 @@
         // The next two matches should be detected as the same type, despite
         // repeated subtype match.
         {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY,
-         "chrome.1.0i39i143i362j46i39i143l2j46i39i143i362j46i39i143",
+         "chrome.1.0i39i143i362j46i39i143j185i39i143j46i39i143i362j46i39i143",
          searchbox_stats_1,
          omnibox::TYPE_ENTITY,
          {omnibox::SUBTYPE_PERSONAL, omnibox::SUBTYPE_TRENDS}},
         {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY,
-         "chrome.2.0i39i143i362j46i39i143l2j46i39i143i362j46i39i143",
+         "chrome.2.0i39i143i362j46i39i143j185i39i143j46i39i143i362j46i39i143",
          searchbox_stats_2,
-         omnibox::TYPE_ENTITY,
+         omnibox::TYPE_CATEGORICAL_QUERY,
          {omnibox::SUBTYPE_PERSONAL, omnibox::SUBTYPE_TRENDS,
           omnibox::SUBTYPE_PERSONAL}},
         // This match should not be bundled together with previous two, because
         // it comes with additional subtype information (42).
         {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY,
-         "chrome.3.0i39i143i362j46i39i143l2j46i39i143i362j46i39i143",
+         "chrome.3.0i39i143i362j46i39i143j185i39i143j46i39i143i362j46i39i143",
          searchbox_stats_3,
          omnibox::TYPE_ENTITY,
          {omnibox::SUBTYPE_PERSONAL, omnibox::SUBTYPE_TRENDS,
@@ -1157,7 +1160,7 @@
         // This match should not be bundled together with the group before,
         // because these items are not adjacent.
         {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY,
-         "chrome.4.0i39i143i362j46i39i143l2j46i39i143i362j46i39i143",
+         "chrome.4.0i39i143i362j46i39i143j185i39i143j46i39i143i362j46i39i143",
          searchbox_stats_4,
          omnibox::TYPE_ENTITY,
          {omnibox::SUBTYPE_PERSONAL, omnibox::SUBTYPE_TRENDS}},
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
index 464dbbb..23535fc0 100644
--- a/components/omnibox/browser/document_provider.cc
+++ b/components/omnibox/browser/document_provider.cc
@@ -422,10 +422,12 @@
   return false;
 }
 
-std::string FindStringKeyOrEmpty(const base::Value::Dict& value,
-                                 base::StringPiece key) {
+// If `value[key]`, returns it. Otherwise, returns `fallback`.
+std::string FindStringKeyOrFallback(const base::Value::Dict& value,
+                                    base::StringPiece key,
+                                    std::string fallback = "") {
   auto* ptr = value.FindString(key);
-  return ptr ? *ptr : "";
+  return ptr ? *ptr : fallback;
 }
 
 }  // namespace
@@ -807,8 +809,8 @@
     }
 
     const base::Value::Dict& result = result_value.GetDict();
-    const std::string title = FindStringKeyOrEmpty(result, "title");
-    const std::string url = FindStringKeyOrEmpty(result, "url");
+    const std::string title = FindStringKeyOrFallback(result, "title");
+    const std::string url = FindStringKeyOrFallback(result, "url");
     if (title.empty() || url.empty()) {
       continue;
     }
@@ -851,23 +853,22 @@
 
     AutocompleteMatch match(this, score, false,
                             AutocompleteMatchType::DOCUMENT_SUGGESTION);
-    // Use full URL for displayed text and navigation. Use "originalUrl" for
-    // deduping if present.
-    match.fill_into_edit = base::UTF8ToUTF16(url);
+    // Use full URL for navigation. If present, use "originalUrl" for display &
+    // deduping, as it's shorter.
+    const std::string short_url =
+        FindStringKeyOrFallback(result, "originalUrl", url);
+    match.fill_into_edit = base::UTF8ToUTF16(short_url);
     match.destination_url = GURL(url);
-    const std::string* original_url = result.FindString("originalUrl");
-    if (original_url) {
-      // |AutocompleteMatch::GURLToStrippedGURL()| will try to use
-      // |GetURLForDeduping()| to extract a doc ID and generate a canonical doc
-      // URL; this is ideal as it handles different URL formats pointing to the
-      // same doc. Otherwise, it'll resort to the typical stripped URL
-      // generation that can still be used for generic deduping and as a key to
-      // |matches_cache_|.
-      match.stripped_destination_url = AutocompleteMatch::GURLToStrippedGURL(
-          GURL(*original_url), input_, client_->GetTemplateURLService(),
-          std::u16string(), /*keep_search_intent_params=*/false,
-          /*normalize_search_terms=*/false);
-    }
+    // `AutocompleteMatch::GURLToStrippedGURL()` will try to use
+    // `GetURLForDeduping()` to extract a doc ID and generate a canonical doc
+    // URL; this is ideal as it handles different URL formats pointing to the
+    // same doc. Otherwise, it'll resort to the typical stripped URL generation
+    // that can still be used for generic deduping and as a key to
+    // `matches_cache_`.
+    match.stripped_destination_url = AutocompleteMatch::GURLToStrippedGURL(
+        GURL(short_url), input_, client_->GetTemplateURLService(),
+        std::u16string(), /*keep_search_intent_params=*/false,
+        /*normalize_search_terms=*/false);
 
     match.contents =
         AutocompleteMatch::SanitizeString(base::UTF8ToUTF16(title));
@@ -875,8 +876,9 @@
     const base::Value::Dict* metadata = result.FindDict("metadata");
     if (metadata) {
       const std::string update_time =
-          FindStringKeyOrEmpty(*metadata, "updateTime");
-      const std::string mimetype = FindStringKeyOrEmpty(*metadata, "mimeType");
+          FindStringKeyOrFallback(*metadata, "updateTime");
+      const std::string mimetype =
+          FindStringKeyOrFallback(*metadata, "mimeType");
       if (metadata->FindString("mimeType")) {
         match.document_type = GetIconForMIMEType(mimetype);
         match.RecordAdditionalInfo(
diff --git a/components/omnibox/browser/document_provider_unittest.cc b/components/omnibox/browser/document_provider_unittest.cc
index 2519424..9d03ea23 100644
--- a/components/omnibox/browser/document_provider_unittest.cc
+++ b/components/omnibox/browser/document_provider_unittest.cc
@@ -359,12 +359,17 @@
             GURL("https://documentprovider.tld/doc?id=1"));
   EXPECT_EQ(matches[0].relevance, 1234);  // Server-specified.
   EXPECT_EQ(matches[0].stripped_destination_url, GURL(kSampleStrippedURL));
+  EXPECT_EQ(matches[0].fill_into_edit,
+            base::UTF8ToUTF16(std::string(kSampleOriginalURL)));
 
   EXPECT_EQ(matches[1].contents, u"Document 2 longer title");
   EXPECT_EQ(matches[1].destination_url,
             GURL("https://documentprovider.tld/doc?id=2"));
   EXPECT_EQ(matches[1].relevance, 0);
-  EXPECT_TRUE(matches[1].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[1].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=2"));
+  EXPECT_EQ(matches[1].fill_into_edit,
+            u"https://documentprovider.tld/doc?id=2");
 
   EXPECT_EQ(matches[2].contents, u"Document 3 longer title");
   EXPECT_EQ(matches[2].destination_url,
@@ -374,6 +379,8 @@
   // using |AutocompleteMatch::GURLToStrippedGURL()|.
   EXPECT_EQ(matches[2].stripped_destination_url,
             "http://sites.google.com/google.com/abc/def");
+  EXPECT_EQ(matches[2].fill_into_edit,
+            u"http://sites.google.com/google.com/abc/def");
 
   EXPECT_FALSE(provider_->backoff_for_session_);
 }
@@ -595,13 +602,15 @@
   EXPECT_EQ(matches[1].destination_url,
             GURL("https://documentprovider.tld/doc?id=2"));
   EXPECT_EQ(matches[1].relevance, 1233);  // Tie demoted
-  EXPECT_TRUE(matches[1].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[1].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=2"));
 
   EXPECT_EQ(matches[2].contents, u"Document 3");
   EXPECT_EQ(matches[2].destination_url,
             GURL("https://documentprovider.tld/doc?id=3"));
   EXPECT_EQ(matches[2].relevance, 1232);  // Tie demoted, twice.
-  EXPECT_TRUE(matches[2].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[2].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=3"));
 
   EXPECT_FALSE(provider_->backoff_for_session_);
 }
@@ -656,7 +665,8 @@
   EXPECT_EQ(matches[1].destination_url,
             GURL("https://documentprovider.tld/doc?id=2"));
   EXPECT_EQ(matches[1].relevance, 1233);  // Tie demoted
-  EXPECT_TRUE(matches[1].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[1].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=2"));
 
   EXPECT_EQ(matches[2].contents, u"Document 3");
   EXPECT_EQ(matches[2].destination_url,
@@ -664,7 +674,8 @@
   // Document 2's demotion caused an implicit tie.
   // Ensure we demote this one as well.
   EXPECT_EQ(matches[2].relevance, 1232);
-  EXPECT_TRUE(matches[2].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[2].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=3"));
 
   EXPECT_FALSE(provider_->backoff_for_session_);
 }
@@ -719,14 +730,16 @@
   EXPECT_EQ(matches[1].destination_url,
             GURL("https://documentprovider.tld/doc?id=2"));
   EXPECT_EQ(matches[1].relevance, 0);  // Tie demoted
-  EXPECT_TRUE(matches[1].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[1].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=2"));
 
   EXPECT_EQ(matches[2].contents, u"Document 3");
   EXPECT_EQ(matches[2].destination_url,
             GURL("https://documentprovider.tld/doc?id=3"));
   // Tie is demoted further.
   EXPECT_EQ(matches[2].relevance, 0);
-  EXPECT_TRUE(matches[2].stripped_destination_url.is_empty());
+  EXPECT_EQ(matches[2].stripped_destination_url,
+            GURL("http://documentprovider.tld/doc?id=3"));
 
   EXPECT_FALSE(provider_->backoff_for_session_);
 }
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc
index bd173cc..dce65dd 100644
--- a/components/omnibox/browser/search_suggestion_parser.cc
+++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -12,6 +12,7 @@
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/containers/fixed_flat_map.h"
+#include "base/feature_list.h"
 #include "base/i18n/icu_string_conversions.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
@@ -30,6 +31,7 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/suggestion_group_util.h"
 #include "components/omnibox/browser/url_prefix.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_fixer.h"
 #include "components/url_formatter/url_formatter.h"
@@ -96,8 +98,14 @@
       return AutocompleteMatchType::NAVSUGGEST;
     case omnibox::TYPE_PERSONALIZED_NAVIGATION:
       return AutocompleteMatchType::NAVSUGGEST_PERSONALIZED;
-    default:
+    default: {
+      // Use `ACMatchType::SEARCH_SUGGEST_ENTITY` for categorical suggestions.
+      if (suggest_type == omnibox::TYPE_CATEGORICAL_QUERY &&
+          base::FeatureList::IsEnabled(omnibox::kCategoricalSuggestions)) {
+        return AutocompleteMatchType::SEARCH_SUGGEST_ENTITY;
+      }
       return AutocompleteMatchType::SEARCH_SUGGEST;
+    }
   }
 }
 
diff --git a/components/omnibox/browser/search_suggestion_parser_unittest.cc b/components/omnibox/browser/search_suggestion_parser_unittest.cc
index 7689d4f..de8de8ad 100644
--- a/components/omnibox/browser/search_suggestion_parser_unittest.cc
+++ b/components/omnibox/browser/search_suggestion_parser_unittest.cc
@@ -5,12 +5,14 @@
 #include "components/omnibox/browser/search_suggestion_parser.h"
 
 #include "base/base64.h"
+#include "base/feature_list.h"
 #include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/test_scheme_classifier.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -726,6 +728,68 @@
   }
 }
 
+TEST(SearchSuggestionParserTest, ParseValidTypes) {
+  std::string json_data = R"([
+      "",
+      ["one", "two", "three", "four", "five"],
+      ["", "", "", "", ""],
+      [],
+      {
+        "google:clientdata": { "bpc": false, "tlw": false },
+        "google:suggestsubtypes": [[], [], [], [], []],
+        "google:suggestrelevance": [607, 606, 605, 604, 603, 602],
+        "google:suggesttype": ["QUERY", "ENTITY", "CATEGORICAL_QUERY", 1, "UNKNOWN"]
+      }])";
+  absl::optional<base::Value> root_val = base::JSONReader::Read(json_data);
+  ASSERT_TRUE(root_val);
+  ASSERT_TRUE(root_val.value().is_list());
+  TestSchemeClassifier scheme_classifier;
+  AutocompleteInput input(u"", metrics::OmniboxEventProto::NTP_REALBOX,
+                          scheme_classifier);
+  SearchSuggestionParser::Results results;
+  ASSERT_TRUE(SearchSuggestionParser::ParseSuggestResults(
+      root_val->GetList(), input, scheme_classifier,
+      /*default_result_relevance=*/400,
+      /*is_keyword_result=*/false, &results));
+
+  ASSERT_EQ(5u, results.suggest_results.size());
+  {
+    const auto& suggestion_result = results.suggest_results[0];
+    ASSERT_EQ(u"one", suggestion_result.suggestion());
+    ASSERT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, suggestion_result.type());
+    ASSERT_EQ(omnibox::TYPE_QUERY, suggestion_result.suggest_type());
+  }
+  {
+    const auto& suggestion_result = results.suggest_results[1];
+    ASSERT_EQ(u"two", suggestion_result.suggestion());
+    ASSERT_EQ(AutocompleteMatchType::SEARCH_SUGGEST_ENTITY,
+              suggestion_result.type());
+    ASSERT_EQ(omnibox::TYPE_ENTITY, suggestion_result.suggest_type());
+  }
+  {
+    const auto& suggestion_result = results.suggest_results[2];
+    ASSERT_EQ(u"three", suggestion_result.suggestion());
+    ASSERT_EQ(base::FeatureList::IsEnabled(omnibox::kCategoricalSuggestions)
+                  ? AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
+                  : AutocompleteMatchType::SEARCH_SUGGEST,
+              suggestion_result.type());
+    ASSERT_EQ(omnibox::TYPE_CATEGORICAL_QUERY,
+              suggestion_result.suggest_type());
+  }
+  {
+    const auto& suggestion_result = results.suggest_results[3];
+    ASSERT_EQ(u"four", suggestion_result.suggestion());
+    ASSERT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, suggestion_result.type());
+    ASSERT_EQ(omnibox::TYPE_QUERY, suggestion_result.suggest_type());
+  }
+  {
+    const auto& suggestion_result = results.suggest_results[4];
+    ASSERT_EQ(u"five", suggestion_result.suggestion());
+    ASSERT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, suggestion_result.type());
+    ASSERT_EQ(omnibox::TYPE_QUERY, suggestion_result.suggest_type());
+  }
+}
+
 TEST(SearchSuggestionParserTest, ParseValidSubtypes) {
   std::string json_data = R"([
       "",
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 35eec65..3913b1c 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -686,4 +686,11 @@
 BASE_FEATURE(kActionsInSuggest,
              "OmniboxActionsInSuggest",
              base::FEATURE_ENABLED_BY_DEFAULT);
+
+// If enabled, treats categorical suggestions just like the entity suggestions
+// by reusing the `ACMatchType::SEARCH_SUGGEST_ENTITY` and reports the original
+// `omnibox::TYPE_CATEGORICAL_QUERY` to the server.
+BASE_FEATURE(kCategoricalSuggestions,
+             "CategoricalSuggestions",
+             base::FEATURE_ENABLED_BY_DEFAULT);
 }  // namespace omnibox
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 4b78d1e1..59e6046 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -163,6 +163,9 @@
 // Data driven feature; flag helps tune behavior.
 BASE_DECLARE_FEATURE(kActionsInSuggest);
 
+// Adds support for categorical suggestion type.
+BASE_DECLARE_FEATURE(kCategoricalSuggestions);
+
 }  // namespace omnibox
 
 #endif  // COMPONENTS_OMNIBOX_COMMON_OMNIBOX_FEATURES_H_
diff --git a/components/optimization_guide/core/model_util.cc b/components/optimization_guide/core/model_util.cc
index 4e1a4cb86..5fc70e1 100644
--- a/components/optimization_guide/core/model_util.cc
+++ b/components/optimization_guide/core/model_util.cc
@@ -212,6 +212,20 @@
   return true;
 }
 
+base::FilePath ConvertToRelativePath(const base::FilePath& parent,
+                                     const base::FilePath& child) {
+  DCHECK(parent.IsAbsolute());
+  DCHECK(child.IsAbsolute());
+  DCHECK(parent.IsParent(child));
+  const auto parent_components = parent.GetComponents();
+  const auto child_components = child.GetComponents();
+  base::FilePath relative_path;
+  for (size_t i = parent_components.size(); i < child_components.size(); i++) {
+    relative_path = relative_path.Append(child_components[i]);
+  }
+  return relative_path;
+}
+
 std::string GetModelCacheKeyHash(proto::ModelCacheKey model_cache_key) {
   std::string bytes;
   model_cache_key.SerializeToString(&bytes);
diff --git a/components/optimization_guide/core/model_util.h b/components/optimization_guide/core/model_util.h
index 42e3a80..080f040 100644
--- a/components/optimization_guide/core/model_util.h
+++ b/components/optimization_guide/core/model_util.h
@@ -51,6 +51,12 @@
 // Checks all the files in |file_paths_to_check| exists.
 bool CheckAllPathsExist(const std::vector<base::FilePath>& file_paths_to_check);
 
+// Returns the relative filepath for |child| w.r.t. |parent|. For example, with
+// child="/foo/bar/baz/abc.txt"  and parent="/foo/bar/", this returns the
+// relative path "baz/abc.txt".
+base::FilePath ConvertToRelativePath(const base::FilePath& parent,
+                                     const base::FilePath& child);
+
 // Returns the hash of |model_cache_key| that can be used as key in a
 // persistent dict, or can be used as file paths.
 std::string GetModelCacheKeyHash(proto::ModelCacheKey model_cache_key);
diff --git a/components/optimization_guide/core/optimization_guide_store.cc b/components/optimization_guide/core/optimization_guide_store.cc
index 2263ad52..2699d2d 100644
--- a/components/optimization_guide/core/optimization_guide_store.cc
+++ b/components/optimization_guide/core/optimization_guide_store.cc
@@ -105,23 +105,6 @@
   return key_set.find(key) != key_set.end();
 }
 
-// Returns the relative filepath for |child| w.r.t. parent. For example, with
-// child="/foo/bar/baz/abc.txt"  and parent="/foo/bar/", this returns the
-// relative path "baz/abc.txt".
-base::FilePath ConvertToRelativePath(const base::FilePath& parent,
-                                     const base::FilePath& child) {
-  DCHECK(parent.IsAbsolute());
-  DCHECK(child.IsAbsolute());
-  DCHECK(parent.IsParent(child));
-  const auto parent_components = parent.GetComponents();
-  const auto child_components = child.GetComponents();
-  base::FilePath relative_path;
-  for (size_t i = parent_components.size(); i < child_components.size(); i++) {
-    relative_path = relative_path.Append(child_components[i]);
-  }
-  return relative_path;
-}
-
 }  // namespace
 
 OptimizationGuideStore::OptimizationGuideStore(
diff --git a/components/optimization_guide/core/prediction_model_store.cc b/components/optimization_guide/core/prediction_model_store.cc
index e9fadce..2f87e2d 100644
--- a/components/optimization_guide/core/prediction_model_store.cc
+++ b/components/optimization_guide/core/prediction_model_store.cc
@@ -161,8 +161,9 @@
   if (!metadata) {
     return false;
   }
-  // Check the existence of model dir as an indication of validity.
-  return metadata->GetModelBaseDir().has_value();
+  // Model dir should exist and be a relative path.
+  return metadata->GetModelBaseDir() &&
+         !metadata->GetModelBaseDir()->IsAbsolute();
 }
 
 bool PredictionModelStore::HasModelWithVersion(
@@ -175,6 +176,11 @@
   if (!metadata) {
     return false;
   }
+  if (!metadata->GetModelBaseDir() ||
+      metadata->GetModelBaseDir()->IsAbsolute()) {
+    // Model dir should exist and be a relative path.
+    return false;
+  }
   auto actual_version = metadata->GetVersion();
   if (!actual_version) {
     RemoveModel(optimization_target, model_cache_key,
@@ -205,19 +211,18 @@
     return;
   }
   auto base_model_dir = metadata->GetModelBaseDir();
-  if (!base_model_dir) {
+  if (!base_model_dir || base_model_dir->IsAbsolute()) {
     RemoveModel(optimization_target, model_cache_key,
                 PredictionModelStoreModelRemovalReason::kInvalidModelDir);
     std::move(callback).Run(nullptr);
     return;
   }
-  DCHECK(base_store_dir_.IsParent(*base_model_dir));
 
   background_task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(
           &PredictionModelStore::LoadAndVerifyModelInBackgroundThread,
-          optimization_target, *base_model_dir),
+          optimization_target, base_store_dir_.Append(*base_model_dir)),
       base::BindOnce(&PredictionModelStore::OnModelLoaded,
                      weak_ptr_factory_.GetWeakPtr(), optimization_target,
                      model_cache_key, std::move(callback)));
@@ -277,8 +282,7 @@
 
   ModelStoreMetadataEntryUpdater metadata(local_state_, optimization_target,
                                           model_cache_key);
-  auto base_model_dir = metadata.GetModelBaseDir();
-  DCHECK(base_store_dir_.IsParent(*base_model_dir));
+  DCHECK(!metadata.GetModelBaseDir()->IsAbsolute());
   metadata.SetVersion(model_info.version());
   if (model_info.has_valid_duration()) {
     metadata.SetExpiryTime(
@@ -308,7 +312,8 @@
            ? base::Seconds(model_info.valid_duration().seconds())
            : features::StoredModelsValidDuration()));
   metadata.SetKeepBeyondValidDuration(model_info.keep_beyond_valid_duration());
-  metadata.SetModelBaseDir(base_model_dir);
+  metadata.SetModelBaseDir(
+      ConvertToRelativePath(base_store_dir_, base_model_dir));
 
   background_task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
@@ -371,10 +376,16 @@
                                           model_cache_key);
   auto base_model_dir = metadata.GetModelBaseDir();
   if (base_model_dir) {
-    DCHECK(base_store_dir_.IsParent(*base_model_dir));
+    // Backward compatibility: Model dirs were absolute in the earlier versions,
+    // and it was only in experiment. The latest versions use relative paths.
+    DCHECK(!base_model_dir->IsAbsolute() ||
+           base_store_dir_.IsParent(*base_model_dir));
+    base::FilePath absolute_model_dir =
+        base_model_dir->IsAbsolute() ? *base_model_dir
+                                     : base_store_dir_.Append(*base_model_dir);
     ScopedDictPrefUpdate pref_update(
         local_state_, prefs::localstate::kStoreFilePathsToDelete);
-    pref_update->Set(FilePathToString(*base_model_dir), true);
+    pref_update->Set(FilePathToString(absolute_model_dir), true);
   }
   // Continue removing the metadata even if the model dirs does not exist.
   metadata.ClearMetadata();
@@ -385,11 +396,12 @@
   DCHECK(local_state_);
   for (const auto& expired_model_dir :
        ModelStoreMetadataEntryUpdater::PurgeAllInactiveMetadata(local_state_)) {
-    DCHECK(base_store_dir_.IsParent(expired_model_dir));
+    DCHECK(!expired_model_dir.IsAbsolute());
     // This is called at startup. So no need to schedule the deletion of the
     // model dirs, and instead can be deleted immediately.
     background_task_runner_->PostTask(
-        FROM_HERE, base::GetDeletePathRecursivelyCallback(expired_model_dir));
+        FROM_HERE, base::GetDeletePathRecursivelyCallback(
+                       base_store_dir_.Append(expired_model_dir)));
   }
 }
 
diff --git a/components/optimization_guide/core/prediction_model_store_unittest.cc b/components/optimization_guide/core/prediction_model_store_unittest.cc
index 26cfb769..ce12dce 100644
--- a/components/optimization_guide/core/prediction_model_store_unittest.cc
+++ b/components/optimization_guide/core/prediction_model_store_unittest.cc
@@ -168,6 +168,12 @@
             model_detail.base_model_dir.Append(GetBaseFileNameForModels()));
   EXPECT_EQ(0, loaded_model->model_info().additional_files_size());
 
+  auto metadata_entry = ModelStoreMetadataEntry::GetModelMetadataEntryIfExists(
+      local_state_prefs_.get(), kTestOptimizationTargetFoo, model_cache_key);
+  EXPECT_EQ(
+      model_detail.base_model_dir,
+      temp_models_dir_.GetPath().Append(*metadata_entry->GetModelBaseDir()));
+
   WaitForModeLoad(kTestOptimizationTargetBar, model_cache_key);
   EXPECT_FALSE(last_loaded_prediction_model());
 }
@@ -279,6 +285,9 @@
       local_state_prefs_.get(), kTestOptimizationTargetFoo, model_cache_key);
   EXPECT_LE(base::Minutes(99),
             metadata_entry->GetExpiryTime() - base::Time::Now());
+  EXPECT_EQ(
+      model_detail.base_model_dir,
+      temp_models_dir_.GetPath().Append(*metadata_entry->GetModelBaseDir()));
   EXPECT_TRUE(metadata_entry->GetKeepBeyondValidDuration());
 }
 
diff --git a/components/page_load_metrics/common/page_load_metrics.mojom b/components/page_load_metrics/common/page_load_metrics.mojom
index 65e20e5..f1d3e332 100644
--- a/components/page_load_metrics/common/page_load_metrics.mojom
+++ b/components/page_load_metrics/common/page_load_metrics.mojom
@@ -404,6 +404,17 @@
   // e.g. if there are two resources, and one is handed by the service worker,
   // and one did not, this flag will be true because one was network fallback.
   bool mock_fallback;
+
+  // True even if one dictionary sub resource is handled by a service worker.
+  // i.e. the service worker called `respondWith` to return the resource.
+  // e.g. if there are two resources, and one is handed by the service worker,
+  // and one did not, this flag will be true because one was handled.
+  bool dictionary_handled;
+  // True even if one dictionary sub resource caused a network fallback.
+  // i.e. the service worker did not call `respondWith`, and network fallback.
+  // e.g. if there are two resources, and one is handed by the service worker,
+  // and one did not, this flag will be true because one was network fallback.
+  bool dictionary_fallback;
 };
 
 // Enumeration of distinct cache types.
diff --git a/components/page_load_metrics/common/page_load_metrics_mojom_traits.cc b/components/page_load_metrics/common/page_load_metrics_mojom_traits.cc
index 0c9aa00b..52a9826 100644
--- a/components/page_load_metrics/common/page_load_metrics_mojom_traits.cc
+++ b/components/page_load_metrics/common/page_load_metrics_mojom_traits.cc
@@ -56,6 +56,8 @@
   out->speculation_rules_fallback = data.speculation_rules_fallback();
   out->mock_handled = data.mock_handled();
   out->mock_fallback = data.mock_fallback();
+  out->dictionary_handled = data.dictionary_handled();
+  out->dictionary_fallback = data.dictionary_fallback();
   return true;
 }
 
diff --git a/components/page_load_metrics/common/page_load_metrics_mojom_traits.h b/components/page_load_metrics/common/page_load_metrics_mojom_traits.h
index c1ddf730..4460f7d 100644
--- a/components/page_load_metrics/common/page_load_metrics_mojom_traits.h
+++ b/components/page_load_metrics/common/page_load_metrics_mojom_traits.h
@@ -158,6 +158,15 @@
     return d.mock_fallback;
   }
 
+  static bool dictionary_handled(
+      const blink::ServiceWorkerSubresourceLoadMetrics& d) {
+    return d.dictionary_handled;
+  }
+  static bool dictionary_fallback(
+      const blink::ServiceWorkerSubresourceLoadMetrics& d) {
+    return d.dictionary_fallback;
+  }
+
   static bool Read(
       page_load_metrics::mojom::ServiceWorkerSubresourceLoadMetricsDataView
           data,
diff --git a/components/password_manager/core/browser/password_form.cc b/components/password_manager/core/browser/password_form.cc
index 380c5be9..e11d5204 100644
--- a/components/password_manager/core/browser/password_form.cc
+++ b/components/password_manager/core/browser/password_form.cc
@@ -4,10 +4,10 @@
 
 #include "components/password_manager/core/browser/password_form.h"
 
-#include <compare>
 #include <ostream>
 #include <sstream>
 #include <string>
+#include <tuple>
 
 #include "base/json/json_writer.h"
 #include "base/json/values_util.h"
@@ -219,15 +219,23 @@
     : value(value), field_renderer_id(field_renderer_id), name(name) {}
 
 AlternativeElement::AlternativeElement(const AlternativeElement& rhs) = default;
+
 AlternativeElement::AlternativeElement(AlternativeElement&& rhs) = default;
+
 AlternativeElement& AlternativeElement::operator=(
     const AlternativeElement& rhs) = default;
+
 AlternativeElement& AlternativeElement::operator=(AlternativeElement&& rhs) =
     default;
+
 AlternativeElement::~AlternativeElement() = default;
+
 bool AlternativeElement::operator==(const AlternativeElement&) const = default;
-std::strong_ordering AlternativeElement::operator<=>(
-    const AlternativeElement&) const = default;
+
+bool AlternativeElement::operator<(const AlternativeElement& other) const {
+  return std::tie(value, field_renderer_id, name) <
+         std::tie(other.value, other.field_renderer_id, other.name);
+}
 
 std::ostream& operator<<(std::ostream& os, const AlternativeElement& element) {
   base::Value::Dict element_json;
diff --git a/components/password_manager/core/browser/password_form.h b/components/password_manager/core/browser/password_form.h
index 52fa5ae..a737d53 100644
--- a/components/password_manager/core/browser/password_form.h
+++ b/components/password_manager/core/browser/password_form.h
@@ -45,7 +45,7 @@
   ~AlternativeElement();
 
   bool operator==(const AlternativeElement&) const;
-  std::strong_ordering operator<=>(const AlternativeElement&) const;
+  bool operator<(const AlternativeElement&) const;
 
   // The value of the field.
   std::u16string value;
diff --git a/components/password_manager/core/browser/password_manager_features_util_unittest.cc b/components/password_manager/core/browser/password_manager_features_util_unittest.cc
index 843888f..22695364 100644
--- a/components/password_manager/core/browser/password_manager_features_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_features_util_unittest.cc
@@ -62,8 +62,7 @@
     sync_service_.SetHasSyncConsent(false);
     sync_service_.SetTransportState(
         syncer::SyncService::TransportState::ACTIVE);
-    sync_service_.SetDisableReasons(
-        {syncer::SyncService::DisableReason::DISABLE_REASON_USER_CHOICE});
+    sync_service_.SetDisableReasons({});
     ASSERT_FALSE(sync_service_.IsSyncFeatureEnabled());
   }
 
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 6671318..f431b1b 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -650,7 +650,11 @@
   kNoteEdited = 10,
   kNoteDeleted = 11,
   kCredentialRowWithNoteClicked = 12,
-  kMaxValue = kCredentialRowWithNoteClicked,
+  kNotePartiallySelected = 13,
+  kNoteFullySelected = 14,
+  kNotePartiallyCopied = 15,
+  kNoteFullyCopied = 16,
+  kMaxValue = kNoteFullyCopied,
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
diff --git a/components/password_manager/core/browser/password_store_proxy_backend.cc b/components/password_manager/core/browser/password_store_proxy_backend.cc
index 8e99883b..15a4e094 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend.cc
@@ -35,11 +35,6 @@
 
 using sync_util::IsPasswordSyncEnabled;
 
-bool ShouldExecuteDeletionsOnShadowBackend(PrefService* prefs,
-                                           bool is_syncing) {
-  return is_syncing;
-}
-
 bool ShouldErrorResultInFallback(PasswordStoreBackendError error) {
   switch (error.recovery_type) {
     case PasswordStoreBackendErrorRecoveryType::kUnrecoverable:
@@ -223,8 +218,7 @@
     const PasswordForm& form,
     PasswordChangesOrErrorReply callback) {
   main_backend()->RemoveLoginAsync(form, std::move(callback));
-  if (ShouldExecuteDeletionsOnShadowBackend(
-          prefs_, IsPasswordSyncEnabled(sync_service_))) {
+  if (UsesAndroidBackendAsMainBackend()) {
     shadow_backend()->RemoveLoginAsync(form, base::DoNothing());
   }
 }
@@ -242,8 +236,7 @@
   main_backend()->RemoveLoginsByURLAndTimeAsync(
       url_filter, delete_begin, delete_end, base::NullCallback(),
       std::move(callback));
-  if (ShouldExecuteDeletionsOnShadowBackend(
-          prefs_, IsPasswordSyncEnabled(sync_service_))) {
+  if (UsesAndroidBackendAsMainBackend()) {
     shadow_backend()->RemoveLoginsByURLAndTimeAsync(
         url_filter, std::move(delete_begin), std::move(delete_end),
         base::NullCallback(), base::DoNothing());
@@ -256,8 +249,7 @@
     PasswordChangesOrErrorReply callback) {
   main_backend()->RemoveLoginsCreatedBetweenAsync(delete_begin, delete_end,
                                                   std::move(callback));
-  if (ShouldExecuteDeletionsOnShadowBackend(
-          prefs_, IsPasswordSyncEnabled(sync_service_))) {
+  if (UsesAndroidBackendAsMainBackend()) {
     shadow_backend()->RemoveLoginsCreatedBetweenAsync(
         std::move(delete_begin), std::move(delete_end), base::DoNothing());
   }
diff --git a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
index c6f4343..0a377499 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
@@ -363,6 +363,26 @@
 }
 
 TEST_F(PasswordStoreProxyBackendTest,
+       UseBuiltInBackendWhenUnenrolledRemoveLoginAsync) {
+  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
+                      true);
+  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
+  PasswordForm form = CreateTestForm();
+  PasswordStoreChangeList change_list;
+  change_list.push_back(PasswordStoreChange(Type::REMOVE, form));
+  EXPECT_CALL(mock_reply,
+              Run(VariantWith<PasswordChanges>(Optional(change_list))));
+  // Removals are not mirrored on the android backend.
+  EXPECT_CALL(built_in_backend(), RemoveLoginAsync(Eq(form), _))
+      .WillOnce(WithArg<1>(
+          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
+            std::move(reply).Run(change_list);
+          })));
+  EXPECT_CALL(android_backend(), RemoveLoginAsync(Eq(form), _)).Times(0);
+  proxy_backend().RemoveLoginAsync(form, mock_reply.Get());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
        UseMainBackendToRemoveLoginsByURLAndTimeAsync) {
   base::Time kStart = base::Time::FromTimeT(111111);
   base::Time kEnd = base::Time::FromTimeT(22222222);
@@ -386,6 +406,32 @@
 }
 
 TEST_F(PasswordStoreProxyBackendTest,
+       UseBuiltInBackendToRemoveLoginsByURLAndTimeAsyncWhenUnenrolled) {
+  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
+                      true);
+  base::Time kStart = base::Time::FromTimeT(111111);
+  base::Time kEnd = base::Time::FromTimeT(22222222);
+  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
+  PasswordStoreChangeList change_list;
+  change_list.push_back(PasswordStoreChange(Type::REMOVE, CreateTestForm()));
+  EXPECT_CALL(mock_reply,
+              Run(VariantWith<PasswordChanges>(Optional(change_list))));
+  // Removals are not mirrored on the android backend.
+  EXPECT_CALL(built_in_backend(),
+              RemoveLoginsByURLAndTimeAsync(_, Eq(kStart), Eq(kEnd), _, _))
+      .WillOnce(WithArg<4>(
+          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
+            std::move(reply).Run(change_list);
+          })));
+  EXPECT_CALL(android_backend(),
+              RemoveLoginsByURLAndTimeAsync(_, Eq(kStart), Eq(kEnd), _, _))
+      .Times(0);
+  proxy_backend().RemoveLoginsByURLAndTimeAsync(
+      base::BindRepeating(&FilterNoUrl), kStart, kEnd, base::NullCallback(),
+      mock_reply.Get());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
        UseMainBackendToRemoveLoginsCreatedBetweenAsync) {
   base::Time kStart = base::Time::FromTimeT(111111);
   base::Time kEnd = base::Time::FromTimeT(22222222);
@@ -408,6 +454,31 @@
 }
 
 TEST_F(PasswordStoreProxyBackendTest,
+       UseBuiltInBackendToRemoveLoginsCreatedBetweenAsyncWhenUnenrolled) {
+  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
+                      true);
+  base::Time kStart = base::Time::FromTimeT(111111);
+  base::Time kEnd = base::Time::FromTimeT(22222222);
+  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
+  PasswordStoreChangeList change_list;
+  change_list.push_back(PasswordStoreChange(Type::REMOVE, CreateTestForm()));
+  EXPECT_CALL(mock_reply,
+              Run(VariantWith<PasswordChanges>(Optional(change_list))));
+  // Removals are not mirrored on the android backend.
+  EXPECT_CALL(built_in_backend(),
+              RemoveLoginsCreatedBetweenAsync(Eq(kStart), Eq(kEnd), _))
+      .WillOnce(WithArg<2>(
+          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
+            std::move(reply).Run(change_list);
+          })));
+  EXPECT_CALL(android_backend(),
+              RemoveLoginsCreatedBetweenAsync(Eq(kStart), Eq(kEnd), _))
+      .Times(0);
+  proxy_backend().RemoveLoginsCreatedBetweenAsync(kStart, kEnd,
+                                                  mock_reply.Get());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
        UseMainBackendToDisableAutoSignInForOriginsAsync) {
   base::MockCallback<base::OnceClosure> mock_reply;
   EXPECT_CALL(mock_reply, Run);
diff --git a/components/password_manager/ios/ios_password_manager_driver_factory.mm b/components/password_manager/ios/ios_password_manager_driver_factory.mm
index 9d26bc80..f06b8d76 100644
--- a/components/password_manager/ios/ios_password_manager_driver_factory.mm
+++ b/components/password_manager/ios/ios_password_manager_driver_factory.mm
@@ -6,6 +6,10 @@
 
 #include "components/password_manager/core/browser/password_manager.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 // static
 IOSPasswordManagerDriver*
 IOSPasswordManagerDriverFactory::FromWebStateAndWebFrame(
diff --git a/components/password_manager/ios/password_controller_driver_helper.mm b/components/password_manager/ios/password_controller_driver_helper.mm
index c24869d..5e8ddad 100644
--- a/components/password_manager/ios/password_controller_driver_helper.mm
+++ b/components/password_manager/ios/password_controller_driver_helper.mm
@@ -6,6 +6,10 @@
 
 #import "components/password_manager/ios/ios_password_manager_driver_factory.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 @implementation PasswordControllerDriverHelper {
   web::WebState* _webState;
 }
diff --git a/components/performance_manager/public/features.h b/components/performance_manager/public/features.h
index 5bd08e57..0943715 100644
--- a/components/performance_manager/public/features.h
+++ b/components/performance_manager/public/features.h
@@ -119,13 +119,31 @@
 // * If kHeuristicMemorySaver is enabled, HeuristicMemorySaverPolicy will be
 //   turned on.
 // * If kHeuristicMemorySaver is disabled, all memory saver policies will be
-//   turned off (for the control group of experiemnts).
+//   turned off (for the control group of experiments).
+//
+// This only affects the original UI. If the experimental multistate UI is
+// enabled (through the kHighEfficiencyMultistateMode feature), this is not
+// checked.
 //
 // Note: to get uniform control and experiment groups,
 // kForceHeuristicMemorySaver should only be tested for users who are valid for
 // randomized studies (eg. not for users with the HighEfficiencyModeState pref
 // managed by enterprise policy). It's always safe to read kHeuristicMemorySaver
 // without kForceHeuristicMemorySaver to get the policy params.
+//
+// To run an A/B experiment, the following feature configs should be used:
+//
+// * Experiment group(s):
+//   * kForceHeuristicMemorySaver ON
+//   * kHeuristicMemorySaver ON (with parameters to control the policy)
+//   * kHighEfficiencyMultistateMode OFF
+// * Control group:
+//   * kForceHeuristicMemorySaver ON
+//   * kHeuristicMemorySaver OFF
+//   * kHighEfficiencyMultistateMode OFF
+//
+// Users who enable kHighEfficiencyMultistateMode through chrome://flags will
+// be excluded from the experiment.
 BASE_DECLARE_FEATURE(kForceHeuristicMemorySaver);
 
 // Round 2 Performance Controls features
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
index 8f591f4..fd233e9c 100644
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -7,6 +7,7 @@
 #include "base/no_destructor.h"
 #include "base/notreached.h"
 #include "build/build_config.h"
+#include "components/permissions/features.h"
 #include "components/permissions/permission_util.h"
 #include "components/permissions/request_type.h"
 #include "components/strings/grit/components_strings.h"
@@ -244,7 +245,9 @@
 #endif
 
 bool PermissionRequest::ShouldUseTwoOriginPrompt() const {
-  return request_type_ == RequestType::kStorageAccess;
+  return request_type_ == RequestType::kStorageAccess &&
+         base::FeatureList::IsEnabled(
+             permissions::features::kPermissionStorageAccessAPI);
 }
 
 void PermissionRequest::PermissionGranted(bool is_one_time) {
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc
index 7db2994a..9726659 100644
--- a/components/permissions/permission_request_manager.cc
+++ b/components/permissions/permission_request_manager.cc
@@ -544,6 +544,10 @@
 }
 
 GURL PermissionRequestManager::GetEmbeddingOrigin() const {
+  if (embedding_origin_for_testing_.has_value()) {
+    return embedding_origin_for_testing_.value();
+  }
+
   return PermissionUtil::GetLastCommittedOriginAsURL(
       web_contents()->GetPrimaryMainFrame());
 }
diff --git a/components/permissions/permission_request_manager.h b/components/permissions/permission_request_manager.h
index 4d7ff6e6..066a4f7 100644
--- a/components/permissions/permission_request_manager.h
+++ b/components/permissions/permission_request_manager.h
@@ -238,6 +238,10 @@
     enabled_app_level_notification_permission_for_testing_ = enabled;
   }
 
+  void set_embedding_origin_for_testing(const GURL& embedding_origin) {
+    embedding_origin_for_testing_ = embedding_origin;
+  }
+
   base::ObserverList<Observer>* get_observer_list_for_testing() {
     CHECK_IS_TEST();
     return &observer_list_;
@@ -495,6 +499,8 @@
 
   absl::optional<bool> enabled_app_level_notification_permission_for_testing_;
 
+  absl::optional<GURL> embedding_origin_for_testing_;
+
   // A timer is used to pre-ignore the permission request if it's been displayed
   // as a quiet chip.
   base::OneShotTimer preignore_timer_;
diff --git a/components/permissions/test/mock_permission_prompt.cc b/components/permissions/test/mock_permission_prompt.cc
index 578fea33..03bbbcd 100644
--- a/components/permissions/test/mock_permission_prompt.cc
+++ b/components/permissions/test/mock_permission_prompt.cc
@@ -7,6 +7,7 @@
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "components/permissions/features.h"
 #include "components/permissions/permission_uma_util.h"
 #include "components/permissions/request_type.h"
 #include "components/permissions/test/mock_permission_prompt_factory.h"
@@ -61,7 +62,9 @@
     EXPECT_FALSE(permissions::GetIconId(request_type).is_empty());
 #endif
     EXPECT_EQ(request->ShouldUseTwoOriginPrompt(),
-              request_type == permissions::RequestType::kStorageAccess);
+              request_type == permissions::RequestType::kStorageAccess &&
+                  base::FeatureList::IsEnabled(
+                      permissions::features::kPermissionStorageAccessAPI));
   }
 }
 
diff --git a/components/permissions/unused_site_permissions_service.cc b/components/permissions/unused_site_permissions_service.cc
index 8954e41..1185ec4 100644
--- a/components/permissions/unused_site_permissions_service.cc
+++ b/components/permissions/unused_site_permissions_service.cc
@@ -172,11 +172,7 @@
 
   base::Value::List* permission_type_list =
       stored_value.GetDict().FindList(kRevokedKey);
-  // Check the format of the returned value since it is coming from disk.
-  if (!permission_type_list) {
-    NOTREACHED();
-    return;
-  }
+  CHECK(permission_type_list);
 
   // Re-grant the permissions that are revoked. This service only auto-revokes
   // permissions that were ALLOW, so re-granting will switch those permissions
diff --git a/components/permissions_strings.grdp b/components/permissions_strings.grdp
index dd1e73e..2573edc 100644
--- a/components/permissions_strings.grdp
+++ b/components/permissions_strings.grdp
@@ -115,6 +115,9 @@
   <message name="IDS_AR_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to use AR. Follows a prompt: 'This site would like to:">
     Create a 3D map of your surroundings and track camera position
   </message>
+  <message name="IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_PROMPT_TITLE" translateable="false" desc="The label that is used to introduce storage access permission request to the user in a popup.">
+    <ph name="EMBEDDED_URL">$1<ex>news.site</ex></ph> wants to verify who you are before displaying content on <ph name="TOP_LEVEL_URL">$2<ex>content_domain.site</ex></ph>
+  </message>
   <message name="IDS_STORAGE_ACCESS_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site needs access to its data while it is embedded into another site. Follows a prompt: 'This site would like to:'">
     Access cookies and site data.
   </message>
@@ -123,6 +126,9 @@
 
 This will otherwise be blocked by your privacy settings. This will allow the content you interacted with to work correctly, but may allow <ph name="EMBEDDED_URL">$1<ex>news.site</ex></ph> to track your activity.
   </message>
+  <message name="IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_EXPLANATION" translateable="false" desc="Explanation of the permission request shown if the user is visiting a site needs access to its data while it is embedded into another site.">
+    Allow <ph name="EMBEDDED_URL">$1<ex>news.site</ex></ph> to access info they've saved about you? Access lasts for 30 days. See settings to turn Embedded content on or off.
+  </message>
   <message name="IDS_WINDOW_MANAGEMENT_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to manage windows. Follows a prompt: 'This site would like to:'">
     Manage windows on all your displays
   </message>
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc
index 502e6e5..90ed0ff 100644
--- a/components/policy/core/common/policy_pref_names.cc
+++ b/components/policy/core/common/policy_pref_names.cc
@@ -122,16 +122,6 @@
 const char kSendMouseEventsDisabledFormControlsEnabled[] =
     "policy.send_mouse_events_disabled_form_controls_enabled";
 
-// If true the feature PPAPISharedImagesSwapChain will be allowed, otherwise
-// feature will be forced off.
-const char kPPAPISharedImagesSwapChainAllowed[] =
-    "policy.ppapi_shared_images_swap_chain_allowed";
-
-// If true then support for the PPB_VideoDecoder(Dev) API will be enabled;
-// otherwise the browser will decide whether the API is supported.
-const char kForceEnablePepperVideoDecoderDevAPI[] =
-    "policy.force_enable_pepper_video_decoder_dev_api";
-
 // Boolean controlling whether SafeSearch is mandatory for Google Web Searches.
 const char kForceGoogleSafeSearch[] = "settings.force_google_safesearch";
 
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h
index 84870dcac..1c51950 100644
--- a/components/policy/core/common/policy_pref_names.h
+++ b/components/policy/core/common/policy_pref_names.h
@@ -63,8 +63,6 @@
 extern const char kEventPathEnabled[];
 extern const char kOffsetParentNewSpecBehaviorEnabled[];
 extern const char kSendMouseEventsDisabledFormControlsEnabled[];
-extern const char kPPAPISharedImagesSwapChainAllowed[];
-extern const char kForceEnablePepperVideoDecoderDevAPI[];
 extern const char kForceGoogleSafeSearch[];
 extern const char kForceYouTubeRestrict[];
 extern const char kHideWebStoreIcon[];
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/ForceEnablePepperVideoDecoderDevAPI.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/ForceEnablePepperVideoDecoderDevAPI.yaml
index 9beeab6..9a92c9c 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/ForceEnablePepperVideoDecoderDevAPI.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/ForceEnablePepperVideoDecoderDevAPI.yaml
@@ -13,17 +13,16 @@
   This policy can be used in case our ongoing elimination of support for this API
   exposes problems. If you must use the policy, please file a bug on crbug.com
   explaining your use case and CC {blundell, vasilyt}@chromium.org. The policy is
-  scheduled to live through <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
-  version 114, after which support for this API is planned to be eliminated
-  unconditionally.
+  available through <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
+  version 114, after which support for this API was eliminated unconditionally.
 
   NOTE: Only newly-started renderer processes will reflect changes to this
   policy while the browser is running.
 
 supported_on:
-# TODO(crbug.com/1408421): Remove this policy on ~May 6 after 114 has branched.
-- chrome.*:111-
-- chrome_os:111-
+- chrome.*:111-114
+- chrome_os:111-114
+deprecated: true
 device_only: false
 supported_chrome_os_management:
 - google_cloud
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/PPAPISharedImagesSwapChainAllowed.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/PPAPISharedImagesSwapChainAllowed.yaml
index 0565347a..9761cf8b 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/PPAPISharedImagesSwapChainAllowed.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/PPAPISharedImagesSwapChainAllowed.yaml
@@ -23,9 +23,9 @@
   policy while the browser is running.
 
 supported_on:
-# TODO(crbug.com/1410109): Remove this policy on ~May 6 after 114 has branched.
-- chrome.*:110-
-- chrome_os:110-
+- chrome.*:110-114
+- chrome_os:110-114
+deprecated: true
 device_only: false
 supported_chrome_os_management:
 - google_cloud
diff --git a/components/policy/test/data/policy_test_cases.json b/components/policy/test/data/policy_test_cases.json
index b4abee3d..ab95e34 100644
--- a/components/policy/test/data/policy_test_cases.json
+++ b/components/policy/test/data/policy_test_cases.json
@@ -21786,80 +21786,10 @@
     "reason_for_missing_test": "Policy was removed"
   },
   "PPAPISharedImagesSwapChainAllowed": {
-    "os": [
-      "win",
-      "linux",
-      "mac",
-      "chromeos_ash",
-      "chromeos_lacros"
-    ],
-    "policy_pref_mapping_tests": [
-      {
-        "policies": {},
-        "prefs": {
-          "policy.ppapi_shared_images_swap_chain_allowed": {
-            "location": "local_state",
-            "default_value": true
-          }
-        }
-      },
-      {
-        "policies": { "PPAPISharedImagesSwapChainAllowed": true },
-        "prefs": {
-          "policy.ppapi_shared_images_swap_chain_allowed": {
-            "location": "local_state",
-            "value": true
-          }
-        }
-      },
-      {
-        "policies": { "PPAPISharedImagesSwapChainAllowed": false },
-        "prefs": {
-          "policy.ppapi_shared_images_swap_chain_allowed": {
-            "location": "local_state",
-            "value": false
-          }
-        }
-      }
-    ]
+    "reason_for_missing_test": "Policy was removed"
   },
   "ForceEnablePepperVideoDecoderDevAPI": {
-    "os": [
-      "win",
-      "linux",
-      "mac",
-      "chromeos_ash",
-      "chromeos_lacros"
-    ],
-    "policy_pref_mapping_tests": [
-      {
-        "policies": {},
-        "prefs": {
-          "policy.force_enable_pepper_video_decoder_dev_api": {
-            "location": "local_state",
-            "default_value": false
-          }
-        }
-      },
-      {
-        "policies": { "ForceEnablePepperVideoDecoderDevAPI": true },
-        "prefs": {
-          "policy.force_enable_pepper_video_decoder_dev_api": {
-            "location": "local_state",
-            "value": true
-          }
-        }
-      },
-      {
-        "policies": { "ForceEnablePepperVideoDecoderDevAPI": false },
-        "prefs": {
-          "policy.force_enable_pepper_video_decoder_dev_api": {
-            "location": "local_state",
-            "value": false
-          }
-        }
-      }
-    ]
+    "reason_for_missing_test": "Policy was removed"
   },
   "PrivacySandboxPromptEnabled": {
     "os": [
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 3a1fce46a..06e14d8 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -2326,11 +2326,8 @@
   page_params->content_area = gfx::Rect(print_params.page_size);
   bool is_pdf =
       IsPrintingPdfFrame(prep_frame_view_->frame(), prep_frame_view_->node());
-  PrintPageInternal(print_params, printed_pages[0], page_count,
-                    GetScaleFactor(print_params.scale_factor, is_pdf), frame,
-                    &metafile);
-  for (size_t i = 1; i < printed_pages.size(); ++i) {
-    PrintPageInternal(print_params, printed_pages[i], page_count,
+  for (uint32_t printed_page : printed_pages) {
+    PrintPageInternal(print_params, printed_page, page_count,
                       GetScaleFactor(print_params.scale_factor, is_pdf), frame,
                       &metafile);
   }
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc
index f88d000..76283af 100644
--- a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc
+++ b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc
@@ -177,9 +177,9 @@
 
     EXPECT_TRUE(user_rule_iterator->HasNext());
     auto rule = user_rule_iterator->Next();
-    EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.primary_pattern);
-    EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-    EXPECT_EQ(base::Value(state), rule.value);
+    EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->primary_pattern);
+    EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+    EXPECT_EQ(base::Value(state), rule->value());
 
     // Nothing should have ended up in the managed provider, which will present
     // as a null iterator.
@@ -202,9 +202,9 @@
 
   EXPECT_TRUE(user_rule_iterator->HasNext());
   auto rule = user_rule_iterator->Next();
-  EXPECT_EQ(kException, rule.primary_pattern.ToString());
-  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule.secondary_pattern);
-  EXPECT_EQ(base::Value(CONTENT_SETTING_BLOCK), rule.value);
+  EXPECT_EQ(kException, rule->primary_pattern.ToString());
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(), rule->secondary_pattern);
+  EXPECT_EQ(base::Value(CONTENT_SETTING_BLOCK), rule->value());
 
   // Nothing should have ended up in the managed provider, which will present
   // as a null iterator.
diff --git a/components/safe_browsing/android/remote_database_manager.cc b/components/safe_browsing/android/remote_database_manager.cc
index 4e9ff20..8571673 100644
--- a/components/safe_browsing/android/remote_database_manager.cc
+++ b/components/safe_browsing/android/remote_database_manager.cc
@@ -137,7 +137,7 @@
     // By default, we check all types except a few.
     static_assert(
         network::mojom::RequestDestination::kMaxValue ==
-            network::mojom::RequestDestination::kWebIdentity,
+            network::mojom::RequestDestination::kDictionary,
         "Decide if new request destination should be skipped on mobile.");
     for (int t_int = 0;
          t_int <=
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc
index 3bf97d3..902f7b9 100644
--- a/components/safe_browsing/content/browser/threat_details.cc
+++ b/components/safe_browsing/content/browser/threat_details.cc
@@ -193,6 +193,8 @@
       return ClientSafeBrowsingReportRequest::FENCED_FRAME;
     case network::mojom::RequestDestination::kWebIdentity:
       return ClientSafeBrowsingReportRequest::WEB_IDENTITY;
+    case network::mojom::RequestDestination::kDictionary:
+      return ClientSafeBrowsingReportRequest::DICTIONARY;
   }
 }
 
diff --git a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
index 4b6438e..585ea4e 100644
--- a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
@@ -1372,6 +1372,8 @@
       return "FENCED_FRAME";
     case ClientSafeBrowsingReportRequest::WEB_IDENTITY:
       return "WEB_IDENTITY";
+    case ClientSafeBrowsingReportRequest::DICTIONARY:
+      return "DICTIONARY";
   }
 }
 
diff --git a/components/safe_browsing/core/browser/sync/sync_utils_unittest.cc b/components/safe_browsing/core/browser/sync/sync_utils_unittest.cc
index f8e32a5..fbbdb33 100644
--- a/components/safe_browsing/core/browser/sync/sync_utils_unittest.cc
+++ b/components/safe_browsing/core/browser/sync/sync_utils_unittest.cc
@@ -28,8 +28,6 @@
   // For the purposes of this test, IdentityManager has no primary account.
 
   // Sync is disabled.
-  sync_service.SetDisableReasons(
-      {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
   sync_service.SetTransportState(syncer::SyncService::TransportState::DISABLED);
   EXPECT_FALSE(SyncUtils::AreSigninAndSyncSetUpForSafeBrowsingTokenFetches(
       &sync_service, identity_manager,
@@ -79,8 +77,6 @@
   syncer::TestSyncService sync_service;
 
   // For the purposes of this test, disable sync.
-  sync_service.SetDisableReasons(
-      {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
   sync_service.SetTransportState(syncer::SyncService::TransportState::DISABLED);
   sync_service.GetUserSettings()->SetSelectedTypes(
       /* sync_everything */ false, {});
@@ -141,14 +137,23 @@
       /*types=*/syncer::UserSelectableTypeSet::All());
 
   // Local sync is enabled.
+  ASSERT_TRUE(SyncUtils::IsHistorySyncEnabled(&sync_service));
   sync_service.SetLocalSyncEnabled(true);
   EXPECT_FALSE(SyncUtils::IsHistorySyncEnabled(&sync_service));
 
   sync_service.SetLocalSyncEnabled(false);
 
-  // The sync feature is disabled.
+  // The user didn't turn sync-the-feature on.
+  ASSERT_TRUE(SyncUtils::IsHistorySyncEnabled(&sync_service));
+  sync_service.SetHasSyncConsent(false);
+  EXPECT_FALSE(SyncUtils::IsHistorySyncEnabled(&sync_service));
+
+  sync_service.SetHasSyncConsent(true);
+
+  // The sync feature is disabled for some reason (e.g. via enterprise policy).
+  ASSERT_TRUE(SyncUtils::IsHistorySyncEnabled(&sync_service));
   sync_service.SetDisableReasons(
-      {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
+      {syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY});
   EXPECT_FALSE(SyncUtils::IsHistorySyncEnabled(&sync_service));
 
   sync_service.SetDisableReasons({});
diff --git a/components/safe_browsing/core/common/proto/csd.proto b/components/safe_browsing/core/common/proto/csd.proto
index f1b3e53..a3bd0b2 100644
--- a/components/safe_browsing/core/common/proto/csd.proto
+++ b/components/safe_browsing/core/common/proto/csd.proto
@@ -1800,6 +1800,8 @@
     FENCED_FRAME = 23;
     // Federated Credential Management requests
     WEB_IDENTITY = 24;
+    // <link rel=dictionary>
+    DICTIONARY = 25;
   }
 
   // Only populated for interstitial reports (URL_PHISHING, URL_MALWARE,
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector.cc b/components/segmentation_platform/internal/data_collection/training_data_collector.cc
index da0c747..9fa60a6 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "components/segmentation_platform/internal/data_collection/training_data_collector_impl.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
 
 namespace segmentation_platform {
 
@@ -16,12 +17,12 @@
     HistogramSignalHandler* histogram_signal_handler,
     UserActionSignalHandler* user_action_signal_handler,
     StorageService* storage_service,
-    const std::vector<std::unique_ptr<Config>>* configs,
     PrefService* profile_prefs,
-    base::Clock* clock) {
+    base::Clock* clock,
+    CachedResultProvider* cached_result_provider) {
   return std::make_unique<TrainingDataCollectorImpl>(
       processor, histogram_signal_handler, user_action_signal_handler,
-      storage_service, configs, profile_prefs, clock);
+      storage_service, profile_prefs, clock, cached_result_provider);
 }
 
 TrainingDataCollector::TrainingDataCollector() = default;
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector.h b/components/segmentation_platform/internal/data_collection/training_data_collector.h
index 6789569a..3c2bab9 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector.h
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "components/segmentation_platform/internal/data_collection/training_data_cache.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
@@ -30,7 +31,6 @@
 class FeatureListQueryProcessor;
 }
 
-struct Config;
 class HistogramSignalHandler;
 
 // Collect training data and report as Ukm message. Live on main thread.
@@ -43,9 +43,9 @@
       HistogramSignalHandler* histogram_signal_handler,
       UserActionSignalHandler* user_action_signal_handler,
       StorageService* storage_service,
-      const std::vector<std::unique_ptr<Config>>* configs,
       PrefService* profile_prefs,
-      base::Clock* clock);
+      base::Clock* clock,
+      CachedResultProvider* cached_result_provider);
 
   // Parameters used for reporting immediate output collections.
   struct ImmediaCollectionParam {
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
index 49867f0..4c044c27 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
@@ -15,6 +15,8 @@
 #include "components/segmentation_platform/internal/config_parser.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_cache.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
+#include "components/segmentation_platform/internal/database/config_holder.h"
 #include "components/segmentation_platform/internal/database/signal_storage_config.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h"
 #include "components/segmentation_platform/internal/metadata/metadata_utils.h"
@@ -60,21 +62,6 @@
   return hash_index_map;
 }
 
-// Find the segmentation key from the configs that contains the segment ID.
-std::string GetSegmentationKey(
-    const std::vector<std::unique_ptr<Config>>* configs,
-    SegmentId segment_id) {
-  if (!configs)
-    return std::string();
-
-  for (const auto& config : *configs) {
-    auto it = config->segments.find(segment_id);
-    if (it != config->segments.end())
-      return config->segmentation_key;
-  }
-  return std::string();
-}
-
 // Returns a list of preferred segment info for each segment ID in the list.
 std::map<SegmentId, proto::SegmentInfo> GetPreferredSegmentInfo(
     DefaultModelManager::SegmentInfoList&& segment_list) {
@@ -104,17 +91,18 @@
     HistogramSignalHandler* histogram_signal_handler,
     UserActionSignalHandler* user_action_signal_handler,
     StorageService* storage_service,
-    const std::vector<std::unique_ptr<Config>>* configs,
     PrefService* profile_prefs,
-    base::Clock* clock)
+    base::Clock* clock,
+    CachedResultProvider* cached_result_provider)
     : segment_info_database_(storage_service->segment_info_database()),
       feature_list_query_processor_(processor),
       histogram_signal_handler_(histogram_signal_handler),
       user_action_signal_handler_(user_action_signal_handler),
       signal_storage_config_(storage_service->signal_storage_config()),
-      configs_(configs),
+      config_holder_(storage_service->config_holder()),
       clock_(clock),
       result_prefs_(std::make_unique<SegmentationResultPrefs>(profile_prefs)),
+      cached_result_provider_(cached_result_provider),
       training_cache_(std::make_unique<TrainingDataCache>(
           storage_service->segment_info_database())),
       default_model_manager_(storage_service->default_model_manager()) {}
@@ -129,8 +117,7 @@
 }
 
 void TrainingDataCollectorImpl::OnServiceInitialized() {
-  base::flat_set<SegmentId> segment_ids =
-      GetAllSegmentIdsFromConfigs(*configs_);
+  base::flat_set<SegmentId> segment_ids = config_holder_->all_segment_ids();
   if (segment_ids.empty()) {
     return;
   }
@@ -363,8 +350,9 @@
   // TODO(qinmin): update SegmentationUkmHelper::RecordTrainingData()
   // and ukm file for description of the prediction result as it is
   // the segment selection result, rather than model result.
-  std::string segmentation_key =
-      GetSegmentationKey(configs_, segment_info.segment_id());
+  const Config* config =
+      config_holder_->GetConfigForSegmentId(segment_info.segment_id());
+  std::string segmentation_key = config ? config->segmentation_key : "";
 
   std::vector<int> output_indexes;
   auto output_values = output_tensors;
@@ -380,10 +368,26 @@
     output_values.emplace_back(param->output_value);
   }
 
+  // Cached results are stored in two formats depending on whether the model is
+  // using the legacy output config or the new multi-output model config.
+  // |prediction_results| represents the new format which may contains multiple
+  // outputs as floats.
+  absl::optional<proto::PredictionResult> prediction_result;
+  // |selected_segment| represents the legacy format which contains a single
+  // segment ID.
+  absl::optional<SelectedSegment> selected_segment;
+
+  if (metadata_utils::ConfigUsesLegacyOutput(config)) {
+    selected_segment =
+        result_prefs_->ReadSegmentationResultFromPref(segmentation_key);
+  } else {
+    prediction_result =
+        cached_result_provider_->GetPredictionResultForClient(segmentation_key);
+  }
+
   auto ukm_source_id = SegmentationUkmHelper::GetInstance()->RecordTrainingData(
       segment_info.segment_id(), segment_info.model_version(), input_tensors,
-      output_values, output_indexes, segment_info.prediction_result(),
-      result_prefs_->ReadSegmentationResultFromPref(segmentation_key));
+      output_values, output_indexes, prediction_result, selected_segment);
   if (ukm_source_id == ukm::kInvalidSourceId) {
     VLOG(1) << "Failed to collect training data for segment:"
             << segment_info.segment_id();
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
index 7a873ac..826271d 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
@@ -15,6 +15,8 @@
 #include "base/metrics/histogram_base.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_cache.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
+#include "components/segmentation_platform/internal/database/config_holder.h"
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
@@ -27,7 +29,6 @@
 namespace segmentation_platform {
 using proto::SegmentId;
 
-struct Config;
 class SegmentationResultPrefs;
 
 // Implementation of TrainingDataCollector.
@@ -39,9 +40,9 @@
                             HistogramSignalHandler* histogram_signal_handler,
                             UserActionSignalHandler* user_action_signal_handler,
                             StorageService* storage_service,
-                            const std::vector<std::unique_ptr<Config>>* configs,
                             PrefService* profile_prefs,
-                            base::Clock* clock);
+                            base::Clock* clock,
+                            CachedResultProvider* cached_result_provider);
   ~TrainingDataCollectorImpl() override;
 
   // TrainingDataCollector implementation.
@@ -134,12 +135,14 @@
   const raw_ptr<HistogramSignalHandler> histogram_signal_handler_;
   const raw_ptr<UserActionSignalHandler> user_action_signal_handler_;
   const raw_ptr<SignalStorageConfig> signal_storage_config_;
-  const raw_ptr<const std::vector<std::unique_ptr<Config>>> configs_;
+  const raw_ptr<const ConfigHolder> config_holder_;
   const raw_ptr<base::Clock> clock_;
 
   // Helper class to read/write results to the prefs.
   std::unique_ptr<SegmentationResultPrefs> result_prefs_;
 
+  const raw_ptr<CachedResultProvider> cached_result_provider_;
+
   // Cache class to temporarily store training data in the observation period.
   std::unique_ptr<TrainingDataCache> training_cache_;
 
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
index a607083..235dbf9 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
@@ -15,11 +15,16 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
+#include "components/segmentation_platform/internal/database/cached_result_writer.h"
+#include "components/segmentation_platform/internal/database/client_result_prefs.h"
+#include "components/segmentation_platform/internal/database/config_holder.h"
 #include "components/segmentation_platform/internal/database/mock_signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/test_segment_info_database.h"
 #include "components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.h"
 #include "components/segmentation_platform/internal/metadata/metadata_utils.h"
 #include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
+#include "components/segmentation_platform/internal/platform_options.h"
 #include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
 #include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
 #include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h"
@@ -30,6 +35,7 @@
 #include "components/segmentation_platform/public/local_state_helper.h"
 #include "components/segmentation_platform/public/model_provider.h"
 #include "components/segmentation_platform/public/proto/model_metadata.pb.h"
+#include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 #include "components/segmentation_platform/public/proto/types.pb.h"
 #include "components/segmentation_platform/public/segmentation_platform_service.h"
 #include "components/ukm/test_ukm_recorder.h"
@@ -50,9 +56,12 @@
     SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
 constexpr auto kTestOptimizationTarget1 =
     SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
+constexpr auto kTestOptimizationTarget2 =
+    SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR;
 constexpr char kHistogramName0[] = "histogram0";
 constexpr char kHistogramName1[] = "histogram1";
 constexpr char kSegmentationKey[] = "test_key";
+constexpr char kSegmentationKey2[] = "test_key_2";
 constexpr int64_t kModelVersion = 123;
 constexpr int kSample = 1;
 constexpr DecisionType kOnDemandDecisionType =
@@ -112,17 +121,58 @@
     result_prefs.SaveSegmentationResultToPref(kSegmentationKey,
                                               selected_segment);
 
+    // Add another configuration under kTestOptimizationTarget2 that uses the
+    // new output config with a multi class classifier.
+    configs_.emplace_back(std::make_unique<Config>());
+    configs_[1]->segmentation_key = kSegmentationKey2;
+    configs_[1]->segments.insert(
+        {kTestOptimizationTarget2,
+         std::make_unique<Config::SegmentMetadata>("UmaNameNewTab")});
+
+    // Create a ClientResult object to store in prefs, it'll be used when
+    // recording the training data for kTestOptimizationTarget2.
+    proto::ClientResult client_2_result;
+    proto::PredictionResult* client_2_prediction_result =
+        client_2_result.mutable_client_result();
+    proto::OutputConfig* client_2_output_config =
+        client_2_prediction_result->mutable_output_config();
+    auto* client_2_classifier = client_2_output_config->mutable_predictor()
+                                    ->mutable_multi_class_classifier();
+    client_2_classifier->add_class_labels("Foo");
+    client_2_classifier->add_class_labels("Bar");
+    client_2_classifier->add_class_labels("Baz");
+    client_2_classifier->add_class_labels("Foo");
+    client_2_classifier->add_class_labels("Bar");
+
+    client_2_prediction_result->add_result(0.f);
+    client_2_prediction_result->add_result(0.f);
+    client_2_prediction_result->add_result(1.f);
+    client_2_prediction_result->add_result(0.f);
+    client_2_prediction_result->add_result(0.f);
+    client_2_prediction_result->set_timestamp_us(
+        (base::Time::Now() - base::Days(3))
+            .ToDeltaSinceWindowsEpoch()
+            .InMicroseconds());
+
+    CachedResultWriter(std::make_unique<ClientResultPrefs>(&prefs_), &clock_)
+        .UpdatePrefsIfExpired(configs_[1].get(), client_2_result,
+                              PlatformOptions::CreateDefault());
+
     storage_service_ = std::make_unique<StorageService>(
         std::move(test_segment_info_db), nullptr,
         std::move(signal_storage_config),
         std::make_unique<DefaultModelManager>(nullptr,
                                               base::flat_set<SegmentId>()),
+        std::make_unique<ConfigHolder>(std::move(configs_)),
         &ukm_data_manager_);
 
+    cached_result_provider_ = std::make_unique<CachedResultProvider>(
+        &prefs_, storage_service_->config_holder()->configs());
+
     collector_ = std::make_unique<TrainingDataCollectorImpl>(
         &feature_list_processor_, &histogram_signal_handler_,
-        &user_action_signal_handler_, storage_service_.get(), &configs_,
-        &prefs_, &clock_);
+        &user_action_signal_handler_, storage_service_.get(), &prefs_, &clock_,
+        cached_result_provider_.get());
   }
 
  protected:
@@ -143,19 +193,19 @@
     collector_.reset();
     collector_ = std::make_unique<TrainingDataCollectorImpl>(
         &feature_list_processor_, &histogram_signal_handler_,
-        &user_action_signal_handler_, storage_service_.get(), &configs_,
-        &prefs_, &clock_);
+        &user_action_signal_handler_, storage_service_.get(), &prefs_, &clock_,
+        cached_result_provider_.get());
   }
 
-  proto::SegmentInfo* CreateSegmentInfo(DecisionType type,
+  proto::SegmentInfo* CreateSegmentInfo(SegmentId segment_id,
+                                        DecisionType type,
                                         bool upload_tensors = false) {
-    test_segment_db()->AddUserActionFeature(kTestOptimizationTarget0, "action",
-                                            1, 1, proto::Aggregation::COUNT);
+    test_segment_db()->AddUserActionFeature(segment_id, "action", 1, 1,
+                                            proto::Aggregation::COUNT);
     // Segment 0 contains 1 immediate collection uma output for
     // |kHistogramName0|, 1 uma output collection with delay for
     // |kHistogramName1|.
-    auto* segment_info =
-        CreateSegment(kTestOptimizationTarget0, upload_tensors);
+    auto* segment_info = CreateSegment(segment_id, upload_tensors);
 
     auto* trigger = segment_info->mutable_model_metadata()
                         ->mutable_training_outputs()
@@ -231,20 +281,20 @@
     return output;
   }
 
-  void SetupFeatureProcessorResult1(base::Time prediction,
-                                    absl::optional<base::Time> observaton) {
+  void SetupFeatureProcessorResult(proto::SegmentId segment_id,
+                                   base::Time prediction,
+                                   absl::optional<base::Time> observation) {
     EXPECT_CALL(
         *feature_list_processor(),
         ProcessFeatureList(
-            _, _, kTestOptimizationTarget0, prediction, base::Time(),
+            _, _, segment_id, prediction, base::Time(),
             processing::FeatureListQueryProcessor::ProcessOption::kInputsOnly,
             _))
         .WillOnce(RunOnceCallback<6>(false, ModelProvider::Request{1.f},
                                      ModelProvider::Response{2.f, 3.f}));
-    if (observaton) {
+    if (observation) {
       EXPECT_CALL(*feature_list_processor(),
-                  ProcessFeatureList(_, _, kTestOptimizationTarget0, prediction,
-                                     *observaton,
+                  ProcessFeatureList(_, _, segment_id, prediction, *observation,
                                      processing::FeatureListQueryProcessor::
                                          ProcessOption::kOutputsOnly,
                                      _))
@@ -331,6 +381,7 @@
   std::vector<std::unique_ptr<Config>> configs_;
   NiceMock<MockUkmDataManager> ukm_data_manager_;
   std::unique_ptr<StorageService> storage_service_;
+  std::unique_ptr<CachedResultProvider> cached_result_provider_;
 };
 
 // No segment info in database. Do nothing.
@@ -343,7 +394,7 @@
 
 // Histogram not in the output list will not trigger a training data report..
 TEST_F(TrainingDataCollectorImplTest, IrrelevantHistogramNotReported) {
-  CreateSegmentInfo(kOnDemandDecisionType);
+  CreateSegmentInfo(kTestOptimizationTarget0, kOnDemandDecisionType);
   Init();
   collector()->OnHistogramSignalUpdated("irrelevant_histogram", kSample);
   task_environment()->RunUntilIdle();
@@ -360,7 +411,8 @@
   EXPECT_CALL(*signal_storage_config(), MeetsSignalCollectionRequirement(_, _))
       .WillOnce(Return(false));
 
-  CreateSegmentInfo(kPeriodicDecisionType, /*upload_tensors=*/true);
+  CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType,
+                    /*upload_tensors=*/true);
   clock()->Advance(base::Hours(24));
   Init();
   task_environment()->RunUntilIdle();
@@ -369,7 +421,8 @@
 
 // No UKM report due to model updated recently.
 TEST_F(TrainingDataCollectorImplTest, ModelUpdatedRecently) {
-  auto* segment_info = CreateSegmentInfo(kPeriodicDecisionType);
+  auto* segment_info =
+      CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   base::TimeDelta min_signal_collection_length =
       segment_info->model_metadata().min_signal_collection_length() *
       metadata_utils::GetTimeUnit(segment_info->model_metadata());
@@ -390,7 +443,7 @@
   LocalStateHelper::GetInstance().SetPrefTime(
       kSegmentationUkmMostRecentAllowedTimeKey,
       clock()->Now() - base::Seconds(300));
-  CreateSegmentInfo(kOnDemandDecisionType);
+  CreateSegmentInfo(kTestOptimizationTarget0, kOnDemandDecisionType);
   Init();
   collector()->OnHistogramSignalUpdated(kHistogramName0, kSample);
   task_environment()->RunUntilIdle();
@@ -399,11 +452,12 @@
 
 // Tests that continuous collection happens on startup.
 TEST_F(TrainingDataCollectorImplTest, ContinuousCollectionOnStartupNoDelay) {
-  CreateSegmentInfo(kPeriodicDecisionType, /*upload_tensors=*/true);
+  CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType,
+                    /*upload_tensors=*/true);
   clock()->Advance(base::Days(1));
 
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, base::Time());
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current, base::Time());
 
   Init();
   task_environment()->RunUntilIdle();
@@ -412,10 +466,13 @@
 
 // Tests that ReportCollectedContinuousTrainingData() works well later if
 // no data is reported on start up.
-TEST_F(TrainingDataCollectorImplTest, ReportCollectedContinuousTrainingData) {
+TEST_F(TrainingDataCollectorImplTest,
+       ReportCollectedContinuousTrainingData_LegacyConfig) {
   base::Time prediction_time = clock()->Now() + base::Days(1);
-  SetupFeatureProcessorResult1(prediction_time, base::Time());
-  CreateSegmentInfo(kPeriodicDecisionType, /*upload_tensors=*/true);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, prediction_time,
+                              base::Time());
+  CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType,
+                    /*upload_tensors=*/true);
   Init();
   clock()->Advance(base::Days(1));
   WaitForContinuousCollection();
@@ -423,21 +480,57 @@
       {Segmentation_ModelExecution::kOptimizationTargetName,
        Segmentation_ModelExecution::kModelVersionName,
        Segmentation_ModelExecution::kInput0Name,
-       Segmentation_ModelExecution::kPredictionResult1Name,
        Segmentation_ModelExecution::kSelectionResultName,
        Segmentation_ModelExecution::kOutputDelaySecName,
        Segmentation_ModelExecution::kActualResultName,
        Segmentation_ModelExecution::kActualResult2Name},
       {kTestOptimizationTarget0, kModelVersion,
        SegmentationUkmHelper::FloatToInt64(1.f),
-       SegmentationUkmHelper::FloatToInt64(0.6f),
        SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE,
        base::Days(1).InSeconds(), SegmentationUkmHelper::FloatToInt64(2.f),
        SegmentationUkmHelper::FloatToInt64(3.f)});
 }
 
+// Tests that ReportCollectedContinuousTrainingData() works well later if
+// no data is reported on start up.
+TEST_F(TrainingDataCollectorImplTest,
+       ReportCollectedContinuousTrainingData_MultiOutputConfig) {
+  base::Time prediction_time = clock()->Now() + base::Days(1);
+  SetupFeatureProcessorResult(kTestOptimizationTarget2, prediction_time,
+                              base::Time());
+  CreateSegmentInfo(kTestOptimizationTarget2, kPeriodicDecisionType,
+                    /*upload_tensors=*/true);
+  Init();
+  clock()->Advance(base::Days(1));
+  WaitForContinuousCollection();
+  // |kTestOptimizationTarget2| uses a multi-class classifier, so all the result
+  // scores are recorded.
+  ExpectUkm(
+      {Segmentation_ModelExecution::kOptimizationTargetName,
+       Segmentation_ModelExecution::kModelVersionName,
+       Segmentation_ModelExecution::kInput0Name,
+       Segmentation_ModelExecution::kPredictionResult1Name,
+       Segmentation_ModelExecution::kPredictionResult2Name,
+       Segmentation_ModelExecution::kPredictionResult3Name,
+       Segmentation_ModelExecution::kPredictionResult4Name,
+       Segmentation_ModelExecution::kPredictionResult5Name,
+       Segmentation_ModelExecution::kOutputDelaySecName,
+       Segmentation_ModelExecution::kActualResultName,
+       Segmentation_ModelExecution::kActualResult2Name},
+      {kTestOptimizationTarget2, kModelVersion,
+       SegmentationUkmHelper::FloatToInt64(1.f),
+       SegmentationUkmHelper::FloatToInt64(0.f),
+       SegmentationUkmHelper::FloatToInt64(0.f),
+       SegmentationUkmHelper::FloatToInt64(1.f),
+       SegmentationUkmHelper::FloatToInt64(0.f),
+       SegmentationUkmHelper::FloatToInt64(0.f), base::Days(3).InSeconds(),
+       SegmentationUkmHelper::FloatToInt64(2.f),
+       SegmentationUkmHelper::FloatToInt64(3.f)});
+}
+
 TEST_F(TrainingDataCollectorImplTest, ContinuousWithExactPrediction) {
-  auto* segment_info = CreateSegmentInfo(kPeriodicDecisionType);
+  auto* segment_info =
+      CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   segment_info->mutable_model_metadata()
       ->mutable_training_outputs()
       ->mutable_trigger_config()
@@ -446,7 +539,8 @@
   const base::TimeDelta kNextUserSession = base::Days(10);
 
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, current + base::Days(7));
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current,
+                              current + base::Days(7));
 
   Init();
   collector()->OnDecisionTime(kTestOptimizationTarget0, nullptr,
@@ -458,7 +552,8 @@
 }
 
 TEST_F(TrainingDataCollectorImplTest, ContinuousWithFlexibleObservation) {
-  auto* segment_info = CreateSegmentInfo(kPeriodicDecisionType);
+  auto* segment_info =
+      CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   segment_info->mutable_model_metadata()
       ->mutable_training_outputs()
       ->mutable_trigger_config()
@@ -471,7 +566,8 @@
   const base::TimeDelta kNextUserSession = base::Days(10);
 
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, current + kNextUserSession);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current,
+                              current + kNextUserSession);
 
   Init();
   collector()->OnDecisionTime(kTestOptimizationTarget0, nullptr,
@@ -486,14 +582,17 @@
   clock()->Advance(base::Days(10));
   const base::TimeDelta kDelay = base::Days(7);
   const base::TimeDelta kNextUserSession = base::Days(10);
-  auto* segment_info = CreateSegmentInfo(kPeriodicDecisionType);
+  auto* segment_info =
+      CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   AddTimeTrigger(segment_info, kDelay);
 
   base::Time current = clock()->Now();
   base::Time next_session = current + kNextUserSession;
 
-  SetupFeatureProcessorResult1(current - base::Days(7), current);
-  SetupFeatureProcessorResult1(next_session - base::Days(7), next_session);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current - base::Days(7),
+                              current);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0,
+                              next_session - base::Days(7), next_session);
 
   Init();
   task_environment()->RunUntilIdle();
@@ -511,7 +610,8 @@
               ProcessFeatureList(_, _, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<6>(false, ModelProvider::Request{1.f},
                                          ModelProvider::Response{2.f, 3.f}));
-  CreateSegmentInfo(kPeriodicDecisionType, /*upload_tensors=*/true);
+  CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType,
+                    /*upload_tensors=*/true);
   Init();
   clock()->Advance(base::Hours(24));
   WaitForContinuousCollection();
@@ -538,7 +638,7 @@
                                          ModelProvider::Response{2.f, 3.f}));
   LocalStateHelper::GetInstance().SetPrefTime(
       kSegmentationUkmMostRecentAllowedTimeKey, base::Time());
-  CreateSegmentInfo(kPeriodicDecisionType);
+  CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   Init();
   collector()->ReportCollectedContinuousTrainingData();
   task_environment()->RunUntilIdle();
@@ -550,10 +650,12 @@
 TEST_F(TrainingDataCollectorImplTest, DataCollectionWithUMATrigger) {
   constexpr base::TimeDelta kTriggerDuration = base::Seconds(10);
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, current + kTriggerDuration);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current,
+                              current + kTriggerDuration);
 
   // Create a segment that contain a uma trigger.
-  CreateSegmentInfo(kOnDemandDecisionType, /*upload_tensors=*/true);
+  CreateSegmentInfo(kTestOptimizationTarget0, kOnDemandDecisionType,
+                    /*upload_tensors=*/true);
   Init();
 
   // Wait for input collection to be done and cached in memory.
@@ -574,11 +676,13 @@
 TEST_F(TrainingDataCollectorImplTest, DataCollectionWithUserActionTrigger) {
   constexpr base::TimeDelta kTriggerDuration = base::Seconds(10);
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, current + kTriggerDuration);
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current,
+                              current + kTriggerDuration);
 
   // Create a segment that contain a uma trigger.
   AddUserActionTrigger(
-      CreateSegmentInfo(kOnDemandDecisionType, /*upload_tensors=*/true),
+      CreateSegmentInfo(kTestOptimizationTarget0, kOnDemandDecisionType,
+                        /*upload_tensors=*/true),
       kHistogramName1);
   Init();
 
@@ -604,7 +708,8 @@
                                          ModelProvider::Response{2.f, 3.f}));
 
   // Create a segment that contain a uma trigger.
-  CreateSegmentInfo(kOnDemandDecisionType, /*upload_tensors=*/true);
+  CreateSegmentInfo(kTestOptimizationTarget0, kOnDemandDecisionType,
+                    /*upload_tensors=*/true);
 
   // Create a second segment that contain the same uma trigger.
   test_segment_db()->AddUserActionFeature(kTestOptimizationTarget1, "action", 1,
@@ -647,7 +752,8 @@
 
   // Create a segment that contain a time delay trigger and a uma trigger.
   auto* segment_info =
-      CreateSegmentInfo(proto::TrainingOutputs::TriggerConfig::ONDEMAND);
+      CreateSegmentInfo(kTestOptimizationTarget0,
+                        proto::TrainingOutputs::TriggerConfig::ONDEMAND);
   AddTimeTrigger(segment_info, base::Seconds(10));
   Init();
 
@@ -676,7 +782,8 @@
 }
 
 TEST_F(TrainingDataCollectorImplTest, DataCollectionWithStoreToDisk) {
-  auto* segment_info = CreateSegmentInfo(kPeriodicDecisionType);
+  auto* segment_info =
+      CreateSegmentInfo(kTestOptimizationTarget0, kPeriodicDecisionType);
   segment_info->mutable_model_metadata()
       ->mutable_training_outputs()
       ->mutable_trigger_config()
@@ -685,7 +792,8 @@
   const base::TimeDelta kNextUserSession = base::Days(10);
 
   base::Time current = clock()->Now();
-  SetupFeatureProcessorResult1(current, current + base::Days(7));
+  SetupFeatureProcessorResult(kTestOptimizationTarget0, current,
+                              current + base::Days(7));
 
   // Trigger decision time with the collector and wait for the database to store
   // the training data.
diff --git a/components/segmentation_platform/internal/database/config_holder.cc b/components/segmentation_platform/internal/database/config_holder.cc
index 82e0392..f230235 100644
--- a/components/segmentation_platform/internal/database/config_holder.cc
+++ b/components/segmentation_platform/internal/database/config_holder.cc
@@ -6,6 +6,7 @@
 
 #include "components/segmentation_platform/internal/config_parser.h"
 #include "components/segmentation_platform/internal/metadata/metadata_utils.h"
+#include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 
 namespace segmentation_platform {
 
@@ -50,6 +51,17 @@
   return key_for_updated_segment->second;
 }
 
+const Config* ConfigHolder::GetConfigForSegmentId(
+    proto::SegmentId segment_id) const {
+  for (const auto& config : configs_) {
+    auto it = config->segments.find(segment_id);
+    if (it != config->segments.end()) {
+      return config.get();
+    }
+  }
+  return nullptr;
+}
+
 bool ConfigHolder::IsLegacySegmentationKey(
     const std::string& segmentation_key) const {
   return legacy_output_segmentation_keys_.contains(segmentation_key);
diff --git a/components/segmentation_platform/internal/database/config_holder.h b/components/segmentation_platform/internal/database/config_holder.h
index 9a20a01b..1868bf9 100644
--- a/components/segmentation_platform/internal/database/config_holder.h
+++ b/components/segmentation_platform/internal/database/config_holder.h
@@ -39,6 +39,8 @@
   absl::optional<std::string> GetKeyForSegmentId(
       proto::SegmentId segment_id) const;
 
+  const Config* GetConfigForSegmentId(proto::SegmentId segment_id) const;
+
   // Returns true if the Config is legacy, does not support output config and
   // uses discrete mapping.
   bool IsLegacySegmentationKey(const std::string& segmentation_key) const;
diff --git a/components/segmentation_platform/internal/database/storage_service.cc b/components/segmentation_platform/internal/database/storage_service.cc
index e51f9990..ffc8d460 100644
--- a/components/segmentation_platform/internal/database/storage_service.cc
+++ b/components/segmentation_platform/internal/database/storage_service.cc
@@ -101,8 +101,10 @@
     std::unique_ptr<SignalDatabase> signal_database,
     std::unique_ptr<SignalStorageConfig> signal_storage_config,
     std::unique_ptr<DefaultModelManager> default_model_manager,
+    std::unique_ptr<ConfigHolder> config_holder,
     UkmDataManager* ukm_data_manager)
-    : default_model_manager_(std::move(default_model_manager)),
+    : config_holder_(std::move(config_holder)),
+      default_model_manager_(std::move(default_model_manager)),
       segment_info_database_(std::move(segment_info_database)),
       signal_database_(std::move(signal_database)),
       signal_storage_config_(std::move(signal_storage_config)),
diff --git a/components/segmentation_platform/internal/database/storage_service.h b/components/segmentation_platform/internal/database/storage_service.h
index c03ef19..d8e1fab 100644
--- a/components/segmentation_platform/internal/database/storage_service.h
+++ b/components/segmentation_platform/internal/database/storage_service.h
@@ -93,6 +93,7 @@
                  std::unique_ptr<SignalDatabase> signal_database,
                  std::unique_ptr<SignalStorageConfig> signal_storage_config,
                  std::unique_ptr<DefaultModelManager> default_model_manager,
+                 std::unique_ptr<ConfigHolder> config_holder,
                  UkmDataManager* ukm_data_manager);
 
   ~StorageService();
@@ -112,7 +113,7 @@
   // Executes all database maintenance tasks.
   void ExecuteDatabaseMaintenanceTasks(bool is_startup);
 
-  const ConfigHolder& config_holder() const { return *config_holder_; }
+  const ConfigHolder* config_holder() const { return config_holder_.get(); }
 
   CachedResultProvider* cached_result_provider() {
     return cached_result_provider_.get();
diff --git a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
index 8bb343e..f78dd68 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
@@ -42,9 +42,9 @@
   void SetUp() override {
     auto moved_signal_db = std::make_unique<MockSignalDatabase>();
     signal_database_ = moved_signal_db.get();
-    storage_service_ =
-        std::make_unique<StorageService>(nullptr, std::move(moved_signal_db),
-                                         nullptr, nullptr, &ukm_data_manager_);
+    storage_service_ = std::make_unique<StorageService>(
+        nullptr, std::move(moved_signal_db), nullptr, nullptr, nullptr,
+        &ukm_data_manager_);
     clock_.SetNow(base::Time::Now());
     segment_id_ = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
   }
diff --git a/components/segmentation_platform/internal/metadata/metadata_utils.cc b/components/segmentation_platform/internal/metadata/metadata_utils.cc
index 88dbb40..c28febd6 100644
--- a/components/segmentation_platform/internal/metadata/metadata_utils.cc
+++ b/components/segmentation_platform/internal/metadata/metadata_utils.cc
@@ -447,7 +447,7 @@
   return client_result;
 }
 
-bool ConfigUsesLegacyOutput(Config* config) {
+bool ConfigUsesLegacyOutput(const Config* config) {
   // List of config segments ids that doesn't support multi output and uses
   // legacy output. Please delete `SegmentId` from this list if segment is
   // migrated to support multi output.
diff --git a/components/segmentation_platform/internal/metadata/metadata_utils.h b/components/segmentation_platform/internal/metadata/metadata_utils.h
index 5bcadaa8..1ddbaa42 100644
--- a/components/segmentation_platform/internal/metadata/metadata_utils.h
+++ b/components/segmentation_platform/internal/metadata/metadata_utils.h
@@ -134,7 +134,7 @@
 
 // Returns true if config has not migrated to multi output and uses legacy
 // output.
-bool ConfigUsesLegacyOutput(Config* config);
+bool ConfigUsesLegacyOutput(const Config* config);
 
 }  // namespace metadata_utils
 }  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.cc b/components/segmentation_platform/internal/scheduler/execution_service.cc
index 8659ba3..02e5135 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.cc
+++ b/components/segmentation_platform/internal/scheduler/execution_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/task/sequenced_task_runner.h"
 #include "components/prefs/pref_service.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/execution_request.h"
@@ -47,7 +48,8 @@
     const PlatformOptions& platform_options,
     std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder,
     const std::vector<std::unique_ptr<Config>>* configs,
-    PrefService* profile_prefs) {
+    PrefService* profile_prefs,
+    CachedResultProvider* cached_result_provider) {
   storage_service_ = storage_service;
 
   feature_list_query_processor_ =
@@ -58,8 +60,8 @@
   training_data_collector_ = TrainingDataCollector::Create(
       feature_list_query_processor_.get(),
       signal_handler->deprecated_histogram_signal_handler(),
-      signal_handler->user_action_signal_handler(), storage_service, configs,
-      profile_prefs, clock);
+      signal_handler->user_action_signal_handler(), storage_service,
+      profile_prefs, clock, cached_result_provider);
 
   model_executor_ = std::make_unique<ModelExecutorImpl>(
       clock, feature_list_query_processor_.get());
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.h b/components/segmentation_platform/internal/scheduler/execution_service.h
index 48dc00d..ee4b1247 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.h
+++ b/components/segmentation_platform/internal/scheduler/execution_service.h
@@ -12,6 +12,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/clock.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
+#include "components/segmentation_platform/internal/database/cached_result_provider.h"
 #include "components/segmentation_platform/internal/execution/execution_request.h"
 #include "components/segmentation_platform/internal/execution/model_execution_manager_impl.h"
 #include "components/segmentation_platform/internal/scheduler/model_execution_scheduler.h"
@@ -60,7 +61,8 @@
       const PlatformOptions& platform_options,
       std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder,
       const std::vector<std::unique_ptr<Config>>* configs,
-      PrefService* profile_prefs);
+      PrefService* profile_prefs,
+      CachedResultProvider* cached_result_provider);
 
   // Returns the training data collector.
   TrainingDataCollector* training_data_collector() {
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
index 171c070..b5197f98 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -79,15 +79,15 @@
         model_provider_factory_.get(), profile_prefs_);
   }
 
-  const auto& config_holder = storage_service_->config_holder();
+  const auto* config_holder = storage_service_->config_holder();
 
   prefs_migrator_ = std::make_unique<PrefsMigrator>(
-      init_params->profile_prefs.get(), config_holder.configs());
+      init_params->profile_prefs.get(), config_holder->configs());
 
   // Construct signal processors.
   signal_handler_.Initialize(
       storage_service_.get(), init_params->history_service,
-      config_holder.all_segment_ids(),
+      config_holder->all_segment_ids(),
       base::BindRepeating(
           &SegmentationPlatformServiceImpl::OnModelRefreshNeeded,
           weak_ptr_factory_.GetWeakPtr()));
@@ -95,12 +95,12 @@
   prefs_migrator_->MigrateOldPrefsToNewPrefs();
 
   field_trial_recorder_->RecordFieldTrialAtStartup(
-      config_holder.configs(), storage_service_->cached_result_provider());
+      config_holder->configs(), storage_service_->cached_result_provider());
 
   request_dispatcher_ = std::make_unique<RequestDispatcher>(
-      &config_holder, storage_service_->cached_result_provider());
+      config_holder, storage_service_->cached_result_provider());
 
-  for (const auto& config : config_holder.configs()) {
+  for (const auto& config : config_holder->configs()) {
     if (!metadata_utils::ConfigUsesLegacyOutput(config.get())) {
       continue;
     }
@@ -116,11 +116,11 @@
   proxy_ = std::make_unique<ServiceProxyImpl>(
       storage_service_->segment_info_database(),
       storage_service_->default_model_manager(),
-      storage_service_->signal_storage_config(), &config_holder.configs(),
+      storage_service_->signal_storage_config(), &config_holder->configs(),
       platform_options_, &segment_selectors_);
   segment_score_provider_ =
       SegmentScoreProvider::Create(storage_service_->segment_info_database(),
-                                   config_holder.all_segment_ids());
+                                   config_holder->all_segment_ids());
 
   // Kick off initialization of all databases. Internal operations will be
   // delayed until they are all complete.
@@ -135,7 +135,7 @@
           init_params->device_info_tracker));
 
   result_refresh_manager_ = std::make_unique<ResultRefreshManager>(
-      config_holder.configs(),
+      config_holder->configs(),
       std::move(storage_service_->cached_result_writer()), platform_options_);
 }
 
@@ -232,10 +232,10 @@
   storage_init_status_ = success;
   OnServiceStatusChanged();
 
-  const auto& config_holder = storage_service_->config_holder();
+  const auto* config_holder = storage_service_->config_holder();
 
   if (!success) {
-    for (const auto& config : config_holder.configs()) {
+    for (const auto& config : config_holder->configs()) {
       stats::RecordSegmentSelectionFailure(
           *config, stats::SegmentationSelectionFailureReason::kDBInitFailure);
     }
@@ -255,10 +255,10 @@
       base::BindRepeating(
           &SegmentationPlatformServiceImpl::OnSegmentationModelUpdated,
           weak_ptr_factory_.GetWeakPtr()),
-      task_runner_, config_holder.all_segment_ids(),
+      task_runner_, config_holder->all_segment_ids(),
       model_provider_factory_.get(), std::move(observers), platform_options_,
-      std::move(input_delegate_holder_), &config_holder.configs(),
-      profile_prefs_);
+      std::move(input_delegate_holder_), &config_holder->configs(),
+      profile_prefs_, storage_service_->cached_result_provider());
 
   proxy_->SetExecutionService(&execution_service_);
 
@@ -330,7 +330,7 @@
 SegmentationPlatformServiceImpl::CreateSegmentResultProviders() {
   std::map<std::string, std::unique_ptr<SegmentResultProvider>>
       result_providers;
-  for (const auto& config : storage_service_->config_holder().configs()) {
+  for (const auto& config : storage_service_->config_holder()->configs()) {
     result_providers[config->segmentation_key] = SegmentResultProvider::Create(
         storage_service_->segment_info_database(),
         storage_service_->signal_storage_config(),
diff --git a/components/segmentation_platform/internal/segmentation_ukm_helper.cc b/components/segmentation_platform/internal/segmentation_ukm_helper.cc
index b731ab8..bad53f8 100644
--- a/components/segmentation_platform/internal/segmentation_ukm_helper.cc
+++ b/components/segmentation_platform/internal/segmentation_ukm_helper.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/time/clock.h"
+#include "base/time/time.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h"
 #include "components/segmentation_platform/internal/stats.h"
@@ -187,6 +188,10 @@
     std::vector<float> results(prediction_result->result().begin(),
                                prediction_result->result().end());
     AddPredictionResultToUkmModelExecution(&execution_result, results);
+    base::Time prediction_time = base::Time::FromDeltaSinceWindowsEpoch(
+        base::Microseconds(prediction_result->timestamp_us()));
+    execution_result.SetOutputDelaySec(
+        (base::Time::Now() - prediction_time).InSeconds());
   }
   if (selected_segment.has_value()) {
     execution_result.SetSelectionResult(selected_segment->segment_id);
diff --git a/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc b/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc
index 2745d100..8f243a8 100644
--- a/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc
+++ b/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc
@@ -11,17 +11,20 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
+#include "base/time/time.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h"
 #include "components/segmentation_platform/public/config.h"
 #include "components/segmentation_platform/public/features.h"
 #include "components/segmentation_platform/public/local_state_helper.h"
+#include "components/segmentation_platform/public/proto/prediction_result.pb.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 #include "components/segmentation_platform/public/segmentation_platform_service.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 using Segmentation_ModelExecution = ukm::builders::Segmentation_ModelExecution;
 
@@ -45,10 +48,15 @@
       kRoundingError);
 }
 
-absl::optional<proto::PredictionResult> GetPredictionResult() {
+absl::optional<proto::PredictionResult> GetPredictionResult(
+    absl::optional<base::Time> prediction_time = absl::nullopt) {
   proto::PredictionResult result;
   result.add_result(0.5);
   result.add_result(0.4);
+  if (prediction_time.has_value()) {
+    result.set_timestamp_us(
+        prediction_time->ToDeltaSinceWindowsEpoch().InMicroseconds());
+  }
   return result;
 }
 
@@ -144,7 +152,8 @@
   selected_segment.selection_time = base::Time::Now() - base::Seconds(10);
   SegmentationUkmHelper::GetInstance()->RecordTrainingData(
       proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 101, input_tensors,
-      outputs, output_indexes, GetPredictionResult(), selected_segment);
+      outputs, output_indexes,
+      GetPredictionResult(selected_segment.selection_time), selected_segment);
   ExpectUkmMetrics(Segmentation_ModelExecution::kEntryName,
                    {Segmentation_ModelExecution::kOptimizationTargetName,
                     Segmentation_ModelExecution::kModelVersionName,
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
index 9b40d91..5156234 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
+#include "components/segmentation_platform/internal/database/config_holder.h"
 #include "components/segmentation_platform/internal/database/mock_signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/internal/database/signal_database.h"
@@ -116,7 +117,8 @@
     storage_service_ = std::make_unique<StorageService>(
         std::move(moved_segment_database), nullptr,
         std::move(moved_signal_config),
-        std::make_unique<TestDefaultModelManager>(), ukm_data_manager_.get());
+        std::make_unique<TestDefaultModelManager>(), nullptr,
+        ukm_data_manager_.get());
 
     signal_filter_processor_ = std::make_unique<SignalFilterProcessor>(
         storage_service_.get(), user_action_signal_handler_.get(),
diff --git a/components/services/screen_ai/public/cpp/screen_ai_service_router.cc b/components/services/screen_ai/public/cpp/screen_ai_service_router.cc
index 7a30641e..8bee8a7 100644
--- a/components/services/screen_ai/public/cpp/screen_ai_service_router.cc
+++ b/components/services/screen_ai/public/cpp/screen_ai_service_router.cc
@@ -14,6 +14,7 @@
 #include "components/services/screen_ai/public/cpp/screen_ai_install_state.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/service_process_host.h"
+#include "content/public/browser/service_process_host_passkeys.h"
 
 namespace {
 
@@ -96,12 +97,16 @@
 void ScreenAIServiceRouter::LaunchIfNotRunning() {
   if (screen_ai_service_.is_bound())
     return;
-
-  if (!ScreenAIInstallState::GetInstance()->IsComponentAvailable()) {
+  auto* screen_ai_install = ScreenAIInstallState::GetInstance();
+  if (!screen_ai_install->IsComponentAvailable()) {
     VLOG(0)
         << "ScreenAI service launch triggered when component is not available.";
     return;
   }
+#if BUILDFLAG(IS_WIN)
+  base::FilePath library_path = screen_ai_install->get_component_binary_path();
+  std::vector<base::FilePath> preload_libraries = {library_path};
+#endif  // BUILDFLAG(IS_WIN)
 
   // TODO(https://crbug.com/1443341): Make sure the library is sandboxed and
   // loaded from the same folder and component updater doesn't download a new
@@ -110,6 +115,11 @@
       screen_ai_service_.BindNewPipeAndPassReceiver(),
       content::ServiceProcessHost::Options()
           .WithDisplayName("Screen AI Service")
+#if BUILDFLAG(IS_WIN)
+          .WithPreloadedLibraries(
+              preload_libraries,
+              content::ServiceProcessHostPreloadLibraries::GetPassKey())
+#endif  // BUILDFLAG(IS_WIN)
           .Pass());
   DCHECK(screen_ai_service_.is_bound());
 
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h
index c5d432a..df79abe 100644
--- a/components/signin/public/identity_manager/identity_manager.h
+++ b/components/signin/public/identity_manager/identity_manager.h
@@ -55,6 +55,7 @@
 class AccountTrackerService;
 class GaiaCookieManagerService;
 class NewTabPageUI;
+class PrivacySandboxSettingsDelegate;
 
 namespace signin {
 
@@ -591,10 +592,11 @@
   FRIEND_TEST_ALL_PREFIXES(IdentityManagerTest, RefreshAccountInfoIfStale);
   FRIEND_TEST_ALL_PREFIXES(IdentityManagerTest, FindExtendedPrimaryAccountInfo);
 
-  // Only caller to FindExtendedPrimaryAccountInfo().
-  // TODO(https://crbug.com/1213351): Delete once the private call has been
+  // Both classes only call FindExtendedPrimaryAccountInfo().
+  // TODO(https://crbug.com/1213351): Delete once the private calls have been
   // removed.
   friend class ::NewTabPageUI;
+  friend class ::PrivacySandboxSettingsDelegate;
 
   // Returns the extended account info for the primary account. This function
   // does not require tokens to be loaded.
diff --git a/components/strings/components_strings_af.xtb b/components/strings/components_strings_af.xtb
index c7145e9..8faa6e2 100644
--- a/components/strings/components_strings_af.xtb
+++ b/components/strings/components_strings_af.xtb
@@ -1093,6 +1093,7 @@
 <translation id="3658742229777143148">Hersiening</translation>
 <translation id="3664782872746246217">Sleutelwoorde:</translation>
 <translation id="3667704023705708645">Ondernemingkapitaal</translation>
+<translation id="3671117652518853176">Wanneer dit afgeskakel is, kan jy van tyd tot tyd gevra word om vir sekuriteitdoeleindes te verifieer</translation>
 <translation id="3671540257457995106">Laat grootteverandering toe?</translation>
 <translation id="3672568546897166916">Fout by <ph name="ERROR_PATH" />: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">Derde rol</translation>
@@ -1127,6 +1128,7 @@
 <translation id="3736520371357197498">As jy die risiko's vir jou sekuriteit verstaan, mag jy <ph name="BEGIN_LINK" />hierdie onveilige werf besoek<ph name="END_LINK" /> voordat die gevaarlike programme verwyder is.</translation>
 <translation id="3738166223076830879">Jou administrateur bestuur jou blaaier.</translation>
 <translation id="3740319564441798148">Langafstandbus- en spoorvervoer</translation>
+<translation id="3743765582345153106">Verifieer altyd wanneer jy outvul gebruik</translation>
 <translation id="3744111561329211289">Agtergrondsinkronisering</translation>
 <translation id="3744286742364977428">Lêers wat jy aflaai, word na Google Cloud of derde partye gestuur om ontleed te word. Hulle kan byvoorbeeld vir sensitiewe data of wanware geskandeer word en kan op grond van maatskappybeleide geberg word.</translation>
 <translation id="3744899669254331632">Jy kan <ph name="SITE" /> nie nou onmiddelllik besoek nie, omdat die webwerf deurmekaar eiebewyse gestuur het wat Chrome nie kan verwerk nie. Netwerkfoute en -aanvalle is gewoonlik tydelik, so hierdie bladsy sal waarskynlik later werk.</translation>
@@ -1729,6 +1731,7 @@
 <translation id="5171045022955879922">Soek of tik URL in</translation>
 <translation id="5172758083709347301">Masjien</translation>
 <translation id="5177076414499237632">Kom meer te wete oor hierdie bladsy se bron en onderwerp</translation>
+<translation id="5179490652562926740">Betalingverifikasie-instellings is gestoor</translation>
 <translation id="5179510805599951267">Nie in <ph name="ORIGINAL_LANGUAGE" /> nie? Meld hierdie fout aan</translation>
 <translation id="518639307526414276">Troeteldierkos en troeteldiersorgbenodigdhede</translation>
 <translation id="5190072300954988691">Kamera en mikrofoon nie toegelaat nie</translation>
diff --git a/components/strings/components_strings_am.xtb b/components/strings/components_strings_am.xtb
index 7f7c0d6a..1445c158 100644
--- a/components/strings/components_strings_am.xtb
+++ b/components/strings/components_strings_am.xtb
@@ -1092,6 +1092,7 @@
 <translation id="3658742229777143148">ክለሳ</translation>
 <translation id="3664782872746246217">ቁልፍ ቃላት፦</translation>
 <translation id="3667704023705708645">ቬንቸር ካፒታል</translation>
+<translation id="3671117652518853176">በሚጠፋበት ጊዜ ለደህንነት ዓላማዎች ሲባል በየጊዜው እንዲያረጋግጡ ሊጠየቁ ይችላሉ</translation>
 <translation id="3671540257457995106">መጠን መቀየር ይፈቀድ?</translation>
 <translation id="3672568546897166916"><ph name="ERROR_PATH" /> ላይ ስህተት፦ <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">ሦስተኛ ጥቅልል</translation>
@@ -1126,6 +1127,7 @@
 <translation id="3736520371357197498">ደህንነትዎ ላይ የሚያመጣቸውን ስጋቶች ከተረዱ አደገኛ ፕሮግራሞቹ ከመወገዳቸው በፊት <ph name="BEGIN_LINK" />ይህን ደህንነቱ ያልተጠበቀ ጣቢያ ሊጎብኙ<ph name="END_LINK" /> ይችላሉ።</translation>
 <translation id="3738166223076830879">የእርስዎ አሳሽ በእርስዎ አስተዳዳሪ የሚተዳደር ነው።</translation>
 <translation id="3740319564441798148">የረጅም ርቀት አውቶቡስ እና ባቡር</translation>
+<translation id="3743765582345153106">ራስ-ሙላ በሚጠቀሙበት ጊዜ ሁልጊዜ ያረጋግጡ</translation>
 <translation id="3744111561329211289">የዳራ ስምረት</translation>
 <translation id="3744286742364977428">እርስዎ የሚያወርዷቸው ፋይሎች ወደ Google ደመና ወይም ሶስተኛ ወገኖች ለትንታኔ ይላካሉ። ለምሳሌ፣ አደጋ ሊያስከትል ለሚችል ውሂብ ወይም ለተንኮል አዘል ዌር ሊቃኙ እና ምናልባት በኩባንያ መመሪያዎች መሰረት ሊከማቹ ይችላሉ።</translation>
 <translation id="3744899669254331632">የድር ጣቢያው Chromium ሊያስኬዳቸው የማይችሉ የተዘበራረቁ ምስክርነቶችን ስለላከ አሁን ላይ <ph name="SITE" />ን መጎብኘት አይችሉም። የአውታረ መረብ ስህተቶች እና ጥቃቶች ብዙውን ጊዜ ጊዜያዊ ናቸው፣ ስለዚህ ይህ ገፅ በኋላ ላይ ምናልባት ሊሰራ ይችል ይሆናል።</translation>
@@ -1728,6 +1730,7 @@
 <translation id="5171045022955879922">ይፈልጉ ወይም ዩአርኤል ይጻፉ</translation>
 <translation id="5172758083709347301">ማሽን</translation>
 <translation id="5177076414499237632">ስለዚህ ገፅ ምንጭ እና ርዕስ ይወቁ</translation>
+<translation id="5179490652562926740">የክፍያ ማረጋገጫ ቅንብሮች ተቀምጠዋል</translation>
 <translation id="5179510805599951267">በ<ph name="ORIGINAL_LANGUAGE" /> አይደለም? ይህን ስህተት ሪፖርት ያድርጉ</translation>
 <translation id="518639307526414276">የቤት እንስሳት ምግብ እና የቤት እንስሳት እንክብካቤ አቅርቦቶች</translation>
 <translation id="5190072300954988691">ካሜራ እና ማይክሮፎን አይፈቀዱም</translation>
diff --git a/components/strings/components_strings_ar.xtb b/components/strings/components_strings_ar.xtb
index cc05f41..1c49ad3 100644
--- a/components/strings/components_strings_ar.xtb
+++ b/components/strings/components_strings_ar.xtb
@@ -3224,6 +3224,7 @@
 <translation id="8870494189203302833">نفس الترتيب والوجه للأسفل</translation>
 <translation id="8870700989640064057">هل تريد طباعة الملف السرّي؟</translation>
 <translation id="8871553383647848643">تخصيص مظهر المتصفِّح</translation>
+<translation id="8871603420762394026">‏يشارك Chrome الآن معلومات محدودة جدًا مع المواقع الإلكترونية، مثل وقت عرض الإعلان لك، لمساعدة المواقع الإلكترونية في قياس أداء الإعلانات.</translation>
 <translation id="8874824191258364635">أدخِل رقم بطاقة صحيحًا</translation>
 <translation id="8876033571432926051">ألعاب بسيطة</translation>
 <translation id="8877780815363510165">صيد أسماك</translation>
diff --git a/components/strings/components_strings_be.xtb b/components/strings/components_strings_be.xtb
index c95af0a..318552c 100644
--- a/components/strings/components_strings_be.xtb
+++ b/components/strings/components_strings_be.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Скіньце свой пароль</translation>
 <translation id="2003775180883135320">Чатыры дзіркі зверху</translation>
 <translation id="201174227998721785">Кіруйце дазволамі і данымі, якія захоўваюцца на сайтах, праз налады Chrome</translation>
+<translation id="2012276282211112603">Тэм пакуль няма</translation>
 <translation id="2019607688127825327">Кнопка "Кіраваць наладамі спецыяльных магчымасцей". Каб персаналізаваць інструменты даступнасці ў наладах Chrome, націсніце Enter</translation>
 <translation id="2021333772895814435">У адпаведнасці з гэтай палітыкай сінхранізацыя аўтаматычна адключаецца для наступных тыпаў даных: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 x 19 цаляў</translation>
diff --git a/components/strings/components_strings_da.xtb b/components/strings/components_strings_da.xtb
index 479aa8c7..fd9bddf 100644
--- a/components/strings/components_strings_da.xtb
+++ b/components/strings/components_strings_da.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Nulstil din adgangskode nu</translation>
 <translation id="2003775180883135320">Fire huller øverst</translation>
 <translation id="201174227998721785">Administrer tilladelser og data, der gemmes på websites, i Chrome-indstillingerne</translation>
+<translation id="2012276282211112603">Der er ingen emner at vise lige nu</translation>
 <translation id="2019607688127825327">Knappen "Administrer indstillinger for hjælpefunktioner" – tryk på Enter for at personligt tilpasse dine hjælpefunktioner i Chrome-indstillingerne</translation>
 <translation id="2021333772895814435">Denne politik deaktiverer automatisk synkronisering på tværs af enheder for: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 x 19 tommer</translation>
@@ -738,7 +739,7 @@
 <translation id="2730326759066348565"><ph name="BEGIN_LINK" />Køre Diagnosticering af forbindelse<ph name="END_LINK" /></translation>
 <translation id="2730600605555029057">Klassisk musik</translation>
 <translation id="2731382536835015353">44 x 68 tommer</translation>
-<translation id="2734319753272419592">Giv Google tilladelse til at bruge din kurv til at søge efter tilpassede rabatter. Hvis der er tilgængelige rabatter, vises de automatisk i din kurv.</translation>
+<translation id="2734319753272419592">Giv Google tilladelse til at bruge din kurv til at søge efter personligt tilpassede rabatter. Hvis der er tilgængelige rabatter, vises de automatisk i din kurv.</translation>
 <translation id="2740531572673183784">OK</translation>
 <translation id="2742511345840685325">Bordtennis</translation>
 <translation id="2742870351467570537">Fjern valgte elementer</translation>
@@ -1092,6 +1093,7 @@
 <translation id="3658742229777143148">Revision</translation>
 <translation id="3664782872746246217">Søgeord:</translation>
 <translation id="3667704023705708645">Risikovillig kapital</translation>
+<translation id="3671117652518853176">Når funktionen er deaktiveret, kan du af sikkerhedsmæssige årsager blive bedt om at verificere af og til</translation>
 <translation id="3671540257457995106">Vil du tillade valg af andre størrelser?</translation>
 <translation id="3672568546897166916">Fejl: <ph name="ERROR_PATH" /> – <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">Tredje papirrulle</translation>
@@ -1126,6 +1128,7 @@
 <translation id="3736520371357197498">Hvis du forstår den sikkerhedsrisiko, du udsætter dig for, kan du <ph name="BEGIN_LINK" />gå til dette usikre website<ph name="END_LINK" />, inden de farlige programmer er fjernet.</translation>
 <translation id="3738166223076830879">Din browser administreres af din administrator.</translation>
 <translation id="3740319564441798148">Langtursbus og -tog</translation>
+<translation id="3743765582345153106">Verificer altid, når du bruger autofyld</translation>
 <translation id="3744111561329211289">Synkronisering i baggrunden</translation>
 <translation id="3744286742364977428">De filer, du downloader, sendes til Google Cloud eller tredjeparter, hvor de analyseres. De kan f.eks. blive scannet for følsomme oplysninger eller malware og kan blive gemt i henhold til virksomhedens politikker.</translation>
 <translation id="3744899669254331632">Du kan ikke gå til <ph name="SITE" /> lige nu, da websitet sendte krypterede loginoplysninger, som Chromium ikke kan behandle. Netværksfejl og angreb er normalt midlertidige, så denne side vil sandsynligvis fungere igen senere.</translation>
@@ -1415,7 +1418,7 @@
 <translation id="4414515549596849729">cookies og websitedata</translation>
 <translation id="4415426530740016218">Afhentningsadresse</translation>
 <translation id="4424024547088906515">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
-<translation id="4428065317363009941">Annoncetilpasning</translation>
+<translation id="4428065317363009941">Personlig tilpasning af annoncer</translation>
 <translation id="443121186588148776">Serieport</translation>
 <translation id="4432688616882109544"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller der er ikke angivet et.</translation>
 <translation id="4432792777822557199">Sider på <ph name="SOURCE_LANGUAGE" /> oversættes fremover til <ph name="TARGET_LANGUAGE" /></translation>
@@ -1728,6 +1731,7 @@
 <translation id="5171045022955879922">Søg, eller angiv webadresse</translation>
 <translation id="5172758083709347301">Maskine</translation>
 <translation id="5177076414499237632">Få flere oplysninger om denne sides kilde og emne</translation>
+<translation id="5179490652562926740">Indstillingerne for verificering ved betaling blev gemt</translation>
 <translation id="5179510805599951267">Ikke på <ph name="ORIGINAL_LANGUAGE" />? Rapporter denne fejl</translation>
 <translation id="518639307526414276">Foder og udstyr til kæledyr</translation>
 <translation id="5190072300954988691">Adgang til kamera og mikrofon er ikke tilladt</translation>
@@ -2288,7 +2292,7 @@
 <translation id="6612010098632894193">Onlinevideo</translation>
 <translation id="6615297766614333076">Stabler 2</translation>
 <translation id="6624427990725312378">Kontaktoplysninger</translation>
-<translation id="6627727261837091711">Vis oplysninger om personlig annoncetilpasning</translation>
+<translation id="6627727261837091711">Vis oplysninger om personlig tilpasning af annoncer</translation>
 <translation id="6628463337424475685"><ph name="ENGINE" /> -søgning</translation>
 <translation id="6630043285902923878">Finder USB-enheder...</translation>
 <translation id="6630809736994426279">Brugere med ondsindede hensigter, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan forsøge at installere farlige programmer på din Mac, som stjæler eller sletter dine oplysninger (f.eks. fotos, adgangskoder, beskeder og kreditkort). <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb
index 07b6b69..c771f7cc 100644
--- a/components/strings/components_strings_en-GB.xtb
+++ b/components/strings/components_strings_en-GB.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Reset your password now</translation>
 <translation id="2003775180883135320">Quad punch top</translation>
 <translation id="201174227998721785">Manage permissions and data stored across sites in Chrome settings</translation>
+<translation id="2012276282211112603">No topics to show right now</translation>
 <translation id="2019607688127825327">Manage accessibility settings button; press Enter to personalise your accessibility tools in Chrome settings</translation>
 <translation id="2021333772895814435">This policy automatically disables syncing across devices for: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 in x 19 in</translation>
diff --git a/components/strings/components_strings_es-419.xtb b/components/strings/components_strings_es-419.xtb
index 31f4bc29..057262a 100644
--- a/components/strings/components_strings_es-419.xtb
+++ b/components/strings/components_strings_es-419.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Restablecer tu contraseña ahora</translation>
 <translation id="2003775180883135320">Perforación cuádruple en la parte superior</translation>
 <translation id="201174227998721785">En la configuración de Chrome, administra los permisos y datos almacenados en los sitios</translation>
+<translation id="2012276282211112603">No hay temas para mostrar en este momento</translation>
 <translation id="2019607688127825327">Botón Administrar la configuración de accesibilidad: presiona Intro para personalizar tus herramientas de accesibilidad en la configuración de Chrome</translation>
 <translation id="2021333772895814435">Esta política inhabilita automáticamente la sincronización entre dispositivos de <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">30.5 × 48.3 cm (12 × 19 in)</translation>
diff --git a/components/strings/components_strings_fa.xtb b/components/strings/components_strings_fa.xtb
index 0a25a5a..4c5215e 100644
--- a/components/strings/components_strings_fa.xtb
+++ b/components/strings/components_strings_fa.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">هم‌اکنون گذرواژه‌تان را بازنشانی کنید</translation>
 <translation id="2003775180883135320">چهار سوراخ در بالا</translation>
 <translation id="201174227998721785">‏مدیریت اجازه‌ها و داده‌های ذخیره‌شده در سایت‌ها در تنظیمات Chrome</translation>
+<translation id="2012276282211112603">درحال‌حاضر هیچ موضوعی برای نمایش وجود ندارد</translation>
 <translation id="2019607688127825327">‏دکمه «مدیریت تنظیمات دسترس‌پذیری»؛ برای شخصی کردن ابزارهای دسترس‌پذیری در تنظیمات Chrome، کلید «ورود» را فشار دهید</translation>
 <translation id="2021333772895814435">این خط‌مشی همگام‌سازی را در همه دستگاه‌ها برای این موارد به‌طور خودکار غیرفعال می‌کند: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">۱۹ × ۱۲ اینچ</translation>
diff --git a/components/strings/components_strings_fi.xtb b/components/strings/components_strings_fi.xtb
index 6a94cda..b0520aa2 100644
--- a/components/strings/components_strings_fi.xtb
+++ b/components/strings/components_strings_fi.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Pyydä uusi salasana</translation>
 <translation id="2003775180883135320">Neljä reikää yläreunassa</translation>
 <translation id="201174227998721785">Ylläpidä sivustoille tallennettuja lupia ja dataa Chromen asetuksista</translation>
+<translation id="2012276282211112603">Näytettäviä aiheita ei juuri nyt ole</translation>
 <translation id="2019607688127825327">Muuta esteettömyysasetuksia ‑painike, personoi esteettömyystyökaluja Chromen asetuksista painamalla Enter</translation>
 <translation id="2021333772895814435">Käytäntö poistaa automaattisesti käytöstä seuraavien laitteiden synkronoinnin: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 x 19 tuumaa</translation>
diff --git a/components/strings/components_strings_fr-CA.xtb b/components/strings/components_strings_fr-CA.xtb
index 44e292cc..fd0f455 100644
--- a/components/strings/components_strings_fr-CA.xtb
+++ b/components/strings/components_strings_fr-CA.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Réinitialiser votre mot de passe maintenant</translation>
 <translation id="2003775180883135320">Quadruple perforation dans le haut</translation>
 <translation id="201174227998721785">Gérez les autorisations et les données stockées pour les sites dans les paramètres de Chrome</translation>
+<translation id="2012276282211112603">Aucun sujet à afficher pour le moment</translation>
 <translation id="2019607688127825327">Bouton Gérer les paramètres d'accessibilité, appuyez sur la touche Entrée pour personnaliser vos outils d'accessibilité dans les paramètres de Chrome</translation>
 <translation id="2021333772895814435">Cette politique désactive automatiquement la synchronisation entre les appareils pour : <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 po x 19 po</translation>
diff --git a/components/strings/components_strings_fr.xtb b/components/strings/components_strings_fr.xtb
index 2aab307..57ed0d8 100644
--- a/components/strings/components_strings_fr.xtb
+++ b/components/strings/components_strings_fr.xtb
@@ -1555,7 +1555,7 @@
 <translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
 <translation id="4766713847338118463">Double agrafe en bas</translation>
 <translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
-<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ fenêtre pop-up bloquée}one{# fenêtre pop-up bloquée}other{# fenêtres pop-up bloquées}}</translation>
+<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Fenêtre pop-up bloquée}one{# fenêtre pop-up bloquée}other{# fenêtres pop-up bloquées}}</translation>
 <translation id="4780366598804516005">Boîte aux lettres 1</translation>
 <translation id="4785376858512657294">Gérer le compte Google</translation>
 <translation id="4785689107224900852">Passer à cet onglet</translation>
diff --git a/components/strings/components_strings_hu.xtb b/components/strings/components_strings_hu.xtb
index a457808..13a6b9cf 100644
--- a/components/strings/components_strings_hu.xtb
+++ b/components/strings/components_strings_hu.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Jelszó visszaállítása</translation>
 <translation id="2003775180883135320">Négy lyuk felül</translation>
 <translation id="201174227998721785">A a webhelyek engedélyeinek és tárolt adatainak a Chrome-beállítások közötti kezelése</translation>
+<translation id="2012276282211112603">Jelenleg nincsenek megjeleníthető témák</translation>
 <translation id="2019607688127825327">Kisegítő lehetőségek beállításainak kezelése gomb. Nyomja le az Entert, ha személyre szeretné szabni a kisegítő eszközöket a Chrome beállításaiban.</translation>
 <translation id="2021333772895814435">Ez a házirend automatikusan letiltja a következő eszközök közötti szinkronizálását: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 × 19 hüvelyk</translation>
diff --git a/components/strings/components_strings_hy.xtb b/components/strings/components_strings_hy.xtb
index f9903929..5d66c60 100644
--- a/components/strings/components_strings_hy.xtb
+++ b/components/strings/components_strings_hy.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Վերակայեք գաղտնաբառը</translation>
 <translation id="2003775180883135320">Չորս անցք վերևում</translation>
 <translation id="201174227998721785">Կառավարեք թույլտվությունները և կայքերում պահված տվյալները Chrome-ի կարգավորումներում</translation>
+<translation id="2012276282211112603">Այս պահին թեմաներ չկան</translation>
 <translation id="2019607688127825327">«Կառավարել հատուկ գործառույթների կարգավորումները» կոճակ։ Սեղմեք Enter՝ Chrome-ի կարգավորումներում հատուկ գործառույթների գործիքներն անհատականացնելու համար։</translation>
 <translation id="2021333772895814435">Այս կանոնն ավտոմատ անջատում է համաժամացումը սարքերում հետևյալի համար՝ <ph name="ACTION_LIST" />։</translation>
 <translation id="202224654587969958">12 x 19 դյույմ</translation>
diff --git a/components/strings/components_strings_ja.xtb b/components/strings/components_strings_ja.xtb
index 7877542..d66f170 100644
--- a/components/strings/components_strings_ja.xtb
+++ b/components/strings/components_strings_ja.xtb
@@ -2536,7 +2536,7 @@
 <translation id="7217745192097460130">Touch ID を使用して本人確認し、購入手続きを完了しますか?</translation>
 <translation id="7219179957768738017">この接続には <ph name="SSL_VERSION" /> を使用しています。</translation>
 <translation id="7220786058474068424">処理しています</translation>
-<translation id="7221855153210829124">通知の表示</translation>
+<translation id="7221855153210829124">通知を表示</translation>
 <translation id="722454870747268814">新しいシークレット タブ</translation>
 <translation id="7233592378249864828">確認シートの印刷</translation>
 <translation id="7234638337680728591">ガソリン料金、燃費</translation>
diff --git a/components/strings/components_strings_lo.xtb b/components/strings/components_strings_lo.xtb
index b3bdc82..be0feac 100644
--- a/components/strings/components_strings_lo.xtb
+++ b/components/strings/components_strings_lo.xtb
@@ -598,6 +598,7 @@
 <translation id="2380886658946992094">Legal</translation>
 <translation id="2383455408879745299">ປັບແຕ່ງເຄື່ອງມືການຊ່ວຍເຂົ້າເຖິງຂອງທ່ານໃນການຕັ້ງຄ່າ Chrome ໃຫ້ເປັນແບບສ່ວນຕົວ</translation>
 <translation id="2384307209577226199">ຄ່າເລີ່ມຕົ້ນ​ວິ​ສາ​ຫະ​ກິດ</translation>
+<translation id="238459632961158867">ເວັບໄຊ</translation>
 <translation id="2385809941344967209">ອັບເດດ Chrome ຈາກການຕັ້ງຄ່າ Chrome ຂອງທ່ານ</translation>
 <translation id="2386255080630008482">ໃບຢັ້ງຢືນຂອງເຊີບເວີຖືກຖອນຄືນແລ້ວ.</translation>
 <translation id="239293030466334554">ເປີດປະທຸນ</translation>
@@ -1047,6 +1048,7 @@
 <translation id="3566336457819493938">215 x 315 ມມ</translation>
 <translation id="3567778190852720481">ບໍ່ສາມາດລົງທະບຽນດ້ວຍບັນຊີວິສາຫະກິດໄດ້ (ບັນຊີວິສາຫະກິດບໍ່ມີສິດ).</translation>
 <translation id="3567901620846335314">100 x 150 ມມ</translation>
+<translation id="3568886473829759308">ເຂົ້າເຖິງເວັບໄຊເພື່ອເບິ່ງຂໍ້ມູນ, ຊັບພະຍາກອນ ຫຼື ການບໍລິການທີ່ສະໜອງໂດຍທຸລະກິດ.</translation>
 <translation id="3574305903863751447"><ph name="CITY" />, <ph name="STATE" /> <ph name="COUNTRY" /></translation>
 <translation id="3575121482199441727">ອະນຸຍາດສຳລັບເວັບໄຊນີ້</translation>
 <translation id="3575168918110434329">A4x7</translation>
@@ -1093,6 +1095,7 @@
 <translation id="3658742229777143148">ການ​ດັດ​ແກ້</translation>
 <translation id="3664782872746246217">ຄີເວີດ:</translation>
 <translation id="3667704023705708645">ບໍລິສັດຮ່ວມທຶນ</translation>
+<translation id="3671117652518853176">ເມື່ອປິດໄວ້, ລະບົບອາດຂໍໃຫ້ທ່ານຢັ້ງຢືນເປັນບາງໄລຍະເພື່ອຈຸດປະສົງດ້ານຄວາມປອດໄພ</translation>
 <translation id="3671540257457995106">ອະນຸຍາດໃຫ້ປັບຂະໜາດໄດ້ບໍ?</translation>
 <translation id="3672568546897166916">ເກີດຂໍ້ຜິດພາດຢູ່ <ph name="ERROR_PATH" />: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">ມ້ວນທີສາມ</translation>
@@ -1127,6 +1130,7 @@
 <translation id="3736520371357197498">ຖ້າທ່ານເຂົ້າໃຈຄວາມສ່ຽງຕໍ່ຄວາມປອດໄພຂອງທ່ານ, ທ່ານອາດຈະ <ph name="BEGIN_LINK" />ເຂົ້າເບິ່ງເວັບໄຊທ໌ທີ່ບໍ່ປອດໄພນີ້<ph name="END_LINK" /> ກ່ອນໂປຣແກຼມທີ່ເປັນອັນຕະລາຍຈະຖືກເອົາອອກໄປ.</translation>
 <translation id="3738166223076830879">ໂປຣແກຣມທ່ອງເວັບຂອງທ່ານຖືກຈັດການໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ.</translation>
 <translation id="3740319564441798148">ລົດເມ ແລະ ລົດໄຟທາງໄກ</translation>
+<translation id="3743765582345153106">ຢັ້ງຢືນຕະຫຼອດເວລາເມື່ອໃຊ້ການຕື່ມຂໍ້ມູນອັດຕະໂນມັດ</translation>
 <translation id="3744111561329211289">ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ</translation>
 <translation id="3744286742364977428">ໄຟລ໌ທີ່ທ່ານດາວໂຫຼດຈະຖືກສົ່ງໃຫ້ Google Cloud ຫຼື ພາກສ່ວນທີສາມເພື່ອວິເຄາະ. ຕົວຢ່າງ: ພວກມັນອາດຖືກສະແກນເພື່ອຊອກຫາຂໍ້ມູນທີ່ລະອຽດອ່ອນ ຫຼື ເມົາແວ ແລະ ອາດຖືກຈັດເກັບໄວ້ໂດຍອ້າງອີງໃສ່ນະໂຍບາຍບໍລິສັດ.</translation>
 <translation id="3744899669254331632">ທ່ານ​ບໍ່​ສາ​ມາດ​ເຂົ້າ​ເບິ່ງ <ph name="SITE" /> ໄດ້​ດຽວ​ນີ້ ເພາະ​ວ່າ​ເວັບ​ໄຊ​ທ໌​ສົ່ງ​​ໃບຢັ້ງ​ຢືນທີ່​ຖືກ​ລົບ​ກວນ​ທີ່ Chromium ບໍ່​ສາ​ມາດ​ດຳ​ເນີນ​ການ​ໄດ້​ແລ້ວ. ປົກ​ກະ​ຕິນັ້ນ ຄວາມ​ຜິດ​ພາດ ແລະ​ການ​ໂຈມ​ຕີ​ເຄືອ​ຂ່າຍ​ຈະ​ມີ​ຊົ່ວ​ຄາວ, ດັ່ງ​ນັ້ນ ໜ້າ​ນີ້​ອາດ​ຈະ​ເຮັດ​ວຽກ​ໄດ້​ພາຍ​ຫຼັງ.</translation>
@@ -1365,6 +1369,7 @@
 <translation id="4300675098767811073">ເຈາະຮູເບື້ອງຂວາຫຼາຍຮູ</translation>
 <translation id="4302514097724775343">ແຕະ dino ເພື່ອຫຼິ້ນ</translation>
 <translation id="4304049446746819918">{0,plural, =1{ນະໂຍບາຍຜູ້ເບິ່ງແຍງລະບົບບໍ່ແນະນຳໃຫ້ຍ້າຍໄຟລ໌ນີ້ໄປໃສ່ <ph name="DESTINATION_NAME" />}other{ນະໂຍບາຍຜູ້ເບິ່ງແຍງລະບົບບໍ່ແນະນຳໃຫ້ຍ້າຍໄຟລ໌ເຫຼົ່ານີ້ໄປໃສ່ <ph name="DESTINATION_NAME" />}}</translation>
+<translation id="4304485328308299773">ອ່ານການປະເມີນຜະລິດຕະພັນ, ບໍລິການ ຫຼື ປະສົບການຂອງລູກຄ້າເພື່ອຊ່ວຍແຈ້ງການຕັດສິນໃຈຂອງທ່ານດ້ວຍຄຳຕິຊົມ.</translation>
 <translation id="4305666528087210886">ບໍ່ສາມາດເຂົ້າເຖິງໄຟລ໌ຂອງທ່ານໄດ້</translation>
 <translation id="4306529830550717874">ບັນທຶກທີ່ຢູ່ບໍ?</translation>
 <translation id="4306812610847412719">ຄລິບບອດ</translation>
@@ -1529,6 +1534,7 @@
 <translation id="4724144314178270921">ສາມາດຂໍເບິ່ງຂໍ້ຄວາມ ແລະ ຮູບຢູ່ຄລິບບອດຂອງທ່ານ</translation>
 <translation id="4726672564094551039">ໂຫຼດນະ​ໂຍ​ບາຍຄືນໃໝ່</translation>
 <translation id="4728558894243024398">ເວທີ</translation>
+<translation id="4730977633786878901">ຄຳຕິຊົມ</translation>
 <translation id="4731638775147756694">ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານໄດ້ບລັອກແອັບພລິເຄຊັນນີ້ໄວ້ແລ້ວ</translation>
 <translation id="4733082559415072992"><ph name="URL" /> ຕ້ອງການໃຊ້ສະຖານທີ່ຂອງອຸປະກອນຂອງທ່ານ</translation>
 <translation id="4736491186715342415">ຍານຍົນ</translation>
@@ -1729,6 +1735,7 @@
 <translation id="5171045022955879922">ຊອກຫາ ຫຼື ພິມ URL</translation>
 <translation id="5172758083709347301">ເຄື່ອງຈັກ</translation>
 <translation id="5177076414499237632">ສຶກສາກ່ຽວກັບແຫຼ່ງທີ່ມາ ແລະ ຫົວຂໍ້ຂອງໜ້ານີ້</translation>
+<translation id="5179490652562926740">ບັນທຶກການຕັ້ງຄ່າການຢັ້ງຢືນການຈ່າຍເງິນແລ້ວ</translation>
 <translation id="5179510805599951267">ບໍ່ເປັນ <ph name="ORIGINAL_LANGUAGE" /> ບໍ? ລາຍງານຄວາມຜິດພາດນີ້</translation>
 <translation id="518639307526414276">ອາຫານ ແລະ ອຸປະກອນເບິ່ງແຍງສັດລ້ຽງ</translation>
 <translation id="5190072300954988691">ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນ</translation>
@@ -2159,6 +2166,7 @@
 <translation id="6284292079994426700">26 x 38 ນິ້ວ</translation>
 <translation id="6284517535531159884">ປະເພດຂອງເມັດຮູບແບບ</translation>
 <translation id="6285507000506177184">ປຸ່ມຈັດການການດາວໂຫຼດໃນ Chrome, ກົດ Enter ເພື່ອຈັດການໄຟລ໌ທີ່ທ່ານດາວໂຫຼດມາແລ້ວໃນ Chrome</translation>
+<translation id="6287197303017372967">ຮັບເສັ້ນທາງໄປຫາປາຍທາງຂອງທ່ານດ້ວຍການຊີ້ນໍາແບບເທື່ອລະຂັ້ນຕອນໂດຍໃຊ້ຄຸນສົມບັດການນໍາທາງ.</translation>
 <translation id="6289939620939689042">ສີໜ້າເຈ້ຍ</translation>
 <translation id="6293309776179964942">JIS B5</translation>
 <translation id="6295618774959045776">CVC:</translation>
@@ -2182,6 +2190,7 @@
 <translation id="633770708279464947">ຄ່າ <ph name="SECURE_DNS_SALT" /> ບໍ່ຖືກຕ້ອງ ແລະ ຈະບໍ່ຖືກນຳໃຊ້.</translation>
 <translation id="6340739886198108203">ນະໂຍບາຍຜູ້ເບິ່ງແຍງລະບົບບໍ່ແນະນຳໃຫ້ຖ່າຍຮູບ ຫຼື ບັນທຶກໜ້າຈໍໃນເວລາປາກົດມີເນື້ອຫາທີ່ເປັນຄວາມລັບ:</translation>
 <translation id="6341434961864773665">{0,plural, =1{ນະໂຍບາຍຜູ້ເບິ່ງແຍງລະບົບບໍ່ແນະນຳໃຫ້ອັບໂຫຼດໄຟລ໌ນີ້ໄປໃສ່ <ph name="DESTINATION_NAME" />}other{ນະໂຍບາຍຜູ້ເບິ່ງແຍງລະບົບບໍ່ແນະນຳໃຫ້ອັບໂຫຼດໄຟລ໌ເຫຼົ່ານີ້ໄປໃສ່ <ph name="DESTINATION_NAME" />}}</translation>
+<translation id="634500758737709758">ເສັ້ນທາງ</translation>
 <translation id="6348220984832452017">ຮູບແບບທີ່ນຳໃຊ້ຢູ່</translation>
 <translation id="6349101878882523185">ຕິດຕັ້ງ <ph name="APP_NAME" /></translation>
 <translation id="6353505687280762741">{COUNT,plural, =0{ບໍ່ມີ}=1{1 ລະຫັດຜ່ານ (ສຳລັບ <ph name="DOMAIN_LIST" />, ຊິ້ງຂໍ້ມູນແລ້ວ)}=2{2 ລະຫັດຜ່ານ (ສຳລັບ <ph name="DOMAIN_LIST" />, ຊິ້ງຂໍ້ມູນແລ້ວ)}other{# ລະຫັດຜ່ານ (ສຳລັບ <ph name="DOMAIN_LIST" />, ຊິ້ງຂໍ້ມູນແລ້ວ)}}</translation>
@@ -2369,6 +2378,7 @@
 <translation id="6823746213313229853">ສົນທະນາວິທະຍຸ</translation>
 <translation id="6825578344716086703">ທ່ານໄດ້ພະຍາຍາມຕິດຕໍ່ຫາ <ph name="DOMAIN" />, ແຕ່ເຊີບເວີໄດ້ນຳສະເໜີໃບຢັ້ງຢືນທີ່ລົງລາຍເຊັນໂດຍການໃຊ້ຂັ້ນຕອນລາຍເຊັນທີ່ອ່ອນ (ເຊັ່ນວ່າ SHA-1). ອັນນີ້ໝາຍຄວາມວ່າຂໍ້ມູນປະຈຳຕົວຄວາມປອດໄພທີ່ເຊີບເວີນໍາສະເໜີນັ້ນສາມາດຖືກປອມໄດ້, ແລະ ເຊີບເວີດັ່ງກ່າວອາດຈະບໍ່ແມ່ນເຊີບເວີທີ່ທ່ານຄາດໄວ້ (ທ່ານອາດຈະກໍາລັງສື່ສານກັບຜູ້ໂຈມຕີຢູ່).</translation>
 <translation id="6826993739343257035">ອະນຸຍາດ AR ບໍ?</translation>
+<translation id="6828150717884939426">ໂທ</translation>
 <translation id="6828866289116430505">ພັນທຸສາດ</translation>
 <translation id="6831043979455480757">ແປພາສາ</translation>
 <translation id="683108308100148227">ເຊື່ອງລາຍການ</translation>
@@ -3094,6 +3104,7 @@
 <translation id="8539500321752640291">ອະນຸຍາດ 2 ຢ່າງບໍ?</translation>
 <translation id="8541158209346794904">ອຸປະກອນ Bluetooth</translation>
 <translation id="8541410041357371550">ເວັບໄຊນີ້ຮັບຫົວຂໍ້ໂຄສະນາຂອງທ່ານຈາກ Chrome ເພື່ອສະແດງໂຄສະນາທີ່ກ່ຽວຂ້ອງຫຼາຍຂຶ້ນໃຫ້ທ່ານເຫັນ</translation>
+<translation id="8541579497401304453">ເຊື່ອມຕໍ່ກັບທຸລະກິດໂດຍການເລີ່ມຕົ້ນການໂທທາງໂທລະສັບ.</translation>
 <translation id="8542014550340843547">ໜີບກະຫຼັບເຟີຢູ່ລຸ່ມສຸດສາມເທື່ອ</translation>
 <translation id="8542617028204211143">SRA0</translation>
 <translation id="8543181531796978784">ທ່ານ​ສາ​ມາດ​ <ph name="BEGIN_ERROR_LINK" />ລາຍ​ງານ​ບັນ​ຫາ​ທີ່ກວດ​ພົບ​ໄດ້<ph name="END_ERROR_LINK" /> ຫຼື, ຖ້າທ່ານເຂົ້າໃຈຄວາມສ່ຽງຕໍ່ຄວາມປອດໄພຂອງທ່ານ, <ph name="BEGIN_LINK" />ເຂົ້າ​ເບິ່ງ​ເວັບ​ໄຊ​ທ໌​ທີ່​ບໍ່​ປອດ​ໄພ​ນີ້<ph name="END_LINK" />.</translation>
diff --git a/components/strings/components_strings_my.xtb b/components/strings/components_strings_my.xtb
index f571de2e..1a3faec7 100644
--- a/components/strings/components_strings_my.xtb
+++ b/components/strings/components_strings_my.xtb
@@ -439,6 +439,7 @@
 <translation id="2003709556000175978">သင့်စကားဝှက်ကို ယခု ပြင်ဆင်သတ်မှတ်ရန်</translation>
 <translation id="2003775180883135320">ထိပ်တွင် လေးချက်ဖောက်ရန်</translation>
 <translation id="201174227998721785">Chrome ဆက်တင်များတွင် ဝဘ်ဆိုက်အားလုံးရှိ ခွင့်ပြုချက်များနှင့် သိမ်းထားသောဒေတာများကို စီမံရန်</translation>
+<translation id="2012276282211112603">ယခုပြရန် အကြောင်းအရာ မရှိပါ</translation>
 <translation id="2019607688127825327">အများသုံးနိုင်မှု ဆက်တင်များ စီမံရန်ခလုတ်၊ Chrome ဆက်တင်များတွင် အများသုံးနိုင်မှုတူးလ်ကို ပုဂ္ဂိုလ်ရေးသီးသန့်ပြုလုပ်ရန် Enter နှိပ်ပါ</translation>
 <translation id="2021333772895814435">ဤမူဝါဒသည် ဖော်ပြပါတို့အတွက် စက်များတွင် စင့်ခ်လုပ်ခြင်းကို အလိုအလျောက် ပိတ်ထားသည်- <ph name="ACTION_LIST" />။</translation>
 <translation id="202224654587969958">၁၂ x ၁၉ လက်မ</translation>
diff --git a/components/strings/components_strings_ne.xtb b/components/strings/components_strings_ne.xtb
index 5c878ab7..928c4181 100644
--- a/components/strings/components_strings_ne.xtb
+++ b/components/strings/components_strings_ne.xtb
@@ -1090,6 +1090,7 @@
 <translation id="3658742229777143148">संशोधन</translation>
 <translation id="3664782872746246217">किवर्डहरू:</translation>
 <translation id="3667704023705708645">उद्यम पुँजी</translation>
+<translation id="3671117652518853176">यो सेटिङ अफ गरिएका अवस्थामा सुरक्षासम्बन्धी प्रयोजनहरूका लागि तपाईंलाई बेला बेलामा पुष्टि गर्न लगाइन सक्छ</translation>
 <translation id="3671540257457995106">आकार बदल्न दिने हो?</translation>
 <translation id="3672568546897166916"><ph name="ERROR_PATH" /> मा त्रुटि भयो: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">तेस्रो रोल</translation>
@@ -1124,6 +1125,7 @@
 <translation id="3736520371357197498">यदि तपाईं आफ्नो सुरक्षामा भएका जोखिमहरूलाई बुझ्नुहुन्छ भने, तपाईं खतरनाक कार्यक्रमहरू हटाइनु भन्दा पहिले तपाईं <ph name="BEGIN_LINK" />यो असुरक्षित साइट भ्रमण<ph name="END_LINK" /> गर्न सक्नुहुन्छ।</translation>
 <translation id="3738166223076830879">तपाईंका एड्मिन तपाईंको ब्राउजर व्यवस्थापन गर्नुहुन्छ।</translation>
 <translation id="3740319564441798148">लामो दूरीका बस तथा रेल</translation>
+<translation id="3743765582345153106">अटोफिल प्रयोग गर्दा सधैँ पुष्टि गर्न लगाइयोस्</translation>
 <translation id="3744111561329211289">पृष्ठभूमिमा सिंक गर्ने सुविधा</translation>
 <translation id="3744286742364977428">तपाईंले डाउनलोड गर्ने फाइलहरू विश्लेषण गर्ने प्रयोजनका लागि Google Cloud मा वा तेस्रा पक्ष समक्ष पठाइन्छन्। उदाहरणका लागि, ती फाइलमा संवेदनशील डेटा वा मालवेयर छन् कि छैनन् भनी जाँच गरिन सक्छ र कम्पनीका नीतिका आधारमा ती फाइल भण्डारण गरिन सक्छ।</translation>
 <translation id="3744899669254331632">तपाईं अहिले <ph name="SITE" />को  भ्रमण गर्न सक्नुहुन्न किनकि क्रोमियमले प्रशोधन गर्न सक्दैन भन्नेवेबसाइटले अपत्यारिला प्रमाणहरू पठायो। सञ्जाल त्रुटि र आक्रमणहरू सामन्यतया: अस्थायी हुन्छन्, यसैले यो पृष्ठले पछि सायद  काम गर्ने छ।</translation>
@@ -1726,6 +1728,7 @@
 <translation id="5171045022955879922">युआरएल खोल्नुहोस् वा टाइप गर्नुहोस्</translation>
 <translation id="5172758083709347301">यन्त्र</translation>
 <translation id="5177076414499237632">यो पेजका स्रोत र विषयका बारेमा जान्नुहोस्</translation>
+<translation id="5179490652562926740">भुक्तानीको प्रमाणीकरणसम्बन्धी सेटिङ सेभ गरिएको छ</translation>
 <translation id="5179510805599951267"><ph name="ORIGINAL_LANGUAGE" /> मा छैन? यो त्रुटि रिपोर्ट गर्नुहोस्</translation>
 <translation id="518639307526414276">पाल्तु जनावरको खाना तथा हेरचाहका सामग्री</translation>
 <translation id="5190072300954988691">क्यामेरा तथा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएको छैन</translation>
diff --git a/components/strings/components_strings_sk.xtb b/components/strings/components_strings_sk.xtb
index ea0c8d75..d07764f 100644
--- a/components/strings/components_strings_sk.xtb
+++ b/components/strings/components_strings_sk.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Obnovte heslo</translation>
 <translation id="2003775180883135320">Štyri dierky hore</translation>
 <translation id="201174227998721785">Spravujte v nastaveniach Chromu povolenia a údaje uložené na rôznych weboch</translation>
+<translation id="2012276282211112603">Momentálne nie sú žiadne témy na zobrazenie</translation>
 <translation id="2019607688127825327">Tlačidlo na správu nastavení dostupnosti, stlačením klávesa Enter si prispôsobte nástroje dostupnosti v nastaveniach Chromu</translation>
 <translation id="2021333772895814435">Toto pravidlo automaticky deaktivuje synchronizáciu medzi zariadeniami pre: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 × 19 palcov</translation>
diff --git a/components/strings/components_strings_sw.xtb b/components/strings/components_strings_sw.xtb
index 1725b351..791491f7 100644
--- a/components/strings/components_strings_sw.xtb
+++ b/components/strings/components_strings_sw.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Badilisha nenosiri lako sasa</translation>
 <translation id="2003775180883135320">Toboa mara nne juu</translation>
 <translation id="201174227998721785">Dhibiti ruhusa na data iliyohifadhiwa kwenye tovuti mbalimbali katika mipangilio ya Chrome</translation>
+<translation id="2012276282211112603">Hakuna mada za kuonyesha kwa sasa</translation>
 <translation id="2019607688127825327">Kitufe cha 'Dhibiti mipangilio ya ufikivu', bonyeza 'Enter' ili uweke mapendeleo ya zana zako za ufikivu katika mipangilio ya Chrome</translation>
 <translation id="2021333772895814435">Sera hii inazima kiotomatiki usawazishaji kwenye vifaa vya: <ph name="ACTION_LIST" /></translation>
 <translation id="202224654587969958">Inchi 12 x 19</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index 1618ac2..599952ec 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -1095,6 +1095,7 @@
 <translation id="3658742229777143148">పునర్విమర్శ</translation>
 <translation id="3664782872746246217">కీవర్డ్‌లు:</translation>
 <translation id="3667704023705708645">వెంచర్ క్యాపిటల్</translation>
+<translation id="3671117652518853176">ఆఫ్ చేసినప్పుడు, సెక్యూరిటీ కారణాల దృష్ట్యా అప్పుడప్పుడూ వెరిఫై చేయమని మిమ్మల్ని అడగవచ్చు</translation>
 <translation id="3671540257457995106">సైజ్‌ మార్చడానికి అనుమతించాలా?</translation>
 <translation id="3672568546897166916"><ph name="ERROR_PATH" />‌లో ఎర్రర్ ఏర్పడింది: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">థర్డ్ రోల్</translation>
@@ -1129,6 +1130,7 @@
 <translation id="3736520371357197498">మీ భద్రతకు వాటిల్లే ఆపదల గురించి మీకు అర్థం అయ్యి ఉంటే, ప్రమాదకరమైన ప్రోగ్రామ్‌లు తీసివేయబడటానికి ముందే <ph name="BEGIN_LINK" />ఈ అసురక్షితమైన సైట్‌ను సందర్శించవచ్చు<ph name="END_LINK" />.</translation>
 <translation id="3738166223076830879">మీ బ్రౌజర్ మీ అడ్మినిస్ట్రేట‌ర్ ద్వారా మేనేజ్ చేయబడుతోంది.</translation>
 <translation id="3740319564441798148">ఎక్కువ దూరం తిరిగే బస్సు &amp; రైలు</translation>
+<translation id="3743765582345153106">ఆటోఫిల్‌ను ఉపయోగిస్తున్నప్పుడు ఎల్లప్పుడూ వెరిఫై చేయండి</translation>
 <translation id="3744111561329211289">బ్యాక్‌గ్రౌండ్ సింక్</translation>
 <translation id="3744286742364977428">మీరు డౌన్‌లోడ్ చేసిన ఫైల్స్ Google క్లౌడ్ లేదా థర్డ్ పార్టీలకు విశ్లేషణ కోసం పంపబడతాయి. ఉదాహరణకు, అవి సున్నితమైన డేటా లేదా మాల్వేర్ కోసం స్కాన్ చేయబడవచ్చు, కంపెనీ పాలసీని బట్టి స్టోర్ చేయబడవచ్చు.</translation>
 <translation id="3744899669254331632">మీరు సందర్శించాలనుకుంటున్న <ph name="SITE" /> వెబ్‌సైట్, Chromium ప్రాసెస్ చేయలేని చిందరవందరైన ఆధారాలను పంపినందున ప్రస్తుతం దాన్ని సందర్శించలేరు. నెట్‌వర్క్ ఎర్ర‌ర్‌లు మరియు దాడులు సాధారణంగా తాత్కాలికంగా మాత్రమే ఉంటాయి. కాబట్టి ఈ పేజీ బహుశా తర్వాత పని చేయవచ్చు.</translation>
@@ -1731,6 +1733,7 @@
 <translation id="5171045022955879922">URLను వెతకండి లేదా టైప్ చేయండి</translation>
 <translation id="5172758083709347301">మెషీన్</translation>
 <translation id="5177076414499237632">ఈ పేజీ సోర్స్ &amp; టాపిక్ గురించి తెలుసుకోండి</translation>
+<translation id="5179490652562926740">పేమెంట్ వెరిఫికేషన్ సెట్టింగ్‌లు సేవ్ అయ్యాయి</translation>
 <translation id="5179510805599951267"><ph name="ORIGINAL_LANGUAGE" />లో లేదా? ఈ ఎర్రర్‌ను రిపోర్ట్ చేయండి</translation>
 <translation id="518639307526414276">పెంపుడు జంతువుల ఆహారం &amp; సంరక్షణ వస్తువులు</translation>
 <translation id="5190072300954988691">కెమెరా, మైక్రోఫోన్‌కు అనుమతి లేదు</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index 64308358..269b662 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -1088,6 +1088,7 @@
 <translation id="3658742229777143148">Versiya</translation>
 <translation id="3664782872746246217">Kalit soʻzlar:</translation>
 <translation id="3667704023705708645">Venchur kapitali</translation>
+<translation id="3671117652518853176">Yoqilmasa, xavfsizlik maqsadlarida ora-orada tasdiqlash talab qilinishi mumkin</translation>
 <translation id="3671540257457995106">Oʻlchami oʻzgaraversinmi?</translation>
 <translation id="3672568546897166916">Xato: <ph name="ERROR_PATH" />: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">Uchinchi oʻram</translation>
@@ -1122,6 +1123,7 @@
 <translation id="3736520371357197498">Shaxsiy ma’lumotlaringizga havfli bo‘lishiga qaramay va zararli dasturlar hali olib tashlanmagan bo‘lsa ham bu saytga baribir o‘tishni xohlasangiz, <ph name="BEGIN_LINK" />bu yerni bosing<ph name="END_LINK" />.</translation>
 <translation id="3738166223076830879">Brauzeringiz administrator tomonidan boshqariladi.</translation>
 <translation id="3740319564441798148">Uzoq masofali avtobus va temir yoʻl</translation>
+<translation id="3743765582345153106">Avtomatik kiritishda har doim tasdiqlansin</translation>
 <translation id="3744111561329211289">Orqa fonda sinxronlash</translation>
 <translation id="3744286742364977428">Siz yuklab oladigan fayllar tekshiruv uchun Google Cloud yoki boshqa tashqi xizmatlarga yuboriladi. Masalan, tarkibida maxfiy yoki zararli axborotlar mavjudligini aniqlash uchun tekshirilishi va kompaniya siyosati asosida saqlanishi mumkin.</translation>
 <translation id="3744899669254331632"><ph name="SITE" /> saytiga o‘tib bo‘lmadi, chunki veb-sayt shifrlangan hisob ma’lumotlarini yubordi, Chromium ular bilan ishlay olmaydi. Tarmoq xatoligi yoki saytga hujumlar odatda vaqtinchalik bo‘ladi, shu sababli bu sahifa keyinroq ishga tushishi mumkin.</translation>
@@ -1724,6 +1726,7 @@
 <translation id="5171045022955879922">Qidiring yoki URL manzili kiriting</translation>
 <translation id="5172758083709347301">Mahalliy kompyuter</translation>
 <translation id="5177076414499237632">Bu sahifa manbasi va mavzusi haqida batafsil</translation>
+<translation id="5179490652562926740">Toʻlovni tasdiqlash sozlamasi saqlandi</translation>
 <translation id="5179510805599951267">Bu <ph name="ORIGINAL_LANGUAGE" /> tili emasmi? Xatolik haqida xabar yuboring</translation>
 <translation id="518639307526414276">Uy hayvonlari uchun oziq-ovqat va parvarishlash vositalari</translation>
 <translation id="5190072300954988691">Kamera va mikrofondan foydalanishga ruxsat berilmagan</translation>
diff --git a/components/strings/components_strings_vi.xtb b/components/strings/components_strings_vi.xtb
index cb76c40..fddc4d2 100644
--- a/components/strings/components_strings_vi.xtb
+++ b/components/strings/components_strings_vi.xtb
@@ -1086,7 +1086,7 @@
 <translation id="3646643500201740985">Đo lường hiệu suất quảng cáo</translation>
 <translation id="3647286794400715637">Mỗi mục nhập chuỗi url phải chứa từ 1 đến 2 URL.</translation>
 <translation id="3650584904733503804">Xác thực thành công</translation>
-<translation id="3650594806107685466">Để đảm bảo an toàn cho thẻ của bạn, hãy nhập CVC trên <ph name="SIDE_OF_CARD" /></translation>
+<translation id="3650594806107685466">Để đảm bảo an toàn cho thẻ của bạn, hãy nhập số CVC có trên <ph name="SIDE_OF_CARD" /></translation>
 <translation id="3653033846669030038">Công viên giải trí</translation>
 <translation id="3655241534245626312">Chuyển đến phần cài đặt về quyền</translation>
 <translation id="3655670868607891010">Nếu bạn thường xuyên thấy thông báo này, hãy thử các <ph name="HELP_LINK" /> sau.</translation>
diff --git a/components/strings/components_strings_zu.xtb b/components/strings/components_strings_zu.xtb
index 105acb8..f74fd1f 100644
--- a/components/strings/components_strings_zu.xtb
+++ b/components/strings/components_strings_zu.xtb
@@ -438,6 +438,7 @@
 <translation id="2003709556000175978">Setha kabusha iphasiwedi yakho manje</translation>
 <translation id="2003775180883135320">Ukushaya kane phezulu</translation>
 <translation id="201174227998721785">Phatha izimvume nedatha egcinwe kuwo wonke amasayithi we-Chrome</translation>
+<translation id="2012276282211112603">Azikho izihloko ezingaboniswa njengamanje</translation>
 <translation id="2019607688127825327">Phatha inkinobho yamasethingi wokufinyeleleka, u-Enter ukwenza amathuluzi wakho wokufinyeleleka abe ngawakho kumasethingi we-Chrome</translation>
 <translation id="2021333772895814435">Le nqubomgomo ikhubaza ngokuzenzekelayo ukuvumelanisa kuwo wonke amadivayisi: <ph name="ACTION_LIST" />.</translation>
 <translation id="202224654587969958">12 x 19 phakathi</translation>
@@ -1089,6 +1090,7 @@
 <translation id="3658742229777143148">Isibuyekezo</translation>
 <translation id="3664782872746246217">Amagama angukhiye:</translation>
 <translation id="3667704023705708645">Ikhephithali yebhizinisi</translation>
+<translation id="3671117652518853176">Uma ivaliwe, ungase ucelwe ngezikhathi ezithile ukuthi uqinisekise ngezinjongo zokuphepha</translation>
 <translation id="3671540257457995106">Vumela ukushintsha usayizi?</translation>
 <translation id="3672568546897166916">Iphutha ku-<ph name="ERROR_PATH" />: <ph name="ERROR_MESSAGE" /></translation>
 <translation id="3675563144891642599">Umqulu Wesithathu</translation>
@@ -1123,6 +1125,7 @@
 <translation id="3736520371357197498">Uma uqonda izingozi zokuvikeleka kwakho, ungase <ph name="BEGIN_LINK" />uvakashele le sayithi engaphephile<ph name="END_LINK" /> ngaphambi kokususwa kwezinhlelo eziyingozi.</translation>
 <translation id="3738166223076830879">Isiphequluli sakho siphethwe umlawuli wakho.</translation>
 <translation id="3740319564441798148">Ibhasi nesitimela yebanga elide</translation>
+<translation id="3743765582345153106">Qinisekisa njalo uma usebenzisa ukugcwalisa okuzenzakalelayo</translation>
 <translation id="3744111561329211289">Ukuvumelanisa ngemuva</translation>
 <translation id="3744286742364977428">Amafayela owadawunilodayo athunyelwa ku-Google Cloud noma kuzinkampani zangaphandle ukuze ahlaziywe. Ngokwesibonelo, zingase askenwe idatha ebucayi noma uhlelo olungayilungele ikhompyutha futhi angase agcinwe ngokusekelwe kuzinqubomgomo zenkampani.</translation>
 <translation id="3744899669254331632">Awukwazi ukuvakashela i-<ph name="SITE" /> khona manje ngoba iwebhusayithi ithumele ukuqinisekiswa okugaqagaqa i-Chromium engakwazi ukubucubungula. Amaphutha wenethiwekhi nokuhlaselwa kuvamise ukuba ngokwesikhashana, ngakho-ke leli khasi lizosebenza ngemuva kwesikhathi.</translation>
@@ -1725,6 +1728,7 @@
 <translation id="5171045022955879922">Sesha noma thayipha i-URL</translation>
 <translation id="5172758083709347301">Umshini</translation>
 <translation id="5177076414499237632">Funda mayelana nomthombo waleli khasi nesihloko</translation>
+<translation id="5179490652562926740">Amasethingi okuqinisekisa inkokhelo alondoloziwe</translation>
 <translation id="5179510805599951267">Akukho ngesi-<ph name="ORIGINAL_LANGUAGE" />? Bika leli phutha</translation>
 <translation id="518639307526414276">Ukudla kwemfuyo nokunakekelwa kwemfuyo</translation>
 <translation id="5190072300954988691">Ikhamera nemakrofoni akuvunyelwe</translation>
diff --git a/components/supervised_user/DEPS b/components/supervised_user/DEPS
index d7d373c6..153a3d2 100644
--- a/components/supervised_user/DEPS
+++ b/components/supervised_user/DEPS
@@ -13,6 +13,7 @@
   "+components/signin",
   "+components/sync",
   "+components/url_matcher",
+  "+components/user_manager",
   "+extensions/buildflags",
   "+google_apis",
   "+net",
diff --git a/components/supervised_user/core/browser/BUILD.gn b/components/supervised_user/core/browser/BUILD.gn
index 2a48ff2a..3e67f60 100644
--- a/components/supervised_user/core/browser/BUILD.gn
+++ b/components/supervised_user/core/browser/BUILD.gn
@@ -40,6 +40,8 @@
     "remote_web_approvals_manager.h",
     "supervised_user_error_page.cc",
     "supervised_user_error_page.h",
+    "supervised_user_interstitial.cc",
+    "supervised_user_interstitial.h",
     "supervised_user_metrics_service.cc",
     "supervised_user_metrics_service.h",
     "supervised_user_pref_store.cc",
@@ -82,6 +84,7 @@
     "//components/supervised_user/core/common",
     "//components/sync",
     "//components/url_matcher:url_matcher",
+    "//components/user_manager:user_manager",
     "//google_apis",
     "//net",
     "//services/network/public/cpp",
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/components/supervised_user/core/browser/supervised_user_interstitial.cc
similarity index 83%
rename from chrome/browser/supervised_user/supervised_user_interstitial.cc
rename to components/supervised_user/core/browser/supervised_user_interstitial.cc
index bbe2a1e2..607f1c3a 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.cc
+++ b/components/supervised_user/core/browser/supervised_user_interstitial.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
+#include "components/supervised_user/core/browser/supervised_user_interstitial.h"
 
 #include <stddef.h>
 
@@ -16,8 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "components/prefs/pref_service.h"
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/web_content_handler.h"
@@ -31,6 +29,7 @@
 #include "components/user_manager/user_manager.h"
 #endif
 
+namespace supervised_user {
 namespace {
 
 // TODO(b/250924204): Implement shared logic to get the user's given name.
@@ -46,10 +45,10 @@
 
 // static
 std::unique_ptr<SupervisedUserInterstitial> SupervisedUserInterstitial::Create(
-    std::unique_ptr<supervised_user::WebContentHandler> web_content_handler,
-    supervised_user::SupervisedUserService& supervised_user_service,
+    std::unique_ptr<WebContentHandler> web_content_handler,
+    SupervisedUserService& supervised_user_service,
     const GURL& url,
-    supervised_user::FilteringBehaviorReason reason) {
+    FilteringBehaviorReason reason) {
   std::unique_ptr<SupervisedUserInterstitial> interstitial = base::WrapUnique(
       new SupervisedUserInterstitial(std::move(web_content_handler),
                                      supervised_user_service, url, reason));
@@ -60,10 +59,10 @@
 }
 
 SupervisedUserInterstitial::SupervisedUserInterstitial(
-    std::unique_ptr<supervised_user::WebContentHandler> web_content_handler,
-    supervised_user::SupervisedUserService& supervised_user_service,
+    std::unique_ptr<WebContentHandler> web_content_handler,
+    SupervisedUserService& supervised_user_service,
     const GURL& url,
-    supervised_user::FilteringBehaviorReason reason)
+    FilteringBehaviorReason reason)
     : supervised_user_service_(supervised_user_service),
       web_content_handler_(std::move(web_content_handler)),
       url_(url),
@@ -72,11 +71,12 @@
 
 // static
 std::string SupervisedUserInterstitial::GetHTMLContents(
-    supervised_user::SupervisedUserService* supervised_user_service,
+    SupervisedUserService* supervised_user_service,
     PrefService* pref_service,
-    supervised_user::FilteringBehaviorReason reason,
+    FilteringBehaviorReason reason,
     bool already_sent_request,
-    bool is_main_frame) {
+    bool is_main_frame,
+    const std::string& application_locale) {
   std::string custodian = supervised_user_service->GetCustodianName();
   std::string second_custodian =
       supervised_user_service->GetSecondCustodianName();
@@ -93,11 +93,10 @@
       supervised_user_service->remote_web_approvals_manager()
           .AreApprovalRequestsEnabled();
 
-  return supervised_user::BuildErrorPageHtml(
+  return BuildErrorPageHtml(
       allow_access_requests, profile_image_url, profile_image_url2, custodian,
       custodian_email, second_custodian, second_custodian_email, reason,
-      g_browser_process->GetApplicationLocale(), already_sent_request,
-      is_main_frame);
+      application_locale, already_sent_request, is_main_frame);
 }
 
 void SupervisedUserInterstitial::GoBack() {
@@ -133,7 +132,7 @@
       supervised_user_service_->GetSecondCustodianName();
 
   std::u16string reason = l10n_util::GetStringUTF16(
-      supervised_user::GetBlockMessageID(reason_, second_custodian.empty()));
+      GetBlockMessageID(reason_, second_custodian.empty()));
   web_content_handler_->ShowFeedback(url_, reason);
   return;
 }
@@ -149,3 +148,4 @@
   UMA_HISTOGRAM_ENUMERATION(kInterstitialPermissionSourceHistogramName, source,
                             RequestPermissionSource::HISTOGRAM_BOUNDING_VALUE);
 }
+}  // namespace supervised_user
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.h b/components/supervised_user/core/browser/supervised_user_interstitial.h
similarity index 73%
rename from chrome/browser/supervised_user/supervised_user_interstitial.h
rename to components/supervised_user/core/browser/supervised_user_interstitial.h
index adb5db8..bfa6f015 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.h
+++ b/components/supervised_user/core/browser/supervised_user_interstitial.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_SUPERVISED_USER_SUPERVISED_USER_INTERSTITIAL_H_
-#define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_INTERSTITIAL_H_
+#ifndef COMPONENTS_SUPERVISED_USER_CORE_BROWSER_SUPERVISED_USER_INTERSTITIAL_H_
+#define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_SUPERVISED_USER_INTERSTITIAL_H_
 
 #include <memory>
 #include <string>
@@ -13,12 +13,11 @@
 #include "components/supervised_user/core/browser/supervised_user_error_page.h"
 #include "url/gurl.h"
 
+class PrefService;
+
 namespace supervised_user {
 class WebContentHandler;
 class SupervisedUserService;
-}
-
-class PrefService;
 
 // This class is used by SupervisedUserNavigationObserver to handle requests
 // from supervised user error page. The error page is shown when a page is
@@ -70,17 +69,18 @@
   ~SupervisedUserInterstitial();
 
   static std::unique_ptr<SupervisedUserInterstitial> Create(
-      std::unique_ptr<supervised_user::WebContentHandler> web_content_handler,
-      supervised_user::SupervisedUserService& supervised_user_service,
+      std::unique_ptr<WebContentHandler> web_content_handler,
+      SupervisedUserService& supervised_user_service,
       const GURL& url,
-      supervised_user::FilteringBehaviorReason reason);
+      FilteringBehaviorReason reason);
 
   static std::string GetHTMLContents(
-      supervised_user::SupervisedUserService* supervised_user_service,
+      SupervisedUserService* supervised_user_service,
       PrefService* pref_service,
-      supervised_user::FilteringBehaviorReason reason,
+      FilteringBehaviorReason reason,
       bool already_sent_request,
-      bool is_main_frame);
+      bool is_main_frame,
+      const std::string& application_locale);
 
   void GoBack();
   void RequestUrlAccessRemote(base::OnceCallback<void(bool)> callback);
@@ -89,26 +89,26 @@
 
   // Getter methods.
   const GURL& url() const { return url_; }
-  supervised_user::WebContentHandler* web_content_handler() {
+  WebContentHandler* web_content_handler() {
     return web_content_handler_.get();
   }
 
  private:
   SupervisedUserInterstitial(
-      std::unique_ptr<supervised_user::WebContentHandler> web_content_handler,
-      supervised_user::SupervisedUserService& supervised_user_service,
+      std::unique_ptr<WebContentHandler> web_content_handler,
+      SupervisedUserService& supervised_user_service,
       const GURL& url,
-      supervised_user::FilteringBehaviorReason reason);
+      FilteringBehaviorReason reason);
   void OutputRequestPermissionSourceMetric();
 
-  const raw_ref<supervised_user::SupervisedUserService>
-      supervised_user_service_;
+  const raw_ref<SupervisedUserService> supervised_user_service_;
 
-  std::unique_ptr<supervised_user::WebContentHandler> web_content_handler_;
+  std::unique_ptr<WebContentHandler> web_content_handler_;
 
   // The last committed url for this frame.
   GURL url_;
-  supervised_user::FilteringBehaviorReason reason_;
+  FilteringBehaviorReason reason_;
 };
+}  // namespace supervised_user
 
-#endif  // CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_INTERSTITIAL_H_
+#endif  // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_SUPERVISED_USER_INTERSTITIAL_H_
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index 4781d59..ca980a3 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -179,6 +179,7 @@
 // is enabled. If the feature is on, the new approach is used, which leans on
 // the state reported by IdentityManager. If false, the legacy approach is used,
 // which is based on preference prefs::kSyncRequested.
+// TODO(crbug.com/1219990): Remove this.
 BASE_DECLARE_FEATURE(kSyncIgnoreSyncRequestedPreference);
 #endif  // BUILDFLAG(!IS_CHROMEOS_ASH)
 
diff --git a/components/sync/driver/sync_internals_util.cc b/components/sync/driver/sync_internals_util.cc
index f37d79fc..492419b6 100644
--- a/components/sync/driver/sync_internals_util.cc
+++ b/components/sync/driver/sync_internals_util.cc
@@ -151,8 +151,6 @@
     reason_strings.push_back("Enterprise policy");
   if (disable_reasons.Has(SyncService::DISABLE_REASON_NOT_SIGNED_IN))
     reason_strings.push_back("Not signed in");
-  if (disable_reasons.Has(SyncService::DISABLE_REASON_USER_CHOICE))
-    reason_strings.push_back("User choice");
   if (disable_reasons.Has(SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR))
     reason_strings.push_back("Unrecoverable error");
   return base::JoinString(reason_strings, ", ");
diff --git a/components/sync/driver/sync_service.cc b/components/sync/driver/sync_service.cc
index c26dad70..ad732a7 100644
--- a/components/sync/driver/sync_service.cc
+++ b/components/sync/driver/sync_service.cc
@@ -35,7 +35,9 @@
 }
 
 bool SyncService::CanSyncFeatureStart() const {
-  return GetDisableReasons().Empty() && HasSyncConsent();
+  return GetDisableReasons().Empty() && HasSyncConsent() &&
+         !IsSyncFeatureDisabledViaDashboard() &&
+         IsSyncFeatureConsideredRequested();
 }
 
 bool SyncService::IsEngineInitialized() const {
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 5d64d35..c2f2f92e 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -116,10 +116,8 @@
 //   setup-in-progress handles, datatype configuration will begin.
 class SyncService : public KeyedService {
  public:
-  // The set of reasons due to which Sync can be disabled.
-  // Except for DISABLE_REASON_USER_CHOICE, these apply to both
-  // sync-the-transport and sync-the-feature.
-  // Meant to be used as a enum set.
+  // The set of reasons due to which Sync can be disabled. These apply to both
+  // sync-the-transport and sync-the-feature. Meant to be used as a enum set.
   enum DisableReason {
     // Sync is disabled by enterprise policy, either browser policy (through
     // prefs) or account policy received from the Sync server.
@@ -127,13 +125,6 @@
     DISABLE_REASON_FIRST = DISABLE_REASON_ENTERPRISE_POLICY,
     // Sync can't start because there is no authenticated user.
     DISABLE_REASON_NOT_SIGNED_IN,
-    // Sync-the-feature is suppressed by user choice. This mostly means there is
-    // no signed-in user (in which case DISABLE_REASON_NOT_SIGNED_IN will also
-    // be present), but can also happen after a "Reset Sync" operation from the
-    // dashboard.
-    // TODO(crbug.com/1429261): Remove this reason (and update the comment
-    // above), so that all the reasons affect Sync-the-transport.
-    DISABLE_REASON_USER_CHOICE,
     // Sync has encountered an unrecoverable error. It won't attempt to start
     // again until either the browser is restarted, or the user fully signs out
     // and back in again.
@@ -503,6 +494,19 @@
 
  protected:
   SyncService() = default;
+
+  // This is needed here for CanSyncFeatureStart().
+  //
+  // Returns whether SyncService should consider the user opted into enabling
+  // sync-the-feature, given two alternative ways to determine it (except on
+  // Ash where both are relevant). Historically, this was referred to as NOT
+  // having DISABLE_REASON_USER_CHOICE.
+  // TODO(crbug.com/1444344): Remove this API together with
+  // CanSyncFeatureStart().
+  // TODO(crbug.com/1219990): This API may also be removed once feature
+  // kSyncIgnoreSyncRequestedPreference is cleaned up, since HasSyncConsent()
+  // and GetDisableReasons() guarantee that this function returns true.
+  virtual bool IsSyncFeatureConsideredRequested() const = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/driver/sync_service_impl.cc b/components/sync/driver/sync_service_impl.cc
index e2dffe6..67ad70a77 100644
--- a/components/sync/driver/sync_service_impl.cc
+++ b/components/sync/driver/sync_service_impl.cc
@@ -73,6 +73,7 @@
 };
 
 void RecordSyncInitialState(SyncService::DisableReasonSet disable_reasons,
+                            bool is_sync_feature_requested,
                             bool first_setup_complete,
                             bool is_regular_profile_for_uma) {
   SyncInitialState sync_state = CAN_START;
@@ -81,7 +82,7 @@
   } else if (disable_reasons.Has(
                  SyncService::DISABLE_REASON_ENTERPRISE_POLICY)) {
     sync_state = NOT_ALLOWED_BY_POLICY;
-  } else if (disable_reasons.Has(SyncService::DISABLE_REASON_USER_CHOICE)) {
+  } else if (!is_sync_feature_requested) {
     if (first_setup_complete) {
       sync_state = NOT_REQUESTED;
     } else {
@@ -131,41 +132,6 @@
       user_agent, std::move(pending_url_loader_factory));
 }
 
-// Returns whether SyncService should consider the user opted into enabling
-// sync-the-feature, given two alternative ways to determine it (except on
-// Ash where both are relevant).
-bool IsSyncFeatureConsideredRequested(bool has_sync_consent,
-                                      const SyncPrefs& sync_prefs) {
-  CHECK(!sync_prefs.IsLocalSyncEnabled());
-
-  if (sync_prefs.IsSyncClientDisabledByPolicy()) {
-    return false;
-  }
-
-  const bool is_sync_requested = sync_prefs.IsSyncRequested();
-
-  // In most cases, the two values are identical. In this case there is no
-  // reason to evaluate the feature toggle or reconcile the two values.
-  if (has_sync_consent == is_sync_requested) {
-    return has_sync_consent;
-  }
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // On Ash, `has_sync_consent` should always be true, and what actually matters
-  // is `is_sync_requested`, which is set to false if the server reports
-  // DISABLE_SYNC_ON_CLIENT (e.g. reset via dashboard).
-  return is_sync_requested;
-#else
-  // On all platforms except Chrome Ash, `has_sync_consent` is the new way to
-  // determine whether DISABLE_REASON_USER_CHOICE should be reported. Use it
-  // if the feature toggle is enabled and otherwise fall back to the legacy
-  // `is_sync_requested`.
-  return base::FeatureList::IsEnabled(kSyncIgnoreSyncRequestedPreference)
-             ? has_sync_consent
-             : is_sync_requested;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
 base::TimeDelta GetDeferredInitDelay() {
   if (base::FeatureList::IsEnabled(kDeferredSyncStartupCustomDelay)) {
     return base::Seconds(kDeferredSyncStartupCustomDelayInSeconds.Get());
@@ -297,9 +263,12 @@
   // Note: We need to record the initial state *after* calling
   // RegisterForAuthNotifications(), because before that the authenticated
   // account isn't initialized.
-  RecordSyncInitialState(GetDisableReasons(),
-                         user_settings_->IsInitialSyncFeatureSetupComplete(),
-                         is_regular_profile_for_uma_);
+  RecordSyncInitialState(
+      GetDisableReasons(),
+      /*is_sync_feature_requested=*/
+      IsLocalSyncEnabled() || IsSyncFeatureConsideredRequested(),
+      user_settings_->IsInitialSyncFeatureSetupComplete(),
+      is_regular_profile_for_uma_);
 
   if (base::FeatureList::IsEnabled(
           kSyncAllowClearingMetadataWhenDataTypeIsStopped) &&
@@ -329,9 +298,11 @@
       !sync_prefs_.IsSyncRequestedSetExplicitly()) {
     SetSyncFeatureRequested();
   }
-  bool force_immediate = (start_behavior_ == AUTO_START &&
-                          !HasDisableReason(DISABLE_REASON_USER_CHOICE) &&
-                          !user_settings_->IsInitialSyncFeatureSetupComplete());
+
+  bool force_immediate =
+      (start_behavior_ == AUTO_START &&
+       !user_settings_->IsInitialSyncFeatureSetupComplete() &&
+       (IsLocalSyncEnabled() || IsSyncFeatureConsideredRequested()));
   if (force_immediate) {
     TryStart();
   } else if (IsEngineAllowedToRun()) {
@@ -444,10 +415,7 @@
 }
 
 bool SyncServiceImpl::IsEngineAllowedToRun() const {
-  // USER_CHOICE does not prevent starting up the Sync transport.
-  DisableReasonSet disable_reasons = GetDisableReasons();
-  disable_reasons.Remove(DISABLE_REASON_USER_CHOICE);
-  return disable_reasons.Empty() && !auth_manager_->IsSyncPaused();
+  return GetDisableReasons().Empty() && !auth_manager_->IsSyncPaused();
 }
 
 void SyncServiceImpl::OnProtocolEvent(const ProtocolEvent& event) {
@@ -729,9 +697,6 @@
     if (!IsSignedIn()) {
       result.Put(DISABLE_REASON_NOT_SIGNED_IN);
     }
-    if (!IsSyncFeatureConsideredRequested(HasSyncConsent(), sync_prefs_)) {
-      result.Put(DISABLE_REASON_USER_CHOICE);
-    }
   }
 
   if (unrecoverable_error_reason_) {
@@ -1225,8 +1190,7 @@
   // TODO(crbug.com/1443446): A simpler and more robust implementation for this
   // state would be to use a dedicated pref.
   return user_settings_->IsInitialSyncFeatureSetupComplete() &&
-         !IsLocalSyncEnabled() &&
-         !IsSyncFeatureConsideredRequested(HasSyncConsent(), sync_prefs_);
+         !IsLocalSyncEnabled() && !IsSyncFeatureConsideredRequested();
 }
 
 bool SyncServiceImpl::CanConfigureDataTypes(
@@ -1297,6 +1261,38 @@
   return sync_client_.get();
 }
 
+bool SyncServiceImpl::IsSyncFeatureConsideredRequested() const {
+  CHECK(!IsLocalSyncEnabled());
+
+  if (sync_prefs_.IsSyncClientDisabledByPolicy()) {
+    return false;
+  }
+
+  const bool has_sync_consent = HasSyncConsent();
+  const bool is_sync_requested = sync_prefs_.IsSyncRequested();
+
+  // In most cases, the two values are identical. In this case there is no
+  // reason to evaluate the feature toggle or reconcile the two values.
+  if (has_sync_consent == is_sync_requested) {
+    return has_sync_consent;
+  }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On Ash, `has_sync_consent` should always be true, and what actually matters
+  // is `is_sync_requested`, which is set to false if the server reports
+  // DISABLE_SYNC_ON_CLIENT (e.g. reset via dashboard).
+  return is_sync_requested;
+#else
+  // On all platforms except Chrome Ash, `has_sync_consent` is the new way to
+  // determine whether sync-the-feature is considered requested, if the feature
+  // toggle is enabled and otherwise fall back to the legacy
+  // `is_sync_requested`.
+  return base::FeatureList::IsEnabled(kSyncIgnoreSyncRequestedPreference)
+             ? has_sync_consent
+             : is_sync_requested;
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
 void SyncServiceImpl::AddObserver(SyncServiceObserver* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observers_->AddObserver(observer);
diff --git a/components/sync/driver/sync_service_impl.h b/components/sync/driver/sync_service_impl.h
index 635f0e0..5f1f01c 100644
--- a/components/sync/driver/sync_service_impl.h
+++ b/components/sync/driver/sync_service_impl.h
@@ -240,6 +240,9 @@
 
   SyncClient* GetSyncClientForTest();
 
+ protected:
+  bool IsSyncFeatureConsideredRequested() const override;
+
  private:
   enum UnrecoverableErrorReason {
     ERROR_REASON_ENGINE_INIT_FAILURE,
diff --git a/components/sync/driver/sync_service_impl_startup_unittest.cc b/components/sync/driver/sync_service_impl_startup_unittest.cc
index d379c6e..78524d8 100644
--- a/components/sync/driver/sync_service_impl_startup_unittest.cc
+++ b/components/sync/driver/sync_service_impl_startup_unittest.cc
@@ -176,10 +176,9 @@
   // Should not actually start, rather just clean things up and wait
   // to be enabled.
   sync_service()->Initialize();
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      sync_service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            sync_service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             sync_service()->GetTransportState());
   EXPECT_EQ(nullptr, data_type_manager());
@@ -499,11 +498,9 @@
   CreateSyncService(SyncServiceImpl::MANUAL_START);
 
   sync_service()->Initialize();
-  // Sync was disabled due to the policy, setting SyncRequested to false and
-  // causing DISABLE_REASON_USER_CHOICE.
+  // Sync was disabled due to the policy.
   EXPECT_EQ(SyncService::DisableReasonSet(
-                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY,
-                 SyncService::DISABLE_REASON_USER_CHOICE}),
+                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY}),
             sync_service()->GetDisableReasons());
   // Service should not be started by Initialize() since it's managed.
   EXPECT_EQ(nullptr, data_type_manager());
@@ -534,7 +531,15 @@
   sync_prefs()->SetSyncRequested(true);
   sync_prefs()->SetFirstSetupComplete();
   SimulateTestUserSigninAndEnableSyncFeature();
+
+  // To make this test more realistic, the StartBehavior is chosen depending on
+  // the platform, which influences the behavior for
+  // IsSyncFeatureDisabledViaDashboard().
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  CreateSyncService(SyncServiceImpl::AUTO_START);
+#else
   CreateSyncService(SyncServiceImpl::MANUAL_START);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Initialize() and wait for deferred startup.
   sync_service()->Initialize();
@@ -552,11 +557,9 @@
   pref_service()->SetBoolean(prefs::internal::kSyncManaged, true);
   // Give re-startup a chance to happen (it shouldn't!).
   base::RunLoop().RunUntilIdle();
-  // Sync was disabled due to the policy, setting SyncRequested to false and
-  // causing DISABLE_REASON_USER_CHOICE.
+  // Sync was disabled due to the policy.
   ASSERT_EQ(SyncService::DisableReasonSet(
-                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY,
-                 SyncService::DISABLE_REASON_USER_CHOICE}),
+                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY}),
             sync_service()->GetDisableReasons());
   EXPECT_FALSE(sync_service()->IsEngineInitialized());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
@@ -574,28 +577,22 @@
   EXPECT_TRUE(sync_service()->IsEngineInitialized());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             sync_service()->GetTransportState());
+  EXPECT_EQ(SyncService::DisableReasonSet(),
+            sync_service()->GetDisableReasons());
 
-  // On ChromeOS Ash, DISABLE_REASON_USER_CHOICE stays even after the policy is
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  EXPECT_TRUE(
+      sync_service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete());
+  // On ChromeOS Ash, sync-the-feature stays disabled even after the policy is
   // removed, for historic reasons. It is unclear if this behavior is optional,
   // because it is indistinguishable from the sync-reset-via-dashboard case.
   // It can be resolved by invoking SetSyncFeatureRequested().
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_USER_CHOICE}),
-      sync_service()->GetDisableReasons());
+  EXPECT_TRUE(sync_service()->IsSyncFeatureDisabledViaDashboard());
 #else
-  if (GetParam()) {
-    EXPECT_EQ(SyncService::DisableReasonSet(),
-              sync_service()->GetDisableReasons());
-  } else {
-    EXPECT_EQ(SyncService::DisableReasonSet(
-                  {SyncService::DISABLE_REASON_USER_CHOICE}),
-              sync_service()->GetDisableReasons());
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
   EXPECT_FALSE(
       sync_service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete());
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
   EXPECT_FALSE(sync_service()->IsSyncFeatureEnabled());
   EXPECT_FALSE(sync_service()->IsSyncFeatureActive());
 }
@@ -641,10 +638,9 @@
 
   // There is no signed-in user, so also nobody has decided that Sync should be
   // started.
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      sync_service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            sync_service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             sync_service()->GetTransportState());
 
@@ -654,9 +650,7 @@
   component_factory()->AllowFakeEngineInitCompletion(false);
   SimulateTestUserSigninWithoutSyncFeature();
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_USER_CHOICE}),
-      sync_service()->GetDisableReasons());
+  EXPECT_TRUE(sync_service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::INITIALIZING,
             sync_service()->GetTransportState());
   EXPECT_FALSE(sync_service()->IsSyncFeatureEnabled());
diff --git a/components/sync/driver/sync_service_impl_unittest.cc b/components/sync/driver/sync_service_impl_unittest.cc
index b2d7e67..49b216d9 100644
--- a/components/sync/driver/sync_service_impl_unittest.cc
+++ b/components/sync/driver/sync_service_impl_unittest.cc
@@ -261,7 +261,7 @@
   SignIn();
   CreateService(SyncServiceImpl::MANUAL_START);
   InitializeForNthSync();
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 }
@@ -269,7 +269,7 @@
 TEST_F(SyncServiceImplTest, SuccessfulLocalBackendInitialization) {
   CreateServiceWithLocalSyncBackend();
   InitializeForNthSync();
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 }
@@ -289,7 +289,7 @@
       /*selected_types=*/UserSelectableTypeSet::All());
   service()->Initialize();
 
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
 
   // Sync should immediately start up in transport mode.
   base::RunLoop().RunUntilIdle();
@@ -343,11 +343,9 @@
   SignIn();
   CreateService(SyncServiceImpl::MANUAL_START);
   InitializeForNthSync();
-  // Sync was disabled due to the policy, setting SyncRequested to false and
-  // causing DISABLE_REASON_USER_CHOICE.
+  // Sync was disabled due to the policy.
   EXPECT_EQ(SyncService::DisableReasonSet(
-                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY,
-                 SyncService::DISABLE_REASON_USER_CHOICE}),
+                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY}),
             service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
@@ -384,11 +382,9 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   InitializeForNthSync();
-  // Sync was disabled due to the policy, setting SyncRequested to false and
-  // causing DISABLE_REASON_USER_CHOICE.
+  // Sync was disabled due to the policy.
   EXPECT_EQ(SyncService::DisableReasonSet(
-                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY,
-                 SyncService::DISABLE_REASON_USER_CHOICE}),
+                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY}),
             service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
@@ -403,6 +399,7 @@
             service()->GetTransportState());
   EXPECT_FALSE(service()->IsSyncFeatureEnabled());
   EXPECT_FALSE(service()->IsSyncFeatureActive());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS Ash, the first setup is marked as complete automatically, due
@@ -410,13 +407,11 @@
   ASSERT_TRUE(
       service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete());
 
-  // On ChromeOS Ash, DISABLE_REASON_USER_CHOICE stays even after the policy is
-  // removed, for historic reasons. It is unclear if this behavior is optimal,
+  // On ChromeOS Ash, sync-the-feature stays disabled even after the policy is
+  // removed, for historic reasons. It is unclear if this behavior is optional,
   // because it is indistinguishable from the sync-reset-via-dashboard case.
   // It can be resolved by invoking SetSyncFeatureRequested().
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_TRUE(service()->IsSyncFeatureDisabledViaDashboard());
   service()->SetSyncFeatureRequested();
 
 #else
@@ -455,11 +450,9 @@
 
   prefs()->SetManagedPref(prefs::internal::kSyncManaged, base::Value(true));
 
-  // Sync was disabled due to the policy, setting SyncRequested to false and
-  // causing DISABLE_REASON_USER_CHOICE.
+  // Sync was disabled due to the policy.
   EXPECT_EQ(SyncService::DisableReasonSet(
-                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY,
-                 SyncService::DISABLE_REASON_USER_CHOICE}),
+                {SyncService::DISABLE_REASON_ENTERPRISE_POLICY}),
             service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
@@ -503,10 +496,9 @@
   // Wait for SyncServiceImpl to be notified.
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
   EXPECT_FALSE(service()->IsSyncFeatureActive());
@@ -535,11 +527,9 @@
       signin_metrics::SignoutDelete::kIgnoreMetric);
   // Wait for SyncServiceImpl to be notified.
   base::RunLoop().RunUntilIdle();
-  // SyncRequested was set to false, causing DISABLE_REASON_USER_CHOICE.
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
 }
@@ -567,10 +557,9 @@
   // These are specific to sync-the-feature and should be cleared.
   EXPECT_FALSE(
       service()->GetUserSettings()->IsInitialSyncFeatureSetupComplete());
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            service()->GetDisableReasons());
   EXPECT_EQ(1, component_factory()->clear_transport_data_call_count());
 #if BUILDFLAG(IS_IOS)
   SyncPrefs sync_prefs(prefs());
@@ -614,18 +603,6 @@
   EXPECT_FALSE(sync_prefs.IsOptedInForBookmarksAndReadingListAccountStorage());
 #endif  // BUILDFLAG(IS_IOS)
 }
-
-TEST_F(SyncServiceImplTest, DisableReasonUserChoiceIfStartsSignedOut) {
-  // Set up bad state.
-  SyncPrefs sync_prefs(prefs());
-  sync_prefs.SetSyncRequested(true);
-
-  CreateService(SyncServiceImpl::MANUAL_START);
-  service()->Initialize();
-
-  EXPECT_TRUE(
-      service()->HasDisableReason(SyncService::DISABLE_REASON_USER_CHOICE));
-}
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(SyncServiceImplTest, GetSyncTokenStatus) {
@@ -1033,9 +1010,7 @@
   // Ash does not support signout.
   EXPECT_TRUE(
       identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync));
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   // Since ChromeOS doesn't support signout and so the account is still there
   // and available, Sync will restart in standalone transport mode.
   base::RunLoop().RunUntilIdle();
@@ -1049,10 +1024,9 @@
   EXPECT_FALSE(
       identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin));
 #endif
-  EXPECT_EQ(
-      SyncService::DisableReasonSet({SyncService::DISABLE_REASON_NOT_SIGNED_IN,
-                                     SyncService::DISABLE_REASON_USER_CHOICE}),
-      service()->GetDisableReasons());
+  EXPECT_EQ(SyncService::DisableReasonSet(
+                {SyncService::DISABLE_REASON_NOT_SIGNED_IN}),
+            service()->GetDisableReasons());
   EXPECT_EQ(SyncService::TransportState::DISABLED,
             service()->GetTransportState());
   EXPECT_TRUE(service()->GetLastSyncedTimeForDebugging().is_null());
@@ -1131,21 +1105,21 @@
   prefs()->SetManagedPref(prefs::internal::kSyncManaged, base::Value(false));
   CreateServiceWithLocalSyncBackend();
   InitializeForNthSync();
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 
   // The transport should continue active even if kSyncManaged becomes true.
   prefs()->SetManagedPref(prefs::internal::kSyncManaged, base::Value(true));
 
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 
   // Setting kSyncManaged back to false should also make no difference.
   prefs()->SetManagedPref(prefs::internal::kSyncManaged, base::Value(false));
 
-  EXPECT_EQ(SyncService::DisableReasonSet(), service()->GetDisableReasons());
+  EXPECT_TRUE(service()->GetDisableReasons().Empty());
   EXPECT_EQ(SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
 }
diff --git a/components/sync/driver/sync_service_utils.cc b/components/sync/driver/sync_service_utils.cc
index f714708..c026b6ba 100644
--- a/components/sync/driver/sync_service_utils.cc
+++ b/components/sync/driver/sync_service_utils.cc
@@ -19,7 +19,7 @@
   // "everything" (i.e. the default setting). If a data type is missing there,
   // it must be because the user explicitly disabled it.
   if (!sync_service || sync_service->IsLocalSyncEnabled() ||
-      !sync_service->CanSyncFeatureStart() ||
+      !sync_service->IsSyncFeatureEnabled() ||
       !sync_service->GetPreferredDataTypes().Has(type)) {
     return UploadState::NOT_ACTIVE;
   }
diff --git a/components/sync/driver/sync_service_utils_unittest.cc b/components/sync/driver/sync_service_utils_unittest.cc
index 9e009e1..cdef7bc 100644
--- a/components/sync/driver/sync_service_utils_unittest.cc
+++ b/components/sync/driver/sync_service_utils_unittest.cc
@@ -192,7 +192,7 @@
             GetUploadToGoogleState(&service, syncer::DEVICE_INFO));
 }
 
-TEST(SyncServiceUtilsTest, UploadToGoogleDisabledForSecondaryAccount) {
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledInTransportMode) {
   TestSyncService service;
   service.SetDisableReasons(SyncService::DisableReasonSet());
   service.GetUserSettings()->SetSelectedTypes(
@@ -217,4 +217,25 @@
             GetUploadToGoogleState(&service, syncer::BOOKMARKS));
 }
 
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfInitialSetupIncomplete) {
+  TestSyncService service;
+  service.SetDisableReasons(SyncService::DisableReasonSet());
+  service.GetUserSettings()->SetSelectedTypes(
+      /*sync_everything=*/true,
+      /*types=*/UserSelectableTypeSet::All());
+  service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
+  service.SetNonEmptyLastCycleSnapshot();
+
+  // Sanity check: Everything's looking good, so upload is considered active.
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Clear the first-setup-complete bit.
+  service.GetUserSettings()->ClearFirstSetupComplete();
+
+  // This should make the upload state NOT active.
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
 }  // namespace syncer
diff --git a/components/sync/driver/sync_session_durations_metrics_recorder_unittest.cc b/components/sync/driver/sync_session_durations_metrics_recorder_unittest.cc
index aab61ec..daa8898 100644
--- a/components/sync/driver/sync_session_durations_metrics_recorder_unittest.cc
+++ b/components/sync/driver/sync_session_durations_metrics_recorder_unittest.cc
@@ -159,16 +159,16 @@
 }
 
 TEST_F(SyncSessionDurationsMetricsRecorderTest,
-       OptedInToSync_SyncDisabledByUser) {
+       OptedInToSync_SyncDisabledByEnterprisePolicy) {
   EnableSync();
-  sync_service_.SetDisableReasons({SyncService::DISABLE_REASON_USER_CHOICE});
+  sync_service_.SetDisableReasons(
+      {SyncService::DISABLE_REASON_ENTERPRISE_POLICY});
 
   base::HistogramTester ht;
   StartAndEndSession(kSessionTime);
 
-  // If the user opted in to sync, but then disabled sync (e.g. via policy or
-  // from the Android OS settings), then they are counted as having opted out
-  // of sync.
+  // If the user opted in to sync, but then disabled sync via enterprise policy,
+  // then they are counted as having opted out of sync.
   ExpectOneSessionWithDuration(ht, {"NotOptedInToSyncWithAccount"},
                                kSessionTime);
   ExpectNoSession(
@@ -195,7 +195,7 @@
        SyncDisabled_PrimaryAccountInAuthError) {
   EnableSync();
   SetInvalidCredentialsAuthError();
-  sync_service_.SetDisableReasons({SyncService::DISABLE_REASON_USER_CHOICE});
+  sync_service_.SetHasSyncConsent(false);
 
   base::HistogramTester ht;
   StartAndEndSession(kSessionTime);
diff --git a/components/sync/engine/get_updates_processor.cc b/components/sync/engine/get_updates_processor.cc
index 5b513b0a..6febc99 100644
--- a/components/sync/engine/get_updates_processor.cc
+++ b/components/sync/engine/get_updates_processor.cc
@@ -162,6 +162,10 @@
   // (e.g. Bookmark URLs but not their containing folders).
   get_updates->set_fetch_folders(true);
 
+  // This is a deprecated field that should be cleaned up after server's
+  // behavior is updated.
+  get_updates->set_create_mobile_bookmarks_folder(true);
+
   bool need_encryption_key = ShouldRequestEncryptionKey(cycle->context());
   get_updates->set_need_encryption_key(need_encryption_key);
 
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index 96ea1d1..225a45c 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -642,6 +642,7 @@
   VISIT_REP(from_progress_marker);
   VISIT(streaming);
   VISIT(need_encryption_key);
+  VISIT(create_mobile_bookmarks_folder);
   VISIT_ENUM(get_updates_origin);
   VISIT(is_retry);
   VISIT_REP(client_contexts);
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto
index e093ec5..86d8b92 100644
--- a/components/sync/protocol/sync.proto
+++ b/components/sync/protocol/sync.proto
@@ -186,6 +186,11 @@
   // other datatypes, so repeated usage will likely result in throttling.
   optional bool need_encryption_key = 8 [default = false];
 
+  // Whether to create the mobile bookmarks folder if it's not
+  // already created.  Set to true by all modern clients.
+  optional bool create_mobile_bookmarks_folder = 1000
+      [default = false, deprecated = true];
+
   // This value is an updated version of the GetUpdatesCallerInfo's
   // GetUpdatesSource.  It describes the reason for the GetUpdate request.
   // Introduced in M29.
@@ -204,8 +209,6 @@
   reserved "requested_types";
   reserved 5;
   reserved "batch_size";
-  reserved 1000;
-  reserved "create_mobile_bookmarks_folder";
 }
 
 // Message from a client asking the server to clear its data. This causes the
diff --git a/components/sync/test/fake_sync_service.cc b/components/sync/test/fake_sync_service.cc
index e4fa55cb2..a2a1933 100644
--- a/components/sync/test/fake_sync_service.cc
+++ b/components/sync/test/fake_sync_service.cc
@@ -173,6 +173,10 @@
     int method_type_hint,
     base::OnceClosure callback) {}
 
+bool FakeSyncService::IsSyncFeatureConsideredRequested() const {
+  return HasSyncConsent();
+}
+
 void FakeSyncService::Shutdown() {}
 
 }  // namespace syncer
diff --git a/components/sync/test/fake_sync_service.h b/components/sync/test/fake_sync_service.h
index cc43703..3779fc8 100644
--- a/components/sync/test/fake_sync_service.h
+++ b/components/sync/test/fake_sync_service.h
@@ -80,6 +80,9 @@
   // KeyedService implementation.
   void Shutdown() override;
 
+ protected:
+  bool IsSyncFeatureConsideredRequested() const override;
+
  private:
   GURL sync_service_url_;
 };
diff --git a/components/sync/test/mock_sync_service.cc b/components/sync/test/mock_sync_service.cc
index 4c8ce530..0652841 100644
--- a/components/sync/test/mock_sync_service.cc
+++ b/components/sync/test/mock_sync_service.cc
@@ -6,7 +6,12 @@
 
 namespace syncer {
 
-MockSyncService::MockSyncService() = default;
+MockSyncService::MockSyncService() {
+  // A sensible default is to return true, because in most cases it is used in
+  // combination with HasSyncConsent(), which defaults to false.
+  ON_CALL(*this, IsSyncFeatureConsideredRequested)
+      .WillByDefault(testing::Return(true));
+}
 
 MockSyncService::~MockSyncService() = default;
 
diff --git a/components/sync/test/mock_sync_service.h b/components/sync/test/mock_sync_service.h
index 1c5dc60a..e575aebd 100644
--- a/components/sync/test/mock_sync_service.h
+++ b/components/sync/test/mock_sync_service.h
@@ -137,6 +137,7 @@
               GetAllNodesForDebugging,
               (base::OnceCallback<void(base::Value::List)> callback),
               (override));
+  MOCK_METHOD(bool, IsSyncFeatureConsideredRequested, (), (const override));
 
   // KeyedService implementation.
   MOCK_METHOD(void, Shutdown, (), (override));
diff --git a/components/sync/test/test_sync_service.cc b/components/sync/test/test_sync_service.cc
index d73c21b5..926606f 100644
--- a/components/sync/test/test_sync_service.cc
+++ b/components/sync/test/test_sync_service.cc
@@ -142,7 +142,6 @@
 }
 
 void TestSyncService::SetSyncFeatureRequested() {
-  disable_reasons_.Remove(SyncService::DISABLE_REASON_USER_CHOICE);
   sync_feature_disabled_via_dashboard_ = false;
 }
 
@@ -313,6 +312,10 @@
     int method_type_hint,
     base::OnceClosure callback) {}
 
+bool TestSyncService::IsSyncFeatureConsideredRequested() const {
+  return HasSyncConsent();
+}
+
 void TestSyncService::Shutdown() {
   for (SyncServiceObserver& observer : observers_)
     observer.OnSyncShutdown(this);
diff --git a/components/sync/test/test_sync_service.h b/components/sync/test/test_sync_service.h
index a0f51115..76b7ad8 100644
--- a/components/sync/test/test_sync_service.h
+++ b/components/sync/test/test_sync_service.h
@@ -123,6 +123,9 @@
   // KeyedService implementation.
   void Shutdown() override;
 
+ protected:
+  bool IsSyncFeatureConsideredRequested() const override;
+
  private:
   TestSyncUserSettings user_settings_;
 
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index ab84151..cf9d32dd 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -51,7 +51,7 @@
 
 class ScopedRemoteUpdateBookmarks {
  public:
-  // |bookmark_model|, |bookmark_undo_service| and |observer| must not be null
+  // `bookmark_model`, `bookmark_undo_service` and `observer` must not be null
   // and must outlive this object.
   ScopedRemoteUpdateBookmarks(bookmarks::BookmarkModel* bookmark_model,
                               BookmarkUndoService* bookmark_undo_service,
@@ -123,8 +123,11 @@
 }  // namespace
 
 BookmarkModelTypeProcessor::BookmarkModelTypeProcessor(
-    BookmarkUndoService* bookmark_undo_service)
+    BookmarkUndoService* bookmark_undo_service,
+    bool wipe_model_on_stopping_sync_with_clear_data)
     : bookmark_undo_service_(bookmark_undo_service),
+      wipe_model_on_stopping_sync_with_clear_data_(
+          wipe_model_on_stopping_sync_with_clear_data),
       max_bookmarks_till_sync_enabled_(kDefaultMaxBookmarksTillSyncEnabled) {}
 
 BookmarkModelTypeProcessor::~BookmarkModelTypeProcessor() {
@@ -141,7 +144,7 @@
 
   worker_ = std::move(worker);
 
-  // |bookmark_tracker_| is instantiated only after initial sync is done.
+  // `bookmark_tracker_` is instantiated only after initial sync is done.
   if (bookmark_tracker_) {
     NudgeForCommitIfNeeded();
   }
@@ -164,7 +167,7 @@
     GetLocalChangesCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Processor should never connect if
-  // |last_initial_merge_remote_updates_exceeded_limit_| is set.
+  // `last_initial_merge_remote_updates_exceeded_limit_` is set.
   DCHECK(!last_initial_merge_remote_updates_exceeded_limit_);
   BookmarkLocalChangesBuilder builder(bookmark_tracker_.get(), bookmark_model_);
   std::move(callback).Run(builder.BuildCommitRequests(max_entries));
@@ -176,7 +179,7 @@
     const syncer::FailedCommitResponseDataList& error_response_list) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // |error_response_list| is ignored, because all errors are treated as
+  // `error_response_list` is ignored, because all errors are treated as
   // transient and the processor with eventually retry.
   for (const syncer::CommitResponseData& response : committed_response_list) {
     const SyncedBookmarkTrackerEntity* entity =
@@ -205,10 +208,10 @@
   DCHECK(syncer::IsInitialSyncDone(model_type_state.initial_sync_state()));
   DCHECK(start_callback_.is_null());
   // Processor should never connect if
-  // |last_initial_merge_remote_updates_exceeded_limit_| is set.
+  // `last_initial_merge_remote_updates_exceeded_limit_` is set.
   DCHECK(!last_initial_merge_remote_updates_exceeded_limit_);
 
-  // TODO(crbug.com/1356900): validate incoming updates, e.g. |gc_directive|
+  // TODO(crbug.com/1356900): validate incoming updates, e.g. `gc_directive`
   // must be empty for Bookmarks.
 
   syncer::LogUpdatesReceivedByProcessorHistogram(
@@ -285,7 +288,7 @@
 std::string BookmarkModelTypeProcessor::EncodeSyncMetadata() const {
   std::string metadata_str;
   if (bookmark_tracker_) {
-    // |last_initial_merge_remote_updates_exceeded_limit_| is only set in error
+    // `last_initial_merge_remote_updates_exceeded_limit_` is only set in error
     // cases where the tracker would not be initialized.
     DCHECK(!last_initial_merge_remote_updates_exceeded_limit_);
 
@@ -343,7 +346,7 @@
                  syncer::kSyncEnforceBookmarksCountLimit)) {
     // Report error if remote updates fetched last time during initial merge
     // exceeded limit. Note that here we are only setting
-    // |last_initial_merge_remote_updates_exceeded_limit_|, the actual error
+    // `last_initial_merge_remote_updates_exceeded_limit_`, the actual error
     // would be reported in ConnectIfReady().
     last_initial_merge_remote_updates_exceeded_limit_ = true;
   } else {
@@ -354,8 +357,8 @@
     if (bookmark_tracker_) {
       StartTrackingMetadata();
     } else if (!metadata_str.empty()) {
-      // Even if the field |last_initial_merge_remote_updates_exceeded_limit| is
-      // set and the feature toggle |kSyncEnforceBookmarksCountLimit| not
+      // Even if the field `last_initial_merge_remote_updates_exceeded_limit` is
+      // set and the feature toggle `kSyncEnforceBookmarksCountLimit` not
       // enabled, making the metadata_str non-empty, scheduling a save shouldn't
       // cause any problem.
       DLOG(WARNING)
@@ -398,7 +401,7 @@
     StartCallback start_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(start_callback);
-  // |favicon_service_| should have been set by now.
+  // `favicon_service_` should have been set by now.
   DCHECK(favicon_service_);
   DVLOG(1) << "Sync is starting for Bookmarks";
 
@@ -428,7 +431,7 @@
   // Report error if remote updates fetched last time during initial merge
   // exceeded limit.
   if (last_initial_merge_remote_updates_exceeded_limit_) {
-    // |last_initial_merge_remote_updates_exceeded_limit_| is only set in error
+    // `last_initial_merge_remote_updates_exceeded_limit_` is only set in error
     // case and thus tracker should be empty.
     DCHECK(!bookmark_tracker_);
     start_callback_.Reset();
@@ -510,6 +513,14 @@
         StopTrackingMetadataAndResetTracker();
       }
       last_initial_merge_remote_updates_exceeded_limit_ = false;
+      if (wipe_model_on_stopping_sync_with_clear_data_) {
+        // `CLEAR_METADATA` indicates sync is permanently disabled. Since
+        // `wipe_model_on_stopping_sync_with_clear_data_` is `true`, the
+        // lifetime of local data (bookmarks) is coupled with sync metadata's,
+        // which means disabling sync requires that bookmarks in local storage
+        // are deleted.
+        bookmark_model_->RemoveAllUserBookmarks();
+      }
       schedule_save_closure_.Run();
       break;
     }
@@ -524,7 +535,7 @@
   DCHECK(bookmark_tracker_);
 
   // Issue error and stop sync if the number of local bookmarks exceed limit.
-  // If |error_handler_| is not set, the check is ignored because this gets
+  // If `error_handler_` is not set, the check is ignored because this gets
   // re-evaluated in ConnectIfReady().
   if (error_handler_ &&
       bookmark_tracker_->TrackedBookmarksCount() >
@@ -564,7 +575,7 @@
 
   TRACE_EVENT0("sync", "BookmarkModelTypeProcessor::OnInitialUpdateReceived");
 
-  // |updates| can contain an additional root folder. The server may or may not
+  // `updates` can contain an additional root folder. The server may or may not
   // deliver a root node - it is not guaranteed, but this works as an
   // approximated safeguard.
   const size_t max_initial_updates_count = max_bookmarks_till_sync_enabled_ + 1;
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.h b/components/sync_bookmarks/bookmark_model_type_processor.h
index 1416e08..d14469f0 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -35,9 +35,12 @@
 class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor,
                                    public syncer::ModelTypeControllerDelegate {
  public:
-  // |bookmark_undo_service| must not be nullptr and must outlive this object.
-  explicit BookmarkModelTypeProcessor(
-      BookmarkUndoService* bookmark_undo_service);
+  // `bookmark_undo_service` must not be nullptr and must outlive this object.
+  // If `wipe_model_on_stopping_sync_with_clear_data` is `true`, then calling
+  // `OnSyncStopping` with `CLEAR_METADATA` will trigger the removal of all user
+  // bookmarks from the corresponding `BookmarkModel`.
+  BookmarkModelTypeProcessor(BookmarkUndoService* bookmark_undo_service,
+                             bool wipe_model_on_stopping_sync_with_clear_data);
 
   BookmarkModelTypeProcessor(const BookmarkModelTypeProcessor&) = delete;
   BookmarkModelTypeProcessor& operator=(const BookmarkModelTypeProcessor&) =
@@ -78,10 +81,10 @@
   std::string EncodeSyncMetadata() const;
 
   // It mainly decodes a BookmarkModelMetadata proto serialized in
-  // |metadata_str|, and uses it to fill in the tracker and the model type state
-  // objects. |model| must not be null and must outlive this object. It is used
+  // `metadata_str`, and uses it to fill in the tracker and the model type state
+  // objects. `model` must not be null and must outlive this object. It is used
   // to the retrieve the local node ids, and is stored in the processor to be
-  // used for further model operations. |schedule_save_closure| is a repeating
+  // used for further model operations. `schedule_save_closure` is a repeating
   // closure used to schedule a save of the bookmark model together with the
   // metadata.
   void ModelReadyToSync(const std::string& metadata_str,
@@ -90,7 +93,7 @@
 
   // Sets the favicon service used when processing remote updates. It must be
   // called before the processor is ready to receive remote updates, and hence
-  // before OnSyncStarting() is called. |favicon_service| must not be null.
+  // before OnSyncStarting() is called. `favicon_service` must not be null.
   void SetFaviconService(favicon::FaviconService* favicon_service);
 
   // Returns the estimate of dynamically allocated memory in bytes.
@@ -136,9 +139,9 @@
   void StopTrackingMetadataAndResetTracker();
 
   // Creates a DictionaryValue for local and remote debugging information about
-  // |node| and appends it to |all_nodes|. It does the same for child nodes
-  // recursively. |index| is the index of |node| within its parent. |index|
-  // could computed from |node|, however it's much cheaper to pass from outside
+  // `node` and appends it to `all_nodes`. It does the same for child nodes
+  // recursively. `index` is the index of `node` within its parent. `index`
+  // could computed from `node`, however it's much cheaper to pass from outside
   // since we iterate over child nodes already in the calling sites.
   void AppendNodeAndChildrenForDebugging(const bookmarks::BookmarkNode* node,
                                          int index,
@@ -163,6 +166,11 @@
   // Used to suspend bookmark undo when processing remote changes.
   const raw_ptr<BookmarkUndoService, DanglingUntriaged> bookmark_undo_service_;
 
+  // Controls whether bookmarks should be wiped when sync is stopped. Contains
+  // `true` for Account `BookmarkModel` and `false` for LocalOrSyncable
+  // `BookmarkModel`.
+  const bool wipe_model_on_stopping_sync_with_clear_data_;
+
   // The callback used to schedule the persistence of bookmark model as well as
   // the metadata to a file during which latest metadata should also be pulled
   // via EncodeSyncMetadata. Processor should invoke it upon changes in the
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index c6e3532..f8950df 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -50,6 +50,7 @@
 using testing::IsNull;
 using testing::NiceMock;
 using testing::NotNull;
+using testing::Pointer;
 using testing::UnorderedElementsAre;
 
 const char kBookmarkBarTag[] = "bookmark_bar";
@@ -244,7 +245,8 @@
  public:
   BookmarkModelTypeProcessorTest()
       : processor_(std::make_unique<BookmarkModelTypeProcessor>(
-            &bookmark_undo_service_)),
+            &bookmark_undo_service_,
+            /*wipe_model_on_stopping_sync_with_clear_data=*/false)),
         bookmark_model_(bookmarks::TestBookmarkClient::CreateModel()) {
     processor_->SetFaviconService(&favicon_service_);
   }
@@ -306,9 +308,10 @@
   }
 
   // Simulate browser restart.
-  void ResetModelTypeProcessor() {
-    processor_ =
-        std::make_unique<BookmarkModelTypeProcessor>(&bookmark_undo_service_);
+  void ResetModelTypeProcessor(
+      bool wipe_model_on_stopping_sync_with_clear_data = false) {
+    processor_ = std::make_unique<BookmarkModelTypeProcessor>(
+        &bookmark_undo_service_, wipe_model_on_stopping_sync_with_clear_data);
     processor_->SetFaviconService(&favicon_service_);
   }
 
@@ -517,7 +520,9 @@
       CreateNodeMetadata(bookmarknode, kNodeId);
 
   // Create a new processor and init it with the metadata str.
-  BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
+  BookmarkModelTypeProcessor new_processor(
+      bookmark_undo_service(),
+      /*wipe_model_on_stopping_sync_with_clear_data=*/false);
 
   std::string metadata_str;
   model_metadata.SerializeToString(&metadata_str);
@@ -546,7 +551,9 @@
   SimulateModelReadyToSyncWithInitialSyncDone();
 
   // Create a new processor and init it with the same metadata str.
-  BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
+  BookmarkModelTypeProcessor new_processor(
+      bookmark_undo_service(),
+      /*wipe_model_on_stopping_sync_with_clear_data=*/false);
   new_processor.ModelReadyToSync(processor()->EncodeSyncMetadata(),
                                  base::DoNothing(), bookmark_model());
 
@@ -579,7 +586,9 @@
   bookmark_metadata->mutable_metadata()->set_server_id(kBookmarkBarId);
 
   // Create a new processor and init it with the metadata str.
-  BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
+  BookmarkModelTypeProcessor new_processor(
+      bookmark_undo_service(),
+      /*wipe_model_on_stopping_sync_with_clear_data=*/false);
 
   // A save should be scheduled.
   NiceMock<base::MockCallback<base::RepeatingClosure>>
@@ -606,7 +615,9 @@
                          /*server_id=*/kBookmarkBarId);
 
   // Create a new processor and init it with the metadata str.
-  BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
+  BookmarkModelTypeProcessor new_processor(
+      bookmark_undo_service(),
+      /*wipe_model_on_stopping_sync_with_clear_data=*/false);
 
   // A save should be scheduled.
   NiceMock<base::MockCallback<base::RepeatingClosure>>
@@ -1574,6 +1585,41 @@
 }
 
 TEST_F(BookmarkModelTypeProcessorTest,
+       ShouldWipeBookmarksIfStoppedWithClearMetadata) {
+  ResetModelTypeProcessor(/*wipe_model_on_stopping_sync_with_clear_data=*/true);
+
+  const GURL kUrl("http://www.example.com");
+  bookmark_model()->AddURL(bookmark_model()->bookmark_bar_node(), /*index=*/0,
+                           u"foo", kUrl);
+  const bookmarks::BookmarkNode* folder = bookmark_model()->AddFolder(
+      bookmark_model()->mobile_node(), /*index=*/0, u"folder");
+  bookmark_model()->AddURL(folder, /*index=*/0, u"bar", kUrl);
+
+  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateOnSyncStarting();
+  ASSERT_FALSE(bookmark_model()->HasNoUserCreatedBookmarksOrFolders());
+
+  processor()->OnSyncStopping(syncer::CLEAR_METADATA);
+  EXPECT_TRUE(bookmark_model()->HasNoUserCreatedBookmarksOrFolders());
+}
+
+TEST_F(BookmarkModelTypeProcessorTest,
+       ShouldNotWipeBookmarksIfStoppedWithKeepMetadata) {
+  ResetModelTypeProcessor(/*wipe_model_on_stopping_sync_with_clear_data=*/true);
+
+  const GURL kUrl("http://www.example.com");
+  const bookmarks::BookmarkNode* node = bookmark_model()->AddURL(
+      bookmark_model()->mobile_node(), /*index=*/0, u"foo", kUrl);
+
+  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateOnSyncStarting();
+
+  processor()->OnSyncStopping(syncer::KEEP_METADATA);
+  EXPECT_THAT(bookmark_model()->mobile_node()->children(),
+              ElementsAre(Pointer(Eq(node))));
+}
+
+TEST_F(BookmarkModelTypeProcessorTest,
        ShouldNotClearMetadataWhileStoppedWithoutMetadataInitially) {
   SimulateModelReadyToSyncWithoutLocalMetadata();
   ASSERT_THAT(processor()->GetTrackerForTest(), IsNull());
diff --git a/components/sync_bookmarks/bookmark_sync_service.cc b/components/sync_bookmarks/bookmark_sync_service.cc
index afeafd5..0105edd 100644
--- a/components/sync_bookmarks/bookmark_sync_service.cc
+++ b/components/sync_bookmarks/bookmark_sync_service.cc
@@ -10,8 +10,11 @@
 namespace sync_bookmarks {
 
 BookmarkSyncService::BookmarkSyncService(
-    BookmarkUndoService* bookmark_undo_service)
-    : bookmark_model_type_processor_(bookmark_undo_service) {}
+    BookmarkUndoService* bookmark_undo_service,
+    bool wipe_model_on_stopping_sync_with_clear_data)
+    : bookmark_model_type_processor_(
+          bookmark_undo_service,
+          wipe_model_on_stopping_sync_with_clear_data) {}
 
 BookmarkSyncService::~BookmarkSyncService() = default;
 
diff --git a/components/sync_bookmarks/bookmark_sync_service.h b/components/sync_bookmarks/bookmark_sync_service.h
index 7544836..94edb706 100644
--- a/components/sync_bookmarks/bookmark_sync_service.h
+++ b/components/sync_bookmarks/bookmark_sync_service.h
@@ -34,8 +34,12 @@
 // This service owns the BookmarkModelTypeProcessor.
 class BookmarkSyncService : public KeyedService {
  public:
-  // |bookmark_undo_service| must not be null and must outlive this object.
-  explicit BookmarkSyncService(BookmarkUndoService* bookmark_undo_service);
+  // If `wipe_model_on_stopping_sync_with_clear_data` is `true`, then the
+  // `bookmark_undo_service` must not be null and must outlive this object.
+  // lifetime of bookmarks in the associated storage is coupled with sync
+  // metadata's, so disabling sync will delete bookmarks in the storage.
+  BookmarkSyncService(BookmarkUndoService* bookmark_undo_service,
+                      bool wipe_model_on_stopping_sync_with_clear_data);
 
   BookmarkSyncService(const BookmarkSyncService&) = delete;
   BookmarkSyncService& operator=(const BookmarkSyncService&) = delete;
@@ -51,7 +55,7 @@
       bookmarks::BookmarkModel* model);
 
   // Returns the ModelTypeControllerDelegate for syncer::BOOKMARKS.
-  // |favicon_service| is the favicon service used when processing updates in
+  // `favicon_service` is the favicon service used when processing updates in
   // the underlying processor. It could have been a separate a setter in
   // BookmarkSyncService instead of passing it as a parameter to
   // GetBookmarkSyncControllerDelegate(). However, this would incur the risk of
diff --git a/components/test/data/dom_distiller/test_util.js b/components/test/data/dom_distiller/test_util.js
index 8db96e3..43a4449 100644
--- a/components/test/data/dom_distiller/test_util.js
+++ b/components/test/data/dom_distiller/test_util.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+let resolve;
+let reject;
+window.completePromise = new Promise((res, rej) => {
+  resolve = res;
+  reject = rej;
+});
+
 // Based on BrowserTestReporter() in //chrome/test/data/webui/mocha_adapter.js
 // TODO(crbug.com/1027612): Look into using that class directly.
 function TestReporter(runner) {
@@ -33,7 +40,10 @@
   });
 
   runner.on('end', function() {
-    window.domAutomationController.send(failures === 0 && passes > 0);
+    if (failures === 0 && passes > 0) {
+      return resolve();
+    }
+    return reject(new Error('Some tests failed, or no tests were run'));
   });
 }
 
diff --git a/components/ui_devtools/views/BUILD.gn b/components/ui_devtools/views/BUILD.gn
index 2b27259..85aaee1 100644
--- a/components/ui_devtools/views/BUILD.gn
+++ b/components/ui_devtools/views/BUILD.gn
@@ -53,6 +53,7 @@
       "overlay_agent_mac.h",
       "overlay_agent_mac.mm",
     ]
+    configs += [ "//build/config/compiler:enable_arc" ]
   }
 }
 
diff --git a/components/ui_devtools/views/dom_agent_mac.mm b/components/ui_devtools/views/dom_agent_mac.mm
index 979e3ae..f3e7f30 100644
--- a/components/ui_devtools/views/dom_agent_mac.mm
+++ b/components/ui_devtools/views/dom_agent_mac.mm
@@ -10,9 +10,13 @@
 #include "components/ui_devtools/views/widget_element.h"
 #include "ui/views/widget/native_widget_mac.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ui_devtools {
 
-DOMAgentMac::DOMAgentMac() {}
+DOMAgentMac::DOMAgentMac() = default;
 
 DOMAgentMac::~DOMAgentMac() {
   CHECK(!IsInObserverList());
@@ -67,7 +71,7 @@
 }
 
 void DOMAgentMac::InitializeRootsFromOpenWindows() {
-  for (NSWindow* window : [NSApp windows]) {
+  for (NSWindow* window in NSApp.windows) {
     if (views::Widget* widget =
             views::Widget::GetWidgetForNativeWindow(window)) {
       widget->AddObserver(this);
diff --git a/components/ui_devtools/views/overlay_agent_mac.mm b/components/ui_devtools/views/overlay_agent_mac.mm
index cc85470..d45edf9 100644
--- a/components/ui_devtools/views/overlay_agent_mac.mm
+++ b/components/ui_devtools/views/overlay_agent_mac.mm
@@ -9,6 +9,10 @@
 #include "components/ui_devtools/views/view_element.h"
 #include "components/ui_devtools/views/widget_element.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ui_devtools {
 
 OverlayAgentMac::OverlayAgentMac(DOMAgent* dom_agent)
diff --git a/components/unexportable_keys/BUILD.gn b/components/unexportable_keys/BUILD.gn
index 9fae7acc..d16aae2b 100644
--- a/components/unexportable_keys/BUILD.gn
+++ b/components/unexportable_keys/BUILD.gn
@@ -13,6 +13,8 @@
     "ref_counted_unexportable_signing_key.h",
     "service_error.h",
     "unexportable_key_id.h",
+    "unexportable_key_loader.cc",
+    "unexportable_key_loader.h",
     "unexportable_key_service.h",
     "unexportable_key_service_impl.cc",
     "unexportable_key_service_impl.h",
@@ -46,6 +48,7 @@
 
   sources = [
     "background_long_task_scheduler_unittest.cc",
+    "unexportable_key_loader_unittest.cc",
     "unexportable_key_service_impl_unittest.cc",
     "unexportable_key_task_manager_unittest.cc",
   ]
diff --git a/components/unexportable_keys/service_error.h b/components/unexportable_keys/service_error.h
index 3b97b32..cc426ef 100644
--- a/components/unexportable_keys/service_error.h
+++ b/components/unexportable_keys/service_error.h
@@ -9,7 +9,7 @@
 
 namespace unexportable_keys {
 
-// Various errors returned by `UnexportableKeyService`.
+// Various errors returned by this component.
 enum class ServiceError {
   // crypto:: operation returned an error.
   kCryptoApiFailed,
@@ -21,7 +21,9 @@
   // Unexportable key provider is not available on this platform.
   kNoKeyProvider,
   // None of the requested algorithms are supported by the key provider.
-  kAlgorithmNotSupported
+  kAlgorithmNotSupported,
+  // The key object hasn't been created yet. Try again later.
+  kKeyNotReady,
 };
 
 // Return value for methods which perform unexportable keys operations that may
diff --git a/components/unexportable_keys/unexportable_key_loader.cc b/components/unexportable_keys/unexportable_key_loader.cc
new file mode 100644
index 0000000..5fb68709
--- /dev/null
+++ b/components/unexportable_keys/unexportable_key_loader.cc
@@ -0,0 +1,110 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/unexportable_keys/unexportable_key_loader.h"
+
+#include <memory>
+
+#include "base/containers/span.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ref.h"
+#include "base/memory/weak_ptr.h"
+#include "components/unexportable_keys/background_task_priority.h"
+#include "components/unexportable_keys/service_error.h"
+#include "components/unexportable_keys/unexportable_key_id.h"
+#include "components/unexportable_keys/unexportable_key_service.h"
+#include "crypto/signature_verifier.h"
+
+namespace unexportable_keys {
+
+// static
+std::unique_ptr<UnexportableKeyLoader>
+UnexportableKeyLoader::CreateFromWrappedKey(
+    UnexportableKeyService& unexportable_key_service,
+    base::span<const uint8_t> wrapped_key,
+    BackgroundTaskPriority priority) {
+  std::unique_ptr<UnexportableKeyLoader> loader =
+      base::WrapUnique(new UnexportableKeyLoader());
+  loader->LoadFromWrappedKey(unexportable_key_service, wrapped_key, priority);
+  return loader;
+}
+
+// static
+std::unique_ptr<UnexportableKeyLoader> UnexportableKeyLoader::CreateWithNewKey(
+    UnexportableKeyService& unexportable_key_service,
+    base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
+        acceptable_algorithms,
+    BackgroundTaskPriority priority) {
+  std::unique_ptr<UnexportableKeyLoader> loader =
+      base::WrapUnique(new UnexportableKeyLoader());
+  loader->GenerateNewKey(unexportable_key_service, acceptable_algorithms,
+                         priority);
+  return loader;
+}
+
+UnexportableKeyLoader::~UnexportableKeyLoader() = default;
+
+void UnexportableKeyLoader::InvokeCallbackAfterKeyLoaded(
+    base::OnceCallback<void(ServiceErrorOr<UnexportableKeyId>)> callback) {
+  if (state_ == State::kReady) {
+    // The key is ready, we can invoke the callback immediately.
+    std::move(callback).Run(key_id_or_error_);
+    return;
+  }
+  CHECK_EQ(state_, State::kLoading);
+  on_load_callbacks_.push_back(std::move(callback));
+}
+
+ServiceErrorOr<UnexportableKeyId>
+UnexportableKeyLoader::GetKeyIdOrErrorForTesting() {
+  return key_id_or_error_;
+}
+
+UnexportableKeyLoader::State UnexportableKeyLoader::GetStateForTesting() {
+  return state_;
+}
+
+UnexportableKeyLoader::UnexportableKeyLoader() = default;
+
+void UnexportableKeyLoader::LoadFromWrappedKey(
+    UnexportableKeyService& unexportable_key_service,
+    base::span<const uint8_t> wrapped_key,
+    BackgroundTaskPriority priority) {
+  CHECK_EQ(state_, State::kNotStarted);
+  state_ = State::kLoading;
+  unexportable_key_service.FromWrappedSigningKeySlowlyAsync(
+      wrapped_key, priority,
+      base::BindOnce(&UnexportableKeyLoader::OnKeyLoaded,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+void UnexportableKeyLoader::GenerateNewKey(
+    UnexportableKeyService& unexportable_key_service,
+    base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
+        acceptable_algorithms,
+    BackgroundTaskPriority priority) {
+  CHECK_EQ(state_, State::kNotStarted);
+  state_ = State::kLoading;
+  unexportable_key_service.GenerateSigningKeySlowlyAsync(
+      acceptable_algorithms, priority,
+      base::BindOnce(&UnexportableKeyLoader::OnKeyLoaded,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void UnexportableKeyLoader::OnKeyLoaded(
+    ServiceErrorOr<UnexportableKeyId> key_id_or_error) {
+  CHECK_EQ(state_, State::kLoading);
+  state_ = State::kReady;
+  key_id_or_error_ = key_id_or_error;
+
+  std::vector<base::OnceCallback<void(ServiceErrorOr<UnexportableKeyId>)>>
+      callbacks;
+  callbacks.swap(on_load_callbacks_);
+  for (auto& callback : callbacks) {
+    std::move(callback).Run(key_id_or_error_);
+  }
+}
+
+}  // namespace unexportable_keys
diff --git a/components/unexportable_keys/unexportable_key_loader.h b/components/unexportable_keys/unexportable_key_loader.h
new file mode 100644
index 0000000..25b252b
--- /dev/null
+++ b/components/unexportable_keys/unexportable_key_loader.h
@@ -0,0 +1,99 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_LOADER_H_
+#define COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_LOADER_H_
+
+#include <memory>
+
+#include "base/containers/span.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "components/unexportable_keys/background_task_priority.h"
+#include "components/unexportable_keys/service_error.h"
+#include "components/unexportable_keys/unexportable_key_id.h"
+#include "crypto/signature_verifier.h"
+
+namespace unexportable_keys {
+
+class UnexportableKeyService;
+
+// This class facilitates creation of `UnexportableKeyId` and allows scheduling
+// callbacks to be called once a key is loaded.
+//
+// This class is designed for a single use: it allows loading only one key.
+// Create multiple instances of this class to load multiple keys.
+class UnexportableKeyLoader {
+ public:
+  enum class State {
+    // A key hasn't been requested yet by this class.
+    kNotStarted,
+    // A key is being loaded either by creating it from a wrapped key or by
+    // generating a brand new key.
+    kLoading,
+    // Terminal state of the loader. Either a key has been loaded successfully
+    // or a key load terminated with an error.
+    kReady
+  };
+
+  // Creates a new loader for a key that has previously been serialized into a
+  // `wrapped_key`.
+  static std::unique_ptr<UnexportableKeyLoader> CreateFromWrappedKey(
+      UnexportableKeyService& unexportable_key_service,
+      base::span<const uint8_t> wrapped_key,
+      BackgroundTaskPriority priority);
+
+  // Creates a new loader that will generate a brand new key.
+  static std::unique_ptr<UnexportableKeyLoader> CreateWithNewKey(
+      UnexportableKeyService& unexportable_key_service,
+      base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
+          acceptable_algorithms,
+      BackgroundTaskPriority priority);
+
+  UnexportableKeyLoader(const UnexportableKeyLoader&) = delete;
+  UnexportableKeyLoader& operator=(const UnexportableKeyLoader&) = delete;
+
+  ~UnexportableKeyLoader();
+
+  // Registers `callback` to be called when a key is loaded. Invokes `callback`
+  // immediately if a key has already been loaded.
+  void InvokeCallbackAfterKeyLoaded(
+      base::OnceCallback<void(ServiceErrorOr<UnexportableKeyId>)> callback);
+
+  // If a key hasn't been loaded yet, returns ServiceError::kKeyNotReady.
+  // Otherwise, returns a loaded key ID or a terminal error state.
+  // Public for testing.
+  ServiceErrorOr<UnexportableKeyId> GetKeyIdOrErrorForTesting();
+
+  // Returns the current state of the loader.
+  // Public for testing.
+  State GetStateForTesting();
+
+ private:
+  // Use one of the Create* static methods to create an object of this class.
+  UnexportableKeyLoader();
+
+  void LoadFromWrappedKey(UnexportableKeyService& unexportable_key_service,
+                          base::span<const uint8_t> wrapped_key,
+                          BackgroundTaskPriority priority);
+  void GenerateNewKey(
+      UnexportableKeyService& unexportable_key_service,
+      base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
+          acceptable_algorithms,
+      BackgroundTaskPriority priority);
+
+  void OnKeyLoaded(ServiceErrorOr<UnexportableKeyId> key_id_or_error);
+
+  ServiceErrorOr<UnexportableKeyId> key_id_or_error_ =
+      base::unexpected(ServiceError::kKeyNotReady);
+  State state_ = State::kNotStarted;
+  std::vector<base::OnceCallback<void(ServiceErrorOr<UnexportableKeyId>)>>
+      on_load_callbacks_;
+
+  base::WeakPtrFactory<UnexportableKeyLoader> weak_ptr_factory_{this};
+};
+
+}  // namespace unexportable_keys
+
+#endif  // COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_LOADER_H_
diff --git a/components/unexportable_keys/unexportable_key_loader_unittest.cc b/components/unexportable_keys/unexportable_key_loader_unittest.cc
new file mode 100644
index 0000000..b5fd3a1
--- /dev/null
+++ b/components/unexportable_keys/unexportable_key_loader_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/unexportable_keys/unexportable_key_loader.h"
+
+#include "base/check.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/unexportable_keys/background_task_priority.h"
+#include "components/unexportable_keys/service_error.h"
+#include "components/unexportable_keys/unexportable_key_service_impl.h"
+#include "components/unexportable_keys/unexportable_key_task_manager.h"
+#include "crypto/scoped_mock_unexportable_key_provider.h"
+#include "crypto/signature_verifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace unexportable_keys {
+
+namespace {
+
+constexpr crypto::SignatureVerifier::SignatureAlgorithm
+    kAcceptableAlgorithms[] = {crypto::SignatureVerifier::ECDSA_SHA256};
+constexpr BackgroundTaskPriority kTaskPriority =
+    BackgroundTaskPriority::kUserVisible;
+
+}  // namespace
+
+class UnexportableKeyLoaderTest : public testing::Test {
+ public:
+  UnexportableKeyLoaderTest()
+      : task_manager_(std::make_unique<UnexportableKeyTaskManager>()),
+        service_(std::make_unique<UnexportableKeyServiceImpl>(*task_manager_)) {
+  }
+
+  UnexportableKeyServiceImpl& service() { return *service_; }
+
+  void RunBackgroundTasks() { task_environment_.RunUntilIdle(); }
+
+  void ResetService() {
+    task_manager_ = std::make_unique<UnexportableKeyTaskManager>();
+    service_ = std::make_unique<UnexportableKeyServiceImpl>(*task_manager_);
+  }
+
+  void DisableKeyProvider() {
+    // Using `emplace()` to destroy the existing scoped object before
+    // constructing a new one.
+    scoped_key_provider_.emplace<crypto::ScopedNullUnexportableKeyProvider>();
+  }
+
+  std::vector<uint8_t> GenerateNewKeyAndReturnWrappedKey() {
+    base::test::TestFuture<ServiceErrorOr<UnexportableKeyId>> generate_future;
+    service().GenerateSigningKeySlowlyAsync(
+        kAcceptableAlgorithms, kTaskPriority, generate_future.GetCallback());
+    RunBackgroundTasks();
+    ServiceErrorOr<UnexportableKeyId> key_id = generate_future.Get();
+    CHECK(key_id.has_value());
+
+    ServiceErrorOr<std::vector<uint8_t>> wrapped_key =
+        service().GetWrappedKey(*key_id);
+    CHECK(wrapped_key.has_value());
+    return *wrapped_key;
+  }
+
+ private:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::ThreadPoolExecutionMode::
+          QUEUED};  // QUEUED - tasks don't run until `RunUntilIdle()` is
+                    // called.
+  // Provides a mock key provider by default.
+  absl::variant<crypto::ScopedMockUnexportableKeyProvider,
+                crypto::ScopedNullUnexportableKeyProvider>
+      scoped_key_provider_;
+  std::unique_ptr<UnexportableKeyTaskManager> task_manager_;
+  std::unique_ptr<UnexportableKeyServiceImpl> service_;
+};
+
+TEST_F(UnexportableKeyLoaderTest, CreateFromWrappedKeySync) {
+  std::vector<uint8_t> wrapped_key = GenerateNewKeyAndReturnWrappedKey();
+
+  // `wrapped_key` is already registered in the service. The loader should
+  // return a key immediately.
+  auto key_loader = UnexportableKeyLoader::CreateFromWrappedKey(
+      service(), wrapped_key, kTaskPriority);
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kReady);
+  EXPECT_TRUE(key_loader->GetKeyIdOrErrorForTesting().has_value());
+
+  base::test::TestFuture<ServiceErrorOr<UnexportableKeyId>> on_load_future;
+  key_loader->InvokeCallbackAfterKeyLoaded(on_load_future.GetCallback());
+  EXPECT_TRUE(on_load_future.IsReady());
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(), on_load_future.Get());
+}
+
+TEST_F(UnexportableKeyLoaderTest, CreateFromWrappedKeyAsync) {
+  std::vector<uint8_t> wrapped_key = GenerateNewKeyAndReturnWrappedKey();
+  // A new key is still registered inside the service. Reset the service to
+  // remove the key.
+  ResetService();
+
+  auto key_loader = UnexportableKeyLoader::CreateFromWrappedKey(
+      service(), wrapped_key, kTaskPriority);
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kLoading);
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(),
+            base::unexpected(ServiceError::kKeyNotReady));
+
+  base::test::TestFuture<ServiceErrorOr<UnexportableKeyId>> on_load_future;
+  key_loader->InvokeCallbackAfterKeyLoaded(on_load_future.GetCallback());
+  EXPECT_FALSE(on_load_future.IsReady());
+
+  RunBackgroundTasks();
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kReady);
+  EXPECT_TRUE(key_loader->GetKeyIdOrErrorForTesting().has_value());
+  EXPECT_TRUE(on_load_future.IsReady());
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(), on_load_future.Get());
+}
+
+TEST_F(UnexportableKeyLoaderTest, CreateFromWrappedKeyMultipleCallbacks) {
+  std::vector<uint8_t> wrapped_key = GenerateNewKeyAndReturnWrappedKey();
+  // A new key is still registered inside the service. Reset the service to
+  // remove the key.
+  ResetService();
+
+  auto key_loader = UnexportableKeyLoader::CreateFromWrappedKey(
+      service(), wrapped_key, kTaskPriority);
+
+  std::array<base::test::TestFuture<ServiceErrorOr<UnexportableKeyId>>, 5>
+      on_load_futures;
+  for (auto& future : on_load_futures) {
+    key_loader->InvokeCallbackAfterKeyLoaded(future.GetCallback());
+    EXPECT_FALSE(future.IsReady());
+  }
+
+  RunBackgroundTasks();
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kReady);
+  EXPECT_TRUE(key_loader->GetKeyIdOrErrorForTesting().has_value());
+  for (auto& future : on_load_futures) {
+    EXPECT_TRUE(future.IsReady());
+    EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(), future.Get());
+  }
+}
+
+TEST_F(UnexportableKeyLoaderTest, CreateWithNewKey) {
+  auto key_loader = UnexportableKeyLoader::CreateWithNewKey(
+      service(), kAcceptableAlgorithms, kTaskPriority);
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kLoading);
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(),
+            base::unexpected(ServiceError::kKeyNotReady));
+
+  base::test::TestFuture<ServiceErrorOr<UnexportableKeyId>> on_load_future;
+  key_loader->InvokeCallbackAfterKeyLoaded(on_load_future.GetCallback());
+  EXPECT_FALSE(on_load_future.IsReady());
+
+  RunBackgroundTasks();
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kReady);
+  EXPECT_TRUE(key_loader->GetKeyIdOrErrorForTesting().has_value());
+  EXPECT_TRUE(on_load_future.IsReady());
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(), on_load_future.Get());
+}
+
+TEST_F(UnexportableKeyLoaderTest, CreateWithNewKeyFailure) {
+  DisableKeyProvider();
+  auto key_loader = UnexportableKeyLoader::CreateWithNewKey(
+      service(), kAcceptableAlgorithms, kTaskPriority);
+  EXPECT_EQ(key_loader->GetStateForTesting(),
+            UnexportableKeyLoader::State::kReady);
+  EXPECT_EQ(key_loader->GetKeyIdOrErrorForTesting(),
+            base::unexpected(ServiceError::kNoKeyProvider));
+}
+
+TEST_F(UnexportableKeyLoaderTest, SignDataAfterLoading) {
+  auto key_loader = UnexportableKeyLoader::CreateWithNewKey(
+      service(), kAcceptableAlgorithms, kTaskPriority);
+
+  base::test::TestFuture<ServiceErrorOr<std::vector<uint8_t>>> sign_future;
+  key_loader->InvokeCallbackAfterKeyLoaded(base::BindLambdaForTesting(
+      [&](ServiceErrorOr<UnexportableKeyId> key_id_or_error) {
+        ASSERT_TRUE(key_id_or_error.has_value());
+        service().SignSlowlyAsync(*key_id_or_error,
+                                  std::vector<uint8_t>({1, 2, 3}),
+                                  kTaskPriority, sign_future.GetCallback());
+      }));
+  EXPECT_FALSE(sign_future.IsReady());
+  RunBackgroundTasks();
+  EXPECT_TRUE(sign_future.IsReady());
+  EXPECT_TRUE(sign_future.Get().has_value());
+}
+
+}  // namespace unexportable_keys
diff --git a/components/update_client/update_checker.h b/components/update_client/update_checker.h
index 2e2b8c8..02660fe 100644
--- a/components/update_client/update_checker.h
+++ b/components/update_client/update_checker.h
@@ -31,9 +31,9 @@
       int error,
       int retry_after_sec)>;
 
-  using Factory =
-      std::unique_ptr<UpdateChecker> (*)(scoped_refptr<Configurator> config,
-                                         PersistedData* persistent);
+  using Factory = base::RepeatingCallback<std::unique_ptr<UpdateChecker>(
+      scoped_refptr<Configurator> config,
+      PersistedData* persistent)>;
 
   UpdateChecker(const UpdateChecker&) = delete;
   UpdateChecker& operator=(const UpdateChecker&) = delete;
diff --git a/components/update_client/update_client.cc b/components/update_client/update_client.cc
index 256a5ff3..2d553f0 100644
--- a/components/update_client/update_client.cc
+++ b/components/update_client/update_client.cc
@@ -257,7 +257,7 @@
     scoped_refptr<Configurator> config) {
   return base::MakeRefCounted<UpdateClientImpl>(
       config, base::MakeRefCounted<PingManager>(config),
-      &UpdateChecker::Create);
+      base::BindRepeating(&UpdateChecker::Create));
 }
 
 void RegisterPrefs(PrefRegistrySimple* registry) {
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc
index 88c5cd76..11a7d15 100644
--- a/components/update_client/update_client_unittest.cc
+++ b/components/update_client/update_client_unittest.cc
@@ -348,7 +348,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -566,7 +566,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -800,7 +800,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -1033,7 +1033,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -1152,7 +1152,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -1405,7 +1405,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -1768,7 +1768,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -2090,7 +2090,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -2408,7 +2408,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -2599,7 +2599,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -2815,7 +2815,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
   {
     EXPECT_FALSE(config()->GetPrefService()->FindPreference(
         "updateclientdata.apps.jebgalgnebhfojomionfpkfelancnnkf.pv"));
@@ -2956,7 +2956,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -3093,7 +3093,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
@@ -3197,7 +3197,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   const std::vector<std::string> empty_id_list;
   update_client->Update(
@@ -3266,7 +3266,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   CrxComponent crx;
   crx.app_id = "jebgalgnebhfojomionfpkfelancnnkf";
@@ -3389,7 +3389,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
 
@@ -3672,7 +3672,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -3815,7 +3815,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -3982,7 +3982,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -4220,7 +4220,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   update_client->Install(
       std::string("gjpmebpgbhcamgdgjcmnjfhggjpgcimm"),
@@ -4392,7 +4392,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   const std::vector<std::string> ids = {"gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
   update_client->Update(
@@ -4519,7 +4519,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   class Observer : public UpdateClient::Observer {
    public:
@@ -4737,7 +4737,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   std::vector<CrxUpdateItem> items;
   auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
@@ -4887,7 +4887,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   base::RepeatingClosure cancel;
 
@@ -5068,7 +5068,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   base::RepeatingClosure cancel;
 
@@ -5186,7 +5186,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -5335,7 +5335,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -5445,7 +5445,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -5576,7 +5576,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -5664,7 +5664,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
@@ -5838,7 +5838,7 @@
   scoped_refptr<UpdateClient> update_client =
       base::MakeRefCounted<UpdateClientImpl>(
           config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
+          base::BindRepeating(&MockUpdateChecker::Create));
 
   MockObserver observer;
   {
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc
index 3b1e1b1..cc8331a 100644
--- a/components/update_client/update_engine.cc
+++ b/components/update_client/update_engine.cc
@@ -103,7 +103,6 @@
     scoped_refptr<PingManager> ping_manager,
     const NotifyObserversCallback& notify_observers_callback)
     : config_(config),
-
       update_checker_factory_(update_checker_factory),
       ping_manager_(ping_manager),
       metadata_(
@@ -244,7 +243,7 @@
     update_context->components[id]->Handle(base::DoNothing());
 
   update_context->update_checker =
-      update_checker_factory_(config_, metadata_.get());
+      update_checker_factory_.Run(config_, metadata_.get());
 
   update_context->update_checker->CheckForUpdates(
       update_context, config_->ExtraRequestParams(),
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
index dff9e838..c571195 100644
--- a/components/viz/common/resources/resource_format_utils.cc
+++ b/components/viz/common/resources/resource_format_utils.cc
@@ -133,6 +133,12 @@
   NOTREACHED_NORETURN();
 }
 
+SharedImageFormat SkColorTypeToSinglePlaneSharedImageFormat(
+    SkColorType color_type) {
+  return SharedImageFormat::SinglePlane(
+      SkColorTypeToResourceFormat(color_type));
+}
+
 int BitsPerPixel(ResourceFormat format) {
   switch (format) {
     case RGBA_F16:
diff --git a/components/viz/common/resources/resource_format_utils.h b/components/viz/common/resources/resource_format_utils.h
index 336d222..0ce5867 100644
--- a/components/viz/common/resources/resource_format_utils.h
+++ b/components/viz/common/resources/resource_format_utils.h
@@ -41,6 +41,10 @@
 VIZ_RESOURCE_FORMAT_EXPORT ResourceFormat
 SkColorTypeToResourceFormat(SkColorType color_type);
 
+// Returns the single-plane SharedImageFormat corresponding to `color_type.`
+VIZ_RESOURCE_FORMAT_EXPORT SharedImageFormat
+SkColorTypeToSinglePlaneSharedImageFormat(SkColorType color_type);
+
 // The following functions use unsigned int instead of GLenum, since including
 // third_party/khronos/GLES2/gl2.h causes redefinition errors as
 // macros/functions defined in it conflict with macros/functions defined in
diff --git a/components/viz/service/display/overlay_candidate.h b/components/viz/service/display/overlay_candidate.h
index b995e21..927d60a0 100644
--- a/components/viz/service/display/overlay_candidate.h
+++ b/components/viz/service/display/overlay_candidate.h
@@ -182,7 +182,7 @@
   // is an estimate when 'EstimateOccludedDamage' function is used.
   float damage_area_estimate = 0.f;
 
-  // Damage in buffer space (extents bound by |resource_size_in_pixels|).
+  // Damage in viz Display space, the same space as |display_rect|;
   gfx::RectF damage_rect;
 
   static constexpr uint32_t kInvalidDamageIndex = UINT_MAX;
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc
index 85553b0..6949616 100644
--- a/components/viz/service/display/overlay_candidate_factory.cc
+++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -223,7 +223,7 @@
     const OverlayCandidate& candidate,
     QuadList::ConstIterator quad_list_begin,
     QuadList::ConstIterator quad_list_end) const {
-  gfx::Rect quad_damage = gfx::ToEnclosingRect(GetDamageRect(quad, candidate));
+  gfx::Rect quad_damage = gfx::ToEnclosingRect(GetDamageEstimate(candidate));
   float occluded_damage_estimate_total = 0.f;
   for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
        ++overlap_iter) {
@@ -657,47 +657,27 @@
 
 void OverlayCandidateFactory::AssignDamage(const DrawQuad* quad,
                                            OverlayCandidate& candidate) const {
-  auto& transform = quad->shared_quad_state->quad_to_target_transform;
-  auto damage_rect = GetDamageRect(quad, candidate);
-  gfx::RectF transformed_damage;
-  if (absl::optional<gfx::RectF> transformed =
-          transform.InverseMapRect(damage_rect)) {
-    transformed_damage = *transformed;
-    // The quad's |rect| is in content space. To get to buffer space we need
-    // to remove the |rect|'s pixel offset.
-    auto buffer_damage_origin =
-        transformed_damage.origin() - gfx::PointF(quad->rect.origin());
-    transformed_damage.set_origin(
-        gfx::PointF(buffer_damage_origin.x(), buffer_damage_origin.y()));
-
-    if (!quad->rect.IsEmpty()) {
-      // Normalize damage to be in UVs.
-      transformed_damage.InvScale(quad->rect.width(), quad->rect.height());
-    }
-
-    // The normalization above is not enough if the |uv_rect| is not 0,0-1x1.
-    // This is because texture uvs can effectively magnify damage.
-    if (!candidate.uv_rect.IsEmpty()) {
-      transformed_damage.Scale(candidate.uv_rect.width(),
-                               candidate.uv_rect.height());
-      transformed_damage.Offset(candidate.uv_rect.OffsetFromOrigin());
-    }
-
-    // Buffer damage is in texels not UVs so scale by resource size.
-    transformed_damage.Scale(candidate.resource_size_in_pixels.width(),
-                             candidate.resource_size_in_pixels.height());
-  } else {
-    // If not invertible, set to full damage.
-    // TODO(https://crbug.com/1279965): |resource_size_in_pixels| might not be
-    // properly initialized at this stage.
-    transformed_damage =
-        gfx::RectF(gfx::SizeF(candidate.resource_size_in_pixels));
-  }
+  candidate.damage_rect = GetDamageRect(quad, candidate);
   // For underlays the function 'EstimateVisibleDamage()' is called to update
   // |damage_area_estimate| to more accurately reflect the actual visible
   // damage.
-  candidate.damage_area_estimate = damage_rect.size().GetArea();
-  candidate.damage_rect = transformed_damage;
+  if (!is_delegated_context_) {
+    candidate.damage_area_estimate =
+        GetDamageEstimate(candidate).size().GetArea();
+  }
+}
+
+gfx::RectF OverlayCandidateFactory::GetDamageEstimate(
+    const OverlayCandidate& candidate) const {
+  // If we have assigned damage we can trust that.
+  if (!candidate.damage_rect.IsEmpty()) {
+    return candidate.damage_rect;
+  }
+
+  // Otherwise we will see how much unassigned damage covers the display_rect.
+  return gfx::IntersectRects(
+      OverlayCandidate::DisplayRectInTargetSpace(candidate),
+      gfx::RectF(unassigned_surface_damage_));
 }
 
 gfx::RectF OverlayCandidateFactory::GetDamageRect(
@@ -705,15 +685,7 @@
     const OverlayCandidate& candidate) const {
   const SharedQuadState* sqs = quad->shared_quad_state;
   if (!sqs->overlay_damage_index.has_value()) {
-    // This is a special case where an overlay candidate may have damage but it
-    // does not have a damage index since it was not the only quad in the
-    // original surface. Here the |unassigned_surface_damage_| will contain all
-    // unassigned damage and we use it to conservatively estimate the damage for
-    // this quad. We limit the damage to the candidates quad rect in question.
-    gfx::RectF intersection =
-        OverlayCandidate::DisplayRectInTargetSpace(candidate);
-    intersection.Intersect(gfx::RectF(unassigned_surface_damage_));
-    return intersection;
+    return gfx::RectF();
   }
 
   size_t overlay_damage_index = sqs->overlay_damage_index.value();
@@ -723,7 +695,22 @@
     return gfx::RectF();
   }
 
-  return gfx::RectF((*surface_damage_rect_list_)[overlay_damage_index]);
+  // Assigned damage assumes that |candidate.display_rect| is already in target
+  // space, but that isn't true for transformation matrices.
+  if (absl::holds_alternative<gfx::Transform>(candidate.transform)) {
+    return gfx::RectF();
+  }
+
+  // Ash can't overlay candidates that aren't pixel-aligned so don't bother
+  // assigning damage to them. This would also be a challenge because
+  // |OverlayCandidate.damage_rect| is only a gfx::Rect.
+  if (!candidate.display_rect.IsExpressibleAsRect()) {
+    return gfx::RectF();
+  }
+
+  auto damage = gfx::RectF((*surface_damage_rect_list_)[overlay_damage_index]);
+  DBG_DRAW_RECT("damage_assigned", damage);
+  return damage;
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_candidate_factory.h b/components/viz/service/display/overlay_candidate_factory.h
index 4cfb774..f2b5d0b 100644
--- a/components/viz/service/display/overlay_candidate_factory.h
+++ b/components/viz/service/display/overlay_candidate_factory.h
@@ -100,6 +100,8 @@
                   QuadList::ConstIterator quad_list_begin,
                   QuadList::ConstIterator quad_list_end) const;
 
+  gfx::Rect GetUnassignedDamage() { return unassigned_surface_damage_; }
+
  private:
   CandidateStatus FromDrawQuadResource(const DrawQuad* quad,
                                        ResourceId resource_id,
@@ -132,6 +134,8 @@
   gfx::RectF GetDamageRect(const DrawQuad* quad,
                            const OverlayCandidate& candidate) const;
 
+  gfx::RectF GetDamageEstimate(const OverlayCandidate& candidate) const;
+
   raw_ptr<const AggregatedRenderPass> render_pass_;
   raw_ptr<DisplayResourceProvider> resource_provider_;
   raw_ptr<const SurfaceDamageRectList> surface_damage_rect_list_;
diff --git a/components/viz/service/display/overlay_candidate_factory_unittest.cc b/components/viz/service/display/overlay_candidate_factory_unittest.cc
index 467bd18..a30d8db2 100644
--- a/components/viz/service/display/overlay_candidate_factory_unittest.cc
+++ b/components/viz/service/display/overlay_candidate_factory_unittest.cc
@@ -469,6 +469,7 @@
     OverlayCandidate::CandidateStatus result =
         factory.FromDrawQuad(&quad, candidate);
     ASSERT_EQ(result, OverlayCandidate::CandidateStatus::kSuccess);
+    EXPECT_TRUE(candidate.damage_rect.IsEmpty());
     QuadList quad_list;
     EXPECT_EQ(factory.EstimateVisibleDamage(&quad, candidate, quad_list.begin(),
                                             quad_list.end()),
@@ -486,7 +487,10 @@
     OverlayCandidate::CandidateStatus result =
         factory.FromDrawQuad(&quad, candidate);
     ASSERT_EQ(result, OverlayCandidate::CandidateStatus::kSuccess);
+    // Damage should not be assigned to transformed quads.
+    EXPECT_TRUE(candidate.damage_rect.IsEmpty());
     QuadList quad_list;
+    // But we can still estimate damage for sorting purposes.
     EXPECT_GT(factory.EstimateVisibleDamage(&quad, candidate, quad_list.begin(),
                                             quad_list.end()),
               0);
diff --git a/components/viz/service/display/overlay_processor_delegated.cc b/components/viz/service/display/overlay_processor_delegated.cc
index f71fb44..900510c 100644
--- a/components/viz/service/display/overlay_processor_delegated.cc
+++ b/components/viz/service/display/overlay_processor_delegated.cc
@@ -163,6 +163,8 @@
       &render_pass_filters, is_delegated_context,
       supports_clip_rect_ && enable_clip_rect());
 
+  unassigned_damage_ = gfx::RectF(candidate_factory.GetUnassignedDamage());
+
   const auto kExtraCandiates = needs_background_image_ ? 1 : 0;
   candidates->reserve(quad_list->size() + kExtraCandiates);
   int num_quads_skipped = 0;
@@ -296,6 +298,8 @@
     // Add in all the damage from all fully delegated frames.
     damage_rect->Union(previous_frame_overlay_rect_);
     previous_frame_overlay_rect_ = gfx::Rect();
+    // This is only relevant when delegating.
+    unassigned_damage_ = gfx::RectF();
   }
 
   UMA_HISTOGRAM_ENUMERATION("Viz.DelegatedCompositing.Status",
@@ -323,4 +327,8 @@
     output_surface_plane->reset();
 }
 
+gfx::RectF OverlayProcessorDelegated::GetUnassignedDamage() const {
+  return unassigned_damage_;
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_processor_delegated.h b/components/viz/service/display/overlay_processor_delegated.h
index 8c9b1d4..39da2f77 100644
--- a/components/viz/service/display/overlay_processor_delegated.h
+++ b/components/viz/service/display/overlay_processor_delegated.h
@@ -65,6 +65,8 @@
   void AdjustOutputSurfaceOverlay(
       absl::optional<OutputSurfaceOverlayPlane>* output_surface_plane) override;
 
+  gfx::RectF GetUnassignedDamage() const override;
+
  private:
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused. For some cases in
@@ -110,6 +112,7 @@
   DelegationStatus delegated_status_ = DelegationStatus::kCompositedOther;
   bool supports_clip_rect_ = false;
   bool needs_background_image_ = false;
+  gfx::RectF unassigned_damage_;
 };
 }  // namespace viz
 
diff --git a/components/viz/service/display/overlay_processor_interface.cc b/components/viz/service/display/overlay_processor_interface.cc
index fea01b3..c598a43 100644
--- a/components/viz/service/display/overlay_processor_interface.cc
+++ b/components/viz/service/display/overlay_processor_interface.cc
@@ -219,4 +219,8 @@
   return gfx::kCALayerSuccess;
 }
 
+gfx::RectF OverlayProcessorInterface::GetUnassignedDamage() const {
+  return gfx::RectF();
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_processor_interface.h b/components/viz/service/display/overlay_processor_interface.h
index b5d08d5..2831b21 100644
--- a/components/viz/service/display/overlay_processor_interface.h
+++ b/components/viz/service/display/overlay_processor_interface.h
@@ -195,6 +195,10 @@
 
   virtual gfx::CALayerResult GetCALayerErrorCode() const;
 
+  // For Lacros, get damage that was not assigned to any overlay candidates
+  // during ProcessForOverlays.
+  virtual gfx::RectF GetUnassignedDamage() const;
+
  protected:
   OverlayProcessorInterface() = default;
 };
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 56dcc030..e7a6067 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -840,19 +840,6 @@
   return matrix;
 }
 
-gfx::RectF ScaleForBufferDamageUV(const gfx::RectF buffer_damage_no_uv,
-                                  const gfx::SizeF resource_size) {
-  auto transformed_damage = buffer_damage_no_uv;
-  gfx::RectF uv = {kUVTopLeft.x(), kUVTopLeft.y(),
-                   kUVBottomRight.x() - kUVTopLeft.x(),
-                   kUVBottomRight.y() - kUVTopLeft.y()};
-
-  transformed_damage.Scale(uv.width(), uv.height());
-  transformed_damage.Offset(uv.x() * resource_size.width(),
-                            uv.y() * resource_size.height());
-  return transformed_damage;
-}
-
 template <typename OverlayProcessorType>
 class OverlayTest : public testing::Test {
  protected:
@@ -2485,55 +2472,6 @@
   EXPECT_EQ(1U, candidate_list.size());
 }
 
-TEST_F(SingleOverlayOnTopTest, TargetOffsetCandidateDamageRect) {
-  constexpr auto kOverlayRectInContent = gfx::Rect(13, 27, 32, 16);
-  gfx::Rect rect = kOverlayRectInContent;
-  auto pass = CreateRenderPass();
-  CreateCandidateQuadAt(resource_provider_.get(),
-                        child_resource_provider_.get(), child_provider_.get(),
-                        pass->shared_quad_state_list.back(), pass.get(), rect);
-  constexpr auto kOverlayOffsetTarget = gfx::Vector2d(23.f, 45.f);
-  pass->shared_quad_state_list.back()->quad_to_target_transform.Translate(
-      kOverlayOffsetTarget);
-  OverlayCandidateList candidate_list;
-  OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
-  OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
-  AggregatedRenderPassList pass_list;
-  pass_list.push_back(std::move(pass));
-  SurfaceDamageRectList surface_damage_rect_list;
-  constexpr gfx::Rect display_rect = {
-      kOverlayRectInContent.x() + kOverlayOffsetTarget.x(),
-      kOverlayRectInContent.y() + kOverlayOffsetTarget.y(),
-      kOverlayRectInContent.width(), kOverlayRectInContent.height()};
-
-  constexpr auto kIntendedBufferOffset = gfx::Vector2d(5.f, 7.f);
-  gfx::Rect damage_in_target_space = display_rect;
-  auto inside_quad_offset =
-      kIntendedBufferOffset + display_rect.OffsetFromOrigin();
-  damage_in_target_space.set_origin(
-      gfx::Point(inside_quad_offset.x(), inside_quad_offset.y()));
-  surface_damage_rect_list.push_back(damage_in_target_space);
-  overlay_processor_->AddExpectedRect(gfx::RectF(display_rect));
-  overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
-      render_pass_filters, render_pass_backdrop_filters,
-      std::move(surface_damage_rect_list), nullptr, &candidate_list,
-      &damage_rect_, &content_bounds_);
-  EXPECT_EQ(1U, candidate_list.size());
-  // |transformed_damage| would correspond to candidate buffer damage if our
-  // texture uvs were 0,0 1x1.
-  gfx::RectF transformed_damage = {
-      kIntendedBufferOffset.x(), kIntendedBufferOffset.y(),
-      kOverlayRectInContent.width() - kIntendedBufferOffset.x(),
-      kOverlayRectInContent.height() - kIntendedBufferOffset.y()};
-  // However, the default uvs for candidates are 0.1,0.2 .9x.8  (see the value
-  // of |kUVTopLeft|). So the damage in buffer space is actually smaller because
-  // the uvs have the effect of magnifying portions of the buffer.
-  transformed_damage = ScaleForBufferDamageUV(
-      transformed_damage, gfx::SizeF(kOverlayRectInContent.size()));
-  EXPECT_RECTF_NEAR(transformed_damage, candidate_list[0].damage_rect, 0.0001f);
-}
-
 TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) {
   gfx::Rect rect = kOverlayRect;
   rect.Offset(0, -rect.height());
@@ -5399,22 +5337,13 @@
       overlay_processor_->GetDefaultPrimaryPlane(), &candidate_list,
       &damage_rect_, &content_bounds_);
 
-  // Expected damage is basically the intersection of the rect with the screen
-  // damage but relative to that rect.
-  const auto kExpectedRectRelDamage = gfx::RectF(25 - 15, 0, 5, 32 - 10);
-  const auto kExpectedScaledRelDamage =
-      gfx::ScaleRect(kExpectedRectRelDamage, 0.5f, 0.25f);
+  // Damage is not assigned to specific candidates.
   EXPECT_EQ(main_pass->quad_list.size(), candidate_list.size());
   EXPECT_TRUE(damage_rect_.IsEmpty());
-  EXPECT_RECTF_NEAR(candidate_list[0].damage_rect,
-                    ScaleForBufferDamageUV(kExpectedScaledRelDamage,
-                                           gfx::SizeF(kResourceSize)),
-                    0.001f);
-  EXPECT_RECTF_NEAR(
-      candidate_list[1].damage_rect,
-      ScaleForBufferDamageUV(kExpectedRectRelDamage,
-                             gfx::SizeF(kSmallCandidateRect.size())),
-      0.001f);
+  EXPECT_TRUE(candidate_list[0].damage_rect.IsEmpty());
+  EXPECT_TRUE(candidate_list[1].damage_rect.IsEmpty());
+  EXPECT_RECTF_NEAR(overlay_processor_->GetUnassignedDamage(),
+                    gfx::RectF(kDisplayDamage), 0.0001f);
 }
 
 TEST_F(DelegatedTest, QuadTypes) {
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 8f903a0..6dfc8e1 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -3863,6 +3863,11 @@
   // ScheduleOverlays() will convert this to a buffer-backed solid color overlay
   // if necessary.
   background_candidate.is_solid_color = true;
+  if (overlay_processor_) {
+    background_candidate.damage_rect =
+        overlay_processor_->GetUnassignedDamage();
+    DBG_DRAW_RECT("damage_not_assigned", background_candidate.damage_rect);
+  }
 
   overlay_list.push_back(background_candidate);
 }
diff --git a/components/viz/service/display_embedder/output_presenter_gl.cc b/components/viz/service/display_embedder/output_presenter_gl.cc
index 60323ec..5ae98fc7 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -182,8 +182,8 @@
                                 float device_scale_factor,
                                 gfx::OverlayTransform transform) {
   const gfx::Size size = gfx::SkISizeToSize(image_info.dimensions());
-  image_format_ = SharedImageFormat::SinglePlane(
-      SkColorTypeToResourceFormat(image_info.colorType()));
+  image_format_ =
+      SkColorTypeToSinglePlaneSharedImageFormat(image_info.colorType());
   const bool has_alpha = !image_info.isOpaque();
   return presenter_->Resize(size, device_scale_factor, color_space, has_alpha);
 }
diff --git a/components/webapk/webapk.proto b/components/webapk/webapk.proto
index cc3c1327..7e0e43e8 100644
--- a/components/webapk/webapk.proto
+++ b/components/webapk/webapk.proto
@@ -119,6 +119,7 @@
     PRIMARY_ICON = 1;
     BADGE_ICON = 2;
     SPLASH_ICON = 3;
+    SHORTCUT_ICON = 4;
   }
 
   // Image's URL.
diff --git a/components/webapps/browser/BUILD.gn b/components/webapps/browser/BUILD.gn
index f9b91cef..3426962 100644
--- a/components/webapps/browser/BUILD.gn
+++ b/components/webapps/browser/BUILD.gn
@@ -103,6 +103,8 @@
       "android/webapk/webapk_proto_builder.cc",
       "android/webapk/webapk_proto_builder.h",
       "android/webapk/webapk_types.h",
+      "android/webapp_icon.cc",
+      "android/webapp_icon.h",
       "android/webapps_icon_utils.cc",
       "android/webapps_icon_utils.h",
       "android/webapps_utils.cc",
diff --git a/components/webapps/browser/android/shortcut_info.cc b/components/webapps/browser/android/shortcut_info.cc
index bf144cf..b9341030 100644
--- a/components/webapps/browser/android/shortcut_info.cc
+++ b/components/webapps/browser/android/shortcut_info.cc
@@ -69,17 +69,35 @@
   return shortcut_info;
 }
 
-std::set<GURL> ShortcutInfo::GetWebApkIcons() {
-  std::set<GURL> icons{best_primary_icon_url};
+std::vector<WebappIcon> ShortcutInfo::GetWebApkIcons() {
+  std::vector<WebappIcon> icons;
+  icons.emplace_back(best_primary_icon_url, is_primary_icon_maskable,
+                     webapk::Image::PRIMARY_ICON);
 
-  if (!splash_image_url.is_empty() &&
-      splash_image_url != best_primary_icon_url) {
-    icons.insert(splash_image_url);
+  if (!splash_image_url.is_empty()) {
+    auto it = std::find_if(icons.begin(), icons.end(), [&](auto& icon) {
+      return icon.url() == splash_image_url;
+    });
+    if (it == icons.end()) {
+      icons.emplace_back(splash_image_url, is_splash_image_maskable,
+                         webapk::Image::SPLASH_ICON);
+    } else {
+      it->AddUsage(webapk::Image::SPLASH_ICON);
+    }
   }
 
-  for (const auto& shortcut_icon : best_shortcut_icon_urls) {
-    if (shortcut_icon.is_valid())
-      icons.insert(shortcut_icon);
+  for (const auto& shortcut_icon_url : best_shortcut_icon_urls) {
+    if (shortcut_icon_url.is_valid()) {
+      auto it = std::find_if(icons.begin(), icons.end(), [&](auto& icon) {
+        return icon.url() == shortcut_icon_url;
+      });
+      if (it == icons.end()) {
+        icons.emplace_back(shortcut_icon_url, false,
+                           webapk::Image::SHORTCUT_ICON);
+      } else {
+        it->AddUsage(webapk::Image::SHORTCUT_ICON);
+      }
+    }
   }
 
   return icons;
diff --git a/components/webapps/browser/android/shortcut_info.h b/components/webapps/browser/android/shortcut_info.h
index 72235948..c0d16c1 100644
--- a/components/webapps/browser/android/shortcut_info.h
+++ b/components/webapps/browser/android/shortcut_info.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "components/webapps/browser/android/webapp_icon.h"
 #include "services/device/public/mojom/screen_orientation_lock_types.mojom-shared.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
@@ -135,9 +136,9 @@
   // Updates the source of the shortcut.
   void UpdateSource(const Source source);
 
-  // Returns a set of icons including |best_primary_icon_url|,
+  // Returns a vector of icons including |best_primary_icon_url|,
   // |splash_image_url| and |best_shortcut_icon_urls| if they are not empty
-  std::set<GURL> GetWebApkIcons();
+  std::vector<WebappIcon> GetWebApkIcons();
 
   GURL manifest_url;
   GURL url;
diff --git a/components/webapps/browser/android/shortcut_info_unittest.cc b/components/webapps/browser/android/shortcut_info_unittest.cc
index b0e0e6f..cfab37a 100644
--- a/components/webapps/browser/android/shortcut_info_unittest.cc
+++ b/components/webapps/browser/android/shortcut_info_unittest.cc
@@ -103,12 +103,17 @@
   info_.best_primary_icon_url = best_primary_icon_url;
   info_.splash_image_url = splash_image_url;
 
-  std::set<GURL> result = info_.GetWebApkIcons();
-  std::set<GURL> expected{best_shortcut_icon_url_1, best_shortcut_icon_url_2,
-                          best_primary_icon_url, splash_image_url};
+  std::vector<WebappIcon> result_icons = info_.GetWebApkIcons();
+  ASSERT_EQ(4u, result_icons.size());
 
-  ASSERT_EQ(4u, result.size());
-  ASSERT_EQ(expected, result);
+  std::vector<GURL> result_urls;
+  for (auto icon : result_icons) {
+    result_urls.push_back(icon.url());
+  }
+  std::vector<GURL> expected_urls{best_primary_icon_url, splash_image_url,
+                                  best_shortcut_icon_url_1,
+                                  best_shortcut_icon_url_2};
+  ASSERT_EQ(expected_urls, result_urls);
 }
 
 TEST_F(ShortcutInfoTest, NotContainEmptyOrDuplicateWebApkIcons) {
@@ -119,11 +124,16 @@
   info_.best_shortcut_icon_urls.push_back(best_primary_icon_url);
   info_.best_primary_icon_url = best_primary_icon_url;
 
-  std::set<GURL> result = info_.GetWebApkIcons();
-  std::set<GURL> expected{best_shortcut_icon_url, best_primary_icon_url};
+  std::vector<WebappIcon> result_icons = info_.GetWebApkIcons();
+  std::vector<GURL> result_urls;
+  for (auto icon : result_icons) {
+    result_urls.push_back(icon.url());
+  }
 
-  ASSERT_EQ(2u, result.size());
-  ASSERT_EQ(expected, result);
+  std::vector<GURL> expected{best_primary_icon_url, best_shortcut_icon_url};
+
+  ASSERT_EQ(2u, result_icons.size());
+  ASSERT_EQ(expected, result_urls);
 }
 
 TEST_F(ShortcutInfoTest, NameFallsBackToShortName) {
diff --git a/components/webapps/browser/android/webapk/webapk_icon_hasher.cc b/components/webapps/browser/android/webapk/webapk_icon_hasher.cc
index 46952a9..e33c46b 100644
--- a/components/webapps/browser/android/webapk/webapk_icon_hasher.cc
+++ b/components/webapps/browser/android/webapk/webapk_icon_hasher.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/data_url.h"
 #include "net/base/network_isolation_key.h"
@@ -68,22 +69,21 @@
     network::mojom::URLLoaderFactory* url_loader_factory,
     base::WeakPtr<content::WebContents> web_contents,
     const url::Origin& request_initiator,
-    const std::set<GURL>& icon_urls,
+    const std::vector<WebappIcon>& webapk_icons,
     Murmur2HashMultipleCallback callback) {
   auto icons_ptr = std::make_unique<std::map<std::string, Icon>>();
   auto& icons = *icons_ptr;
 
   auto barrier_closure = base::BarrierClosure(
-      icon_urls.size(),
+      webapk_icons.size(),
       base::BindOnce(&OnAllMurmur2Hashes, std::move(icons_ptr),
                      std::move(callback)));
-
-  for (const auto& icon_url : icon_urls) {
+  for (const auto& webapk_icon : webapk_icons) {
     // |hashes| is owned by |barrier_closure|.
     DownloadAndComputeMurmur2HashWithTimeout(
-        url_loader_factory, web_contents, request_initiator, icon_url,
+        url_loader_factory, web_contents, request_initiator, webapk_icon,
         kDownloadTimeoutInMilliseconds,
-        base::BindOnce(&OnMurmur2Hash, &icons[icon_url.spec()],
+        base::BindOnce(&OnMurmur2Hash, &icons[webapk_icon.url().spec()],
                        barrier_closure));
   }
 }
@@ -93,19 +93,19 @@
     network::mojom::URLLoaderFactory* url_loader_factory,
     base::WeakPtr<content::WebContents> web_contents,
     const url::Origin& request_initiator,
-    const GURL& icon_url,
+    const WebappIcon& webapk_icon,
     int timeout_ms,
     Murmur2HashCallback callback) {
-  if (!icon_url.is_valid()) {
+  if (!webapk_icon.url().is_valid()) {
     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), Icon{}));
     return;
   }
 
-  if (icon_url.SchemeIs(url::kDataScheme)) {
+  if (webapk_icon.url().SchemeIs(url::kDataScheme)) {
     std::string mime_type, char_set, data;
     Icon icon;
-    if (net::DataURL::Parse(icon_url, &mime_type, &char_set, &data) &&
+    if (net::DataURL::Parse(webapk_icon.url(), &mime_type, &char_set, &data) &&
         !data.empty()) {
       icon.hash = ComputeMurmur2Hash(data);
       icon.unsafe_data = std::move(data);
@@ -117,7 +117,7 @@
 
   // The icon hasher will delete itself when it is done.
   new WebApkIconHasher(url_loader_factory, std::move(web_contents),
-                       request_initiator, icon_url, timeout_ms,
+                       request_initiator, webapk_icon, timeout_ms,
                        std::move(callback));
 }
 
@@ -125,7 +125,7 @@
     network::mojom::URLLoaderFactory* url_loader_factory,
     base::WeakPtr<content::WebContents> web_contents,
     const url::Origin& request_initiator,
-    const GURL& icon_url,
+    const WebappIcon& webapk_icon,
     int timeout_ms,
     Murmur2HashCallback callback)
     : callback_(std::move(callback)) {
@@ -142,7 +142,7 @@
       net::IsolationInfo::RequestType::kOther, request_initiator,
       request_initiator, net::SiteForCookies());
   resource_request->request_initiator = request_initiator;
-  resource_request->url = icon_url;
+  resource_request->url = webapk_icon.url();
   simple_url_loader_ = network::SimpleURLLoader::Create(
       std::move(resource_request),
       TRAFFIC_ANNOTATION_WITHOUT_PROTO("webapk icon hasher"));
@@ -150,13 +150,14 @@
       url_loader_factory,
       base::BindOnce(&WebApkIconHasher::OnSimpleLoaderComplete,
                      base::Unretained(this), std::move(web_contents),
-                     timeout_ms));
+                     webapk_icon.GetIdealSizeInPx(), timeout_ms));
 }
 
 WebApkIconHasher::~WebApkIconHasher() {}
 
 void WebApkIconHasher::OnSimpleLoaderComplete(
     base::WeakPtr<content::WebContents> web_contents,
+    int ideal_icon_size,
     int timeout_ms,
     std::unique_ptr<std::string> response_body) {
   download_timeout_timer_.Stop();
@@ -182,12 +183,13 @@
         base::BindOnce(&WebApkIconHasher::OnDownloadTimedOut,
                        base::Unretained(this)));
 
+    const gfx::Size preferred_size(ideal_icon_size, ideal_icon_size);
     web_contents->DownloadImage(
         simple_url_loader->GetFinalURL(),
-        false,        // is_favicon
-        gfx::Size(),  // no preferred size
-        0,            // no max size
-        false,        // normal cache policy
+        false,  // is_favicon
+        preferred_size,
+        std::numeric_limits<int>::max(),  // max size
+        false,                            // normal cache policy
         base::BindOnce(&WebApkIconHasher::OnImageDownloaded,
                        weak_ptr_factory_.GetWeakPtr(),
                        std::move(response_body)));
diff --git a/components/webapps/browser/android/webapk/webapk_icon_hasher.h b/components/webapps/browser/android/webapk/webapk_icon_hasher.h
index f89d966c..cdc69e6a 100644
--- a/components/webapps/browser/android/webapk/webapk_icon_hasher.h
+++ b/components/webapps/browser/android/webapk/webapk_icon_hasher.h
@@ -13,6 +13,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "components/webapps/browser/android/webapp_icon.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/size.h"
@@ -61,14 +62,14 @@
       network::mojom::URLLoaderFactory* url_loader_factory,
       base::WeakPtr<content::WebContents> web_contents,
       const url::Origin& request_initiator,
-      const std::set<GURL>& icon_urls,
+      const std::vector<WebappIcon>& webapp_icon,
       Murmur2HashMultipleCallback callback);
 
   static void DownloadAndComputeMurmur2HashWithTimeout(
       network::mojom::URLLoaderFactory* url_loader_factory,
       base::WeakPtr<content::WebContents> web_contents,
       const url::Origin& request_initiator,
-      const GURL& icon_url,
+      const WebappIcon& webapp_icon,
       int timeout_ms,
       Murmur2HashCallback callback);
 
@@ -76,12 +77,13 @@
   WebApkIconHasher(network::mojom::URLLoaderFactory* url_loader_factory,
                    base::WeakPtr<content::WebContents> web_contents,
                    const url::Origin& request_initiator,
-                   const GURL& icon_url,
+                   const WebappIcon& webapp_icon,
                    int timeout_ms,
                    Murmur2HashCallback callback);
   ~WebApkIconHasher();
 
   void OnSimpleLoaderComplete(base::WeakPtr<content::WebContents> web_contents,
+                              int ideal_icon_size,
                               int timeout_ms,
                               std::unique_ptr<std::string> response_body);
 
diff --git a/components/webapps/browser/android/webapk/webapk_icon_hasher_unittest.cc b/components/webapps/browser/android/webapk/webapk_icon_hasher_unittest.cc
index 1e514c7..e9736b99 100644
--- a/components/webapps/browser/android/webapk/webapk_icon_hasher_unittest.cc
+++ b/components/webapps/browser/android/webapk/webapk_icon_hasher_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "components/webapps/browser/android/webapp_icon.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -48,7 +49,7 @@
            const GURL& icon_url) {
     WebApkIconHasher::DownloadAndComputeMurmur2HashWithTimeout(
         url_loader_factory, web_contents->GetWeakPtr(),
-        url::Origin::Create(icon_url), icon_url, /*timeout_ms=*/300,
+        url::Origin::Create(icon_url), WebappIcon(icon_url), /*timeout_ms=*/300,
         base::BindOnce(&WebApkIconHasherRunner::OnCompleted,
                        base::Unretained(this)));
 
@@ -62,10 +63,14 @@
       content::WebContents* web_contents,
       const std::set<GURL>& icon_urls) {
     std::map<std::string, WebApkIconHasher::Icon> result;
+    std::vector<WebappIcon> icons;
+    for (auto icon_url : icon_urls) {
+      icons.emplace_back(icon_url);
+    }
     base::RunLoop run_loop;
     WebApkIconHasher::DownloadAndComputeMurmur2Hash(
         url_loader_factory, web_contents->GetWeakPtr(),
-        url::Origin::Create(*icon_urls.begin()), icon_urls,
+        url::Origin::Create(*icon_urls.begin()), icons,
         base::BindLambdaForTesting(
             [&](absl::optional<std::map<std::string, WebApkIconHasher::Icon>>
                     hashes) {
@@ -222,7 +227,7 @@
   WebApkIconHasherRunner runner;
   WebApkIconHasher::DownloadAndComputeMurmur2HashWithTimeout(
       test_url_loader_factory(), web_contents()->GetWeakPtr(),
-      url::Origin::Create(icon_url), icon_url, /*timeout_ms=*/300,
+      url::Origin::Create(icon_url), WebappIcon(icon_url), /*timeout_ms=*/300,
       base::BindOnce(&WebApkIconHasherRunner::OnCompleted,
                      base::Unretained(&runner)));
   base::RunLoop().RunUntilIdle();
@@ -265,7 +270,7 @@
   WebApkIconHasherRunner runner;
   WebApkIconHasher::DownloadAndComputeMurmur2HashWithTimeout(
       test_url_loader_factory(), web_contents()->GetWeakPtr(),
-      url::Origin::Create(icon_url), icon_url, /*timeout_ms=*/300,
+      url::Origin::Create(icon_url), WebappIcon(icon_url), /*timeout_ms=*/300,
       base::BindOnce(&WebApkIconHasherRunner::OnCompleted,
                      base::Unretained(&runner)));
   base::RunLoop().RunUntilIdle();
diff --git a/components/webapps/browser/android/webapp_icon.cc b/components/webapps/browser/android/webapp_icon.cc
new file mode 100644
index 0000000..fbcc846
--- /dev/null
+++ b/components/webapps/browser/android/webapp_icon.cc
@@ -0,0 +1,40 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webapps/browser/android/webapp_icon.h"
+
+#include "components/webapps/browser/android/webapps_icon_utils.h"
+
+namespace webapps {
+
+WebappIcon::WebappIcon(const GURL& icon_url) : url_(icon_url) {}
+
+WebappIcon::WebappIcon(const GURL& icon_url,
+                       bool is_maskable,
+                       webapk::Image::Usage usage)
+    : url_(icon_url),
+      purpose_(is_maskable ? webapk::Image::MASKABLE : webapk::Image::ANY) {
+  AddUsage(usage);
+}
+
+WebappIcon::WebappIcon(const WebappIcon&) = default;
+WebappIcon& WebappIcon::operator=(const WebappIcon&) = default;
+WebappIcon::~WebappIcon() = default;
+
+void WebappIcon::AddUsage(webapk::Image::Usage usage) {
+  usages_.insert(usage);
+}
+
+int WebappIcon::GetIdealSizeInPx() const {
+  // The ideal size is the biggest one this icon serves.
+  int ideal_size = 0;
+  for (const auto& usage : usages_) {
+    ideal_size = std::max(
+        ideal_size,
+        WebappsIconUtils::GetIdealIconSizeForIconType(usage, purpose_));
+  }
+  return ideal_size;
+}
+
+}  // namespace webapps
diff --git a/components/webapps/browser/android/webapp_icon.h b/components/webapps/browser/android/webapp_icon.h
new file mode 100644
index 0000000..a08e1bb
--- /dev/null
+++ b/components/webapps/browser/android/webapp_icon.h
@@ -0,0 +1,40 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPP_ICON_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPP_ICON_H_
+
+#include <string>
+#include "components/webapk/webapk.pb.h"
+#include "url/gurl.h"
+
+namespace webapps {
+
+// Information related to WebAPK icon
+class WebappIcon {
+ public:
+  explicit WebappIcon(const GURL& icon_url);
+  explicit WebappIcon(const GURL& icon_url,
+                      bool is_maskable,
+                      webapk::Image::Usage usage);
+
+  WebappIcon(const WebappIcon&);
+  WebappIcon& operator=(const WebappIcon&);
+  ~WebappIcon();
+
+  const GURL url() const { return url_; }
+
+  void AddUsage(webapk::Image::Usage);
+
+  int GetIdealSizeInPx() const;
+
+ private:
+  GURL url_;
+  webapk::Image::Purpose purpose_;
+  std::set<webapk::Image::Usage> usages_;
+};
+
+}  // namespace webapps
+
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPP_ICON_H_
diff --git a/components/webapps/browser/android/webapps_icon_utils.cc b/components/webapps/browser/android/webapps_icon_utils.cc
index ed6b175..3abe9b3 100644
--- a/components/webapps/browser/android/webapps_icon_utils.cc
+++ b/components/webapps/browser/android/webapps_icon_utils.cc
@@ -94,6 +94,25 @@
   return g_ideal_shortcut_icon_size;
 }
 
+int WebappsIconUtils::GetIdealIconSizeForIconType(
+    webapk::Image::Usage usage,
+    webapk::Image::Purpose purpose) {
+  switch (usage) {
+    case webapk::Image::PRIMARY_ICON:
+      if (purpose == webapk::Image::MASKABLE) {
+        return GetIdealAdaptiveLauncherIconSizeInPx();
+      } else {
+        return GetIdealHomescreenIconSizeInPx();
+      }
+    case webapk::Image::SPLASH_ICON:
+      return GetIdealSplashImageSizeInPx();
+    case webapk::Image::SHORTCUT_ICON:
+      return GetIdealShortcutIconSizeInPx();
+    default:
+      return 0;
+  }
+}
+
 bool WebappsIconUtils::DoesAndroidSupportMaskableIcons() {
   return base::android::BuildInfo::GetInstance()->sdk_int() >=
          base::android::SDK_VERSION_OREO;
diff --git a/components/webapps/browser/android/webapps_icon_utils.h b/components/webapps/browser/android/webapps_icon_utils.h
index d8bfa68..7693069 100644
--- a/components/webapps/browser/android/webapps_icon_utils.h
+++ b/components/webapps/browser/android/webapps_icon_utils.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_ICON_UTILS_H_
 
 #include "base/android/scoped_java_ref.h"
+#include "components/webapk/webapk.pb.h"
 
 class SkBitmap;
 class GURL;
@@ -40,6 +41,10 @@
   // Returns the ideal size for a shortcut icon of a WebAPK.
   static int GetIdealShortcutIconSizeInPx();
 
+  // Returns the ideal size for a WebAPK icon of specific type
+  static int GetIdealIconSizeForIconType(webapk::Image::Usage usage,
+                                         webapk::Image::Purpose purpose);
+
   // Returns if the Android version supports Adaptive Icon (i.e. API level >=
   // 26)
   static bool DoesAndroidSupportMaskableIcons();
diff --git a/components/zucchini/io_utils.h b/components/zucchini/io_utils.h
index 69fc613..1af533f6 100644
--- a/components/zucchini/io_utils.h
+++ b/components/zucchini/io_utils.h
@@ -7,13 +7,13 @@
 
 #include <stdint.h>
 
-#include <cctype>
 #include <istream>
 #include <ostream>
 #include <sstream>
 #include <string>
 
 #include "base/memory/raw_ref.h"
+#include "base/strings/string_util.h"
 
 namespace zucchini {
 
@@ -126,7 +126,7 @@
   StrictUInt(const StrictUInt&) = default;
 
   friend std::istream& operator>>(std::istream& istr, StrictUInt<T> obj) {
-    if (!istr.fail() && !::isdigit(istr.peek())) {
+    if (!istr.fail() && !base::IsAsciiDigit(istr.peek())) {
       istr.setstate(std::ios_base::failbit);
       return istr;
     }
diff --git a/content/app/DEPS b/content/app/DEPS
index f98664a5..a34416c4 100644
--- a/content/app/DEPS
+++ b/content/app/DEPS
@@ -12,6 +12,7 @@
   # For loading V8's initial snapshot from external files.
   "+gin/public/isolate_holder.h",
   "+gin/public/snapshot_fd_data.h",
+  "+gin/thread_isolation.h",
   "+gin/v8_initializer.h",
   "+services/network/public/cpp/features.h",
   "+services/resource_coordinator/public",
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 38c5f465..fa26be0 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -92,6 +92,7 @@
 #include "content/public/utility/content_utility_client.h"
 #include "content/renderer/in_process_renderer_thread.h"
 #include "content/utility/in_process_utility_thread.h"
+#include "gin/thread_isolation.h"
 #include "gin/v8_initializer.h"
 #include "media/base/media.h"
 #include "media/media_buildflags.h"
@@ -998,6 +999,13 @@
 
   delegate_->PreSandboxStartup();
 
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  // instantiate the ThreadIsolatedAllocator before we spawn threads
+  if (process_type == switches::kRendererProcess) {
+    gin::GetThreadIsolationData().InitializeBeforeThreadCreation();
+  }
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
 #if BUILDFLAG(IS_WIN)
   if (!sandbox::policy::Sandbox::Initialize(
           sandbox::policy::SandboxTypeFromCommandLine(command_line),
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index 7005fc4..6f45234 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -1602,8 +1602,8 @@
 
   std::vector<std::wstring> paragraphs = {
       L"start",
-      L"text with [:before] and [:after]content, then a",
-      L"bold element with a [block]before content then a italic",
+      L"text with [:before] and [:after]content, then a\n\xFFFC",
+      L"bold element with a [block]before content then a italic\n\xFFFC",
       L"element with a [block] after content",
       L"end",
   };
@@ -1964,7 +1964,7 @@
 
   std::vector<std::wstring> paragraphs = {
       L"start",
-      L"text with [:before] and [:after]content, then a",
+      L"text with [:before] and [:after]content, then a\n\xFFFC",
       L"bold element",
   };
 
diff --git a/content/browser/accessibility/ax_platform_node_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_win_browsertest.cc
index cab493b..9db86f2 100644
--- a/content/browser/accessibility/ax_platform_node_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_win_browsertest.cc
@@ -271,7 +271,7 @@
   LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
       <!DOCTYPE html>
       <html>
-        <body>
+        <body role="none">
           <dialog open>Example Text</dialog>
         </body>
       </html>
@@ -287,7 +287,7 @@
   LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
       <!DOCTYPE html>
       <html>
-        <body>
+        <body role="none">
           <dialog open aria-modal="false">Example Text</dialog>
         </body>
       </html>
@@ -303,7 +303,7 @@
   LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
       <!DOCTYPE html>
       <html>
-        <body>
+        <body role="none">
           <dialog open aria-modal="true">Example Text</dialog>
         </body>
       </html>
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
index 4ab68fe..10e78fc 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
@@ -317,9 +317,12 @@
   EXPECT_FALSE(IsHttpAuthCacheSet());
 }
 
-// Disabled. See https://crbug.com/1444976
 IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverImplBrowserTest,
-                       DISABLED_ClearBackForwardCacheEntries) {
+                       ClearBackForwardCacheEntries) {
+  if (!content::BackForwardCache::IsBackForwardCacheFeatureEnabled()) {
+    return;
+  }
+
   GURL url_1 = ssl_server().GetURL("/title1.html");
   GURL url_2 = ssl_server().GetURL("/title2.html");
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 9f7348d..e880b2e 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -3962,7 +3962,8 @@
   NavigatePrimaryPage(kPrerenderingUrl);
   base::Value::Dict result =
       WaitForNotification("Preload.prerenderAttemptCompleted", true);
-  EXPECT_THAT(*result.FindString("finalStatus"), Eq("TriggerDestroyed"));
+  EXPECT_THAT(*result.FindString("finalStatus"),
+              Eq("OtherPrerenderedPageActivated"));
 
   // TODO(crbug/1332386): Verifies that multiple activations can be received
   // properly when crbug/1350676 is ready. kPrerenderingUrl2 should be canceled
diff --git a/content/browser/devtools/protocol/preload_handler.cc b/content/browser/devtools/protocol/preload_handler.cc
index c726695c..b3c2020 100644
--- a/content/browser/devtools/protocol/preload_handler.cc
+++ b/content/browser/devtools/protocol/preload_handler.cc
@@ -162,6 +162,12 @@
       return Preload::PrerenderFinalStatusEnum::MemoryPressureOnTrigger;
     case PrerenderFinalStatus::kMemoryPressureAfterTriggered:
       return Preload::PrerenderFinalStatusEnum::MemoryPressureAfterTriggered;
+    case PrerenderFinalStatus::kSpeculationRuleRemoved:
+      return Preload::PrerenderFinalStatusEnum::SpeculationRuleRemoved;
+    case PrerenderFinalStatus::kTriggerPageNavigated:
+      return Preload::PrerenderFinalStatusEnum::TriggerPageNavigated;
+    case PrerenderFinalStatus::kOtherPrerenderedPageActivated:
+      return Preload::PrerenderFinalStatusEnum::OtherPrerenderedPageActivated;
   }
 }
 
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index a286513..936cf62 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -183,7 +183,12 @@
           /* screenshot_height */ 40);
 }
 
-IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, DarkModeTextSelection) {
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_DarkModeTextSelection DISABLED_DarkModeTextSelection
+#else
+#define MAYBE_DarkModeTextSelection DarkModeTextSelection
+#endif
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, MAYBE_DarkModeTextSelection) {
 #if BUILDFLAG(IS_MAC)
   if (!MacOSVersionSupportsDarkMode())
     return;
diff --git a/content/browser/media/capture/OWNERS b/content/browser/media/capture/OWNERS
index b79d8b0..f161c6b8 100644
--- a/content/browser/media/capture/OWNERS
+++ b/content/browser/media/capture/OWNERS
@@ -2,6 +2,5 @@
 jophba@chromium.org
 alcooper@chromium.org
 sergeyu@chromium.org
-wez@chromium.org
 
 per-file web_contents_*=ilnik@chromium.org
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index ddaa024..1b6d8b50 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "content/browser/network_service_instance_impl.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -1667,6 +1668,45 @@
   }
 }
 
+#if BUILDFLAG(IS_ANDROID)
+class EmptyNetworkServiceTest : public ContentBrowserTest {
+ public:
+  EmptyNetworkServiceTest() {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{features::kNetworkServiceInProcess, {}},
+         {network::features::kNetworkServiceEmptyOutOfProcess, {}}},
+        {});
+  }
+  EmptyNetworkServiceTest(const EmptyNetworkServiceTest&) = delete;
+  EmptyNetworkServiceTest& operator=(const EmptyNetworkServiceTest&) = delete;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(EmptyNetworkServiceTest, Base) {
+  // This test is only for high-RAM device to create another process.
+  if (!IsInProcessNetworkService()) {
+    GTEST_SKIP();
+  }
+
+  // Check if EmptyNetworkService is available.
+  network::mojom::EmptyNetworkService* empty_network_service =
+      GetEmptyNetworkServiceForTesting();
+  DCHECK(empty_network_service);
+  const int32_t kExpected = 42;
+  int32_t value = 0;
+  base::RunLoop loop;
+  empty_network_service->Ping(kExpected,
+                              base::BindLambdaForTesting([&](int32_t val) {
+                                value = val;
+                                loop.Quit();
+                              }));
+  loop.Run();
+  EXPECT_EQ(kExpected, value);
+}
+#endif
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc
index 0a29375..d5c4405f 100644
--- a/content/browser/network_service_instance_impl.cc
+++ b/content/browser/network_service_instance_impl.cc
@@ -32,7 +32,6 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/buildflags.h"
@@ -110,6 +109,15 @@
 bool g_force_create_network_service_directly = false;
 mojo::Remote<network::mojom::NetworkService>* g_network_service_remote =
     nullptr;
+#if BUILDFLAG(IS_ANDROID)
+mojo::Remote<network::mojom::EmptyNetworkService>*
+    g_empty_network_service_remote = nullptr;
+bool IsEmptyNetworkServiceEnabledForUMA() {
+  return IsInProcessNetworkService() &&
+         base::FeatureList::IsEnabled(
+             network::features::kNetworkServiceEmptyOutOfProcess);
+}
+#endif
 network::NetworkConnectionTracker* g_network_connection_tracker;
 bool g_network_service_is_responding = false;
 base::Time g_last_network_service_crash;
@@ -365,6 +373,21 @@
   GetNetworkTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&CreateInProcessNetworkServiceOnThread,
                                 std::move(receiver)));
+#if BUILDFLAG(IS_ANDROID)
+  if (IsEmptyNetworkServiceEnabledForUMA()) {
+    if (!g_empty_network_service_remote) {
+      g_empty_network_service_remote =
+          new mojo::Remote<network::mojom::EmptyNetworkService>;
+    }
+    g_empty_network_service_remote->reset();
+    mojo::PendingReceiver<network::mojom::EmptyNetworkService> empty_receiver =
+        g_empty_network_service_remote->BindNewPipeAndPassReceiver();
+    ServiceProcessHost::Launch(std::move(empty_receiver),
+                               ServiceProcessHost::Options()
+                                   .WithDisplayName(u"Empty Network Service")
+                                   .Pass());
+  }
+#endif
 }
 
 network::mojom::NetworkServiceParamsPtr CreateNetworkServiceParams() {
@@ -673,6 +696,13 @@
   return g_network_service_remote->get();
 }
 
+#if BUILDFLAG(IS_ANDROID)
+network::mojom::EmptyNetworkService* GetEmptyNetworkServiceForTesting() {
+  DCHECK(IsEmptyNetworkServiceEnabledForUMA());
+  return g_empty_network_service_remote->get();
+}
+#endif
+
 base::CallbackListSubscription RegisterNetworkServiceCrashHandler(
     base::RepeatingClosure handler) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -751,6 +781,12 @@
     g_in_process_instance = nullptr;
   }
   GetNetworkTaskRunnerStorage().reset();
+
+#if BUILDFLAG(IS_ANDROID)
+  if (IsEmptyNetworkServiceEnabledForUMA() && g_empty_network_service_remote) {
+    g_empty_network_service_remote->reset();
+  }
+#endif
 }
 
 namespace {
diff --git a/content/browser/network_service_instance_impl.h b/content/browser/network_service_instance_impl.h
index 206ac659..9a616a4 100644
--- a/content/browser/network_service_instance_impl.h
+++ b/content/browser/network_service_instance_impl.h
@@ -7,8 +7,15 @@
 
 #include "base/callback_list.h"
 #include "base/functional/callback.h"
+#include "build/build_config.h"
 #include "content/common/content_export.h"
 
+#if BUILDFLAG(IS_ANDROID)
+namespace network::mojom {
+class EmptyNetworkService;
+}  // namespace network::mojom
+#endif
+
 namespace content {
 
 // Creates the network::NetworkService object on the IO thread directly instead
@@ -43,6 +50,11 @@
 // process one, allowing it to shut down.
 CONTENT_EXPORT void ShutDownNetworkService();
 
+#if BUILDFLAG(IS_ANDROID)
+CONTENT_EXPORT network::mojom::EmptyNetworkService*
+GetEmptyNetworkServiceForTesting();
+#endif
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_NETWORK_SERVICE_INSTANCE_IMPL_H_
diff --git a/content/browser/preloading/prefetch/OWNERS b/content/browser/preloading/prefetch/OWNERS
index 0b3ac7d..9635927 100644
--- a/content/browser/preloading/prefetch/OWNERS
+++ b/content/browser/preloading/prefetch/OWNERS
@@ -1 +1,5 @@
-curranmax@chromium.org
\ No newline at end of file
+curranmax@chromium.org
+isaboori@chromium.org
+liviutinta@chromium.org
+hiroshige@chromium.org
+kouhei@chromium.org
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index 8ab4892..821efa2 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -1395,7 +1395,8 @@
   host_observer.WaitForDestroyed();
   EXPECT_EQ(GetHostForUrl(kPrerenderingUrl),
             RenderFrameHost::kNoFrameTreeNodeId);
-  ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kTriggerDestroyed);
+  ExpectFinalStatusForSpeculationRule(
+      PrerenderFinalStatus::kSpeculationRuleRemoved);
 }
 
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
@@ -5017,7 +5018,7 @@
       PrerenderFinalStatus::kActivated, 1);
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
-      PrerenderFinalStatus::kTriggerDestroyed, 2);
+      PrerenderFinalStatus::kOtherPrerenderedPageActivated, 2);
 }
 
 // Tests that a cancelled request in the pending queue is skipped and the next
@@ -5072,7 +5073,7 @@
   // The first prerender is destroyed by SpeculationHostImpl.
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
-      PrerenderFinalStatus::kTriggerDestroyed, 1);
+      PrerenderFinalStatus::kOtherPrerenderedPageActivated, 1);
 
   // The second prerender is destroyed directly.
   histogram_tester().ExpectBucketCount(
@@ -5168,7 +5169,7 @@
   // The first prerender was destroyed by SpeculationHostImpl.
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
-      PrerenderFinalStatus::kTriggerDestroyed, 1);
+      PrerenderFinalStatus::kTriggerPageNavigated, 1);
   // The second prerender is destroyed since activation navigation is requested
   // while it's still pending.
   histogram_tester().ExpectBucketCount(
@@ -5449,7 +5450,7 @@
   // The first prerender should be cancelled by the trigger.
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
-      PrerenderFinalStatus::kTriggerDestroyed, 1);
+      PrerenderFinalStatus::kSpeculationRuleRemoved, 1);
   // The second prerender should be successfully activated.
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
@@ -7553,7 +7554,17 @@
   // initial page was in the back/forward cache.
   prerender_observer.WaitForDestroyed();
   EXPECT_FALSE(HasHostForUrl(kPrerenderingUrl));
-  ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kTriggerDestroyed);
+
+  switch (GetParam()) {
+    case BackForwardCacheType::kDisabled:
+      ExpectFinalStatusForSpeculationRule(
+          PrerenderFinalStatus::kTriggerDestroyed);
+      break;
+    case BackForwardCacheType::kEnabled:
+      ExpectFinalStatusForSpeculationRule(
+          PrerenderFinalStatus::kTriggerPageNavigated);
+      break;
+  }
 }
 
 // Tests that a trigger page destroys a prerendered page when it navigates back
@@ -7600,7 +7611,17 @@
   // next page was in the back/forward cache.
   prerender_observer.WaitForDestroyed();
   EXPECT_FALSE(HasHostForUrl(kPrerenderingUrl));
-  ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kTriggerDestroyed);
+
+  switch (GetParam()) {
+    case BackForwardCacheType::kDisabled:
+      ExpectFinalStatusForSpeculationRule(
+          PrerenderFinalStatus::kTriggerDestroyed);
+      break;
+    case BackForwardCacheType::kEnabled:
+      ExpectFinalStatusForSpeculationRule(
+          PrerenderFinalStatus::kTriggerPageNavigated);
+      break;
+  }
 }
 
 // Tests that PrerenderHostRegistry can hold up to two prerendering for the
@@ -8015,7 +8036,7 @@
       PrerenderFinalStatus::kMemoryLimitExceeded, 0);
 
   // Activate one of the prerendered pages. This should cancel the other
-  // prerendered as kTriggerDestroyed.
+  // prerendered pages.
   NavigatePrimaryPage(urls[0]);
   ASSERT_EQ(web_contents()->GetLastCommittedURL(), urls[0]);
   histogram_tester().ExpectBucketCount(
@@ -8023,7 +8044,7 @@
       PrerenderFinalStatus::kActivated, 1);
   histogram_tester().ExpectBucketCount(
       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
-      PrerenderFinalStatus::kTriggerDestroyed, 2);
+      PrerenderFinalStatus::kOtherPrerenderedPageActivated, 2);
 }
 
 // Tests that cross-site urls cannot be prerendered.
diff --git a/content/browser/preloading/prerender/prerender_final_status.h b/content/browser/preloading/prerender/prerender_final_status.h
index 3960a4c..9c255c64 100644
--- a/content/browser/preloading/prerender/prerender_final_status.h
+++ b/content/browser/preloading/prerender/prerender_final_status.h
@@ -114,7 +114,14 @@
   kMemoryPressureOnTrigger = 67,
   kMemoryPressureAfterTriggered = 68,
 
-  kMaxValue = kMemoryPressureAfterTriggered,
+  // A trigger page removed a prerendering URL from
+  // <script type="speculationrules">.
+  kSpeculationRuleRemoved = 69,
+
+  kTriggerPageNavigated = 70,
+  kOtherPrerenderedPageActivated = 71,
+
+  kMaxValue = kOtherPrerenderedPageActivated,
 };
 
 // Helper method to convert PrerenderFinalStatus to PreloadingFailureReason.
diff --git a/content/browser/preloading/prerender/prerender_host.cc b/content/browser/preloading/prerender/prerender_host.cc
index 7951d24..729097a 100644
--- a/content/browser/preloading/prerender/prerender_host.cc
+++ b/content/browser/preloading/prerender/prerender_host.cc
@@ -33,7 +33,6 @@
 #include "url/origin.h"
 
 namespace content {
-
 namespace {
 
 bool AreHttpRequestHeadersCompatible(
@@ -79,18 +78,12 @@
   prerender_headers.RemoveHeader("sec-ch-viewport-height");
   potential_activation_headers.RemoveHeader("sec-ch-viewport-height");
 
-  // Compare headers in serialized strings. The spec doesn't require serialized
-  // string matches, but practically Chrome generates headers in a decisive way,
-  // i.e. in the same order and cases. So we can expect serialized string
-  // comparisons just work. We ensure this assumption through the metric we
-  // handled in AnalyzePrerenderActivationHeader.
-  if (prerender_headers.ToString() == potential_activation_headers.ToString()) {
+  if (PrerenderHost::IsActivationHeaderMatch(potential_activation_headers,
+                                             prerender_headers)) {
     return true;
   }
 
   // The headers mismatch. Analyze the headers asynchronously.
-  // TODO(https://crbug.com/1378921): This is only used to detect if prerender
-  // fails to set headers correctly. Remove this logic after we draw the
   // conclusion.
   base::ThreadPool::PostTask(
       FROM_HERE, {base::TaskPriority::BEST_EFFORT},
@@ -192,6 +185,42 @@
   frame_tree_node_id_ = frame_tree_->root()->frame_tree_node_id();
 }
 
+// static
+bool PrerenderHost::IsActivationHeaderMatch(
+    const net::HttpRequestHeaders& potential_activation_headers,
+    const net::HttpRequestHeaders& prerender_headers) {
+  // The numbers of headers are different.
+  if (potential_activation_headers.GetHeaderVector().size() !=
+      prerender_headers.GetHeaderVector().size()) {
+    return false;
+  }
+
+  // Normalize the headers.
+  using HeaderPair = net::HttpRequestHeaders::HeaderKeyValuePair;
+  auto cmp = [](const HeaderPair& a, const HeaderPair& b) {
+    return a.key < b.key;
+  };
+  auto lower_case = [](HeaderPair& x) { x.key = base::ToLowerASCII(x.key); };
+  auto same_predicate = [](const HeaderPair& a, const HeaderPair& b) {
+    return a.key == b.key && base::EqualsCaseInsensitiveASCII(a.value, b.value);
+  };
+  std::vector<HeaderPair> potential_header_list(
+      potential_activation_headers.GetHeaderVector());
+  std::vector<HeaderPair> prerender_header_list(
+      prerender_headers.GetHeaderVector());
+  std::for_each(potential_header_list.begin(), potential_header_list.end(),
+                lower_case);
+  std::for_each(prerender_header_list.begin(), prerender_header_list.end(),
+                lower_case);
+  std::sort(potential_header_list.begin(), potential_header_list.end(), cmp);
+  std::sort(prerender_header_list.begin(), prerender_header_list.end(), cmp);
+
+  // The two vectors should be exactly the same if the headers are the same.
+  return std::equal(potential_header_list.begin(), potential_header_list.end(),
+                    prerender_header_list.begin(), prerender_header_list.end(),
+                    same_predicate);
+}
+
 PrerenderHost::~PrerenderHost() {
   for (auto& observer : observers_) {
     observer.OnHostDestroyed(
@@ -939,13 +968,6 @@
   attempt_->SetTriggeringOutcome(outcome);
 }
 
-void PrerenderHost::SetEligibility(PreloadingEligibility eligibility) {
-  if (!attempt_)
-    return;
-
-  attempt_->SetEligibility(eligibility);
-}
-
 void PrerenderHost::SetFailureReason(PrerenderFinalStatus status) {
   switch (status) {
     // When adding a new failure reason, consider whether it should be
@@ -959,6 +981,9 @@
     case PrerenderFinalStatus::kActivatedBeforeStarted:
     case PrerenderFinalStatus::kTabClosedByUserGesture:
     case PrerenderFinalStatus::kTabClosedWithoutUserGesture:
+    case PrerenderFinalStatus::kSpeculationRuleRemoved:
+    case PrerenderFinalStatus::kTriggerPageNavigated:
+    case PrerenderFinalStatus::kOtherPrerenderedPageActivated:
       return;
     case PrerenderFinalStatus::kDestroyed:
     case PrerenderFinalStatus::kLowEndDevice:
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index 5847a19..3bf6061 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -102,6 +102,14 @@
   static PrerenderHost* GetPrerenderHostFromFrameTreeNode(
       FrameTreeNode& frame_tree_node);
 
+  // Checks whether two headers are the same in a case-insensitive and
+  // order-insensitive way.
+  // TODO(https://crbug.com/1443922): Migrate this method into
+  // `HttpRequestHeaders`.
+  static bool IsActivationHeaderMatch(
+      const net::HttpRequestHeaders& potential_activation_headers,
+      const net::HttpRequestHeaders& prerender_headers);
+
   PrerenderHost(const PrerenderAttributes& attributes,
                 WebContentsImpl& web_contents,
                 base::WeakPtr<PreloadingAttempt> attempt);
@@ -277,7 +285,6 @@
   // PreloadingFailureReason for PreloadingAttempt associated with this
   // PrerenderHost.
   void SetTriggeringOutcome(PreloadingTriggeringOutcome outcome);
-  void SetEligibility(PreloadingEligibility eligibility);
   void SetFailureReason(PrerenderFinalStatus status);
 
   ActivationNavigationParamsMatch
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc
index b16b6420..39817194 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.cc
+++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -1270,9 +1270,9 @@
   } else {
     CHECK(prerender_new_tab_handle_by_frame_tree_node_id_.empty());
   }
-  CancelHosts(
-      cancelled_prerenders,
-      PrerenderCancellationReason(PrerenderFinalStatus::kTriggerDestroyed));
+  CancelHosts(cancelled_prerenders,
+              PrerenderCancellationReason(
+                  PrerenderFinalStatus::kOtherPrerenderedPageActivated));
   pending_prerenders_.clear();
 
   return host->frame_tree_node_id();
diff --git a/content/browser/preloading/prerender/prerender_host_unittest.cc b/content/browser/preloading/prerender/prerender_host_unittest.cc
index ed38085c..59d70ae 100644
--- a/content/browser/preloading/prerender/prerender_host_unittest.cc
+++ b/content/browser/preloading/prerender/prerender_host_unittest.cc
@@ -34,6 +34,40 @@
 namespace {
 
 using ::testing::_;
+
+TEST(IsActivationHeaderMatchTest, OrderInsensitive) {
+  net::HttpRequestHeaders prerender_headers;
+  prerender_headers.AddHeadersFromString(
+      "name1: value1 \r\n name2: value2 \r\n name3:value3");
+  net::HttpRequestHeaders potential_activation_headers;
+  potential_activation_headers.AddHeadersFromString(
+      "name2: value2 \r\n name3:value3  \r\n name1: value1 ");
+  EXPECT_TRUE(PrerenderHost::IsActivationHeaderMatch(
+      potential_activation_headers, prerender_headers));
+}
+
+TEST(IsActivationHeaderMatchTest, KeyCaseInsensitive) {
+  net::HttpRequestHeaders prerender_headers;
+  prerender_headers.AddHeadersFromString(
+      "NAME1: value1 \r\n name2: value2 \r\n name3:value3");
+  net::HttpRequestHeaders potential_activation_headers;
+  potential_activation_headers.AddHeadersFromString(
+      "name1: value1 \r\n name2: value2  \r\n name3: value3 ");
+  EXPECT_TRUE(PrerenderHost::IsActivationHeaderMatch(
+      potential_activation_headers, prerender_headers));
+}
+
+TEST(IsActivationHeaderMatchTest, ValueCaseInsensitive) {
+  net::HttpRequestHeaders prerender_headers;
+  prerender_headers.AddHeadersFromString(
+      "name1: value1 \r\n name2: value2 \r\n name3:value3");
+  net::HttpRequestHeaders potential_activation_headers;
+  potential_activation_headers.AddHeadersFromString(
+      "name1: value1 \r\n name2: VALUE2  \r\n name3: value3 ");
+  EXPECT_TRUE(PrerenderHost::IsActivationHeaderMatch(
+      potential_activation_headers, prerender_headers));
+}
+
 using ExpectedReadyForActivationState =
     base::StrongAlias<class ExpectedReadyForActivationStateType, bool>;
 
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 1caefef..1c08e95 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -6,7 +6,6 @@
 
 #include "content/browser/preloading/preloading.h"
 #include "content/browser/preloading/prerender/prerender_attributes.h"
-#include "content/browser/preloading/prerender/prerender_final_status.h"
 #include "content/browser/preloading/prerender/prerender_host_registry.h"
 #include "content/browser/preloading/prerender/prerender_metrics.h"
 #include "content/browser/preloading/prerender/prerender_navigation_utils.h"
@@ -48,7 +47,7 @@
 
 PrerendererImpl::~PrerendererImpl() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CancelStartedPrerenders();
+  CancelStartedPrerenders(PrerenderFinalStatus::kTriggerDestroyed);
 }
 
 void PrerendererImpl::PrimaryPageChanged(Page& page) {
@@ -61,7 +60,7 @@
   // before the next primary page swaps in so that the next page can trigger a
   // new prerender without hitting the max number of running prerenders.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CancelStartedPrerenders();
+  CancelStartedPrerenders(PrerenderFinalStatus::kTriggerPageNavigated);
 }
 
 // TODO(isaboori) Part of the logic in |ProcessCandidatesForPrerender| method is
@@ -148,9 +147,9 @@
     started_it = equal_prerender_end;
   }
 
-  registry_->CancelHosts(
-      removed_prerender_rules,
-      PrerenderCancellationReason(PrerenderFinalStatus::kTriggerDestroyed));
+  registry_->CancelHosts(removed_prerender_rules,
+                         PrerenderCancellationReason(
+                             PrerenderFinalStatus::kSpeculationRuleRemoved));
   {
     base::flat_set<int> removed_prerender_rules_set(
         removed_prerender_rules.begin(), removed_prerender_rules.end());
@@ -282,15 +281,15 @@
   return begin != end;
 }
 
-void PrerendererImpl::CancelStartedPrerenders() {
+void PrerendererImpl::CancelStartedPrerenders(
+    PrerenderFinalStatus final_status) {
   if (registry_) {
     std::vector<int> started_prerender_ids;
     for (auto& prerender_info : started_prerenders_) {
       started_prerender_ids.push_back(prerender_info.prerender_host_id);
     }
-    registry_->CancelHosts(
-        started_prerender_ids,
-        PrerenderCancellationReason(PrerenderFinalStatus::kTriggerDestroyed));
+    registry_->CancelHosts(started_prerender_ids,
+                           PrerenderCancellationReason(final_status));
   }
 
   started_prerenders_.clear();
diff --git a/content/browser/preloading/prerenderer_impl.h b/content/browser/preloading/prerenderer_impl.h
index aafa90a..f5566ec 100644
--- a/content/browser/preloading/prerenderer_impl.h
+++ b/content/browser/preloading/prerenderer_impl.h
@@ -5,13 +5,14 @@
 #ifndef CONTENT_BROWSER_PRELOADING_PRERENDERER_IMPL_H_
 #define CONTENT_BROWSER_PRELOADING_PRERENDERER_IMPL_H_
 
+#include "content/browser/preloading/prerender/prerender_final_status.h"
 #include "content/browser/preloading/prerenderer.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
 
-class PrerenderHostRegistry;
 class Page;
+class PrerenderHostRegistry;
 
 // Handles speculation-rules based prerenders.
 class CONTENT_EXPORT PrerendererImpl : public Prerenderer, WebContentsObserver {
@@ -32,7 +33,7 @@
   bool ShouldWaitForPrerenderResult(const GURL& url) override;
 
  private:
-  void CancelStartedPrerenders();
+  void CancelStartedPrerenders(PrerenderFinalStatus final_status);
 
   // This is kept sorted by URL.
   struct PrerenderInfo;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 6a4288d6..5d513ca4 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4081,7 +4081,11 @@
 }
 
 bool RenderFrameHostImpl::IsThirdPartyStoragePartitioningEnabled(
-    RenderFrameHostImpl* main_frame_for_storage_partitioning) {
+    const url::Origin& new_rfh_origin) {
+  const std::vector<RenderFrameHostImpl*> ancestor_chain =
+      GetAncestorChainForStorageKeyCalculation(new_rfh_origin);
+  RenderFrameHostImpl* main_frame_for_storage_partitioning =
+      ancestor_chain.back();
   // If we're in the main frame the state of third-party storage partitioning
   // doesn't matter as the StorageKey will be first-party no matter what.
   if (main_frame_for_storage_partitioning == this) {
@@ -4100,6 +4104,19 @@
           .IsDisableThirdPartyStoragePartitioningEnabled()) {
     return false;
   }
+  // If the deprecation trial is enabled for this third-party frame or parent
+  // frame we have directive to override the current value of
+  // net::features::ThirdPartyStoragePartitioning.
+  std::vector<url::Origin> third_party_origins = {new_rfh_origin};
+  for (size_t i = 0; i < ancestor_chain.size() - 1; ++i) {
+    third_party_origins.push_back(ancestor_chain[i]->GetLastCommittedOrigin());
+  }
+  if (rfs_document_data_for_storage_key->runtime_feature_state_read_context()
+          .IsDisableThirdPartyStoragePartitioningEnabledForThirdParty(
+              main_frame_for_storage_partitioning->GetLastCommittedOrigin(),
+              third_party_origins)) {
+    return false;
+  }
   // If the enterprise policy blocks, we have directive to override the
   // current value of net::features::ThirdPartyStoragePartitioning.
   // We can safely read the last comitted-origin (even during navigation)
@@ -4112,24 +4129,9 @@
   return blink::StorageKey::IsThirdPartyStoragePartitioningEnabled();
 }
 
-blink::StorageKey RenderFrameHostImpl::CalculateStorageKey(
-    const url::Origin& new_rfh_origin,
-    const base::UnguessableToken* nonce) {
-  if (nonce) {
-    // If the nonce isn't null, we can use the simpler form of the constructor.
-    return blink::StorageKey::CreateWithNonce(new_rfh_origin, *nonce);
-  }
-
-  if (base::FeatureList::IsEnabled(
-          features::kShouldAllowFirstPartyStorageKeyOverrideFromEmbedder) &&
-      GetContentClient()->browser()->ShouldUseFirstPartyStorageKey(
-          new_rfh_origin)) {
-    // Extension subframes should not take their top-level site into account
-    // when determining storage access. Thus, we construct all extension frame
-    // StorageKeys as first-party using the extension origin.
-    return blink::StorageKey::CreateFirstParty(new_rfh_origin);
-  }
-
+std::vector<RenderFrameHostImpl*>
+RenderFrameHostImpl::GetAncestorChainForStorageKeyCalculation(
+    const url::Origin& new_rfh_origin) {
   std::vector<RenderFrameHostImpl*> ancestor_chain;
   RenderFrameHostImpl* current = this;
   while (current) {
@@ -4137,7 +4139,7 @@
     current = current->parent_;
   }
 
-  // Make sure to always use the |new_rfh_origin| when referring to the current
+  // Make sure to always use the `new_rfh_origin` when referring to the current
   // RenderFrameHost. The origin might differ when the RenderFrameHost is reused
   // when SiteIsolation is off.
   auto origin = [&](RenderFrameHostImpl* rfh) {
@@ -4168,6 +4170,36 @@
   if (ignore_top_level_extension) {
     ancestor_chain.pop_back();
   }
+  return ancestor_chain;
+}
+
+blink::StorageKey RenderFrameHostImpl::CalculateStorageKey(
+    const url::Origin& new_rfh_origin,
+    const base::UnguessableToken* nonce) {
+  if (nonce) {
+    // If the nonce isn't null, we can use the simpler form of the constructor.
+    return blink::StorageKey::CreateWithNonce(new_rfh_origin, *nonce);
+  }
+
+  if (base::FeatureList::IsEnabled(
+          features::kShouldAllowFirstPartyStorageKeyOverrideFromEmbedder) &&
+      GetContentClient()->browser()->ShouldUseFirstPartyStorageKey(
+          new_rfh_origin)) {
+    // Extension subframes should not take their top-level site into account
+    // when determining storage access. Thus, we construct all extension frame
+    // StorageKeys as first-party using the extension origin.
+    return blink::StorageKey::CreateFirstParty(new_rfh_origin);
+  }
+
+  const std::vector<RenderFrameHostImpl*> ancestor_chain =
+      GetAncestorChainForStorageKeyCalculation(new_rfh_origin);
+
+  // Make sure to always use the `new_rfh_origin` when referring to the current
+  // RenderFrameHost. The origin might differ when the RenderFrameHost is reused
+  // when SiteIsolation is off.
+  auto origin = [&](RenderFrameHostImpl* rfh) {
+    return rfh == this ? new_rfh_origin : rfh->GetLastCommittedOrigin();
+  };
   net::SchemefulSite top_level_site(origin(ancestor_chain.back()));
 
   // Compute the AncestorChainBit. It represents whether every ancestors are
@@ -4189,7 +4221,7 @@
   // We want the RuntimeFeatureStateReadContext from the effective main frame
   // (keeping in mind `ignore_top_level_extension`).
   bool is_third_party_storage_partitioning_allowed =
-      IsThirdPartyStoragePartitioningEnabled(ancestor_chain.back());
+      IsThirdPartyStoragePartitioningEnabled(new_rfh_origin);
 
   return blink::StorageKey::Create(new_rfh_origin, top_level_site,
                                    ancestor_chain_bit,
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 119a14ab..171a001b1 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3979,13 +3979,17 @@
   // Indicates whether this frame has third-party storage
   // partitioning enabled. This depends on the deprecation trial (which can
   // block), content browser client (which can block), and base feature (which
-  // can allow/block). `main_frame_for_storage_partitioning` indicates the top
-  // most frame that third-party storage partitioning is affected by (this can
-  // be the real main frame or it could be a subframe when taking into account
-  // special embedding cases, see CalculateStorageKey's implementation for more
-  // information.)
+  // can allow/block). The `new_rfh_origin` is the same one passed into
+  // CalculateStorageKey.
   bool IsThirdPartyStoragePartitioningEnabled(
-      RenderFrameHostImpl* main_frame_for_storage_partitioning);
+      const url::Origin& new_rfh_origin);
+
+  // Returns the recursive list of parent frames starting with `this` and ending
+  // with the top-level frame, or one frame before the top-level frame if the
+  // top-level frame is an extension. The `new_rfh_origin` is the same one
+  // passed into CalculateStorageKey.
+  std::vector<RenderFrameHostImpl*> GetAncestorChainForStorageKeyCalculation(
+      const url::Origin& new_rfh_origin);
 
   // The RenderViewHost that this RenderFrameHost is associated with.
   //
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 4c2f58b..641dea27 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3379,7 +3379,6 @@
     switches::kDisableOriginTrialControlledBlinkFeatures,
     switches::kDisablePepper3DImageChromium,
     switches::kDisablePermissionsAPI,
-    switches::kDisablePPAPISharedImagesSwapChain,
     switches::kDisablePresentationAPI,
     switches::kDisableRTCSmoothnessAlgorithm,
     switches::kDisableScrollToTextFragment,
@@ -3420,7 +3419,6 @@
     switches::kFileUrlPathAlias,
     switches::kForceDeviceScaleFactor,
     switches::kForceDisplayColorProfile,
-    switches::kForceEnablePepperVideoDecoderDevAPI,
     switches::kForceGpuMemAvailableMb,
     switches::kForceHighContrast,
     switches::kForceRasterColorProfile,
diff --git a/content/browser/renderer_host/runtime_feature_state_controller_impl.cc b/content/browser/renderer_host/runtime_feature_state_controller_impl.cc
index dbdb77ee..6c153939 100644
--- a/content/browser/renderer_host/runtime_feature_state_controller_impl.cc
+++ b/content/browser/renderer_host/runtime_feature_state_controller_impl.cc
@@ -41,14 +41,17 @@
   // Perform security checks by ensuring the following:
   base::flat_map<::blink::mojom::RuntimeFeatureState, bool>
       validated_features{};
+  base::flat_map<::blink::mojom::RuntimeFeatureState, std::vector<std::string>>
+      possible_third_party_features{};
   for (const auto& feature_pair : modified_features) {
     // Ensure the tokens we received are valid for this feature and origin.
-    // TODO(https://crbug.com/1410784): add support for third-party Origin
-    // Trials in the token validation process.
     std::string feature_name;
     blink::TrialTokenValidator validator;
     bool are_tokens_valid = true;
     for (const auto& token : feature_pair.second->tokens) {
+      // Third party tokens will be rejected as invalid here. These will instead
+      // be collected in `possible_third_party_features` for later validation
+      // via Is$FEATURE$EnabledForThirdParty.
       blink::TrialTokenResult result = validator.ValidateTokenAndTrial(
           token, render_frame_host().GetLastCommittedOrigin(),
           base::Time::Now());
@@ -69,11 +72,8 @@
     // 2. The feature we received is an origin trial feature.
     // 3. The feature we received is expected in the browser process.
     if (are_tokens_valid) {
-      // TODO(https://crbug.com/1410784): Since 3p tokens are not currently
-      // supported, we cannot assume that invalid tokens are a sign of a
-      // compromised renderer.
       if (blink::origin_trials::IsTrialValid(feature_name) &&
-          blink::origin_trials::IsTrialEnabledForBrowserProcessReadWriteAccess(
+          blink::origin_trials::IsTrialEnabledForBrowserProcessReadAccess(
               feature_name)) {
         validated_features[feature_pair.first] =
             feature_pair.second->is_enabled;
@@ -84,6 +84,12 @@
             bad_message::RFSCI_BROWSER_VALIDATION_BAD_ORIGIN_TRIAL_TOKEN);
         return;
       }
+    } else if (feature_pair.second->is_enabled) {
+      // If we could not validate the tokens it's possible there's a third-party
+      // origin trial among them. In this case we should store the tokens for
+      // later validation once the potential third-party origin is known.
+      possible_third_party_features[feature_pair.first] =
+          feature_pair.second->tokens;
     }
   }
   // Apply the diff changes to the mutable RuntimeFeatureStateReadContext.
@@ -93,7 +99,7 @@
   document_data
       ->GetMutableRuntimeFeatureStateReadContext(
           base::PassKey<RuntimeFeatureStateControllerImpl>())
-      .ApplyFeatureChange(validated_features);
+      .ApplyFeatureChange(validated_features, possible_third_party_features);
 }
 
 void RuntimeFeatureStateControllerImpl::EnablePersistentTrial(
diff --git a/content/browser/service_process_host_browsertest.cc b/content/browser/service_process_host_browsertest.cc
index 5b8bae0e..26b80ea 100644
--- a/content/browser/service_process_host_browsertest.cc
+++ b/content/browser/service_process_host_browsertest.cc
@@ -19,8 +19,32 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/browser/service_process_host_passkeys.h"
+#endif
+
 namespace content {
 
+#if BUILDFLAG(IS_WIN)
+using LoadStatus = echo::mojom::EchoService::LoadStatus;
+namespace {
+// This is used as the module name to load, and to make the DLL filename.
+constexpr const wchar_t* kEchoPreloadLibrary = L"echo_preload_library";
+
+// DLL path relative to current executable.
+base::FilePath GetDllPath(std::wstring mod_name) {
+  mod_name.append(L".dll");
+  auto exe_dir = base::PathService::CheckedGet(base::BasePathKey::DIR_EXE);
+  return exe_dir.Append(mod_name);
+}
+}  // namespace
+#endif  // BUILDFLAG(IS_WIN)
+
 constexpr char kTestUrl[] = "https://foo.bar";
 
 using ServiceProcessHostBrowserTest = ContentBrowserTest;
@@ -188,4 +212,113 @@
   observer.WaitForDeath();
 }
 
+#if BUILDFLAG(IS_WIN)
+IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryNotSet) {
+  EchoServiceProcessObserver observer;
+  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
+      ServiceProcessHost::Options().Pass());
+  observer.WaitForLaunch();
+
+  base::RunLoop loop;
+  echo_service->LoadNativeLibrary(
+      GetDllPath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
+      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
+        EXPECT_EQ(LoadStatus::kFailedLoadLibrary, status);
+        EXPECT_EQ(DWORD{ERROR_ACCESS_DENIED}, result);
+        loop.Quit();
+      }));
+  loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryPreloaded) {
+  std::vector<base::FilePath> preloads;
+  preloads.push_back(GetDllPath(kEchoPreloadLibrary));
+
+  EchoServiceProcessObserver observer;
+  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
+      ServiceProcessHost::Options()
+          .WithPreloadedLibraries(
+              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
+          .Pass());
+  observer.WaitForLaunch();
+
+  base::RunLoop loop;
+  echo_service->LoadNativeLibrary(
+      GetDllPath(kEchoPreloadLibrary),
+      /*call_sec32_delayload=*/true,
+      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
+        EXPECT_EQ(LoadStatus::kSuccess, status);
+        EXPECT_EQ(0u, result);
+        loop.Quit();
+      }));
+  loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryMultiple) {
+  std::vector<base::FilePath> preloads;
+  // dbghelp is a placeholder - it will likely be loaded already - this test is
+  // validating that multiple libraries can be sent into the child.
+  preloads.push_back(GetDllPath(L"dbghelp"));
+  preloads.push_back(GetDllPath(kEchoPreloadLibrary));
+
+  EchoServiceProcessObserver observer;
+  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
+      ServiceProcessHost::Options()
+          .WithPreloadedLibraries(
+              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
+          .Pass());
+  observer.WaitForLaunch();
+
+  base::RunLoop loop;
+  echo_service->LoadNativeLibrary(
+      GetDllPath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
+      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
+        EXPECT_EQ(LoadStatus::kSuccess, status);
+        EXPECT_EQ(0u, result);
+        loop.Quit();
+      }));
+  loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryModName) {
+  std::vector<base::FilePath> preloads;
+  preloads.push_back(GetDllPath(kEchoPreloadLibrary));
+
+  EchoServiceProcessObserver observer;
+  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
+      ServiceProcessHost::Options()
+          .WithPreloadedLibraries(
+              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
+          .Pass());
+  observer.WaitForLaunch();
+
+  base::RunLoop loop;
+  // Once preloaded can people simply provide the module name?
+  echo_service->LoadNativeLibrary(
+      base::FilePath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
+      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
+        EXPECT_EQ(LoadStatus::kSuccess, status);
+        EXPECT_EQ(0u, result);
+        loop.Quit();
+      }));
+  loop.Run();
+}
+
+// This test causes a CHECK in the child at startup.
+IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryBadPath) {
+  std::vector<base::FilePath> preloads;
+  preloads.push_back(GetDllPath(L"this-is-not-a-library"));
+
+  EchoServiceProcessObserver observer;
+  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
+      ServiceProcessHost::Options()
+          .WithSite(GURL(kTestUrl))  // For WaitForCrash().
+          .WithPreloadedLibraries(
+              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
+          .Pass());
+  observer.WaitForLaunch();
+  observer.WaitForCrash();
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 }  // namespace content
diff --git a/content/browser/service_process_host_impl.cc b/content/browser/service_process_host_impl.cc
index 4d4c17b..87d865f 100644
--- a/content/browser/service_process_host_impl.cc
+++ b/content/browser/service_process_host_impl.cc
@@ -192,12 +192,19 @@
                     ? options.display_name
                     : base::UTF8ToUTF16(*receiver.interface_name()));
   host->SetMetricsName(*receiver.interface_name());
-  if (!ShouldEnableSandbox(sandbox))
+  if (!ShouldEnableSandbox(sandbox)) {
     sandbox = sandbox::mojom::Sandbox::kNoSandbox;
+  }
   host->SetSandboxType(sandbox);
   host->SetExtraCommandLineSwitches(std::move(options.extra_switches));
-  if (options.child_flags)
+  if (options.child_flags) {
     host->set_child_flags(*options.child_flags);
+  }
+#if BUILDFLAG(IS_WIN)
+  if (!options.preload_libraries.empty()) {
+    host->SetPreloadLibraries(options.preload_libraries);
+  }
+#endif  // BUILDFLAG(IS_WIN)
   host->Start();
   host->GetChildProcess()->BindServiceInterface(std::move(receiver));
 }
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 589b081..d140974 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -5092,6 +5092,7 @@
   }
 
   void SetupAndRegisterServiceWorker() {
+    RegisterRequestMonitorForRequestCount();
     RegisterRequestHandlerForSlowResponsePage();
     StartServerAndNavigateToSetup();
 
@@ -5119,6 +5120,14 @@
     return EvalJs(GetPrimaryMainFrame(), "document.body.innerText;");
   }
 
+  int GetRequestCount(const std::string& relative_url) const {
+    const auto& it = request_log_.find(relative_url);
+    if (it == request_log_.end()) {
+      return 0;
+    }
+    return it->second.size();
+  }
+
  private:
   void RegisterRequestHandlerForSlowResponsePage() {
     embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
@@ -5145,6 +5154,10 @@
             return http_response;
           }
 
+          if (base::Contains(request.GetURL().query(), "server_close_socket")) {
+            return std::make_unique<net::test_server::RawHttpResponse>("", "");
+          }
+
           const bool is_slow =
               base::Contains(request.GetURL().query(), "server_slow");
 
@@ -5170,6 +5183,16 @@
           return http_response;
         }));
   }
+  void RegisterRequestMonitorForRequestCount() {
+    embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
+        &ServiceWorkerRaceNetworkRequestBrowserTest::MonitorRequestHandler,
+        base::Unretained(this)));
+  }
+  void MonitorRequestHandler(const net::test_server::HttpRequest& request) {
+    request_log_[request.relative_url].push_back(request);
+  }
+  std::map<std::string, std::vector<net::test_server::HttpRequest>>
+      request_log_;
   base::test::ScopedFeatureList feature_list_;
 };
 
@@ -5212,7 +5235,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_NotFound) {
+                       NetworkRequest_Wins_NotFound_FetchHandler_Respond) {
   SetupAndRegisterServiceWorker();
 
   // Network request is faster, but the response is not found.
@@ -5226,6 +5249,11 @@
       1);
   EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
             GetInnerText());
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
+                       NetworkRequest_Wins_NotFound_FetchHandler_NotRespond) {
+  SetupAndRegisterServiceWorker();
 
   // If the fallback request is not found. Then expect 404.
   NavigateToURLBlockUntilNavigationsComplete(
@@ -5238,20 +5266,26 @@
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
                        NetworkRequest_Wins_FetchHandler_Fallback) {
-  SetupAndRegisterServiceWorker();
+  // If RaceNetworkRequest comes first, there is a network error, and the fetch
+  // handler result is a fallback. In this case the response from
+  // RaceNetworkRequest is not used, because we need to support the case when
+  // the fetch handler returns a meaningful response e.g. offline page.
+  //
   // This test works in the following steps.
   // 1. Start RaceNetworkRequest.
   // 2. Start service worker, and trigger fetch handler that fallback to
   //    network.
-  // 3. Cancel RaceNetworkRequest.
+  // 3. Get a network error during RaceNetworkRequest.
   // 4. Start fallback network request, neither RaceNetworkRequest nor the fetch
   //    handler is involved.
   // 5. Get the response from the fallback network request.
-  const GURL slow_url = embedded_test_server()->GetURL(
-      "/service_worker/mock_response?sw_fallback&sw_slow");
-  NavigateToURLBlockUntilNavigationsComplete(shell(), slow_url, 1);
-  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the network",
-            GetInnerText());
+  SetupAndRegisterServiceWorker();
+  const std::string relative_url =
+      "/service_worker/mock_response?server_close_socket&sw_fallback&sw_slow";
+  EXPECT_FALSE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(relative_url)));
+  // Request count should be 2 (RaceNetworkRequest + fallback request).
+  EXPECT_EQ(2, GetRequestCount(relative_url));
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
@@ -5309,13 +5343,23 @@
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
                        FetchHandler_Wins_Fallback) {
   SetupAndRegisterServiceWorker();
-  // Fetch handler will fallback. This case the response from the default
-  // fallback requset will be used. RaceNetworkRequset is not involved.
-  const GURL slow_url = embedded_test_server()->GetURL(
-      "/service_worker/mock_response?server_slow&sw_fallback");
+  // Fetch handler will fallback. This case the response from RaceNetworkRequest
+  // is returned as a final response.
+  const std::string relative_url =
+      "/service_worker/mock_response?server_slow&sw_fallback";
+  const GURL slow_url = embedded_test_server()->GetURL(relative_url);
   NavigateToURLBlockUntilNavigationsComplete(shell(), slow_url, 1);
   EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Slow response from the network",
             GetInnerText());
+  // Request count should be 1 (RaceNetworkRequest). No additional request to
+  // the server.
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+
+  // TODO(crbug.com/1420517) Ensure if the network error result is from
+  // RaceNetworkRequest. The current code only tests if the network error
+  // happens.
+  ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
+  EXPECT_FALSE(NavigateToURL(shell(), slow_url));
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
@@ -5460,13 +5504,23 @@
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
   observer.WaitUntilRunning();
-  // Fetch handler will fallback. This case the response from the default
-  // fallback requset will be used. RaceNetworkRequset is not involved.
+  // Fetch handler will fallback. This case the response from RaceNetworkRequest
+  // is returned as a final response.
+  const std::string relative_url =
+      "/service_worker/mock_response?server_slow&sw_fallback";
   EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Slow response from the network",
             EvalJs(GetPrimaryMainFrame(),
-                   "fetch('/service_worker/mock_response?"
-                   "server_slow&sw_fallback').then(response => "
-                   "response.text())"));
+                   "fetch('" + relative_url +
+                       "').then(response => response.text())"));
+  // Request count should be 1 (RaceNetworkRequest). No additional request to
+  // the server.
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+
+  // TODO(crbug.com/1420517) Ensure if the network error result is from
+  // RaceNetworkRequest. The current code only tests if the network error
+  // happens.
+  ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
+  EXPECT_FALSE(ExecJs(GetPrimaryMainFrame(), "fetch('" + relative_url + "')"));
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index e0bee95..735a896 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -412,9 +412,27 @@
       blink::ServiceWorkerStatusToString(status), "result",
       ComposeFetchEventResultString(fetch_result, *response));
 
+  // If the response of RaceNetworkRequest is already handled, discard the
+  // fetch handler result.
   if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
     return;
   }
+  // If the RaceNetworkRequest is triggered but the response is not handled
+  // yet, and the fetch handler result is FetchEventResult::kShouldFallback, ask
+  // RaceNetworkRequestURLLoaderClient to handle the response regardless of the
+  // response status not to dispatch additional network request for fallback.
+  if (dispatched_preload_type_ == DispatchedPreloadType::kRaceNetworkRequest &&
+      fetch_result ==
+          ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback) {
+    DCHECK(race_network_request_loader_client_);
+    // Don't ask RaceNetworkRequestURLLoaderClient to handle the response if the
+    // RaceNetworkRequest has already completed because the response from
+    // RaceNetworkRequest is already discarded.
+    if (!race_network_request_loader_client_->request_completed()) {
+      race_network_request_loader_client_->NotifyFetchHandlerFallback();
+      return;
+    }
+  }
   // Use the response from ServiceWorker fetch handler, and cancel the
   // connection for RaceNetworkRequest.
   // TODO(crbug.com/1420517) RaceNetworkRequrest doesn't support fallback case.
diff --git a/content/browser/smart_card/mock_smart_card_context_factory.cc b/content/browser/smart_card/mock_smart_card_context_factory.cc
index d062e59..5923c591 100644
--- a/content/browser/smart_card/mock_smart_card_context_factory.cc
+++ b/content/browser/smart_card/mock_smart_card_context_factory.cc
@@ -5,6 +5,9 @@
 #include "content/browser/smart_card/mock_smart_card_context_factory.h"
 
 using device::mojom::SmartCardCreateContextResult;
+using device::mojom::SmartCardProtocol;
+using device::mojom::SmartCardShareMode;
+using testing::_;
 
 namespace content {
 
@@ -27,4 +30,26 @@
       SmartCardCreateContextResult::NewContext(std::move(context_remote)));
 }
 
+void MockSmartCardContextFactory::ExpectConnectFakeReaderSharedT1(
+    mojo::Receiver<device::mojom::SmartCardConnection>& connection_receiver) {
+  EXPECT_CALL(*this, Connect("Fake reader", SmartCardShareMode::kShared, _, _))
+      .WillOnce([&connection_receiver](
+                    const std::string& reader,
+                    device::mojom::SmartCardShareMode share_mode,
+                    device::mojom::SmartCardProtocolsPtr preferred_protocols,
+                    SmartCardContext::ConnectCallback callback) {
+        EXPECT_FALSE(preferred_protocols->t0);
+        EXPECT_TRUE(preferred_protocols->t1);
+        EXPECT_FALSE(preferred_protocols->raw);
+
+        auto success = device::mojom::SmartCardConnectSuccess::New(
+            connection_receiver.BindNewPipeAndPassRemote(),
+            SmartCardProtocol::kT1);
+
+        std::move(callback).Run(
+            device::mojom::SmartCardConnectResult::NewSuccess(
+                std::move(success)));
+      });
+}
+
 }  // namespace content
diff --git a/content/browser/smart_card/mock_smart_card_context_factory.h b/content/browser/smart_card/mock_smart_card_context_factory.h
index e27e6eb4..c3673a5 100644
--- a/content/browser/smart_card/mock_smart_card_context_factory.h
+++ b/content/browser/smart_card/mock_smart_card_context_factory.h
@@ -41,6 +41,12 @@
                ConnectCallback callback),
               (override));
 
+  // Expect a Connect("Fake reader", kShared, kT1) call.
+  // A pending remote for the given `connection_receiver` will be passed to
+  // the call result on success.
+  void ExpectConnectFakeReaderSharedT1(
+      mojo::Receiver<device::mojom::SmartCardConnection>& connection_receiver);
+
  private:
   mojo::ReceiverSet<device::mojom::SmartCardContextFactory> receivers_;
   mojo::ReceiverSet<device::mojom::SmartCardContext> context_receivers_;
diff --git a/content/browser/smart_card/smart_card_browsertest.cc b/content/browser/smart_card/smart_card_browsertest.cc
index 8fd083a..f670062f 100644
--- a/content/browser/smart_card/smart_card_browsertest.cc
+++ b/content/browser/smart_card/smart_card_browsertest.cc
@@ -81,7 +81,28 @@
   MOCK_METHOD(void, Start, (Observer * observer, StartCallback), (override));
   MOCK_METHOD(void, Stop, (Observer * observer), (override));
 
+  void ExpectStartReturnsFakeReader() {
+    EXPECT_CALL(*this, Start(_, _))
+        .WillOnce([this](SmartCardReaderTracker::Observer* observer,
+                         SmartCardReaderTracker::StartCallback callback) {
+          StartReturnsFakeReader(observer, std::move(callback));
+        });
+  }
+
   ObserverList observer_list;
+
+ private:
+  void StartReturnsFakeReader(SmartCardReaderTracker::Observer* observer,
+                              SmartCardReaderTracker::StartCallback callback) {
+    observer_list.AddObserverIfMissing(observer);
+
+    std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
+    readers.push_back(blink::mojom::SmartCardReaderInfo::New(
+        "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
+        std::vector<uint8_t>()));
+    std::move(callback).Run(blink::mojom::SmartCardGetReadersResult::NewReaders(
+        std::move(readers)));
+  }
 };
 
 class SmartCardTestContentBrowserClient
@@ -615,22 +636,7 @@
 
   {
     InSequence s;
-
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
-
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
+    mock_tracker.ExpectStartReturnsFakeReader();
     // When the document is destroyed
     EXPECT_CALL(mock_tracker, Stop(_));
   }
@@ -669,22 +675,7 @@
 
   {
     InSequence s;
-
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
-
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
+    mock_tracker.ExpectStartReturnsFakeReader();
     // When the document is destroyed
     EXPECT_CALL(mock_tracker, Stop(_));
   }
@@ -741,37 +732,18 @@
 
   MockSmartCardReaderTracker& mock_tracker = CreateMockSmartCardReaderTracker();
 
-  {
-    InSequence s;
-
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
-
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
-    // When the document is destroyed
-    EXPECT_CALL(mock_tracker, Stop(_));
-  }
-
   MockSmartCardContextFactory& mock_context_factory =
       GetFakeSmartCardDelegate().mock_context_factory;
   std::queue<SmartCardContext::ConnectCallback> connect_callbacks;
 
-  // The first two Connect calls are queued. Only from the third call onwards
-  // are all requests answered and the qeue emptied.
   {
     InSequence s;
 
+    mock_tracker.ExpectStartReturnsFakeReader();
+
+    // The first two Connect calls are queued. Only from the third call onwards
+    // are all requests answered and the qeue emptied.
+
     EXPECT_CALL(mock_context_factory,
                 Connect("Fake reader", SmartCardShareMode::kShared, _, _))
         .Times(Exactly(2))
@@ -822,6 +794,9 @@
                 connect_callbacks.pop();
               }
             });
+
+    // When the document is destroyed
+    EXPECT_CALL(mock_tracker, Stop(_));
   }
 
   EXPECT_EQ(
@@ -866,40 +841,9 @@
   {
     InSequence s;
 
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
+    mock_tracker.ExpectStartReturnsFakeReader();
 
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
-    EXPECT_CALL(mock_context_factory,
-                Connect("Fake reader", SmartCardShareMode::kShared, _, _))
-        .WillOnce([&connection_receiver](
-                      const std::string& reader,
-                      device::mojom::SmartCardShareMode share_mode,
-                      device::mojom::SmartCardProtocolsPtr preferred_protocols,
-                      SmartCardContext::ConnectCallback callback) {
-          EXPECT_TRUE(preferred_protocols->t0);
-          EXPECT_TRUE(preferred_protocols->t1);
-          EXPECT_FALSE(preferred_protocols->raw);
-
-          auto success = device::mojom::SmartCardConnectSuccess::New(
-              connection_receiver.BindNewPipeAndPassRemote(),
-              SmartCardProtocol::kT1);
-
-          std::move(callback).Run(
-              device::mojom::SmartCardConnectResult::NewSuccess(
-                  std::move(success)));
-        });
+    mock_context_factory.ExpectConnectFakeReaderSharedT1(connection_receiver);
 
     EXPECT_CALL(mock_connection, Disconnect(SmartCardDisposition::kEject, _))
         .WillOnce([](SmartCardDisposition disposition,
@@ -924,7 +868,7 @@
       }
 
       let reader = readers[0];
-      let connection = await reader.connect("shared", ["t0", "t1"]);
+      let connection = await reader.connect("shared", ["t1"]);
 
       await connection.disconnect("eject");
 
@@ -954,40 +898,9 @@
   {
     InSequence s;
 
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
+    mock_tracker.ExpectStartReturnsFakeReader();
 
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
-    EXPECT_CALL(mock_context_factory,
-                Connect("Fake reader", SmartCardShareMode::kShared, _, _))
-        .WillOnce([&connection_receiver](
-                      const std::string& reader,
-                      device::mojom::SmartCardShareMode share_mode,
-                      device::mojom::SmartCardProtocolsPtr preferred_protocols,
-                      SmartCardContext::ConnectCallback callback) {
-          EXPECT_TRUE(preferred_protocols->t0);
-          EXPECT_TRUE(preferred_protocols->t1);
-          EXPECT_FALSE(preferred_protocols->raw);
-
-          auto success = device::mojom::SmartCardConnectSuccess::New(
-              connection_receiver.BindNewPipeAndPassRemote(),
-              SmartCardProtocol::kT1);
-
-          std::move(callback).Run(
-              device::mojom::SmartCardConnectResult::NewSuccess(
-                  std::move(success)));
-        });
+    mock_context_factory.ExpectConnectFakeReaderSharedT1(connection_receiver);
 
     EXPECT_CALL(mock_connection, Disconnect(SmartCardDisposition::kEject, _))
         .WillOnce([&disconnect_future](
@@ -1014,7 +927,7 @@
       }
 
       let reader = readers[0];
-      let connection = await reader.connect("shared", ["t0", "t1"]);
+      let connection = await reader.connect("shared", ["t1"]);
 
       // This first disconnect() call will go through but won't be finished
       // before the end of this script.
@@ -1048,40 +961,9 @@
   {
     InSequence s;
 
-    EXPECT_CALL(mock_tracker, Start(_, _))
-        .WillOnce(
-            [&mock_tracker](SmartCardReaderTracker::Observer* observer,
-                            SmartCardReaderTracker::StartCallback callback) {
-              mock_tracker.observer_list.AddObserverIfMissing(observer);
+    mock_tracker.ExpectStartReturnsFakeReader();
 
-              std::vector<blink::mojom::SmartCardReaderInfoPtr> readers;
-              readers.push_back(blink::mojom::SmartCardReaderInfo::New(
-                  "Fake reader", blink::mojom::SmartCardReaderState::kEmpty,
-                  std::vector<uint8_t>()));
-              std::move(callback).Run(
-                  blink::mojom::SmartCardGetReadersResult::NewReaders(
-                      std::move(readers)));
-            });
-
-    EXPECT_CALL(mock_context_factory,
-                Connect("Fake reader", SmartCardShareMode::kShared, _, _))
-        .WillOnce([&connection_receiver](
-                      const std::string& reader,
-                      device::mojom::SmartCardShareMode share_mode,
-                      device::mojom::SmartCardProtocolsPtr preferred_protocols,
-                      SmartCardContext::ConnectCallback callback) {
-          EXPECT_FALSE(preferred_protocols->t0);
-          EXPECT_TRUE(preferred_protocols->t1);
-          EXPECT_FALSE(preferred_protocols->raw);
-
-          auto success = device::mojom::SmartCardConnectSuccess::New(
-              connection_receiver.BindNewPipeAndPassRemote(),
-              SmartCardProtocol::kT1);
-
-          std::move(callback).Run(
-              device::mojom::SmartCardConnectResult::NewSuccess(
-                  std::move(success)));
-        });
+    mock_context_factory.ExpectConnectFakeReaderSharedT1(connection_receiver);
 
     EXPECT_CALL(mock_connection, Transmit(SmartCardProtocol::kT1, _, _))
         .WillOnce([](SmartCardProtocol protocol,
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 475614d..26e3644f 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -201,6 +201,13 @@
   extra_switches_ = std::move(switches);
 }
 
+#if BUILDFLAG(IS_WIN)
+void UtilityProcessHost::SetPreloadLibraries(
+    const std::vector<base::FilePath>& preloads) {
+  preload_libraries_ = preloads;
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
 void UtilityProcessHost::AddFileToPreload(
     std::string key,
@@ -435,11 +442,17 @@
         std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
             sandbox_type_, env_, *cmd_line);
 
+#if BUILDFLAG(IS_WIN)
+    if (!preload_libraries_.empty()) {
+      delegate->SetPreloadLibraries(preload_libraries_);
+    }
+#endif  // BUILDFLAG(IS_WIN)
+
 #if BUILDFLAG(USE_ZYGOTE)
     if (zygote_for_testing_.has_value()) {
       delegate->SetZygote(zygote_for_testing_.value());
     }
-#endif
+#endif  // BUILDFLAG(USE_ZYGOTE)
 
     process_->LaunchWithFileData(std::move(delegate), std::move(cmd_line),
                                  std::move(file_data_), true);
diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
index 65e59b1..3aafcc1 100644
--- a/content/browser/utility_process_host.h
+++ b/content/browser/utility_process_host.h
@@ -135,6 +135,12 @@
   // Provides extra switches to append to the process's command line.
   void SetExtraCommandLineSwitches(std::vector<std::string> switches);
 
+#if BUILDFLAG(IS_WIN)
+  // Specifies libraries to preload before the sandbox is locked down. Paths
+  // should be absolute.
+  void SetPreloadLibraries(const std::vector<base::FilePath>& preloads);
+#endif  // BUILDFLAG(IS_WIN)
+
 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
   // Adds to ChildProcessLauncherFileData::files_to_preload, which maps |key| ->
   // |file| in the new process's base::FileDescriptorStore.
@@ -187,6 +193,11 @@
   // Extra command line switches to append.
   std::vector<std::string> extra_switches_;
 
+#if BUILDFLAG(IS_WIN)
+  // Libraries to load before sandbox lockdown. Only used on Windows.
+  std::vector<base::FilePath> preload_libraries_;
+#endif  // BUILDFLAG(IS_WIN)
+
   // Extra files and file descriptors to preload in the new process.
   std::unique_ptr<ChildProcessLauncherFileData> file_data_;
 
diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
index aaf1549..24538d8 100644
--- a/content/browser/utility_sandbox_delegate.h
+++ b/content/browser/utility_sandbox_delegate.h
@@ -7,6 +7,7 @@
 
 #include "base/command_line.h"
 #include "base/environment.h"
+#include "base/files/file_path.h"
 #include "build/build_config.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/zygote/zygote_buildflags.h"
@@ -40,6 +41,12 @@
   bool ShouldUnsandboxedRunInJob() override;
   bool CetCompatible() override;
   bool AllowWindowsFontsDir() override;
+  bool PreSpawnTarget(sandbox::TargetPolicy* policy) override;
+  // Set preload libraries to transfer as part of the sandbox delegate data,
+  // which will used in utility_main to preload these libraries before lockdown.
+  void SetPreloadLibraries(const std::vector<base::FilePath>& preloads) {
+    preload_libraries_ = preloads;
+  }
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE)
@@ -59,6 +66,10 @@
   base::EnvironmentMap env_;
 #endif  // BUILDFLAG(IS_POSIX)
 
+#if BUILDFLAG(IS_WIN)
+  std::vector<base::FilePath> preload_libraries_;
+#endif  // BUILDFLAG(IS_WIN)
+
 #if BUILDFLAG(USE_ZYGOTE)
   absl::optional<raw_ptr<ZygoteCommunication>> zygote_;
 #endif  // BUILDFLAG(USE_ZYGOTE)
diff --git a/content/browser/utility_sandbox_delegate_win.cc b/content/browser/utility_sandbox_delegate_win.cc
index 2f69073..8ed73b5 100644
--- a/content/browser/utility_sandbox_delegate_win.cc
+++ b/content/browser/utility_sandbox_delegate_win.cc
@@ -7,9 +7,10 @@
 #include "base/check.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
+#include "base/pickle.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/services/screen_ai/buildflags/buildflags.h"
-#include "components/services/screen_ai/public/cpp/utilities.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -222,21 +223,23 @@
   if (result != sandbox::SBOX_ALL_OK)
     return false;
 
-  base::FilePath library_binary_path =
-      screen_ai::GetLatestComponentBinaryPath();
-  if (library_binary_path.empty())
-    return false;
-  DCHECK_EQ(library_binary_path.Extension(), FILE_PATH_LITERAL(".dll"));
-
-  // TODO(https://crbug.com/1278249): Preload the binary instead of giving
-  // read permission to the sandbox.
-  result = config->AddRule(sandbox::SubSystem::kFiles,
-                           sandbox::Semantics::kFilesAllowReadonly,
-                           library_binary_path.value().c_str());
-  return result == sandbox::SBOX_ALL_OK;
+  return true;
 }
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 
+// Adds preload-libraries to the delegate blob for utility_main() to access
+// before lockdown is initialized.
+void AddPreloadLibraryDelegateData(
+    sandbox::TargetPolicy* policy,
+    std::vector<base::FilePath>& preload_libraries) {
+  CHECK(!preload_libraries.empty());
+  base::Pickle pickle;
+  for (const auto& library_path : preload_libraries) {
+    library_path.WriteToPickle(&pickle);
+  }
+  policy->AddDelegateData(base::make_span(pickle.data(), pickle.size()));
+}
+
 }  // namespace
 
 std::string UtilitySandboxedProcessLauncherDelegate::GetSandboxTag() {
@@ -398,4 +401,12 @@
   }
   return false;
 }
+
+bool UtilitySandboxedProcessLauncherDelegate::PreSpawnTarget(
+    sandbox::TargetPolicy* policy) {
+  if (!preload_libraries_.empty()) {
+    AddPreloadLibraryDelegateData(policy, preload_libraries_);
+  }
+  return SandboxedProcessLauncherDelegate::PreSpawnTarget(policy);
+}
 }  // namespace content
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index 3759092..71dc39ea 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -51,21 +51,23 @@
       ServiceWorkerResourceLoader::FetchResponseFrom::kServiceWorker) {
     return;
   }
-  // If the response is not 200, use the other response from the fetch handler
-  // instead because it may have a response from the cache.
+
+  head_ = std::move(head);
+
+  // If the fetch handler result is a fallback, commit the RaceNetworkRequest
+  // response. If the result is not a fallback and the response is not 200, use
+  // the other response from the fetch handler instead because it may have a
+  // response from the cache.
   // TODO(crbug.com/1420517): More comprehensive error handling may be needed,
   // especially the case when HTTP cache hit or redirect happened.
-  if (head->headers->response_code() != net::HttpStatusCode::HTTP_OK) {
+  if (!is_fetch_handler_response_fallback_ &&
+      head_->headers->response_code() != net::HttpStatusCode::HTTP_OK) {
     return;
   }
 
   owner_->SetFetchResponseFrom(
       ServiceWorkerResourceLoader::FetchResponseFrom::kWithoutServiceWorker);
-
-  head_ = std::move(head);
-  owner_->CommitResponseHeaders(head_);
-  owner_->CommitResponseBody(head_, std::move(body),
-                             std::move(cached_metadata));
+  CommitResponse(std::move(body), std::move(cached_metadata));
 }
 
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::OnReceiveRedirect(
@@ -88,13 +90,33 @@
 
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::OnComplete(
     const network::URLLoaderCompletionStatus& status) {
+  request_completed_ = true;
   if (!owner_) {
     return;
   }
+  // If the fetch handler result is a fallback, complete the commit of the
+  // RaceNetworkRequest response.
+  if (is_fetch_handler_response_fallback_) {
+    // If there is a network error, OnComplete can be directly called, in that
+    // case |fetch_response_from| is not set yet.
+    if (owner_->fetch_response_from() ==
+        ServiceWorkerResourceLoader::FetchResponseFrom::kNoResponseYet) {
+      owner_->SetFetchResponseFrom(
+          ServiceWorkerResourceLoader::FetchResponseFrom::
+              kWithoutServiceWorker);
+    }
+    owner_->CommitCompleted(status.error_code,
+                            "RaceNetworkRequest has completed due to the fetch "
+                            "handler result is a fallback");
+    return;
+  }
+
   // If the fetch handler wins or there is a network error in
   // RaceNetworkRequest, do nothing. Defer the handling to the owner.
   if (owner_->fetch_response_from() !=
-      ServiceWorkerResourceLoader::FetchResponseFrom::kWithoutServiceWorker) {
+          ServiceWorkerResourceLoader::FetchResponseFrom::
+              kWithoutServiceWorker ||
+      status.error_code != net::OK) {
     return;
   }
 
@@ -107,6 +129,19 @@
   receiver_.Bind(remote->InitWithNewPipeAndPassReceiver());
 }
 
+void ServiceWorkerRaceNetworkRequestURLLoaderClient::
+    NotifyFetchHandlerFallback() {
+  is_fetch_handler_response_fallback_ = true;
+}
+
+void ServiceWorkerRaceNetworkRequestURLLoaderClient::CommitResponse(
+    mojo::ScopedDataPipeConsumerHandle response_body,
+    absl::optional<mojo_base::BigBuffer> cached_metadata) {
+  owner_->CommitResponseHeaders(head_);
+  owner_->CommitResponseBody(head_, std::move(response_body),
+                             std::move(cached_metadata));
+}
+
 net::NetworkTrafficAnnotationTag
 ServiceWorkerRaceNetworkRequestURLLoaderClient::NetworkTrafficAnnotationTag() {
   return net::DefineNetworkTrafficAnnotation(
diff --git a/content/common/service_worker/race_network_request_url_loader_client.h b/content/common/service_worker/race_network_request_url_loader_client.h
index 1b7b0e90..22d8503 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.h
+++ b/content/common/service_worker/race_network_request_url_loader_client.h
@@ -38,6 +38,14 @@
 
   static net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag();
 
+  // When the fetch handler result is fallback, the browser tries to use the
+  // RaceNetworkRequest response rather than dispatching another network
+  // request. This method tells the client to handle the response regardless of
+  // the result.
+  void NotifyFetchHandlerFallback();
+
+  bool request_completed() { return request_completed_; }
+
   // network::mojom::URLLoaderClient overrides:
   void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
   void OnReceiveResponse(
@@ -53,10 +61,19 @@
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
  private:
+  // Commit the head and body through |owner_|'s Commit methods.
+  // This method does not complete the commit process.
+  void CommitResponse(mojo::ScopedDataPipeConsumerHandle response_body,
+                      absl::optional<mojo_base::BigBuffer> cached_metadata);
   mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this};
   const network::ResourceRequest request_;
   base::WeakPtr<ServiceWorkerResourceLoader> owner_;
   network::mojom::URLResponseHeadPtr head_;
+  bool is_fetch_handler_response_fallback_ = false;
+
+  // Indicates if the RaceNetworkRequest is completed or not. This is marked as
+  // completed regardless of whether the response is actually committed or not.
+  bool request_completed_ = false;
 };
 }  // namespace content
 
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 372cf2f1..2d60a858 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -354,6 +354,7 @@
     "serial_delegate.h",
     "service_process_host.cc",
     "service_process_host.h",
+    "service_process_host_passkeys.h",
     "service_process_info.cc",
     "service_process_info.h",
     "service_worker_client_info.cc",
diff --git a/content/public/browser/OWNERS b/content/public/browser/OWNERS
index d3d84033..57b25fc 100644
--- a/content/public/browser/OWNERS
+++ b/content/public/browser/OWNERS
@@ -1,2 +1,6 @@
 # Note: don't add new owners here. Only content/OWNERS review public changes to
 # ensure consistency and that the public API guidelines are followed closely.
+
+# Security review is required for new callers of some ServiceProcessHostOptions.
+per-file service_process_host_passkeys.h=set noparent
+per-file service_process_host_passkeys.h=file://sandbox/OWNERS
diff --git a/content/public/browser/browsing_data_filter_builder.h b/content/public/browser/browsing_data_filter_builder.h
index ed3d3f3..7d0816d 100644
--- a/content/public/browser/browsing_data_filter_builder.h
+++ b/content/public/browser/browsing_data_filter_builder.h
@@ -31,9 +31,9 @@
 // registrable domains.
 //
 // This class defines interface to build filters for various kinds of browsing
-// data. |BuildOriginFilter()| is useful for most browsing data storage backends,
-// but some backends, such as website settings and cookies, use other formats of
-// filter.
+// data. |BuildStorageKeyFilter()| is useful for most browsing data storage
+// backends, but some backends, such as website settings and cookies, use other
+// formats of filter.
 class CONTENT_EXPORT BrowsingDataFilterBuilder {
  public:
   enum class Mode {
@@ -122,7 +122,7 @@
   // Partitioned cookies are unaffected by this setting.
   virtual void SetPartitionedStateAllowedOnly(bool value) = 0;
 
-  // Deprecated: Prefer `BuildOriginFilter()` instead.
+  // Deprecated: Prefer `BuildStorageKeyFilter()` instead.
   // Builds a filter that matches URLs that are in the list to delete, or aren't
   // in the list to preserve.
   virtual base::RepeatingCallback<bool(const GURL&)> BuildUrlFilter() = 0;
diff --git a/content/public/browser/service_process_host.cc b/content/public/browser/service_process_host.cc
index b11ee73..9535af0 100644
--- a/content/public/browser/service_process_host.cc
+++ b/content/public/browser/service_process_host.cc
@@ -58,6 +58,16 @@
   return *this;
 }
 
+#if BUILDFLAG(IS_WIN)
+ServiceProcessHost::Options&
+ServiceProcessHost::Options::WithPreloadedLibraries(
+    std::vector<base::FilePath> preloads,
+    base::PassKey<ServiceProcessHostPreloadLibraries> passkey) {
+  preload_libraries = std::move(preloads);
+  return *this;
+}
+#endif  // #if BUILDFLAG(IS_WIN)
+
 ServiceProcessHost::Options ServiceProcessHost::Options::Pass() {
   return std::move(*this);
 }
diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
index 123bb6f..8610aee7 100644
--- a/content/public/browser/service_process_host.h
+++ b/content/public/browser/service_process_host.h
@@ -28,13 +28,19 @@
 // TODO(crbug.com/1328879): Remove this when fixing the bug.
 #if BUILDFLAG(IS_CASTOS) || BUILDFLAG(IS_CAST_ANDROID)
 #include "mojo/public/cpp/system/message_pipe.h"
-#endif
+#endif  // BUILDFLAG(IS_CASTOS) || BUILDFLAG(IS_CAST_ANDROID)
+
+#if BUILDFLAG(IS_WIN)
+#include "base/files/file_path.h"
+#include "base/types/pass_key.h"
+#endif  // BUILDFLAG(IS_WIN)
 
 namespace base {
 class Process;
 }  // namespace base
 
 namespace content {
+class ServiceProcessHostPreloadLibraries;
 
 // Sandbox type for ServiceProcessHost::Launch<remote>() is found by
 // template matching on |remote|. Consult security-dev@chromium.org and
@@ -98,6 +104,19 @@
     Options& WithProcessCallback(
         base::OnceCallback<void(const base::Process&)>);
 
+#if BUILDFLAG(IS_WIN)
+    // Specifies libraries to preload before the sandbox is locked down. Paths
+    // should be absolute paths. Libraries will be preloaded before sandbox
+    // lockdown. They should later be "loaded" in the utility process using the
+    // same paths after lockdown.
+    // Note that preloading does not occur with --no-sandbox - hence the need to
+    // load in the utility with the full path - this api exists to make the
+    // libraries available for later loading in the sandbox.
+    Options& WithPreloadedLibraries(
+        std::vector<base::FilePath> preload_libraries,
+        base::PassKey<ServiceProcessHostPreloadLibraries> passkey);
+#endif  // BUILDFLAG(IS_WIN)
+
     // Passes the contents of this Options object to a newly returned Options
     // value. This must be called when moving a built Options object into a call
     // to |Launch()|.
@@ -108,6 +127,9 @@
     absl::optional<int> child_flags;
     std::vector<std::string> extra_switches;
     base::OnceCallback<void(const base::Process&)> process_callback;
+#if BUILDFLAG(IS_WIN)
+    std::vector<base::FilePath> preload_libraries;
+#endif  // BUILDFLAG(IS_WIN)
   };
 
   // An interface which can be implemented and registered/unregistered with
diff --git a/content/public/browser/service_process_host_passkeys.h b/content/public/browser/service_process_host_passkeys.h
new file mode 100644
index 0000000..0fda690d9
--- /dev/null
+++ b/content/public/browser/service_process_host_passkeys.h
@@ -0,0 +1,40 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_PASSKEYS_H_
+#define CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_PASSKEYS_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/types/pass_key.h"
+
+namespace screen_ai {
+class ScreenAIServiceRouter;
+}  // namespace screen_ai
+
+namespace content {
+class ServiceProcessHostPreloadLibraries {
+ public:
+  using PassKey = base::PassKey<ServiceProcessHostPreloadLibraries>;
+
+ private:
+  static PassKey GetPassKey() { return PassKey(); }
+
+  // Service launchers using `ServiceProcessHost::Options::WithPreloadLibraries`
+  // should be added here and must be reviewed by the security team.
+  friend class screen_ai::ScreenAIServiceRouter;
+
+  // Tests.
+  FRIEND_TEST_ALL_PREFIXES(ServiceProcessHostBrowserTest,
+                           PreloadLibraryPreloaded);
+  FRIEND_TEST_ALL_PREFIXES(ServiceProcessHostBrowserTest,
+                           PreloadLibraryMultiple);
+  FRIEND_TEST_ALL_PREFIXES(ServiceProcessHostBrowserTest,
+                           PreloadLibraryModName);
+  FRIEND_TEST_ALL_PREFIXES(ServiceProcessHostBrowserTest,
+                           PreloadLibraryBadPath);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_PASSKEYS_H_
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 570835d7..2f7f31e 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -341,14 +341,6 @@
              "EnableMachineLearningModelLoaderWebPlatformApi",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables support for the PPB_VideoDecoder(Dev) API. If this feature is
-// false (and the command-line override is not set in the renderer), the API
-// will appear as unsupported if asked for by a plugin.
-// See crbug.com/1382469 for details.
-BASE_FEATURE(kSupportPepperVideoDecoderDevAPI,
-             "SupportPepperVideoDecoderDevAPI",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enables service workers on chrome-untrusted:// urls.
 BASE_FEATURE(kEnableServiceWorkersForChromeUntrusted,
              "EnableServiceWorkersForChromeUntrusted",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 4aa23518..0cd21701 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -74,7 +74,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEnableCanvas2DLayers);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kEnableMachineLearningModelLoaderWebPlatformApi);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kSupportPepperVideoDecoderDevAPI);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEnableServiceWorkersForChromeScheme);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEnableServiceWorkersForChromeUntrusted);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEnumerateDevicesHideDeviceIDs);
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 701e4544..d8f0862 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -465,11 +465,6 @@
 // file:///alias/some/path.html into file:///replacement/some/path.html.
 const char kFileUrlPathAlias[] = "file-url-path-alias";
 
-// Force-enables the PPB_VideoDecoder(Dev) API, overriding the value from any
-// ongoing Finch experiment.
-const char kForceEnablePepperVideoDecoderDevAPI[] =
-    "force-enable-pepper-video-decoder-dev-api";
-
 // This forces pages to be loaded as presentation receivers.  Useful for testing
 // behavior specific to presentation receivers.
 // Spec: https://www.w3.org/TR/presentation-api/#interface-presentationreceiver
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index fb3c43b..3e4056b 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -142,7 +142,6 @@
 CONTENT_EXPORT extern const char kEnableWebVR[];
 CONTENT_EXPORT extern const char kFileUrlPathAlias[];
 CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
-CONTENT_EXPORT extern const char kForceEnablePepperVideoDecoderDevAPI[];
 CONTENT_EXPORT extern const char kForcePresentationReceiverForTesting[];
 CONTENT_EXPORT extern const char kForceRendererAccessibility[];
 CONTENT_EXPORT extern const char kForceWebRtcIPHandlingPolicy[];
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 8177e8f..34636a5 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -497,8 +497,6 @@
       "pepper/ppb_proxy_impl.h",
       "pepper/ppb_var_deprecated_impl.cc",
       "pepper/ppb_var_deprecated_impl.h",
-      "pepper/ppb_video_decoder_impl.cc",
-      "pepper/ppb_video_decoder_impl.h",
       "pepper/renderer_ppapi_host_impl.cc",
       "pepper/renderer_ppapi_host_impl.h",
       "pepper/renderer_restrict_dispatch_group.h",
diff --git a/content/renderer/PRESUBMIT.py b/content/renderer/PRESUBMIT.py
index 9af8849..204586b 100644
--- a/content/renderer/PRESUBMIT.py
+++ b/content/renderer/PRESUBMIT.py
@@ -18,12 +18,12 @@
       ('.h', '.cc', '.cpp', '.cxx', '.mm'))
 
 def _CheckForUseOfGlobalTaskRunnerGetter(input_api, output_api):
-  """Check that base::ThreadTaskRunnerHandle::Get() or
-  base::SequencedTaskRunnerHandle::Get() is not used."""
+  """Check that base::ThreadTaskRunner::GetCurrentDefault() or
+  base::SequencedTaskRunner::GetCurrentDefault() is not used."""
 
   problems = []
   getter_re = input_api.re.compile(
-      r'(^|\b)base::(Thread|Sequenced)TaskRunnerHandle::Get\(\)')
+      r'(^|\b)base::(Thread|Sequenced)TaskRunner::GetCurrentDefault\(\)')
   for f in input_api.AffectedSourceFiles(_FilterFile):
     for line_number, line in f.ChangedContents():
       if getter_re.search(line):
@@ -31,9 +31,9 @@
 
   if problems:
     return [output_api.PresubmitPromptWarning(
-      'base::ThreadTaskRunnerHandle::Get() and'
-      ' base::SequencedTaskRunnerHandle::Get() are deprecated in renderer;'
-      ' please use RenderFrame::GetTaskRunner for production code and'
+      'base::ThreadTaskRunnerHandle::GetCurrentDefault() and'
+      ' base::SequencedTaskRunnerHandle::GetCurrentDefault() are deprecated in'
+      ' renderer; please use RenderFrame::GetTaskRunner for production code and'
       ' blink::scheduler::Get*TaskRunnerForTesting for tests. Please reach'
       ' out to scheduler-dev@ if you have any questions.', problems)]
   return []
diff --git a/content/renderer/PRESUBMIT_test.py b/content/renderer/PRESUBMIT_test.py
index e1ab42e..39bc98b 100755
--- a/content/renderer/PRESUBMIT_test.py
+++ b/content/renderer/PRESUBMIT_test.py
@@ -16,7 +16,7 @@
 class GetTest(unittest.TestCase):
   def testNewUsageThreadTaskRunnerHandleGet(self):
     diff = ['scoped_refptr<SingleThreadTaskRunner> task_runner =',
-             '    base::ThreadTaskRunnerHandle::Get()']
+             '    base::ThreadTaskRunner::GetCurrentDefault()']
     input_api = MockInputApi()
     input_api.files = [MockAffectedFile('content/renderer/foo.cc', diff)]
     errors = PRESUBMIT._CheckForUseOfGlobalTaskRunnerGetter(input_api,
@@ -25,7 +25,7 @@
 
   def testNewUsageSequencedTaskRunnerHandleGet(self):
     diff = ['scoped_refptr<SequencedThreadTaskRunner> task_runner =',
-             '    base::SequencedTaskRunnerHandle::Get()']
+             '    base::SequencedTaskRunner::GetCurrentDefault()']
     input_api = MockInputApi()
     input_api.files = [MockAffectedFile('content/renderer/foo.cc', diff)]
     errors = PRESUBMIT._CheckForUseOfGlobalTaskRunnerGetter(input_api,
diff --git a/content/renderer/accessibility/ax_image_annotator.cc b/content/renderer/accessibility/ax_image_annotator.cc
index e09a678d..96412327 100644
--- a/content/renderer/accessibility/ax_image_annotator.cc
+++ b/content/renderer/accessibility/ax_image_annotator.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/accessibility/ax_image_annotator.h"
 
-#include <ctype.h>
 #include <utility>
 #include <vector>
 
@@ -15,6 +14,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/public/common/content_client.h"
@@ -519,10 +519,11 @@
     int last_meaningful_char = annotation->text.length() - 1;
     while (last_meaningful_char >= 0) {
       bool is_whitespace_or_punct =
-          isspace(annotation->text[last_meaningful_char]) ||
-          ispunct(annotation->text[last_meaningful_char]);
-      if (!is_whitespace_or_punct)
+          base::IsAsciiWhitespace(annotation->text[last_meaningful_char]) ||
+          base::IsAsciiPunctuation(annotation->text[last_meaningful_char]);
+      if (!is_whitespace_or_punct) {
         break;
+      }
       last_meaningful_char--;
     }
 
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc
index 127b5cd..9ea33109 100644
--- a/content/renderer/pepper/plugin_module.cc
+++ b/content/renderer/pepper/plugin_module.cc
@@ -33,7 +33,6 @@
 #include "content/renderer/pepper/ppb_image_data_impl.h"
 #include "content/renderer/pepper/ppb_proxy_impl.h"
 #include "content/renderer/pepper/ppb_var_deprecated_impl.h"
-#include "content/renderer/pepper/ppb_video_decoder_impl.h"
 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 86cab6b..3cb0a48 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -46,26 +46,6 @@
 
 namespace content {
 
-namespace {
-
-bool UseSharedImagesSwapChainForPPAPI() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisablePPAPISharedImagesSwapChain)) {
-    // This log is to make diagnosing any outages for Enterprise customers
-    // easier.
-    LOG(WARNING) << "NaCL SwapChain: Disabled by policy";
-    return false;
-  }
-
-  auto enabled =
-      base::FeatureList::IsEnabled(features::kPPAPISharedImagesSwapChain);
-  // This log is to make diagnosing any outages for Enterprise customers easier.
-  LOG(WARNING) << "NaCL SwapChain: Feature Controled: " << enabled;
-  return enabled;
-}
-
-}  // namespace
-
 // This class encapsulates ColorBuffer for the plugin. It wraps corresponding
 // SharedImage that we draw to and that we send to display compositor.
 // Can be in one of the 3 states:
@@ -183,16 +163,9 @@
 };
 
 PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance)
-    : PPB_Graphics3D_Shared(instance,
-                            /*use_shared_images_swapchain=*/
-                            UseSharedImagesSwapChainForPPAPI()),
+    : PPB_Graphics3D_Shared(instance),
       bound_to_instance_(false),
-      commit_pending_(false),
-      has_alpha_(false),
-      use_image_chromium_(
-          !base::CommandLine::ForCurrentProcess()->HasSwitch(
-              switches::kDisablePepper3DImageChromium) &&
-          base::FeatureList::IsEnabled(features::kPepper3DImageChromium)) {}
+      commit_pending_(false) {}
 
 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
   if (current_color_buffer_ && current_color_buffer_->IsAttached()) {
@@ -271,27 +244,17 @@
   command_buffer_->EnsureWorkVisible();
 }
 
-void PPB_Graphics3D_Impl::TakeFrontBuffer() {
-  taken_front_buffer_ = GenerateMailbox();
-  command_buffer_->TakeFrontBuffer(taken_front_buffer_);
-}
-
 void PPB_Graphics3D_Impl::ReturnFrontBuffer(const gpu::Mailbox& mailbox,
                                             const gpu::SyncToken& sync_token,
                                             bool is_lost) {
-  if (use_shared_images_swapchain_) {
-    if (is_single_buffered_) {
-      // We don't verify that mailbox is the same we have in the
-      // `current_color_buffer_` because it could have changed do to resize.
-    } else {
-      auto it = inflight_color_buffers_.find(mailbox);
-      DCHECK(it != inflight_color_buffers_.end());
-      RecycleColorBuffer(std::move(it->second), sync_token, is_lost);
-      inflight_color_buffers_.erase(it);
-    }
+  if (is_single_buffered_) {
+    // We don't verify that mailbox is the same we have in the
+    // `current_color_buffer_` because it could have changed do to resize.
   } else {
-    command_buffer_->ReturnFrontBuffer(mailbox, sync_token, is_lost);
-    mailboxes_to_reuse_.push_back(mailbox);
+    auto it = inflight_color_buffers_.find(mailbox);
+    DCHECK(it != inflight_color_buffers_.end());
+    RecycleColorBuffer(std::move(it->second), sync_token, is_lost);
+    inflight_color_buffers_.erase(it);
   }
 }
 
@@ -322,50 +285,6 @@
   return command_buffer_.get();
 }
 
-int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token,
-                                           const gfx::Size& size) {
-  DCHECK(command_buffer_);
-
-  if (use_shared_images_swapchain_)
-    return DoPresent(sync_token, size);
-
-  if (taken_front_buffer_.IsZero()) {
-    DLOG(ERROR) << "TakeFrontBuffer should be called before DoSwapBuffers";
-    return PP_ERROR_FAILED;
-  }
-
-  if (bound_to_instance_) {
-    // If we are bound to the instance, we need to ask the compositor
-    // to commit our backing texture so that the graphics appears on the page.
-    // When the backing texture will be committed we get notified via
-    // ViewFlushedPaint().
-    //
-    // Don't need to check for NULL from GetPluginInstance since when we're
-    // bound, we know our instance is valid.
-    bool is_overlay_candidate = use_image_chromium_;
-    // TODO(reveman): Get texture target from browser process.
-    uint32_t target = GL_TEXTURE_2D;
-#if BUILDFLAG(IS_MAC)
-    if (use_image_chromium_)
-      target = GL_TEXTURE_RECTANGLE_ARB;
-#endif
-    viz::TransferableResource resource = viz::TransferableResource::MakeGpu(
-        taken_front_buffer_, target, sync_token, size,
-        viz::SinglePlaneFormat::kRGBA_8888, is_overlay_candidate);
-    HostGlobals::Get()
-        ->GetInstance(pp_instance())
-        ->CommitTransferableResource(resource);
-    commit_pending_ = true;
-  } else {
-    // Wait for the command to complete on the GPU to allow for throttling.
-    command_buffer_->SignalSyncToken(
-        sync_token, base::BindOnce(&PPB_Graphics3D_Impl::OnSwapBuffers,
-                                   weak_ptr_factory_.GetWeakPtr()));
-  }
-
-  return PP_OK_COMPLETIONPENDING;
-}
-
 bool PPB_Graphics3D_Impl::InitRaw(
     PPB_Graphics3D_API* share_context,
     const gpu::ContextCreationAttribs& requested_attribs,
@@ -407,12 +326,11 @@
 
   has_alpha_ = requested_attribs.alpha_size > 0;
 
-  if (use_shared_images_swapchain_) {
-    is_single_buffered_ = requested_attribs.single_buffer;
-    needs_depth_ = requested_attribs.depth_size > 0;
-    needs_stencil_ = requested_attribs.stencil_size > 0;
-    swapchain_size_ = requested_attribs.offscreen_framebuffer_size;
-  }
+  is_single_buffered_ = requested_attribs.single_buffer;
+  needs_depth_ = requested_attribs.depth_size > 0;
+  needs_stencil_ = requested_attribs.stencil_size > 0;
+  swapchain_size_ = requested_attribs.offscreen_framebuffer_size;
+
   // If we're in single buffered mode, we don't need additional buffer to
   // preserve contents.
   preserve_ = requested_attribs.buffer_preserved && !is_single_buffered_;
@@ -421,14 +339,7 @@
       !requested_attribs.single_buffer)
     samples_count_ = requested_attribs.samples;
 
-  gpu::ContextCreationAttribs attrib_helper = requested_attribs;
-  attrib_helper.should_use_native_gmb_for_backbuffer = use_image_chromium_;
-
-  if (use_shared_images_swapchain_) {
-    // Reset all attribs to default if we use our own default framebuffer.
-    attrib_helper = gpu::ContextCreationAttribs();
-  }
-
+  gpu::ContextCreationAttribs attrib_helper;
   attrib_helper.context_type = gpu::CONTEXT_TYPE_OPENGLES2;
 
   gpu::CommandBufferProxyImpl* share_buffer = nullptr;
@@ -439,8 +350,7 @@
     share_buffer = share_graphics->GetCommandBufferProxy();
   }
 
-  if (use_shared_images_swapchain_)
-    shared_image_interface_ = channel->CreateClientSharedImageInterface();
+  shared_image_interface_ = channel->CreateClientSharedImageInterface();
 
   command_buffer_ = std::make_unique<gpu::CommandBufferProxyImpl>(
       std::move(channel), render_thread->GetGpuMemoryBufferManager(),
@@ -457,17 +367,13 @@
     *shared_state_region = &command_buffer_->GetSharedStateRegion();
   if (capabilities) {
     *capabilities = command_buffer_->GetCapabilities();
-    capabilities->use_shared_images_swapchain_for_ppapi =
-        use_shared_images_swapchain_;
   }
   if (command_buffer_id)
     *command_buffer_id = command_buffer_->GetCommandBufferID();
 
-  if (use_shared_images_swapchain_) {
-    current_color_buffer_ = GetOrCreateColorBuffer();
-    current_color_buffer_->Attach(command_buffer_.get(), samples_count_,
-                                  preserve_, needs_depth_, needs_stencil_);
-  }
+  current_color_buffer_ = GetOrCreateColorBuffer();
+  current_color_buffer_->Attach(command_buffer_.get(), samples_count_,
+                                preserve_, needs_depth_, needs_stencil_);
 
   return true;
 }
@@ -551,20 +457,9 @@
     ppp_graphics_3d->Graphics3DContextLost(this_pp_instance);
 }
 
-gpu::Mailbox PPB_Graphics3D_Impl::GenerateMailbox() {
-  if (!mailboxes_to_reuse_.empty()) {
-    gpu::Mailbox mailbox = mailboxes_to_reuse_.back();
-    mailboxes_to_reuse_.pop_back();
-    return mailbox;
-  }
-
-  return gpu::Mailbox::GenerateLegacyMailbox();
-}
-
-int32_t PPB_Graphics3D_Impl::DoPresent(const gpu::SyncToken& sync_token,
-                                       const gfx::Size& size) {
+int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token,
+                                           const gfx::Size& size) {
   DCHECK(command_buffer_);
-  DCHECK(use_shared_images_swapchain_);
   DCHECK(current_color_buffer_);
   DCHECK_EQ(size, current_color_buffer_->size());
 
@@ -619,14 +514,11 @@
 }
 
 void PPB_Graphics3D_Impl::ResolveAndDetachFramebuffer() {
-  DCHECK(use_shared_images_swapchain_);
   DCHECK(current_color_buffer_);
   current_color_buffer_->Detach(command_buffer_.get());
 }
 
 void PPB_Graphics3D_Impl::DoResize(gfx::Size size) {
-  DCHECK(use_shared_images_swapchain_);
-
   if (swapchain_size_ == size)
     return;
   swapchain_size_ = size;
@@ -643,7 +535,6 @@
 
 std::unique_ptr<PPB_Graphics3D_Impl::ColorBuffer>
 PPB_Graphics3D_Impl::GetOrCreateColorBuffer() {
-  DCHECK(use_shared_images_swapchain_);
   if (!available_color_buffers_.empty()) {
     auto result = std::move(*available_color_buffers_.begin());
     available_color_buffers_.erase(available_color_buffers_.begin());
@@ -659,7 +550,6 @@
     std::unique_ptr<ColorBuffer> buffer,
     const gpu::SyncToken& sync_token,
     bool is_lost) {
-  DCHECK(use_shared_images_swapchain_);
   buffer->Recycle(sync_token);
   if (is_lost || buffer->size() != swapchain_size_)
     return;
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.h b/content/renderer/pepper/ppb_graphics_3d_impl.h
index 52eb2d0..3619982 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.h
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.h
@@ -55,7 +55,6 @@
       int32_t start,
       int32_t end) override;
   void EnsureWorkVisible() override;
-  void TakeFrontBuffer() override;
   void ReturnFrontBuffer(const gpu::Mailbox& mailbox,
                          const gpu::SyncToken& sync_token,
                          bool is_lost);
@@ -105,9 +104,6 @@
   // Notifications sent to plugin.
   void SendContextLost();
 
-  // Reuses a mailbox if one is available, otherwise makes a new one.
-  gpu::Mailbox GenerateMailbox();
-
   // This is called by NaCL process when it wants to present next frame
   // (SwapBuffers call from the plugin). Note that
   // `ResolveAndDetachFramebuffer()` must be called before and `sync_token` must
@@ -131,13 +127,6 @@
   base::flat_map<gpu::Mailbox, std::unique_ptr<ColorBuffer>>
       inflight_color_buffers_;
 
-  // A front buffer that was recently taken from the command buffer. This should
-  // be immediately consumed by DoSwapBuffers().
-  gpu::Mailbox taken_front_buffer_;
-
-  // Mailboxes that are no longer in use.
-  std::vector<gpu::Mailbox> mailboxes_to_reuse_;
-
   // True if context is bound to instance.
   bool bound_to_instance_;
   // True when waiting for compositor to commit our backing texture.
@@ -154,7 +143,6 @@
   bool needs_depth_ = false;
   bool needs_stencil_ = false;
 
-  const bool use_image_chromium_;
   std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_;
   std::unique_ptr<gpu::ClientSharedImageInterface> shared_image_interface_;
 
diff --git a/content/renderer/pepper/ppb_video_decoder_impl.cc b/content/renderer/pepper/ppb_video_decoder_impl.cc
deleted file mode 100644
index 06df16a..0000000
--- a/content/renderer/pepper/ppb_video_decoder_impl.cc
+++ /dev/null
@@ -1,308 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/pepper/ppb_video_decoder_impl.h"
-
-#include <string>
-
-#include "base/check_op.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/notreached.h"
-#include "content/renderer/pepper/host_globals.h"
-#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/pepper/plugin_module.h"
-#include "content/renderer/pepper/ppb_buffer_impl.h"
-#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
-#include "content/renderer/render_thread_impl.h"
-#include "gpu/ipc/client/command_buffer_proxy_impl.h"
-#include "media/base/media_util.h"
-#include "media/gpu/ipc/client/gpu_video_decode_accelerator_host.h"
-#include "media/video/picture.h"
-#include "media/video/video_decode_accelerator.h"
-#include "ppapi/c/dev/pp_video_dev.h"
-#include "ppapi/c/dev/ppb_video_decoder_dev.h"
-#include "ppapi/c/dev/ppp_video_decoder_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/shared_impl/resource_tracker.h"
-#include "ppapi/thunk/enter.h"
-
-using ppapi::TrackedCallback;
-using ppapi::thunk::EnterResourceNoLock;
-using ppapi::thunk::PPB_Buffer_API;
-using ppapi::thunk::PPB_Graphics3D_API;
-
-namespace {
-
-// Convert PP_VideoDecoder_Profile to media::VideoCodecProfile.
-media::VideoCodecProfile PPToMediaProfile(
-    const PP_VideoDecoder_Profile pp_profile) {
-  switch (pp_profile) {
-    case PP_VIDEODECODER_H264PROFILE_NONE:
-    // HACK: PPAPI contains a bogus "none" h264 profile that doesn't
-    // correspond to anything in h.264; but a number of released chromium
-    // versions silently promoted this to Baseline profile, so we retain that
-    // behavior here.  Fall through.
-    case PP_VIDEODECODER_H264PROFILE_BASELINE:
-      return media::H264PROFILE_BASELINE;
-    case PP_VIDEODECODER_H264PROFILE_MAIN:
-      return media::H264PROFILE_MAIN;
-    case PP_VIDEODECODER_H264PROFILE_EXTENDED:
-      return media::H264PROFILE_EXTENDED;
-    case PP_VIDEODECODER_H264PROFILE_HIGH:
-      return media::H264PROFILE_HIGH;
-    case PP_VIDEODECODER_H264PROFILE_HIGH10PROFILE:
-      return media::H264PROFILE_HIGH10PROFILE;
-    case PP_VIDEODECODER_H264PROFILE_HIGH422PROFILE:
-      return media::H264PROFILE_HIGH422PROFILE;
-    case PP_VIDEODECODER_H264PROFILE_HIGH444PREDICTIVEPROFILE:
-      return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
-    case PP_VIDEODECODER_H264PROFILE_SCALABLEBASELINE:
-      return media::H264PROFILE_SCALABLEBASELINE;
-    case PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH:
-      return media::H264PROFILE_SCALABLEHIGH;
-    case PP_VIDEODECODER_H264PROFILE_STEREOHIGH:
-      return media::H264PROFILE_STEREOHIGH;
-    case PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH:
-      return media::H264PROFILE_MULTIVIEWHIGH;
-    case PP_VIDEODECODER_VP8PROFILE_ANY:
-      return media::VP8PROFILE_ANY;
-    default:
-      return media::VIDEO_CODEC_PROFILE_UNKNOWN;
-  }
-}
-
-PP_VideoDecodeError_Dev MediaToPPError(
-    media::VideoDecodeAccelerator::Error error) {
-  switch (error) {
-    case media::VideoDecodeAccelerator::ILLEGAL_STATE:
-      return PP_VIDEODECODERERROR_ILLEGAL_STATE;
-    case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
-      return PP_VIDEODECODERERROR_INVALID_ARGUMENT;
-    case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
-      return PP_VIDEODECODERERROR_UNREADABLE_INPUT;
-    case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
-      return PP_VIDEODECODERERROR_PLATFORM_FAILURE;
-    default:
-      NOTREACHED();
-      return PP_VIDEODECODERERROR_ILLEGAL_STATE;
-  }
-}
-
-}  // namespace
-
-namespace content {
-
-PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PP_Instance instance)
-    : PPB_VideoDecoder_Shared(instance), ppp_videodecoder_(nullptr) {}
-
-PPB_VideoDecoder_Impl::~PPB_VideoDecoder_Impl() { Destroy(); }
-
-// static
-PP_Resource PPB_VideoDecoder_Impl::Create(PP_Instance instance,
-                                          PP_Resource graphics_context,
-                                          PP_VideoDecoder_Profile profile) {
-  scoped_refptr<PPB_VideoDecoder_Impl> decoder(
-      new PPB_VideoDecoder_Impl(instance));
-  if (decoder->Init(graphics_context, profile))
-    return decoder->GetReference();
-  return 0;
-}
-
-bool PPB_VideoDecoder_Impl::Init(PP_Resource graphics_context,
-                                 PP_VideoDecoder_Profile profile) {
-  EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, true);
-  if (enter_context.failed())
-    return false;
-
-  PPB_Graphics3D_Impl* graphics_3d =
-      static_cast<PPB_Graphics3D_Impl*>(enter_context.object());
-
-  gpu::CommandBufferProxyImpl* command_buffer =
-      graphics_3d->GetCommandBufferProxy();
-  if (!command_buffer)
-    return false;
-
-  InitCommon(graphics_context, graphics_3d->gles2_impl());
-  FlushCommandBuffer();
-
-  // This is not synchronous, but subsequent IPC messages will be buffered, so
-  // it is okay to immediately send IPC messages.
-  if (command_buffer->channel()) {
-    decoder_ = base::WrapUnique<media::VideoDecodeAccelerator>(
-        new media::GpuVideoDecodeAcceleratorHost(command_buffer));
-    media::VideoDecodeAccelerator::Config config(PPToMediaProfile(profile));
-    config.supported_output_formats.assign(
-        {media::PIXEL_FORMAT_XRGB, media::PIXEL_FORMAT_ARGB});
-    return decoder_->Initialize(config, this);
-  }
-  return false;
-}
-
-const PPP_VideoDecoder_Dev* PPB_VideoDecoder_Impl::GetPPP() {
-  if (!ppp_videodecoder_) {
-    PluginModule* plugin_module =
-        HostGlobals::Get()->GetInstance(pp_instance())->module();
-    if (plugin_module) {
-      ppp_videodecoder_ = static_cast<const PPP_VideoDecoder_Dev*>(
-          plugin_module->GetPluginInterface(PPP_VIDEODECODER_DEV_INTERFACE));
-    }
-  }
-  return ppp_videodecoder_;
-}
-
-int32_t PPB_VideoDecoder_Impl::Decode(
-    const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
-    scoped_refptr<TrackedCallback> callback) {
-  if (!decoder_)
-    return PP_ERROR_BADRESOURCE;
-
-  EnterResourceNoLock<PPB_Buffer_API> enter(bitstream_buffer->data, true);
-  if (enter.failed())
-    return PP_ERROR_FAILED;
-
-  PPB_Buffer_Impl* buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
-  DCHECK_GE(bitstream_buffer->id, 0);
-  // TODO(crbug.com/844456): The shared memory buffer probably can be read-only,
-  // but only after PPB_Buffer_Impl is updated to deal with that.
-  media::BitstreamBuffer decode_buffer(bitstream_buffer->id,
-                                       buffer->shared_memory().Duplicate(),
-                                       bitstream_buffer->size);
-  if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback))
-    return PP_ERROR_BADARGUMENT;
-
-  FlushCommandBuffer();
-  decoder_->Decode(std::move(decode_buffer));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-void PPB_VideoDecoder_Impl::AssignPictureBuffers(
-    uint32_t no_of_buffers,
-    const PP_PictureBuffer_Dev* buffers) {
-  if (!decoder_)
-    return;
-
-  std::vector<media::PictureBuffer> wrapped_buffers;
-  for (uint32_t i = 0; i < no_of_buffers; i++) {
-    PP_PictureBuffer_Dev in_buf = buffers[i];
-    DCHECK_GE(in_buf.id, 0);
-    media::PictureBuffer::TextureIds ids;
-    ids.push_back(in_buf.texture_id);
-    media::PictureBuffer buffer(
-        in_buf.id, gfx::Size(in_buf.size.width, in_buf.size.height), ids);
-    wrapped_buffers.push_back(buffer);
-  }
-
-  FlushCommandBuffer();
-  decoder_->AssignPictureBuffers(wrapped_buffers);
-}
-
-void PPB_VideoDecoder_Impl::ReusePictureBuffer(int32_t picture_buffer_id) {
-  if (!decoder_)
-    return;
-
-  FlushCommandBuffer();
-  decoder_->ReusePictureBuffer(picture_buffer_id);
-}
-
-int32_t PPB_VideoDecoder_Impl::Flush(scoped_refptr<TrackedCallback> callback) {
-  if (!decoder_)
-    return PP_ERROR_BADRESOURCE;
-
-  if (!SetFlushCallback(callback))
-    return PP_ERROR_INPROGRESS;
-
-  FlushCommandBuffer();
-  decoder_->Flush();
-  return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t PPB_VideoDecoder_Impl::Reset(scoped_refptr<TrackedCallback> callback) {
-  if (!decoder_)
-    return PP_ERROR_BADRESOURCE;
-
-  if (!SetResetCallback(callback))
-    return PP_ERROR_INPROGRESS;
-
-  FlushCommandBuffer();
-  decoder_->Reset();
-  return PP_OK_COMPLETIONPENDING;
-}
-
-void PPB_VideoDecoder_Impl::Destroy() {
-  FlushCommandBuffer();
-
-  decoder_.reset();
-  ppp_videodecoder_ = nullptr;
-
-  ::ppapi::PPB_VideoDecoder_Shared::Destroy();
-}
-
-void PPB_VideoDecoder_Impl::ProvidePictureBuffers(
-    uint32_t requested_num_of_buffers,
-    media::VideoPixelFormat format,
-    uint32_t textures_per_buffer,
-    const gfx::Size& dimensions,
-    uint32_t texture_target) {
-  DCHECK(RenderThreadImpl::current());
-  DCHECK_EQ(1u, textures_per_buffer);
-  if (!GetPPP())
-    return;
-
-  coded_size_ = dimensions;
-  PP_Size out_dim = PP_MakeSize(dimensions.width(), dimensions.height());
-  GetPPP()->ProvidePictureBuffers(pp_instance(), pp_resource(),
-                                  requested_num_of_buffers, &out_dim,
-                                  texture_target);
-}
-
-void PPB_VideoDecoder_Impl::PictureReady(const media::Picture& picture) {
-  // So far picture.visible_rect is not used. If used, visible_rect should
-  // be validated since it comes from GPU process and may not be trustworthy.
-  DCHECK(RenderThreadImpl::current());
-  if (!GetPPP())
-    return;
-
-  PP_Picture_Dev output;
-  output.picture_buffer_id = picture.picture_buffer_id();
-  output.bitstream_buffer_id = picture.bitstream_buffer_id();
-  GetPPP()->PictureReady(pp_instance(), pp_resource(), &output);
-}
-
-void PPB_VideoDecoder_Impl::DismissPictureBuffer(int32_t picture_buffer_id) {
-  DCHECK(RenderThreadImpl::current());
-  if (!GetPPP())
-    return;
-  GetPPP()->DismissPictureBuffer(pp_instance(), pp_resource(),
-                                 picture_buffer_id);
-}
-
-void PPB_VideoDecoder_Impl::NotifyError(
-    media::VideoDecodeAccelerator::Error error) {
-  DCHECK(RenderThreadImpl::current());
-  if (!GetPPP())
-    return;
-
-  PP_VideoDecodeError_Dev pp_error = MediaToPPError(error);
-  GetPPP()->NotifyError(pp_instance(), pp_resource(), pp_error);
-}
-
-void PPB_VideoDecoder_Impl::NotifyResetDone() {
-  DCHECK(RenderThreadImpl::current());
-  RunResetCallback(PP_OK);
-}
-
-void PPB_VideoDecoder_Impl::NotifyEndOfBitstreamBuffer(
-    int32_t bitstream_buffer_id) {
-  DCHECK(RenderThreadImpl::current());
-  RunBitstreamBufferCallback(bitstream_buffer_id, PP_OK);
-}
-
-void PPB_VideoDecoder_Impl::NotifyFlushDone() {
-  DCHECK(RenderThreadImpl::current());
-  RunFlushCallback(PP_OK);
-}
-
-}  // namespace content
diff --git a/content/renderer/pepper/ppb_video_decoder_impl.h b/content/renderer/pepper/ppb_video_decoder_impl.h
deleted file mode 100644
index 2b1d863..0000000
--- a/content/renderer/pepper/ppb_video_decoder_impl.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_PEPPER_PPB_VIDEO_DECODER_IMPL_H_
-#define CONTENT_RENDERER_PEPPER_PPB_VIDEO_DECODER_IMPL_H_
-
-#include <stdint.h>
-
-#include "base/memory/ref_counted.h"
-#include "media/video/video_decode_accelerator.h"
-#include "ppapi/c/dev/pp_video_dev.h"
-#include "ppapi/c/dev/ppp_video_decoder_dev.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/shared_impl/ppb_video_decoder_shared.h"
-#include "ppapi/shared_impl/resource.h"
-#include "ppapi/thunk/ppb_video_decoder_dev_api.h"
-
-struct PP_PictureBuffer_Dev;
-struct PP_VideoBitstreamBuffer_Dev;
-
-namespace content {
-
-class PPB_VideoDecoder_Impl : public ppapi::PPB_VideoDecoder_Shared,
-                              public media::VideoDecodeAccelerator::Client {
- public:
-  // See PPB_VideoDecoder_Dev::Create.  Returns 0 on failure to create &
-  // initialize.
-  static PP_Resource Create(PP_Instance instance,
-                            PP_Resource graphics_context,
-                            PP_VideoDecoder_Profile profile);
-
-  PPB_VideoDecoder_Impl(const PPB_VideoDecoder_Impl&) = delete;
-  PPB_VideoDecoder_Impl& operator=(const PPB_VideoDecoder_Impl&) = delete;
-
-  // PPB_VideoDecoder_Dev_API implementation.
-  int32_t Decode(const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
-                 scoped_refptr<ppapi::TrackedCallback> callback) override;
-  void AssignPictureBuffers(uint32_t no_of_buffers,
-                            const PP_PictureBuffer_Dev* buffers) override;
-  void ReusePictureBuffer(int32_t picture_buffer_id) override;
-  int32_t Flush(scoped_refptr<ppapi::TrackedCallback> callback) override;
-  int32_t Reset(scoped_refptr<ppapi::TrackedCallback> callback) override;
-  void Destroy() override;
-
-  // media::VideoDecodeAccelerator::Client implementation.
-  void ProvidePictureBuffers(uint32_t requested_num_of_buffers,
-                             media::VideoPixelFormat format,
-                             uint32_t textures_per_buffer,
-                             const gfx::Size& dimensions,
-                             uint32_t texture_target) override;
-  void DismissPictureBuffer(int32_t picture_buffer_id) override;
-  void PictureReady(const media::Picture& picture) override;
-  void NotifyError(media::VideoDecodeAccelerator::Error error) override;
-  void NotifyFlushDone() override;
-  void NotifyEndOfBitstreamBuffer(int32_t buffer_id) override;
-  void NotifyResetDone() override;
-
- private:
-  ~PPB_VideoDecoder_Impl() override;
-
-  explicit PPB_VideoDecoder_Impl(PP_Instance instance);
-  bool Init(PP_Resource graphics_context,
-            PP_VideoDecoder_Profile profile);
-  // Returns the associated PPP_VideoDecoder_Dev interface to use when
-  // making calls on the plugin. This fetches the interface lazily. For
-  // out-of-process plugins, this means a synchronous message to the plugin,
-  // so it's important to never call this in response to a synchronous
-  // plugin->renderer message (such as the Create message).
-  const PPP_VideoDecoder_Dev* GetPPP();
-
-  // This is NULL before initialization, and after destruction.
-  // Holds a GpuVideoDecodeAcceleratorHost.
-  std::unique_ptr<media::VideoDecodeAccelerator> decoder_;
-
-  // Used for UMA stats; not frame-accurate.
-  gfx::Size coded_size_;
-
-  // The interface to use when making calls on the plugin. For the most part,
-  // methods should not use this directly but should call GetPPP() instead.
-  const PPP_VideoDecoder_Dev* ppp_videodecoder_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PEPPER_PPB_VIDEO_DECODER_IMPL_H_
diff --git a/content/renderer/pepper/resource_creation_impl.cc b/content/renderer/pepper/resource_creation_impl.cc
index a4a00ac..aa2f0731 100644
--- a/content/renderer/pepper/resource_creation_impl.cc
+++ b/content/renderer/pepper/resource_creation_impl.cc
@@ -4,18 +4,12 @@
 
 #include "content/renderer/pepper/resource_creation_impl.h"
 
-#include "base/command_line.h"
-#include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "build/build_config.h"
-#include "content/common/content_switches_internal.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
 #include "content/renderer/pepper/ppb_audio_impl.h"
 #include "content/renderer/pepper/ppb_buffer_impl.h"
 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
 #include "content/renderer/pepper/ppb_image_data_impl.h"
-#include "content/renderer/pepper/ppb_video_decoder_impl.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_size.h"
 #include "ppapi/c/pp_var.h"
@@ -35,25 +29,6 @@
 
 namespace content {
 
-namespace {
-
-// Returns whether the PPB_VideoDecoder(Dev) API is enabled. The API is enabled
-// iff either:
-// (a) the relevant base::Feature is set, or
-// (b) the relevant "force-enable" switch is passed on the command line (this
-// overrides the value of the base::Feature).
-bool IsVideoDecoderDevAPIEnabled() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kForceEnablePepperVideoDecoderDevAPI)) {
-    return true;
-  }
-
-  return base::FeatureList::IsEnabled(
-      features::kSupportPepperVideoDecoderDevAPI);
-}
-
-}  // namespace
-
 ResourceCreationImpl::ResourceCreationImpl(PepperPluginInstanceImpl* instance) {
 }
 
@@ -311,14 +286,8 @@
     PP_Instance instance,
     PP_Resource graphics3d_id,
     PP_VideoDecoder_Profile profile) {
-  base::UmaHistogramBoolean(
-      "NaCl.ResourceCreationImpl.CreateVideoDecoderDev_Invoked", true);
-
-  if (IsVideoDecoderDevAPIEnabled()) {
-    return create_video_decoder_dev_impl_callback_.Run(instance, graphics3d_id,
-                                                       profile);
-  }
-
+  // This API is no longer supported: See crbug.com/1382469 for details and
+  // history.
   return 0;
 }
 
diff --git a/content/renderer/pepper/resource_creation_impl.h b/content/renderer/pepper/resource_creation_impl.h
index 53c2dfa1..a3105aa4 100644
--- a/content/renderer/pepper/resource_creation_impl.h
+++ b/content/renderer/pepper/resource_creation_impl.h
@@ -9,7 +9,6 @@
 
 #include "base/functional/callback.h"
 #include "content/common/content_export.h"
-#include "content/renderer/pepper/ppb_video_decoder_impl.h"
 #include "ppapi/thunk/resource_creation_api.h"
 
 namespace content {
@@ -23,14 +22,6 @@
 class CONTENT_EXPORT ResourceCreationImpl
     : public ppapi::thunk::ResourceCreationAPI {
  public:
-  using CreateVideoDecoderDevImplCallback = base::RepeatingCallback<
-      PP_Resource(PP_Instance, PP_Resource, PP_VideoDecoder_Profile)>;
-
-  void SetCreateVideoDecoderDevImplCallbackForTesting(
-      const CreateVideoDecoderDevImplCallback& callback) {
-    create_video_decoder_dev_impl_callback_ = callback;
-  }
-
   explicit ResourceCreationImpl(PepperPluginInstanceImpl* instance);
 
   ResourceCreationImpl(const ResourceCreationImpl&) = delete;
@@ -140,10 +131,6 @@
                                     const PP_FloatPoint* wheel_ticks,
                                     PP_Bool scroll_by_page) override;
   PP_Resource CreateX509CertificatePrivate(PP_Instance instance) override;
-
- private:
-  CreateVideoDecoderDevImplCallback create_video_decoder_dev_impl_callback_ =
-      base::BindRepeating(&PPB_VideoDecoder_Impl::Create);
 };
 
 }  // namespace content
diff --git a/content/renderer/pepper/resource_creation_impl_unittest.cc b/content/renderer/pepper/resource_creation_impl_unittest.cc
deleted file mode 100644
index 61f4f3e0..0000000
--- a/content/renderer/pepper/resource_creation_impl_unittest.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/pepper/resource_creation_impl.h"
-#include "base/functional/bind.h"
-#include "base/test/scoped_feature_list.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-class ResourceCreationImplForTesting : public ResourceCreationImpl {
- public:
-  ResourceCreationImplForTesting() : ResourceCreationImpl(nullptr) {}
-
-  ResourceCreationImplForTesting(const ResourceCreationImplForTesting&) =
-      delete;
-  ResourceCreationImplForTesting& operator=(
-      const ResourceCreationImplForTesting&) = delete;
-
-  ~ResourceCreationImplForTesting() override = default;
-
-  // ResourceCreation_API:
-  PP_Resource CreateBrowserFont(
-      PP_Instance instance,
-      const PP_BrowserFont_Trusted_Description* description) override {
-    return 0;
-  }
-  PP_Resource CreateFileChooser(PP_Instance instance,
-                                PP_FileChooserMode_Dev mode,
-                                const PP_Var& accept_types) override {
-    return 0;
-  }
-  PP_Resource CreateFileIO(PP_Instance instance) override { return 0; }
-  PP_Resource CreateFileRef(
-      PP_Instance instance,
-      const ppapi::FileRefCreateInfo& create_info) override {
-    return 0;
-  }
-  PP_Resource CreateFileSystem(PP_Instance instance,
-                               PP_FileSystemType type) override {
-    return 0;
-  }
-  PP_Resource CreateGraphics2D(PP_Instance pp_instance,
-                               const PP_Size* size,
-                               PP_Bool is_always_opaque) override {
-    return 0;
-  }
-  PP_Resource CreatePrinting(PP_Instance instance) override { return 0; }
-  PP_Resource CreateURLLoader(PP_Instance instance) override { return 0; }
-  PP_Resource CreateURLRequestInfo(PP_Instance instance) override { return 0; }
-  PP_Resource CreateWebSocket(PP_Instance instance) override { return 0; }
-};
-
-}  // namespace
-
-class ResourceCreationImplTest : public testing::Test {
- public:
-  ResourceCreationImplTest() = default;
-
-  void SetUp() override {
-    resource_creation_impl_.SetCreateVideoDecoderDevImplCallbackForTesting(
-        base::BindRepeating(
-            &ResourceCreationImplTest::CreateVideoDecoderDevImpl,
-            base::Unretained(this)));
-  }
-
-  void TearDown() override {}
-
- protected:
-  bool was_video_decoder_impl_created() {
-    return was_video_decoder_impl_created_;
-  }
-
-  ResourceCreationImpl* resource_creation_impl() {
-    return &resource_creation_impl_;
-  }
-
- private:
-  PP_Resource CreateVideoDecoderDevImpl(PP_Instance instance,
-                                        PP_Resource graphics_context,
-                                        PP_VideoDecoder_Profile profile) {
-    was_video_decoder_impl_created_ = true;
-    return 0;
-  }
-
-  ResourceCreationImplForTesting resource_creation_impl_;
-  bool was_video_decoder_impl_created_ = false;
-};
-
-TEST_F(ResourceCreationImplTest, APIUnsupportedByDefault) {
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_FALSE(was_video_decoder_impl_created());
-}
-
-TEST_F(ResourceCreationImplTest,
-       APISupportedWhenFeatureEnabledAndSwitchNotPresent) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kSupportPepperVideoDecoderDevAPI);
-
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_TRUE(was_video_decoder_impl_created());
-}
-
-TEST_F(ResourceCreationImplTest,
-       APINotSupportedWhenFeatureDisabledAndSwitchNotPresent) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      features::kSupportPepperVideoDecoderDevAPI);
-
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_FALSE(was_video_decoder_impl_created());
-}
-
-TEST_F(ResourceCreationImplTest,
-       APISupportedWhenFeatureHasDefaultValueAndSwitchIsPresent) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kForceEnablePepperVideoDecoderDevAPI);
-
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_TRUE(was_video_decoder_impl_created());
-}
-
-TEST_F(ResourceCreationImplTest,
-       APISupportedWhenFeatureIsEnabledAndSwitchIsPresent) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kSupportPepperVideoDecoderDevAPI);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kForceEnablePepperVideoDecoderDevAPI);
-
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_TRUE(was_video_decoder_impl_created());
-}
-
-// The command-line switch should override the Feature.
-TEST_F(ResourceCreationImplTest,
-       APISupportedWhenFeatureIsDisabledButSwitchIsPresent) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      features::kSupportPepperVideoDecoderDevAPI);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kForceEnablePepperVideoDecoderDevAPI);
-
-  resource_creation_impl()->CreateVideoDecoderDev(
-      0, 0, static_cast<PP_VideoDecoder_Profile>(-1));
-
-  EXPECT_TRUE(was_video_decoder_impl_created());
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 47556660..7b19d47 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -515,12 +515,20 @@
   // request is not dispatched. OnFallback doesn't delete the instance and flip
   // the status. Those are handled in the process of RaceNetworkRequest
   // handling.
-  // TODO(crbug.com/1432075) Fallback response shoudld be handled as a fallback.
+  // TODO(crbug.com/1432075) Fallback response should be handled as a fallback.
   // The response from RaceNetworkRequest is currently handled by the code path
   // for the non-fallback case.
   if (fetch_response_from() == FetchResponseFrom::kWithoutServiceWorker) {
     return;
   }
+  // If the RaceNetworkRequest is triggered but the response is not handled yet,
+  // ask its URLLoaderClient to handle the response regardless of the response
+  // status not to dispatch additional network request for fallback.
+  if (did_start_race_network_request_) {
+    DCHECK(race_network_request_loader_client_);
+    race_network_request_loader_client_->NotifyFetchHandlerFallback();
+    return;
+  }
 
   // Hand over to the network loader.
   mojo::PendingRemote<network::mojom::URLLoaderClient> client;
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 5059ffb..e2a6fb3d 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -213,6 +213,16 @@
 
   if (is_ios) {
     sources += [
+      "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h",
+      "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm",
+      "browser/bluetooth/ios/shell_bluetooth_chooser_ios.h",
+      "browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm",
+      "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h",
+      "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm",
+      "browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h",
+      "browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h",
+      "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h",
+      "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm",
       "browser/bluetooth/shell_bluetooth_delegate_impl_client.cc",
       "browser/bluetooth/shell_bluetooth_delegate_impl_client.h",
       "browser/shell_file_select_helper.cc",
@@ -362,6 +372,7 @@
   if (is_ios) {
     deps += [
       "//components/permissions",
+      "//components/strings:components_strings",
       "//services/tracing/public/cpp",
       "//services/tracing/public/mojom:mojom",
       "//ui/shell_dialogs",
@@ -522,6 +533,17 @@
     sources += [ "$root_gen_dir/content/browser/tracing/tracing_resources.pak" ]
   }
 
+  if (is_ios) {
+    sources += [
+      "$root_gen_dir/device/bluetooth/strings/bluetooth_strings_en-US.pak",
+      "${root_gen_dir}/components/strings/components_strings_en-US.pak",
+    ]
+    deps += [
+      "//components/strings:components_strings",
+      "//device/bluetooth/strings/",
+    ]
+  }
+
   if (shell_use_toolkit_views) {
     deps += [ "//ui/views/resources" ]
     sources +=
diff --git a/content/shell/DEPS b/content/shell/DEPS
index c3a988f..15e48e5 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -37,6 +37,7 @@
   "+components/keyed_service/core",
   "+components/performance_manager",
   "+components/permissions",
+  "+components/strings/grit",
   "+components/url_formatter",
   "+components/network_session_configurator/browser",
   "+components/viz/common/resources",
diff --git a/content/shell/app/ios-Info.plist b/content/shell/app/ios-Info.plist
index 5e14f3a..278f1aaa 100644
--- a/content/shell/app/ios-Info.plist
+++ b/content/shell/app/ios-Info.plist
@@ -52,5 +52,7 @@
 	<string>Allow content_shell access to microphone</string>
 	<key>NSCameraUsageDescription</key>
 	<string>Allow content_shell access to camera</string>
+	<key>NSBluetoothAlwaysUsageDescription</key>
+	<string>Allow content_shell access to Bluetooth</string>
 </dict>
 </plist>
diff --git a/content/shell/browser/bluetooth/ios/permission_prompt/permission_prompt_ios_factory.cc b/content/shell/browser/bluetooth/ios/permission_prompt/permission_prompt_ios_factory.cc
new file mode 100644
index 0000000..4a24af9d
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/permission_prompt/permission_prompt_ios_factory.cc
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "components/permissions/permission_prompt.h"
+#include "content/public/browser/web_contents.h"
+
+namespace permissions {
+
+std::unique_ptr<PermissionPrompt> PermissionPrompt::Create(
+    content::WebContents* web_contents,
+    Delegate* delegate) {
+  // TODO(crbug.com/1431447): Implement PermissionPrompt.
+  return nullptr;
+}
+
+}  // namespace permissions
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h
new file mode 100644
index 0000000..e7f0c7a
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h
@@ -0,0 +1,55 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_COORDINATOR_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_COORDINATOR_H_
+
+#import <string>
+
+#import <Foundation/Foundation.h>
+
+#import "ui/gfx/native_widget_types.h"
+
+namespace content {
+class ShellBluetoothChooserIOS;
+}  // namespace content
+
+@class ShellDeviceListViewController;
+@class ShellBluetoothChooserMediator;
+@class UIViewController;
+
+@interface ShellBluetoothChooserCoordinator : NSObject
+
+@property(nonatomic, strong)
+    ShellDeviceListViewController* deviceListViewController;
+
+@property(nonatomic, strong)
+    ShellBluetoothChooserMediator* bluetoothChooserMediator;
+
+- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
+                                     title:(NSString*)title
+                          bluetoothChooser:(content::ShellBluetoothChooserIOS*)
+                                               bluetoothChooser;
+
+@end
+
+namespace content {
+
+class ShellBluetoothChooserCoordinatorHolder {
+ public:
+  ShellBluetoothChooserCoordinatorHolder(
+      gfx::NativeWindow native_window,
+      ShellBluetoothChooserIOS* bluetooth_chooser_ios,
+      const std::u16string& title);
+  virtual ~ShellBluetoothChooserCoordinatorHolder();
+
+  ShellBluetoothChooserMediator* getMediator();
+
+ private:
+  ShellBluetoothChooserCoordinator* coordinator_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_COORDINATOR_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm
new file mode 100644
index 0000000..b5f341d
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm
@@ -0,0 +1,67 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h"
+
+#import "base/strings/sys_string_conversions.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h"
+#import "ui/gfx/native_widget_types.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation ShellBluetoothChooserCoordinator
+- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
+                                     title:(NSString*)title
+                          bluetoothChooser:(content::ShellBluetoothChooserIOS*)
+                                               bluetoothChooser {
+  if (!(self = [super init])) {
+    return nil;
+  }
+
+  _deviceListViewController =
+      [[ShellDeviceListViewController alloc] initWithTitle:title];
+  _deviceListViewController.modalPresentationStyle = UIModalPresentationPopover;
+  _deviceListViewController.popoverPresentationController.delegate =
+      _deviceListViewController;
+  _deviceListViewController.popoverPresentationController.sourceView =
+      baseViewController.view;
+  _deviceListViewController.popoverPresentationController.sourceRect =
+      baseViewController.view.bounds;
+
+  _bluetoothChooserMediator = [[ShellBluetoothChooserMediator alloc]
+      initWithBluetoothChooser:bluetoothChooser];
+  _deviceListViewController.listDelegate = _bluetoothChooserMediator;
+  _bluetoothChooserMediator.consumer = _deviceListViewController;
+  [baseViewController presentViewController:_deviceListViewController
+                                   animated:true
+                                 completion:nil];
+  return self;
+}
+
+namespace content {
+
+ShellBluetoothChooserCoordinatorHolder::ShellBluetoothChooserCoordinatorHolder(
+    gfx::NativeWindow native_window,
+    content::ShellBluetoothChooserIOS* bluetooth_chooser_ios,
+    const std::u16string& title) {
+  coordinator_ = [[ShellBluetoothChooserCoordinator alloc]
+      initWithBaseViewController:native_window.rootViewController
+                           title:base::SysUTF16ToNSString(title)
+                bluetoothChooser:bluetooth_chooser_ios];
+}
+
+ShellBluetoothChooserCoordinatorHolder::
+    ~ShellBluetoothChooserCoordinatorHolder() = default;
+
+ShellBluetoothChooserMediator*
+ShellBluetoothChooserCoordinatorHolder::getMediator() {
+  return coordinator_.bluetoothChooserMediator;
+}
+
+}  // namespace content
+
+@end
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h
new file mode 100644
index 0000000..be265886
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_IOS_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_IOS_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "content/public/browser/bluetooth_chooser.h"
+
+namespace content {
+class WebContents;
+class RenderFrameHost;
+class ShellBluetoothChooserCoordinatorHolder;
+
+// Represents a way to ask the user to select a Bluetooth device from a list of
+// options.
+class ShellBluetoothChooserIOS : public BluetoothChooser {
+ public:
+  // Both frame and event_handler must outlive the ShellBluetoothChooserIOS.
+  ShellBluetoothChooserIOS(RenderFrameHost* frame,
+                           const EventHandler& event_handler);
+  ~ShellBluetoothChooserIOS() override;
+
+  enum DialogClosedState {
+    kDialogCanceled = 0,
+    kDialogItemSelected,
+  };
+
+  // BluetoothChooser:
+  void AddOrUpdateDevice(const std::string& device_id,
+                         bool should_update_name,
+                         const std::u16string& device_name,
+                         bool is_gatt_connected,
+                         bool is_paired,
+                         int signal_strength_level) override;
+
+  // Report the dialog's result.
+  void OnDialogFinished(DialogClosedState state, std::string& device_id);
+
+ private:
+  raw_ptr<WebContents> web_contents_;
+  BluetoothChooser::EventHandler event_handler_;
+  std::unique_ptr<ShellBluetoothChooserCoordinatorHolder>
+      shell_bluetooth_chooser_coordinator_holder_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_IOS_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm
new file mode 100644
index 0000000..8ed32521
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm
@@ -0,0 +1,84 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h"
+
+#import "base/functional/bind.h"
+#import "base/strings/sys_string_conversions.h"
+#import "base/strings/utf_string_conversions.h"
+#import "components/permissions/constants.h"
+#import "components/permissions/permission_util.h"
+#import "components/strings/grit/components_strings.h"
+#import "content/public/browser/render_frame_host.h"
+#import "content/public/browser/web_contents.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h"
+#import "ui/base/l10n/l10n_util.h"
+#import "ui/gfx/native_widget_types.h"
+#import "url/origin.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace content {
+
+namespace {
+
+std::u16string CreateChooserTitle(RenderFrameHost* render_frame_host) {
+  if (!render_frame_host) {
+    return u"";
+  }
+  // Ensure the permission request is attributed to the main frame.
+  render_frame_host = render_frame_host->GetMainFrame();
+
+  const url::Origin& origin = render_frame_host->GetLastCommittedOrigin();
+  return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_PROMPT,
+                                    base::UTF8ToUTF16(origin.Serialize()));
+}
+
+}  // namespace
+
+ShellBluetoothChooserIOS::ShellBluetoothChooserIOS(
+    RenderFrameHost* frame,
+    const EventHandler& event_handler)
+    : web_contents_(WebContents::FromRenderFrameHost(frame)),
+      event_handler_(event_handler) {
+  gfx::NativeWindow gfx_window = web_contents_->GetTopLevelNativeWindow();
+  shell_bluetooth_chooser_coordinator_holder_ =
+      std::make_unique<ShellBluetoothChooserCoordinatorHolder>(
+          gfx_window, this, CreateChooserTitle(frame));
+}
+
+ShellBluetoothChooserIOS::~ShellBluetoothChooserIOS() = default;
+
+void ShellBluetoothChooserIOS::AddOrUpdateDevice(
+    const std::string& device_id,
+    bool should_update_name,
+    const std::u16string& device_name,
+    bool is_gatt_connected,
+    bool is_paired,
+    int signal_strength_level) {
+  [shell_bluetooth_chooser_coordinator_holder_->getMediator()
+        addOrUpdateDevice:base::SysUTF8ToNSString(device_id)
+         shouldUpdateName:should_update_name
+               deviceName:base::SysUTF16ToNSString(device_name)
+            gattConnected:is_gatt_connected
+      signalStrengthLevel:signal_strength_level];
+}
+
+void ShellBluetoothChooserIOS::OnDialogFinished(DialogClosedState state,
+                                                std::string& device_id) {
+  switch (state) {
+    case DialogClosedState::kDialogCanceled:
+      event_handler_.Run(BluetoothChooserEvent::CANCELLED, "");
+      return;
+    case DialogClosedState::kDialogItemSelected:
+      event_handler_.Run(BluetoothChooserEvent::SELECTED, device_id);
+      return;
+  }
+  NOTREACHED_NORETURN();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h
new file mode 100644
index 0000000..2612de1
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_MEDIATOR_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_MEDIATOR_H_
+
+#import <Foundation/Foundation.h>
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h"
+
+namespace content {
+class ShellBluetoothChooserIOS;
+}  // namespace content
+
+@protocol ShellBluetoothDeviceListConsumer;
+
+@interface ShellBluetoothChooserMediator
+    : NSObject <ShellBluetoothDeviceListDelegate>
+
+@property(nonatomic, assign)
+    content::ShellBluetoothChooserIOS* bluetoothChooser;
+
+// Consumer that is configured by this mediator.
+@property(nonatomic, assign) id<ShellBluetoothDeviceListConsumer> consumer;
+
+- (instancetype)initWithBluetoothChooser:
+    (content::ShellBluetoothChooserIOS*)bluetoothChooser;
+
+- (void)setConsumer:(id<ShellBluetoothDeviceListConsumer>)consumer;
+
+- (void)addOrUpdateDevice:(NSString*)deviceID
+         shouldUpdateName:(BOOL)shouldUpdateName
+               deviceName:(NSString*)deviceName
+            gattConnected:(BOOL)gattConnected
+      signalStrengthLevel:(NSInteger)signalStrengthLevel;
+@end
+
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_CHOOSER_MEDIATOR_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm
new file mode 100644
index 0000000..cd73e2fb
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm
@@ -0,0 +1,50 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h"
+
+#import "base/strings/sys_string_conversions.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h"
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation ShellBluetoothChooserMediator
+- (instancetype)initWithBluetoothChooser:
+    (content::ShellBluetoothChooserIOS*)bluetoothChooser {
+  if (!(self = [super init])) {
+    return nil;
+  }
+
+  _bluetoothChooser = bluetoothChooser;
+  return self;
+}
+
+- (void)addOrUpdateDevice:(NSString*)deviceID
+         shouldUpdateName:(BOOL)shouldUpdateName
+               deviceName:(NSString*)deviceName
+            gattConnected:(BOOL)gattConnected
+      signalStrengthLevel:(NSInteger)signalStrengthLevel {
+  [self.consumer addOrUpdateDevice:deviceID
+                  shouldUpdateName:shouldUpdateName
+                        deviceName:deviceName
+                     gattConnected:gattConnected
+               signalStrengthLevel:signalStrengthLevel];
+}
+
+#pragma mark - ShellBluetoothDeviceListDelegate
+
+- (void)updateSelectedInfo:(BOOL)selected selectedText:(NSString*)selectedText {
+  std::string device_id = base::SysNSStringToUTF8(selectedText);
+  content::ShellBluetoothChooserIOS::DialogClosedState state =
+      selected ? content::ShellBluetoothChooserIOS::DialogClosedState::
+                     kDialogItemSelected
+               : content::ShellBluetoothChooserIOS::DialogClosedState::
+                     kDialogCanceled;
+  self.bluetoothChooser->OnDialogFinished(state, device_id);
+}
+
+@end
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h
new file mode 100644
index 0000000..75c6ef7c
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_CONSUMER_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_CONSUMER_H_
+
+#import <Foundation/Foundation.h>
+
+// Consumer for model to push configurations to the device list UI.
+@protocol ShellBluetoothDeviceListConsumer <NSObject>
+
+// Adds a cell for a new device to the UITableView or updates the information of
+// an existing cell.
+- (void)addOrUpdateDevice:(NSString*)deviceID
+         shouldUpdateName:(bool)shouldUpdateName
+               deviceName:(NSString*)deviceName
+            gattConnected:(bool)gattConnected
+      signalStrengthLevel:(NSInteger)signalStrengthLevel;
+
+@end
+
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_CONSUMER_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h
new file mode 100644
index 0000000..f0f4aa4c
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h
@@ -0,0 +1,18 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_DELEGATE_H_
+
+#import <Foundation/Foundation.h>
+
+// Delegate to handle actions.
+@protocol ShellBluetoothDeviceListDelegate <NSObject>
+
+// Method invoked when the user taps a item from the list.
+- (void)updateSelectedInfo:(BOOL)selected selectedText:(NSString*)selectedText;
+
+@end
+
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_DELEGATE_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h
new file mode 100644
index 0000000..0be9cb8d
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h
@@ -0,0 +1,45 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_VIEW_CONTROLLER_H_
+#define CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_VIEW_CONTROLLER_H_
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h"
+
+@class DeviceInfo;
+
+@protocol ShellBluetoothDeviceListDelegate;
+
+// The ViewController that has UITableView to show the bluetooth device list.
+@interface ShellDeviceListViewController
+    : UITableViewController <ShellBluetoothDeviceListConsumer,
+                             UIPopoverPresentationControllerDelegate>
+
+// The view controller this coordinator was initialized with.
+@property(weak, nonatomic, readonly) UIViewController* baseViewController;
+
+// Has device IDs according to cell index. It's used to get a device ID when a
+// cell index is known.
+@property(nonatomic, strong) NSMutableArray<NSString*>* deviceIDs;
+
+// Has device information. It's used to get a device information such as a
+// device name when a device ID is known.
+@property(nonatomic, strong)
+    NSMutableDictionary<NSString*, DeviceInfo*>* deviceInfos;
+
+@property(nonatomic, assign) NSInteger selectedRowIndex;
+
+@property(nonatomic, copy) NSString* listTitle;
+
+// Delegate used to handle the device list.
+@property(nonatomic, weak) id<ShellBluetoothDeviceListDelegate> listDelegate;
+
+- (instancetype)initWithTitle:(NSString*)title;
+
+- (void)updateSelectedInformation:(bool)selected;
+@end
+#endif  // CONTENT_SHELL_BROWSER_BLUETOOTH_IOS_SHELL_BLUETOOTH_DEVICE_LIST_VIEW_CONTROLLER_H_
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm
new file mode 100644
index 0000000..c23e6a4
--- /dev/null
+++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm
@@ -0,0 +1,186 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h"
+
+#import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Has device information to display it on a cell of UITableView.
+@interface DeviceInfo : NSObject
+
+@property(nonatomic, copy) NSString* deviceID;
+
+@property(nonatomic, copy) NSString* deviceName;
+
+@property(nonatomic, assign) BOOL gattConnected;
+
+@property(nonatomic, assign) NSInteger signalStrengthLevel;
+
+@property(nonatomic, assign) NSInteger cellIndex;
+
+- (instancetype)initWithDeviceID:(NSString*)deviceID
+                      deviceName:(NSString*)deviceName
+                   gattConnected:(BOOL)gattConnected
+             signalStrengthLevel:(NSInteger)signalStrengthLevel
+                       cellIndex:(NSInteger)cellIndex;
+
+- (void)updateDeviceName:(NSString*)deviceName
+           gattConnected:(BOOL)gattConnected
+     signalStrengthLevel:(NSInteger)signalStrengthLevel;
+@end
+
+@implementation DeviceInfo
+- (instancetype)initWithDeviceID:(NSString*)deviceID
+                      deviceName:(NSString*)deviceName
+                   gattConnected:(BOOL)gattConnected
+             signalStrengthLevel:(NSInteger)signalStrengthLevel
+                       cellIndex:(NSInteger)cellIndex {
+  if ((self = [super init])) {
+    _deviceID = [deviceID copy];
+    _deviceName = [deviceName copy];
+    _gattConnected = gattConnected;
+    _signalStrengthLevel = signalStrengthLevel;
+    _cellIndex = cellIndex;
+  }
+  return self;
+}
+
+- (void)updateDeviceName:(NSString*)deviceName
+           gattConnected:(BOOL)gattConnected
+     signalStrengthLevel:(NSInteger)signalStrengthLevel {
+  self.deviceName = [deviceName copy];
+  self.gattConnected = gattConnected;
+  self.signalStrengthLevel = signalStrengthLevel;
+}
+@end
+
+@implementation ShellDeviceListViewController
+- (instancetype)initWithTitle:(NSString*)title {
+  if (!(self = [super init])) {
+    return nil;
+  }
+  _selectedRowIndex = -1;
+  _listTitle = [title copy];
+
+  return self;
+}
+
+- (NSString*)tableView:(UITableView*)tableView
+    titleForHeaderInSection:(NSInteger)section {
+  return self.listTitle;
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
+  return 1;
+}
+
+- (NSInteger)tableView:(UITableView*)tableView
+    numberOfRowsInSection:(NSInteger)section {
+  return self.deviceIDs.count;
+}
+
+- (UITableViewCell*)tableView:(UITableView*)tableView
+        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
+  static NSString* cellIdentifier = @"cell";
+  UITableViewCell* cell =
+      [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
+
+  if (cell == nil) {
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
+                                  reuseIdentifier:cellIdentifier];
+  }
+  NSString* deviceID = [self.deviceIDs objectAtIndex:indexPath.row];
+  cell.textLabel.text = deviceID;
+  DeviceInfo* info = [self.deviceInfos objectForKey:deviceID];
+  cell.detailTextLabel.text = info.deviceName;
+  // TODO(crbug.com/1431447): Display more information if required.
+  return cell;
+}
+
+- (void)tableView:(UITableView*)tableView
+    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  self.selectedRowIndex = indexPath.row;
+  [self dismissViewControllerAnimated:YES completion:Nil];
+}
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  self.deviceIDs = [[NSMutableArray alloc] init];
+  self.deviceInfos = [[NSMutableDictionary alloc] init];
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+  bool selected = (self.selectedRowIndex != -1);
+  [self updateSelectedInformation:selected];
+}
+
+- (void)updateSelectedInformation:(bool)selected {
+  NSString* selectedText = @"";
+  if (selected) {
+    NSIndexPath* indexPath = [NSIndexPath indexPathForRow:_selectedRowIndex
+                                                inSection:0];
+    UITableViewCell* selectedCell =
+        [self.tableView cellForRowAtIndexPath:indexPath];
+    selectedText = selectedCell.textLabel.text;
+  }
+  [self.listDelegate updateSelectedInfo:selected selectedText:selectedText];
+}
+
+#pragma mark - ShellBluetoothDeviceListConsumer
+
+- (void)addOrUpdateDevice:(NSString*)deviceID
+         shouldUpdateName:(bool)shouldUpdateName
+               deviceName:(NSString*)deviceName
+            gattConnected:(bool)gattConnected
+      signalStrengthLevel:(NSInteger)signalStrengthLevel {
+  DeviceInfo* info = [self.deviceInfos objectForKey:deviceID];
+  if (info) {
+    if (!shouldUpdateName) {
+      return;
+    }
+    if ([info.deviceName isEqualToString:deviceName] &&
+        info.gattConnected == gattConnected &&
+        info.signalStrengthLevel == signalStrengthLevel) {
+      return;
+    }
+    [info updateDeviceName:deviceName
+              gattConnected:gattConnected
+        signalStrengthLevel:signalStrengthLevel];
+    if (info.cellIndex == -1) {
+      // This information is not added to the table yet.
+      return;
+    }
+    NSIndexPath* updatingPath = [NSIndexPath indexPathForRow:info.cellIndex
+                                                   inSection:0];
+    UITableViewCell* updatingCell =
+        [self.tableView cellForRowAtIndexPath:updatingPath];
+    updatingCell.detailTextLabel.text = deviceName;
+    // TODO(crbug.com/1431447): Display more information if required.
+  } else {
+    if (!self.isViewLoaded || !self.view.window) {
+      // If the view disappears, it skips updating the table.
+      return;
+    }
+    [self.deviceIDs addObject:deviceID];
+    DeviceInfo* new_info =
+        [[DeviceInfo alloc] initWithDeviceID:deviceID
+                                  deviceName:deviceName
+                               gattConnected:gattConnected
+                         signalStrengthLevel:signalStrengthLevel
+                                   cellIndex:-1];
+    [self.deviceInfos setObject:new_info forKey:deviceID];
+    [self.tableView beginUpdates];
+    NSInteger rowIndex = self.deviceIDs.count - 1;
+    NSIndexPath* newPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
+    [new_info setCellIndex:rowIndex];
+    [self.tableView insertRowsAtIndexPaths:@[ newPath ]
+                          withRowAnimation:UITableViewRowAnimationAutomatic];
+    [self.tableView endUpdates];
+  }
+}
+@end
diff --git a/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc
index 00716ddb..1052f82 100644
--- a/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc
+++ b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc
@@ -4,8 +4,13 @@
 
 #include "content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h"
 
+#include "build/build_config.h"
 #include "content/public/browser/render_frame_host.h"
 
+#if BUILDFLAG(IS_IOS)
+#include "content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_ios.h"
+#endif
+
 namespace content {
 
 ShellBluetoothDelegateImplClient::ShellBluetoothDelegateImplClient() = default;
@@ -23,8 +28,11 @@
 ShellBluetoothDelegateImplClient::RunBluetoothChooser(
     RenderFrameHost* frame,
     const BluetoothChooser::EventHandler& event_handler) {
-  // TODO(crbug.com/1431447): Implement BluetoothChooser for iOS.
+#if BUILDFLAG(IS_IOS)
+  return std::make_unique<ShellBluetoothChooserIOS>(frame, event_handler);
+#else
   return nullptr;
+#endif
 }
 
 std::unique_ptr<BluetoothScanningPrompt>
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 29333e0b..e57fc4f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1875,6 +1875,8 @@
       "//third_party/isimpledom",
     ]
 
+    data_deps += [ "//services/test/echo:echo_preload_library" ]
+
     libs = [ "uiautomationcore.lib" ]
 
     configs += [ "//build/config/win:delayloads" ]
@@ -3004,7 +3006,6 @@
       "../renderer/pepper/event_conversion_unittest.cc",
       "../renderer/pepper/host_var_tracker_unittest.cc",
       "../renderer/pepper/mock_resource.h",
-      "../renderer/pepper/resource_creation_impl_unittest.cc",
       "../renderer/pepper/v8_var_converter_unittest.cc",
     ]
     deps += [
diff --git a/content/test/data/accessibility/css/before-after-block-expected-blink.txt b/content/test/data/accessibility/css/before-after-block-expected-blink.txt
index 8cb1b0a2..97be2e6 100644
--- a/content/test/data/accessibility/css/before-after-block-expected-blink.txt
+++ b/content/test/data/accessibility/css/before-after-block-expected-blink.txt
@@ -5,7 +5,7 @@
 ++++++++staticText name='A'
 ++++++++++inlineTextBox name='A'
 ++++++++genericContainer ignored htmlTag='b'
-++++++++++genericContainer ignored htmlTag='::before'
+++++++++++genericContainer htmlTag='::before'
 ++++++++++staticText name='bold'
 ++++++++++++inlineTextBox name='bold'
 ++++++++staticText name=' element'
diff --git a/content/test/data/accessibility/css/before-after-code-expected-android-external.txt b/content/test/data/accessibility/css/before-after-code-expected-android-external.txt
index f1ca5d2f..f174c0f 100644
--- a/content/test/data/accessibility/css/before-after-code-expected-android-external.txt
+++ b/content/test/data/accessibility/css/before-after-code-expected-android-external.txt
@@ -1,4 +1,27 @@
 WebView focusable focused scrollable actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
 ++TextView text:"start" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
-++TextView text:"text with [:before] and [:after] content, then abold element with a [block] before content then a italicelement with a [block] after content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
-++TextView text:"end" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
\ No newline at end of file
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++TextView text:"text with " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"[" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:":before" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"]" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:" and " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"[" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:":after" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"]" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:" content, then a" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++TextView text:"bold" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:" element with a " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"[" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"block" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"]" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:" before content then a " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"italic" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++TextView text:"element with a " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"[" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"block" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:"]" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++++TextView text:" after content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
+++TextView text:"end" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/css/transform-expected-blink.txt b/content/test/data/accessibility/css/transform-expected-blink.txt
index 6a0ad03..1f3a20e39 100644
--- a/content/test/data/accessibility/css/transform-expected-blink.txt
+++ b/content/test/data/accessibility/css/transform-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer pageLocation=(0, 50)
 ++++++genericContainer pageLocation=(0, 50)
 ++++++++paragraph pageLocation=(0, 50)
 ++++++++++staticText pageLocation=(0, 50) name='content'
-++++++++++++inlineTextBox pageLocation=(0, 50) name='content'
+++++++++++++inlineTextBox pageLocation=(0, 50) name='content'
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/transform-expected-mac.txt b/content/test/data/accessibility/css/transform-expected-mac.txt
index 27d0ef6..7f9e696 100644
--- a/content/test/data/accessibility/css/transform-expected-mac.txt
+++ b/content/test/data/accessibility/css/transform-expected-mac.txt
@@ -1,4 +1,5 @@
 AXWebArea LocalPosition={x: 0, y: 0}
 ++AXGroup LocalPosition={x: 0, y: 50}
 ++++AXGroup LocalPosition={x: 0, y: 50}
-++++++AXStaticText AXValue='content' LocalPosition={x: 0, y: 50}
+++++++AXGroup LocalPosition={x: 0, y: 50}
+++++++++AXStaticText AXValue='content' LocalPosition={x: 0, y: 50}
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/transform-expected-uia-win.txt b/content/test/data/accessibility/css/transform-expected-uia-win.txt
index 1b1d409..195fb43 100644
--- a/content/test/data/accessibility/css/transform-expected-uia-win.txt
+++ b/content/test/data/accessibility/css/transform-expected-uia-win.txt
@@ -1,4 +1,5 @@
 Document
 ++Group BoundingRectangle=(0, 50, 48, 18) IsControlElement=false
 ++++Group BoundingRectangle=(0, 50, 48, 18) IsControlElement=false
-++++++Text BoundingRectangle=(0, 50, 48, 17) Name='content'
+++++++Group BoundingRectangle=(0, 50, 48, 18) IsControlElement=false
+++++++++Text BoundingRectangle=(0, 50, 48, 17) Name='content'
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/transform-expected-win.txt b/content/test/data/accessibility/css/transform-expected-win.txt
index b270fecb..29e014fe 100644
--- a/content/test/data/accessibility/css/transform-expected-win.txt
+++ b/content/test/data/accessibility/css/transform-expected-win.txt
@@ -1,4 +1,5 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
 ++IA2_ROLE_SECTION location=(0, 50)
-++++IA2_ROLE_PARAGRAPH location=(0, 50)
-++++++ROLE_SYSTEM_STATICTEXT name='content' location=(0, 50)
+++++IA2_ROLE_SECTION location=(0, 50)
+++++++IA2_ROLE_PARAGRAPH location=(0, 50)
+++++++++ROLE_SYSTEM_STATICTEXT name='content' location=(0, 50)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/bounds-fixed-expected-blink.txt b/content/test/data/accessibility/html/bounds-fixed-expected-blink.txt
index a110ddf4..199c949 100644
--- a/content/test/data/accessibility/html/bounds-fixed-expected-blink.txt
+++ b/content/test/data/accessibility/html/bounds-fixed-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea clipsChildren=true
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer
 ++++++genericContainer size=(200, 200) pageSize=(200, 200) unclippedSize=(200, 200) clipsChildren=true
 ++++++++dialog size=(200, 200) pageLocation=(150, 50) pageSize=(200, 200) unclippedLocation=(150, 50) unclippedSize=(200, 200)
 ++++++++++button size=(160, 50) pageSize=(160, 50) name='Button 1'
@@ -8,4 +8,4 @@
 ++++++++++++++inlineTextBox name='Button 1'
 ++++++++++button size=(160, 50) pageSize=(160, 50) name='Button 2'
 ++++++++++++staticText name='Button 2'
-++++++++++++++inlineTextBox name='Button 2'
+++++++++++++++inlineTextBox name='Button 2'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-android-external.txt b/content/test/data/accessibility/html/dialog-expected-android-external.txt
index 0faee2b..3fdbff1 100644
--- a/content/test/data/accessibility/html/dialog-expected-android-external.txt
+++ b/content/test/data/accessibility/html/dialog-expected-android-external.txt
@@ -1,2 +1,3 @@
 WebView focusable focused scrollable actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"]
-++Dialog text:"Text in dialog" paneTitle:"dialog opened." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="dialog", roleDescription="dialog"]
\ No newline at end of file
+++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
+++++Dialog text:"Text in dialog" paneTitle:"dialog opened." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="dialog", roleDescription="dialog"]
diff --git a/content/test/data/accessibility/html/dialog-expected-android.txt b/content/test/data/accessibility/html/dialog-expected-android.txt
index a00521f8..61f6832 100644
--- a/content/test/data/accessibility/html/dialog-expected-android.txt
+++ b/content/test/data/accessibility/html/dialog-expected-android.txt
@@ -1,2 +1,3 @@
 android.webkit.WebView focusable focused scrollable
-++android.app.Dialog role_description='dialog' name='Text in dialog'
\ No newline at end of file
+++android.view.View
+++++android.app.Dialog role_description='dialog' name='Text in dialog'
diff --git a/content/test/data/accessibility/html/dialog-expected-auralinux.txt b/content/test/data/accessibility/html/dialog-expected-auralinux.txt
index 1678791c..9e646d0 100644
--- a/content/test/data/accessibility/html/dialog-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/dialog-expected-auralinux.txt
@@ -1,3 +1,4 @@
 [document web]
-++[dialog]
-++++[static] name='Text in dialog'
+++[section]
+++++[dialog]
+++++++[static] name='Text in dialog'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-blink.txt b/content/test/data/accessibility/html/dialog-expected-blink.txt
index 2031cd98..c457d0b 100644
--- a/content/test/data/accessibility/html/dialog-expected-blink.txt
+++ b/content/test/data/accessibility/html/dialog-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer
 ++++++dialog
 ++++++++staticText name='Text in dialog'
-++++++++++inlineTextBox name='Text in dialog'
+++++++++++inlineTextBox name='Text in dialog'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-fuchsia.txt b/content/test/data/accessibility/html/dialog-expected-fuchsia.txt
index 0f7f56d..3313a1b 100644
--- a/content/test/data/accessibility/html/dialog-expected-fuchsia.txt
+++ b/content/test/data/accessibility/html/dialog-expected-fuchsia.txt
@@ -1,6 +1,6 @@
 UNKNOWN focusable has_input_focus
 ++UNKNOWN hidden
-++++UNKNOWN hidden
+++++UNKNOWN
 ++++++UNKNOWN
 ++++++++STATIC_TEXT label='Text in dialog'
-++++++++++UNKNOWN label='Text in dialog'
\ No newline at end of file
+++++++++++UNKNOWN label='Text in dialog'
diff --git a/content/test/data/accessibility/html/dialog-expected-mac.txt b/content/test/data/accessibility/html/dialog-expected-mac.txt
index d5017e9..65bb711 100644
--- a/content/test/data/accessibility/html/dialog-expected-mac.txt
+++ b/content/test/data/accessibility/html/dialog-expected-mac.txt
@@ -1,3 +1,4 @@
 AXWebArea
-++AXGroup AXSubrole=AXApplicationDialog
-++++AXStaticText AXValue='Text in dialog'
+++AXGroup
+++++AXGroup AXSubrole=AXApplicationDialog
+++++++AXStaticText AXValue='Text in dialog'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-uia-win.txt b/content/test/data/accessibility/html/dialog-expected-uia-win.txt
index 002cbb2..db74f7a 100644
--- a/content/test/data/accessibility/html/dialog-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/dialog-expected-uia-win.txt
@@ -1,3 +1,4 @@
 Document
-++Window IsControlElement=false Window.IsModal=false
-++++Text Name='Text in dialog'
+++Group IsControlElement=false
+++++Window IsControlElement=false Window.IsModal=false
+++++++Text Name='Text in dialog'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-win.txt b/content/test/data/accessibility/html/dialog-expected-win.txt
index 5cecfd7d..e91b184 100644
--- a/content/test/data/accessibility/html/dialog-expected-win.txt
+++ b/content/test/data/accessibility/html/dialog-expected-win.txt
@@ -1,3 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_DIALOG
-++++ROLE_SYSTEM_STATICTEXT name='Text in dialog'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_DIALOG
+++++++ROLE_SYSTEM_STATICTEXT name='Text in dialog'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-android.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-android.txt
index 4465176..5384852 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-android.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-android.txt
@@ -1,5 +1,6 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View
-++++android.view.View scrollable
-++android.view.View
-++++android.view.View scrollable
+++++android.view.View
+++++++android.view.View scrollable
+++++android.view.View
+++++++android.view.View scrollable
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-auralinux.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-auralinux.txt
index 1c48268..cdc46a31 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-auralinux.txt
@@ -1,5 +1,6 @@
 [document web]
-++[internal frame]
-++++[document web]
-++[internal frame]
-++++[document web]
\ No newline at end of file
+++[section]
+++++[internal frame]
+++++++[document web]
+++++[internal frame]
+++++++[document web]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-blink.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-blink.txt
index 3e04afa..9e7554c 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer
 ++++++iframe
 ++++++++rootWebArea
 ++++++++++genericContainer ignored
@@ -8,4 +8,4 @@
 ++++++iframe
 ++++++++rootWebArea
 ++++++++++genericContainer ignored
-++++++++++++genericContainer ignored
+++++++++++++genericContainer ignored
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-fuchsia.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-fuchsia.txt
index 14e283aa1..9afeef1 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-fuchsia.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-fuchsia.txt
@@ -1,6 +1,6 @@
 UNKNOWN focusable has_input_focus
 ++UNKNOWN hidden
-++++UNKNOWN hidden
+++++UNKNOWN
 ++++++UNKNOWN
 ++++++++UNKNOWN focusable
 ++++++++++UNKNOWN hidden
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-mac.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-mac.txt
index ac1b05b..47128acc 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-mac.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-mac.txt
@@ -1,5 +1,6 @@
 AXWebArea
 ++AXGroup
-++++AXWebArea
-++AXGroup
-++++AXWebArea
+++++AXGroup
+++++++AXWebArea
+++++AXGroup
+++++++AXWebArea
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-uia-win.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-uia-win.txt
index fe49b5b2..b74a4a6 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-uia-win.txt
@@ -1,5 +1,6 @@
 Document
-++Document IsControlElement=false
-++++Document
-++Document IsControlElement=false
-++++Document
\ No newline at end of file
+++Group IsControlElement=false
+++++Document IsControlElement=false
+++++++Document
+++++Document IsControlElement=false
+++++++Document
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-empty-positioned-expected-win.txt b/content/test/data/accessibility/html/iframe-empty-positioned-expected-win.txt
index 870cb45..4f3fc65 100644
--- a/content/test/data/accessibility/html/iframe-empty-positioned-expected-win.txt
+++ b/content/test/data/accessibility/html/iframe-empty-positioned-expected-win.txt
@@ -1,5 +1,6 @@
-ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>'
-++IA2_ROLE_INTERNAL_FRAME ia2_hypertext='<obj0>'
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++IA2_ROLE_INTERNAL_FRAME ia2_hypertext='<obj0>'
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
\ No newline at end of file
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>'
+++IA2_ROLE_SECTION ia2_hypertext='<obj0><obj1>'
+++++IA2_ROLE_INTERNAL_FRAME ia2_hypertext='<obj0>'
+++++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++++IA2_ROLE_INTERNAL_FRAME ia2_hypertext='<obj0>'
+++++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-padding-expected-blink.txt b/content/test/data/accessibility/html/iframe-padding-expected-blink.txt
index fd3b047..797d2997 100644
--- a/content/test/data/accessibility/html/iframe-padding-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-padding-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer ignored
+++++++genericContainer pageLocation=(0, 0) pageSize=(300, 100)
 ++++++++iframe pageLocation=(0, 0) pageSize=(300, 100)
 ++++++++++rootWebArea pageLocation=(0, 0) pageSize=(300, 100)
 ++++++++++++genericContainer ignored
@@ -10,7 +10,7 @@
 ++++++++++++++++++button pageLocation=(25, 25) pageSize=(250, 50) name='Ordinary Button'
 ++++++++++++++++++++staticText name='Ordinary Button'
 ++++++++++++++++++++++inlineTextBox name='Ordinary Button'
-++++++genericContainer ignored
+++++++genericContainer pageLocation=(30, 230) pageSize=(300, 100)
 ++++++++iframe pageLocation=(30, 230) pageSize=(300, 100)
 ++++++++++rootWebArea pageLocation=(30, 230) pageSize=(300, 100)
 ++++++++++++genericContainer ignored
@@ -18,4 +18,4 @@
 ++++++++++++++++genericContainer pageLocation=(30, 230) pageSize=(300, 100)
 ++++++++++++++++++button pageLocation=(55, 255) pageSize=(250, 50) name='Second Button'
 ++++++++++++++++++++staticText name='Second Button'
-++++++++++++++++++++++inlineTextBox name='Second Button'
+++++++++++++++++++++++inlineTextBox name='Second Button'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
index fa5a868..6c143d4c 100644
--- a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer pageLocation=(0, 0)
 ++++++iframe pageLocation=(0, 0)
 ++++++++rootWebArea pageLocation=(0, 0)
 ++++++++++genericContainer ignored
@@ -10,4 +10,4 @@
 ++++++++rootWebArea pageLocation=(0, 250)
 ++++++++++genericContainer ignored
 ++++++++++++genericContainer ignored
-++++++++++++++image pageLocation=(15, 265) pageSize=(150, 75)
+++++++++++++++image pageLocation=(15, 265) pageSize=(150, 75)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
index fa5a868..6c143d4c 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer pageLocation=(0, 0)
 ++++++iframe pageLocation=(0, 0)
 ++++++++rootWebArea pageLocation=(0, 0)
 ++++++++++genericContainer ignored
@@ -10,4 +10,4 @@
 ++++++++rootWebArea pageLocation=(0, 250)
 ++++++++++genericContainer ignored
 ++++++++++++genericContainer ignored
-++++++++++++++image pageLocation=(15, 265) pageSize=(150, 75)
+++++++++++++++image pageLocation=(15, 265) pageSize=(150, 75)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-fuchsia.txt b/content/test/data/accessibility/html/iframe-transform-expected-fuchsia.txt
index db0a107..2b49322 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-fuchsia.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-fuchsia.txt
@@ -1,6 +1,6 @@
 UNKNOWN focusable has_input_focus
 ++UNKNOWN hidden
-++++UNKNOWN hidden
+++++UNKNOWN
 ++++++UNKNOWN
 ++++++++UNKNOWN focusable
 ++++++++++UNKNOWN hidden
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt b/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
index f1ced26c9..d74d125d 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-uia-win.txt
@@ -1,7 +1,8 @@
 Document
-++Document IsControlElement=false
-++++Document
-++++++Image
-++Document IsControlElement=false
-++++Document
-++++++Image
\ No newline at end of file
+++Group IsControlElement=false
+++++Document IsControlElement=false
+++++++Document
+++++++++Image
+++++Document IsControlElement=false
+++++++Document
+++++++++Image
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-win.txt b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
index 1b5b2f2..e3590d4a 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-win.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
@@ -1,7 +1,8 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
-++IA2_ROLE_INTERNAL_FRAME location=(0, 0)
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
-++++++ROLE_SYSTEM_GRAPHIC READONLY location=(10, 10) size=(100, 50)
-++IA2_ROLE_INTERNAL_FRAME location=(0, 250)
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 250)
-++++++ROLE_SYSTEM_GRAPHIC READONLY location=(15, 265) size=(150, 75)
\ No newline at end of file
+++IA2_ROLE_SECTION location=(0, 0)
+++++IA2_ROLE_INTERNAL_FRAME location=(0, 0)
+++++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
+++++++++ROLE_SYSTEM_GRAPHIC READONLY location=(10, 10) size=(100, 50)
+++++IA2_ROLE_INTERNAL_FRAME location=(0, 250)
+++++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 250)
+++++++++ROLE_SYSTEM_GRAPHIC READONLY location=(15, 265) size=(150, 75)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
index 5178aca..b9747d6 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
@@ -1,12 +1,12 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer pageLocation=(0, 100)
 ++++++iframe pageLocation=(0, 100) transform
 ++++++++rootWebArea pageLocation=(0, 100)
 ++++++++++genericContainer ignored
-++++++++++++genericContainer ignored
+++++++++++++genericContainer pageLocation=(200, 100)
 ++++++++++++++iframe pageLocation=(200, 100) transform
 ++++++++++++++++rootWebArea pageLocation=(200, 100)
 ++++++++++++++++++genericContainer ignored
 ++++++++++++++++++++genericContainer ignored
-++++++++++++++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
+++++++++++++++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
index 5178aca..b9747d6 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
@@ -1,12 +1,12 @@
 rootWebArea pageLocation=(0, 0)
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer pageLocation=(0, 100)
 ++++++iframe pageLocation=(0, 100) transform
 ++++++++rootWebArea pageLocation=(0, 100)
 ++++++++++genericContainer ignored
-++++++++++++genericContainer ignored
+++++++++++++genericContainer pageLocation=(200, 100)
 ++++++++++++++iframe pageLocation=(200, 100) transform
 ++++++++++++++++rootWebArea pageLocation=(200, 100)
 ++++++++++++++++++genericContainer ignored
 ++++++++++++++++++++genericContainer ignored
-++++++++++++++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
+++++++++++++++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/window-crops-items-expected-blink.txt b/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
index c91fa97..37bd6e08 100644
--- a/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
+++ b/content/test/data/accessibility/html/window-crops-items-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea
 ++genericContainer ignored
-++++genericContainer ignored
+++++genericContainer
 ++++++button size=(300, 150) name='Button fits'
 ++++++++staticText name='Button fits'
 ++++++++++inlineTextBox name='Button fits'
@@ -21,4 +21,4 @@
 ++++++++++inlineTextBox offscreen pageSize=(1, 1) name='Button offscreen top'
 ++++++button size=(300, 150) pageSize=(208, 58) name='Button partially on screen'
 ++++++++staticText offscreen name='Button partially on screen'
-++++++++++inlineTextBox offscreen name='Button partially on screen'
+++++++++++inlineTextBox offscreen name='Button partially on screen'
\ No newline at end of file
diff --git a/content/utility/services.cc b/content/utility/services.cc
index 457b153d..8b06b1a 100644
--- a/content/utility/services.cc
+++ b/content/utility/services.cc
@@ -94,6 +94,12 @@
 #endif  // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)) &&
         // (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
 
+#if BUILDFLAG(IS_ANDROID)
+#include "content/public/common/network_service_util.h"
+#include "services/network/empty_network_service.h"
+#include "services/network/public/cpp/features.h"
+#endif
+
 #if BUILDFLAG(ENABLE_ACCESSIBILITY_SERVICE)
 #if BUILDFLAG(SUPPORTS_OS_ACCESSIBILITY_SERVICE)
 #include "services/accessibility/os_accessibility_service.h"  // nogncheck
@@ -370,6 +376,13 @@
   // The network service runs on the IO thread because it needs a message
   // loop of type IO that can get notified when pipes have data.
   services.Add(RunNetworkService);
+#if BUILDFLAG(IS_ANDROID)
+  if (IsInProcessNetworkService() &&
+      base::FeatureList::IsEnabled(
+          network::features::kNetworkServiceEmptyOutOfProcess)) {
+    network::RegisterEmptyNetworkService(services);
+  }
+#endif
 
   // Add new IO-thread services above this line.
   GetContentClient()->utility()->RegisterIOThreadServices(services);
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index c88b40a..9db246a 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -75,13 +75,17 @@
 #endif
 
 #if BUILDFLAG(IS_WIN)
+#include "base/native_library.h"
+#include "base/pickle.h"
 #include "base/rand_util.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/sandbox.h"
+#endif  // BUILDFLAG(IS_WIN)
 
+#if BUILDFLAG(IS_WIN)
 sandbox::TargetServices* g_utility_target_services = nullptr;
-#endif
+#endif  // BUILDFLAG(IS_WIN)
 
 namespace content {
 
@@ -132,6 +136,37 @@
 }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
+#if BUILDFLAG(IS_WIN)
+// Handle pre-lockdown sandbox hooks
+bool PreLockdownSandboxHook(base::span<const uint8_t> delegate_blob) {
+  CHECK_GT(delegate_blob.size(), 0u);
+  // TODO(1435571) Use a typed structure rather than a base::Pickle for this.
+  // TODO(1435571) Migrate other settable things to delegate_data.
+  base::Pickle libs_pickle(reinterpret_cast<const char*>(delegate_blob.data()),
+                           delegate_blob.size());
+  base::PickleIterator libs_iter(libs_pickle);
+  base::FilePath library_path;
+  while (library_path.ReadFromPickle(&libs_iter)) {
+    CHECK(library_path.IsAbsolute());
+    base::NativeLibraryLoadError lib_error;
+    HMODULE h_mod = base::LoadNativeLibrary(library_path, &lib_error);
+    // We deliberately "leak" `h_mod` so that the module stays loaded.
+    if (!h_mod) {
+      // The browser should not request libraries that do not exist, so crash on
+      // failure.
+      wchar_t dll_name[MAX_PATH];
+      base::wcslcpy(dll_name, library_path.value().c_str(), MAX_PATH);
+      base::debug::Alias(dll_name);
+      base::debug::Alias(&lib_error);
+      NOTREACHED_NORETURN();
+    }
+  }
+  CHECK(libs_iter.ReachedEnd());
+
+  return true;
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 void SetUtilityThreadName(const std::string utility_sub_type) {
   // Typical utility sub-types are audio.mojom.AudioService or
   // proxy_resolver.mojom.ProxyResolverFactory. Using the full sub-type as part
@@ -263,6 +298,15 @@
   }
 #elif BUILDFLAG(IS_WIN)
   g_utility_target_services = parameters.sandbox_info->target_services;
+
+  // Call hooks with data provided by UtilitySandboxedProcessLauncherDelegate.
+  // Must happen before IO thread to preempt any mojo services starting.
+  if (g_utility_target_services) {
+    auto delegate_data = g_utility_target_services->GetDelegateData();
+    if (delegate_data.has_value() && !delegate_data->empty()) {
+      PreLockdownSandboxHook(delegate_data.value());
+    }
+  }
 #endif
 
   ChildProcess utility_process(base::ThreadType::kDefault);
diff --git a/crypto/rsa_private_key_unittest.cc b/crypto/rsa_private_key_unittest.cc
index 67d3a9d8..d123185 100644
--- a/crypto/rsa_private_key_unittest.cc
+++ b/crypto/rsa_private_key_unittest.cc
@@ -353,7 +353,7 @@
 
 TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) {
   std::unique_ptr<crypto::RSAPrivateKey> key_pair(
-      crypto::RSAPrivateKey::Create(512));
+      crypto::RSAPrivateKey::Create(2048));
   ASSERT_TRUE(key_pair.get());
 
   std::unique_ptr<crypto::RSAPrivateKey> key_copy(
diff --git a/docs/security/severity-guidelines.md b/docs/security/severity-guidelines.md
index 5db1495..bc7d69a 100644
--- a/docs/security/severity-guidelines.md
+++ b/docs/security/severity-guidelines.md
@@ -17,6 +17,7 @@
   Chrome, nor could a user be easily convinced to perform by a persuasive web page.
 * Requiring profile destruction or browser shutdown will normally reduce
   severity by one level.
+* [MiraclePtr protection](#TOC-MiraclePtr)
 
 Bugs that require implausible interaction, interactions a user would not
 realistically be convinced to perform, will generally be downgraded to a
@@ -190,7 +191,7 @@
 and, in particular, null pointer dereferences with consistent fixed offsets.
 
 
-## "MiraclePtr" protection against use-after-free
+## "MiraclePtr" protection against use-after-free {#TOC-MiraclePtr}
 
 ["MiraclePtr"](../../base/memory/raw_ptr.md) is a technology designed to
 deterministically prevent exploitation of use-after-free bugs. Address
@@ -210,7 +211,15 @@
 MiraclePtr should make this crash non-exploitable in regular builds.
 ```
 
-For now, ignore these messages while determining severity, because MiraclePtr
-is not yet active on all Chromium platforms. In the future, we'll use this
-protection to reduce the severity of these bugs or even (once we have a lot of
-practical experience) reclassify them as non-security bugs.
+MiraclePtr is now active on all relevant Chromium platforms since main position
+[1136369](https://chromium-review.googlesource.com/c/chromium/src/+/4478673),
+which will be present in Chrome 115.
+
+If a bug impacts only M115 or later and is marked `MiraclePtr Status:
+PROTECTED`, it should be downgraded by one severity level. (For example, a bug
+that would previously be High severity would now be only Medium severity).
+Once M115 has reached Extended Stable, we will apply this rule to all such
+`MiraclePtr Status: PROTECTED` bugs.
+
+Once we have more practical experience across all platforms, we may reclassify
+them as non-security bugs.
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index fa9cac8..1dd470e 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -859,15 +859,19 @@
 Background updates can be disabled entirely through policy.
 
 #### Windows Scheduling of Updates
-The update tasks are scheduled using the OS task scheduler.
+The update wake task is scheduled using the OS task scheduler.
 
-The time resolution for tasks is 1 minute. Tasks are set to run 5 minutes after
-they've been created. If a task execution is missed, it will run as soon as the
-system is able to.
+The time resolution for tasks is 1 minute. The update wake task is set to run 5
+minutes after creation. If a task execution is missed, it will run as soon as
+the system is able to.
+
+The updater runs the wake task at system startup for system installs, via the
+system service, which is set to Automatic Start.
 
 The updater also runs at user login. For system installs, this is done via a
-logon trigger on the scheduled task. For user installs, this is done via the
-"Run" registry entry in `HKCU`.
+logon trigger on the scheduled task. For user installs, this is done via both
+the logon trigger on the scheduled task, as well as the "Run" registry entry in
+`HKCU` for redundancy.
 
 ### On-Demand Updates
 The updater exposes an RPC interface for any user to trigger an update check.
diff --git a/extensions/browser/api/content_settings/content_settings_store.cc b/extensions/browser/api/content_settings/content_settings_store.cc
index 9f9f0409..54363cf 100644
--- a/extensions/browser/api/content_settings/content_settings_store.cc
+++ b/extensions/browser/api/content_settings/content_settings_store.cc
@@ -302,15 +302,16 @@
       continue;
 
     while (rule_iterator->HasNext()) {
-      const Rule& rule = rule_iterator->Next();
+      std::unique_ptr<Rule> rule = rule_iterator->Next();
       base::Value::Dict setting_dict;
-      setting_dict.Set(kPrimaryPatternKey, rule.primary_pattern.ToString());
-      setting_dict.Set(kSecondaryPatternKey, rule.secondary_pattern.ToString());
+      setting_dict.Set(kPrimaryPatternKey, rule->primary_pattern.ToString());
+      setting_dict.Set(kSecondaryPatternKey,
+                       rule->secondary_pattern.ToString());
       setting_dict.Set(
           kContentSettingsTypeKey,
           content_settings_helpers::ContentSettingsTypeToString(key));
       ContentSetting content_setting =
-          content_settings::ValueToContentSetting(rule.value);
+          content_settings::ValueToContentSetting(rule->value());
       DCHECK_NE(CONTENT_SETTING_DEFAULT, content_setting);
 
       std::string setting_string =
diff --git a/extensions/browser/api/content_settings/content_settings_store_unittest.cc b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
index e84138b..0f2016b 100644
--- a/extensions/browser/api/content_settings/content_settings_store_unittest.cc
+++ b/extensions/browser/api/content_settings/content_settings_store_unittest.cc
@@ -27,13 +27,13 @@
 
 namespace {
 
-void CheckRule(const content_settings::Rule& rule,
+void CheckRule(std::unique_ptr<content_settings::Rule> rule,
                const ContentSettingsPattern& primary_pattern,
                const ContentSettingsPattern& secondary_pattern,
                ContentSetting setting) {
-  EXPECT_EQ(primary_pattern.ToString(), rule.primary_pattern.ToString());
-  EXPECT_EQ(secondary_pattern.ToString(), rule.secondary_pattern.ToString());
-  EXPECT_EQ(setting, content_settings::ValueToContentSetting(rule.value));
+  EXPECT_EQ(primary_pattern.ToString(), rule->primary_pattern.ToString());
+  EXPECT_EQ(secondary_pattern.ToString(), rule->secondary_pattern.ToString());
+  EXPECT_EQ(setting, content_settings::ValueToContentSetting(rule->value()));
 }
 
 // Helper class which returns monotonically-increasing base::Time objects.
@@ -69,11 +69,11 @@
   return content_settings::ValueToContentSetting(setting);
 }
 
-std::vector<content_settings::Rule> GetSettingsForOneTypeFromStore(
-    const ContentSettingsStore* store,
-    ContentSettingsType content_type,
-    bool incognito) {
-  std::vector<content_settings::Rule> rules;
+std::vector<std::unique_ptr<content_settings::Rule>>
+GetSettingsForOneTypeFromStore(const ContentSettingsStore* store,
+                               ContentSettingsType content_type,
+                               bool incognito) {
+  std::vector<std::unique_ptr<content_settings::Rule>> rules;
   std::unique_ptr<content_settings::RuleIterator> rule_iterator(
       store->GetRuleIterator(content_type, incognito));
   if (rule_iterator) {
@@ -169,9 +169,11 @@
 
 TEST_F(ContentSettingsStoreTest, GetAllSettings) {
   const bool incognito = false;
-  std::vector<content_settings::Rule> rules = GetSettingsForOneTypeFromStore(
-      store(), ContentSettingsType::COOKIES, incognito);
+  std::vector<std::unique_ptr<content_settings::Rule>> rules =
+      GetSettingsForOneTypeFromStore(store(), ContentSettingsType::COOKIES,
+                                     incognito);
   ASSERT_EQ(0u, rules.size());
+  rules.clear();
 
   // Register first extension.
   std::string ext_id("my_extension");
@@ -185,7 +187,8 @@
   rules = GetSettingsForOneTypeFromStore(store(), ContentSettingsType::COOKIES,
                                          incognito);
   ASSERT_EQ(1u, rules.size());
-  CheckRule(rules[0], pattern, pattern, CONTENT_SETTING_ALLOW);
+  CheckRule(std::move(rules[0]), pattern, pattern, CONTENT_SETTING_ALLOW);
+  rules.clear();
 
   // Register second extension.
   std::string ext_id_2("my_second_extension");
@@ -200,8 +203,9 @@
                                          incognito);
   ASSERT_EQ(2u, rules.size());
   // Rules appear in the reverse installation order of the extensions.
-  CheckRule(rules[0], pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
-  CheckRule(rules[1], pattern, pattern, CONTENT_SETTING_ALLOW);
+  CheckRule(std::move(rules[0]), pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
+  CheckRule(std::move(rules[1]), pattern, pattern, CONTENT_SETTING_ALLOW);
+  rules.clear();
 
   // Disable first extension.
   store()->SetExtensionState(ext_id, false);
@@ -209,7 +213,8 @@
   rules = GetSettingsForOneTypeFromStore(store(), ContentSettingsType::COOKIES,
                                          incognito);
   ASSERT_EQ(1u, rules.size());
-  CheckRule(rules[0], pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
+  CheckRule(std::move(rules[0]), pattern_2, pattern_2, CONTENT_SETTING_BLOCK);
+  rules.clear();
 
   // Uninstall second extension.
   store()->UnregisterExtension(ext_id_2);
diff --git a/extensions/browser/api/web_request/web_request_resource_type.cc b/extensions/browser/api/web_request/web_request_resource_type.cc
index 56a4b0a..9bae3c09f 100644
--- a/extensions/browser/api/web_request/web_request_resource_type.cc
+++ b/extensions/browser/api/web_request/web_request_resource_type.cc
@@ -98,6 +98,9 @@
     case network::mojom::RequestDestination::kManifest:
     case network::mojom::RequestDestination::kPaintWorklet:
     case network::mojom::RequestDestination::kWebIdentity:
+    // The compression dictionary has not been exposed to extensions yet.
+    // We could do so if the need arises.
+    case network::mojom::RequestDestination::kDictionary:
       return WebRequestResourceType::OTHER;
   }
   NOTREACHED();
diff --git a/extensions/browser/core_browser_context_keyed_service_factories.cc b/extensions/browser/core_browser_context_keyed_service_factories.cc
index 0940214b..57e656f 100644
--- a/extensions/browser/core_browser_context_keyed_service_factories.cc
+++ b/extensions/browser/core_browser_context_keyed_service_factories.cc
@@ -11,6 +11,7 @@
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_message_filter.h"
 #include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extension_prefs_helper_factory.h"
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extension_service_worker_message_filter.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
@@ -32,6 +33,7 @@
   ExtensionMessageFilter::EnsureShutdownNotifierFactoryBuilt();
   ExtensionServiceWorkerMessageFilter::EnsureShutdownNotifierFactoryBuilt();
   ExtensionPrefsFactory::GetInstance();
+  ExtensionPrefsHelperFactory::GetInstance();
   ImageLoaderFactory::GetInstance();
   MimeHandlerStreamManager::EnsureFactoryBuilt();
   ProcessManagerFactory::GetInstance();
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc
index 0cd28d1..51adfa0 100644
--- a/extensions/browser/extension_util.cc
+++ b/extensions/browser/extension_util.cc
@@ -214,10 +214,8 @@
          !PermissionsData::CanExecuteScriptEverywhere(extension_id, location);
 }
 
-// The below functionality maps a context to a unique id by increasing a static
-// counter.
 int GetBrowserContextId(content::BrowserContext* context) {
-  using ContextIdMap = std::map<content::BrowserContext*, int>;
+  using ContextIdMap = std::map<std::string, int>;
 
   static int next_id = 0;
   static base::NoDestructor<ContextIdMap> context_map;
@@ -225,17 +223,15 @@
   // we need to get the original context to make sure we take the right context.
   content::BrowserContext* original_context =
       ExtensionsBrowserClient::Get()->GetOriginalContext(context);
-  auto iter = context_map->find(original_context);
+  const std::string& context_id = original_context->UniqueId();
+  auto iter = context_map->find(context_id);
   if (iter == context_map->end()) {
-    iter =
-        context_map->insert(std::make_pair(original_context, next_id++)).first;
+    iter = context_map->insert(std::make_pair(context_id, next_id++)).first;
   }
   DCHECK(iter->second != kUnspecifiedContextId);
   return iter->second;
 }
 
-// Returns whether the |extension| should be loaded in the given
-// |browser_context|.
 bool IsExtensionVisibleToContext(const Extension& extension,
                                  content::BrowserContext* browser_context) {
   // Renderers don't need to know about themes.
@@ -251,7 +247,6 @@
          IsIncognitoEnabled(extension.id(), browser_context);
 }
 
-// Initializes file scheme access if the extension has such permission.
 void InitializeFileSchemeAccessForExtension(
     int render_process_id,
     const std::string& extension_id,
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h
index 1084e73..69c11fe 100644
--- a/extensions/browser/extension_util.h
+++ b/extensions/browser/extension_util.h
@@ -95,7 +95,11 @@
     const Manifest::Type type,
     const mojom::ManifestLocation location);
 
-// Returns a unique int id for each context.
+// Returns a unique int id for each context. Prefer using
+// `BrowserContext::UniqueId()` directly.
+// TODO(crbug.com/1444279):  Migrate callers to use the `context` unique id
+// directly. For that we need to update all data keyed by integer context ids to
+// be keyed by strings instead
 int GetBrowserContextId(content::BrowserContext* context);
 
 // Returns whether the |extension| should be loaded in the given
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc
index ba74b3bc..babfc75b7 100644
--- a/extensions/common/file_util.cc
+++ b/extensions/common/file_util.cc
@@ -313,14 +313,15 @@
   // not on the reserved list. We only warn, and do not block the loading of the
   // extension.
   std::string warning;
-  if (!CheckForIllegalFilenames(extension->path(), &warning))
-    warnings->push_back(InstallWarning(warning));
+  if (!CheckForIllegalFilenames(extension->path(), &warning)) {
+    warnings->emplace_back(warning);
+  }
 
   // Check that the extension does not include any Windows reserved filenames.
   std::string windows_reserved_warning;
   if (!CheckForWindowsReservedFilenames(extension->path(),
                                         &windows_reserved_warning)) {
-    warnings->push_back(InstallWarning(windows_reserved_warning));
+    warnings->emplace_back(windows_reserved_warning);
   }
 
   // Check that extensions don't include private key files.
@@ -336,10 +337,9 @@
       return false;
     }
   } else {
-    for (size_t i = 0; i < private_keys.size(); ++i) {
-      warnings->push_back(InstallWarning(
-          l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTAINS_PRIVATE_KEY,
-                                    private_keys[i].LossyDisplayName())));
+    for (const auto& private_key : private_keys) {
+      warnings->emplace_back(l10n_util::GetStringFUTF8(
+          IDS_EXTENSION_CONTAINS_PRIVATE_KEY, private_key.LossyDisplayName()));
     }
     // Only warn; don't block loading the extension.
   }
diff --git a/extensions/renderer/trace_util.h b/extensions/renderer/trace_util.h
index 39bca3ef..94d011e 100644
--- a/extensions/renderer/trace_util.h
+++ b/extensions/renderer/trace_util.h
@@ -17,7 +17,7 @@
 #define TRACE_RENDERER_EXTENSION_EVENT(event_name, extension_id)              \
   TRACE_EVENT("extensions", event_name,                                       \
               perfetto::protos::pbzero::ChromeTrackEvent::kRenderProcessHost, \
-              *content::RenderThread::Get(),                                  \
+              content::RenderThread::Get(),                                   \
               perfetto::protos::pbzero::ChromeTrackEvent::kChromeExtensionId, \
               ExtensionIdForTracing(extension_id))
 
diff --git a/fuchsia_web/runners/cast/main.cc b/fuchsia_web/runners/cast/main.cc
index ead200e..c8ca91c 100644
--- a/fuchsia_web/runners/cast/main.cc
+++ b/fuchsia_web/runners/cast/main.cc
@@ -97,8 +97,11 @@
   const base::ScopedNaturalServiceBinding resolver_binding(outgoing_directory,
                                                            &resolver);
 
+  // Services from this component will be provided to each web instance.
+  WebInstanceHostWithServicesFromThisComponent web_instance_host(
+      *outgoing_directory);
+
   // Publish the fuchsia.component.runner.ComponentRunner for Cast apps.
-  WebInstanceHost web_instance_host(*outgoing_directory);
   CastRunner runner(
       web_instance_host,
       {.headless = command_line->HasSwitch(kForceHeadlessForTestsSwitch) ||
diff --git a/fuchsia_web/runners/common/web_content_runner.h b/fuchsia_web/runners/common/web_content_runner.h
index 36830b3..6c580624 100644
--- a/fuchsia_web/runners/common/web_content_runner.h
+++ b/fuchsia_web/runners/common/web_content_runner.h
@@ -39,7 +39,7 @@
       base::RepeatingCallback<zx_status_t(
           fuchsia::web::CreateContextParams params,
           fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
-          base::CommandLine extra_args)>;
+          const base::CommandLine& extra_args)>;
 
   using GetWebInstanceConfigCallback =
       base::RepeatingCallback<WebInstanceConfig()>;
diff --git a/fuchsia_web/shell/cast_streaming_shell.cc b/fuchsia_web/shell/cast_streaming_shell.cc
index 0628ea9..2caa1dd 100644
--- a/fuchsia_web/shell/cast_streaming_shell.cc
+++ b/fuchsia_web/shell/cast_streaming_shell.cc
@@ -123,7 +123,7 @@
   }
 
   // Instantiate Web Instance Host.
-  WebInstanceHost web_instance_host(
+  WebInstanceHostWithServicesFromThisComponent web_instance_host(
       *base::ComponentContextForProcess()->outgoing());
   fidl::InterfaceRequest<fuchsia::io::Directory> services_request;
   auto services = sys::ServiceDirectory::CreateWithRequest(&services_request);
diff --git a/fuchsia_web/shell/web_engine_shell.cc b/fuchsia_web/shell/web_engine_shell.cc
index 994ef716..d275a46 100644
--- a/fuchsia_web/shell/web_engine_shell.cc
+++ b/fuchsia_web/shell/web_engine_shell.cc
@@ -218,8 +218,9 @@
   } else {
     // Route services dynamically from web_engine_shell's parent down into
     // created web_instances.
-    web_instance_host = std::make_unique<WebInstanceHost>(
-        *base::ComponentContextForProcess()->outgoing());
+    web_instance_host =
+        std::make_unique<WebInstanceHostWithServicesFromThisComponent>(
+            *base::ComponentContextForProcess()->outgoing());
     if (enable_web_instance_tmp) {
       const zx_status_t status = fdio_open(
           "/tmp",
diff --git a/fuchsia_web/webengine/browser/frame_impl_browsertest.cc b/fuchsia_web/webengine/browser/frame_impl_browsertest.cc
index 8ef15e5..232d261 100644
--- a/fuchsia_web/webengine/browser/frame_impl_browsertest.cc
+++ b/fuchsia_web/webengine/browser/frame_impl_browsertest.cc
@@ -1042,6 +1042,40 @@
   frame.navigation_listener().RunUntilUrlAndTitleEquals(page1_url, kPage1Title);
 }
 
+IN_PROC_BROWSER_TEST_F(FrameImplTest, CreateViewMissingArgs) {
+  auto frame = FrameForTest::Create(context(), {});
+
+  // Close the NavigationEventListener to avoid a test failure resulting, when
+  // it is disconnected as a result of the Frame closing.
+  frame.navigation_listener_binding().Close(ZX_OK);
+
+  // Create a view with GFX, without supplying a valid view token.
+  base::test::TestFuture<zx_status_t> frame_status;
+  frame.ptr().set_error_handler(
+      CallbackToFitFunction(frame_status.GetCallback()));
+
+  frame->CreateView({});
+
+  EXPECT_EQ(frame_status.Get(), ZX_ERR_INVALID_ARGS);
+}
+
+IN_PROC_BROWSER_TEST_F(FrameImplTest, CreateView2MissingArgs) {
+  auto frame = FrameForTest::Create(context(), {});
+
+  // Close the NavigationEventListener to avoid a test failure resulting, when
+  // it is disconnected as a result of the Frame closing.
+  frame.navigation_listener_binding().Close(ZX_OK);
+
+  // Create a view with GFX, without supplying a valid view token.
+  base::test::TestFuture<zx_status_t> frame_status;
+  frame.ptr().set_error_handler(
+      CallbackToFitFunction(frame_status.GetCallback()));
+
+  frame->CreateView2({});
+
+  EXPECT_EQ(frame_status.Get(), ZX_ERR_INVALID_ARGS);
+}
+
 IN_PROC_BROWSER_TEST_F(FrameImplTest, ChildFrameNavigationIgnored) {
   net::test_server::EmbeddedTestServerHandle test_server_handle;
   ASSERT_TRUE(test_server_handle =
diff --git a/fuchsia_web/webengine/context_provider_impl.cc b/fuchsia_web/webengine/context_provider_impl.cc
index d63e7dbb..8b2c702 100644
--- a/fuchsia_web/webengine/context_provider_impl.cc
+++ b/fuchsia_web/webengine/context_provider_impl.cc
@@ -24,6 +24,13 @@
     return;
   }
 
+  // The CreateInstanceForContextWithCopiedArgs() call below requires that
+  // `params` has a service directory.
+  if (!params.has_service_directory()) {
+    context_request.Close(ZX_ERR_INVALID_ARGS);
+    return;
+  }
+
   // Create the instance and request access to its outgoing service directory.
   fidl::InterfaceHandle<fuchsia::io::Directory> services_handle;
   zx_status_t result =
diff --git a/fuchsia_web/webengine/context_provider_impl.h b/fuchsia_web/webengine/context_provider_impl.h
index fe71e006..0560401 100644
--- a/fuchsia_web/webengine/context_provider_impl.h
+++ b/fuchsia_web/webengine/context_provider_impl.h
@@ -37,7 +37,9 @@
 
  private:
   // Manages an isolated Environment, and the web instances hosted within it.
-  WebInstanceHost web_instance_host_;
+  // Services for each web instance are provided by the Service Directory
+  // provided in the Create() call.
+  WebInstanceHostWithoutServices web_instance_host_;
 };
 
 #endif  // FUCHSIA_WEB_WEBENGINE_CONTEXT_PROVIDER_IMPL_H_
diff --git a/fuchsia_web/webengine/context_provider_impl_unittest.cc b/fuchsia_web/webengine/context_provider_impl_unittest.cc
index 67b7c0a2..8068117 100644
--- a/fuchsia_web/webengine/context_provider_impl_unittest.cc
+++ b/fuchsia_web/webengine/context_provider_impl_unittest.cc
@@ -477,29 +477,10 @@
                GetInstanceDirectory(instance_name).AppendASCII("svc"));
 }
 
-TEST_F(ContextProviderImplTest, CanCreateContextWithoutServiceDirectory) {
-  fidl::InterfaceRequest<fuchsia::component::Binder> binder_request;
-  fidl::InterfaceRequest<fuchsia::web::Context> context_request;
-  ExpectChildInstance(binder_request, context_request);
-
-  fuchsia::web::ContextPtr context;
-  const std::string instance_name =
-      CreateAndWaitForInstance(context_provider(), {}, context);
-  ASSERT_FALSE(instance_name.empty());
-
-  // Requests for both interfaces should have been made.
-  ASSERT_TRUE(binder_request);
-  ASSERT_TRUE(context_request);
-
-  const auto& child = GetInstanceDecl(instance_name);
-  const auto& create_child_args = GetInstanceArgs(instance_name);
-
-  ASSERT_THAT(child, UrlIs("fuchsia-pkg://fuchsia.com/web_engine#meta/"
-                           "web_instance.cm"));
-  ASSERT_THAT(create_child_args,
-              Not(HasDynamicDirectoryOffer("svc", fuchsia::io::RW_STAR_DIR)));
-  ASSERT_FALSE(
-      base::PathExists(GetInstanceDirectory(instance_name).AppendASCII("svc")));
+TEST_F(ContextProviderImplTest, CreateContextWithoutServiceDirectoryFails) {
+  fuchsia::web::ContextPtr context_ptr;
+  context_provider().Create({}, context_ptr.NewRequest());
+  ASSERT_EQ(WaitForContextClosedStatus(context_ptr), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ContextProviderImplTest, CreateValidatesDataDirectory) {
diff --git a/fuchsia_web/webinstance_host/web_instance_host.cc b/fuchsia_web/webinstance_host/web_instance_host.cc
index 912ac71..0f279874 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.cc
+++ b/fuchsia_web/webinstance_host/web_instance_host.cc
@@ -44,16 +44,17 @@
 constexpr char kCollectionName[] = "web_instances";
 
 // Returns the URL of the WebInstance component to be launched.
+// `with_webui` is a test-only feature for `web_engine_shell` that causes
+// `web_instance.cm` to be run from the `web_engine_with_webui` package rather
+// than the production `web_engine` package.
 std::string MakeWebInstanceComponentUrl(bool with_webui,
-                                        bool with_service_directory) {
+                                        base::StringPiece component_name) {
   // TODO(crbug.com/1010222): Use a relative component URL when the hosting
   // component is in the same package as web_instance.cm and remove this
   // workaround.
-  return base::StrCat(
-      {"fuchsia-pkg://fuchsia.com/",
-       (with_webui ? "web_engine_with_webui" : "web_engine"), "#meta/",
-       (with_service_directory ? "web_instance_with_svc_directory.cm"
-                               : "web_instance.cm")});
+  return base::StrCat({"fuchsia-pkg://fuchsia.com/",
+                       (with_webui ? "web_engine_with_webui" : "web_engine"),
+                       "#meta/", component_name});
 }
 
 // Returns the "/web_instances" dir from the component's outgoing directory,
@@ -140,9 +141,11 @@
       fidl::InterfaceRequest<fuchsia::web::Debug> debug_request);
 
   // Builds and returns the instance, or an error status value.
+  // `fuchsia.web/Debug` will be published in `outgoing_services_request` if
+  // `SetDebugRequest()` has been called.
   Instance Build(
-      const std::string& instance_component_url,
-      fidl::InterfaceRequest<fuchsia::io::Directory> services_request);
+      base::StringPiece instance_component_url,
+      fidl::InterfaceRequest<fuchsia::io::Directory> outgoing_services_request);
 
  private:
   InstanceBuilder(sys::OutgoingDirectory& outgoing_directory,
@@ -348,8 +351,8 @@
 }
 
 Instance InstanceBuilder::Build(
-    const std::string& instance_component_url,
-    fidl::InterfaceRequest<fuchsia::io::Directory> services_request) {
+    base::StringPiece instance_component_url,
+    fidl::InterfaceRequest<fuchsia::io::Directory> outgoing_services_request) {
   ServeCommandLine();
 
   // Create dynamic offers from `void` for any optional directories
@@ -358,7 +361,7 @@
 
   fcdecl::Child child_decl;
   child_decl.set_name(name_);
-  child_decl.set_url(instance_component_url);
+  child_decl.set_url(std::string(instance_component_url));
   child_decl.set_startup(fcdecl::StartupMode::LAZY);
 
   ::fuchsia::component::CreateChildArgs create_child_args;
@@ -389,7 +392,7 @@
   if (debug_request_) {
     instance_services.Connect(std::move(debug_request_));
   }
-  instance_services.CloneChannel(std::move(services_request));
+  instance_services.CloneChannel(std::move(outgoing_services_request));
 
   // Ownership of the child and `instance_dir_` are now passed to the caller.
   instance_dir_ = nullptr;
@@ -557,26 +560,14 @@
   Uninitialize();
 }
 
-zx_status_t WebInstanceHost::CreateInstanceForContextWithCopiedArgs(
+zx_status_t WebInstanceHost::CreateInstanceForContextWithCopiedArgsAndUrl(
     fuchsia::web::CreateContextParams params,
-    fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
-    base::CommandLine extra_args) {
+    fidl::InterfaceRequest<fuchsia::io::Directory> outgoing_services_request,
+    base::CommandLine extra_args,
+    base::StringPiece instance_component_url,
+    std::vector<std::string> services_to_offer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  const bool with_service_directory = params.has_service_directory();
-
-  // True if the process includes `--with-webui` on its command line. This is a
-  // test-only feature for `web_engine_shell` that causes `web_instance.cm` to
-  // be run from the `web_engine_with_webui` package rather than the production
-  // `web_engine` package.
-  const bool with_webui =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWithWebui);
-
-  // Web UI resources are not supported with a service directory.
-  if (with_webui && with_service_directory) {
-    return ZX_ERR_INVALID_ARGS;
-  }
-
   if (!is_initialized()) {
     Initialize();
   }
@@ -593,17 +584,13 @@
     return status;
   }
 
-  if (with_service_directory) {
+  // Only one method of providing services should be used.
+  CHECK_NE(!services_to_offer.empty(), params.has_service_directory());
+  if (!services_to_offer.empty()) {
+    builder->AppendOffersForServices(services_to_offer);
+  } else {
     builder->ServeServiceDirectory(
         std::move(*params.mutable_service_directory()));
-  } else {
-    std::vector<std::string> services;
-    const auto features = params.has_features()
-                              ? params.features()
-                              : fuchsia::web::ContextFeatureFlags();
-    AppendDynamicServices(features, params.has_playready_key_system(),
-                          services);
-    builder->AppendOffersForServices(services);
   }
 
   // The `config-data` directory is statically offered to all instances.
@@ -633,17 +620,14 @@
     debug_proxy_.RegisterInstance(std::move(debug_handle));
   }
 
-  const auto instance_component_url =
-      MakeWebInstanceComponentUrl(with_webui, with_service_directory);
-
   // Ensure WebInstance is registered before launching it.
   // TODO(crbug.com/1275224): Replace with a different mechanism when available.
   RegisterWebInstanceProductData(instance_component_url);
 
   // TODO(crbug.com/1395054): Replace the with_webui component with direct
   // routing of the resources from web_engine_shell.
-  auto instance =
-      builder->Build(instance_component_url, std::move(services_request));
+  auto instance = builder->Build(instance_component_url,
+                                 std::move(outgoing_services_request));
   // Monitor the instance's Binder to track its destruction.
   instance.binder_ptr.set_error_handler(
       [this, id = instance.id](zx_status_t status) {
@@ -716,3 +700,57 @@
     Uninitialize();
   }
 }
+
+WebInstanceHostWithServicesFromThisComponent::
+    WebInstanceHostWithServicesFromThisComponent(
+        sys::OutgoingDirectory& outgoing_directory)
+    : WebInstanceHost(outgoing_directory) {}
+
+zx_status_t WebInstanceHostWithServicesFromThisComponent::
+    CreateInstanceForContextWithCopiedArgs(
+        fuchsia::web::CreateContextParams params,
+        fidl::InterfaceRequest<fuchsia::io::Directory>
+            outgoing_services_request,
+        const base::CommandLine& extra_args) {
+  // Services are offered from this Component, so they should not be provided.
+  CHECK(!params.has_service_directory());
+
+  const auto instance_component_url = MakeWebInstanceComponentUrl(
+      base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWithWebui),
+      "web_instance.cm");
+
+  std::vector<std::string> services;
+  const auto features = params.has_features()
+                            ? params.features()
+                            : fuchsia::web::ContextFeatureFlags();
+  AppendDynamicServices(features, params.has_playready_key_system(), services);
+
+  return CreateInstanceForContextWithCopiedArgsAndUrl(
+      std::move(params), std::move(outgoing_services_request), extra_args,
+      instance_component_url, services);
+}
+
+WebInstanceHostWithoutServices::WebInstanceHostWithoutServices(
+    sys::OutgoingDirectory& outgoing_directory)
+    : WebInstanceHost(outgoing_directory) {}
+
+zx_status_t
+WebInstanceHostWithoutServices::CreateInstanceForContextWithCopiedArgs(
+    fuchsia::web::CreateContextParams params,
+    fidl::InterfaceRequest<fuchsia::io::Directory> outgoing_services_request,
+    const base::CommandLine& extra_args) {
+  // Services are not offered from this Component, so they must be provided.
+  CHECK(params.has_service_directory());
+
+  // Web UI resources are not supported with a service directory.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWithWebui)) {
+    return ZX_ERR_INVALID_ARGS;
+  }
+
+  const auto instance_component_url = MakeWebInstanceComponentUrl(
+      /* with_webui */ false, "web_instance_with_svc_directory.cm");
+
+  return CreateInstanceForContextWithCopiedArgsAndUrl(
+      std::move(params), std::move(outgoing_services_request), extra_args,
+      instance_component_url, {});
+}
diff --git a/fuchsia_web/webinstance_host/web_instance_host.h b/fuchsia_web/webinstance_host/web_instance_host.h
index 3d3672f..38f21db 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.h
+++ b/fuchsia_web/webinstance_host/web_instance_host.h
@@ -18,6 +18,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ref.h"
 #include "base/sequence_checker.h"
+#include "base/strings/string_piece_forward.h"
 #include "base/uuid.h"
 #include "fuchsia_web/webinstance_host/fuchsia_web_debug_proxy.h"
 
@@ -31,6 +32,7 @@
 
 // Helper class that allows web_instance Components to be launched based on
 // caller-supplied |CreateContextParams|.
+// Use one of the concrete subclasses when instantiating.
 //
 // Note that Components using this class must:
 // 1. Include `web_instance_host.shard.cml` in their component manifest.
@@ -43,28 +45,20 @@
 // TODO(crbug.com/1275224): Remove these requirements when platform supports it.
 class WebInstanceHost {
  public:
-  // The host will offer capabilities to child instances via
-  // `outgoing_directory`. WebInstanceHost owners must serve the directory
-  // before creating web instances, and must ensure that the directory outlives
-  // the WebInstanceHost instance.
-  // TODO(crbug.com/1327587): Remove `outgoing_directory` if and when it is
-  // possible for tests to serve a test-specific outgoing directory via
-  // base::TestComponentContextForProcess on a separate thread.
-  explicit WebInstanceHost(sys::OutgoingDirectory& outgoing_directory);
-  ~WebInstanceHost();
+  virtual ~WebInstanceHost();
 
   WebInstanceHost(const WebInstanceHost&) = delete;
   WebInstanceHost& operator=(const WebInstanceHost&) = delete;
 
   // Creates a new web_instance Component and connects |services_request| to it.
-  // Returns ZX_OK if |params| were valid, and the Component was launched.
-  // |extra_args| are included on the command line when launching the new
-  // web_instance. Use base::CommandLine(base::CommandLine::NO_PROGRAM) for
+  // Returns ZX_OK if `params` were valid, and the Component was launched.
+  // `extra_args` are included on the command line when launching the new
+  // web_instance. Use `base::CommandLine(base::CommandLine::NO_PROGRAM)` for
   // empty args.
-  zx_status_t CreateInstanceForContextWithCopiedArgs(
+  virtual zx_status_t CreateInstanceForContextWithCopiedArgs(
       fuchsia::web::CreateContextParams params,
       fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
-      base::CommandLine extra_args);
+      const base::CommandLine& extra_args) = 0;
 
   // Exposes a fuchsia.web.Debug protocol implementation that can be used
   // to receive notifications of DevTools debug ports for new web instances.
@@ -77,6 +71,30 @@
     tmp_dir_ = std::move(tmp_dir);
   }
 
+ protected:
+  // The host will offer capabilities to child instances via
+  // `outgoing_directory`. WebInstanceHost owners must serve the directory
+  // before creating web instances, and must ensure that the directory outlives
+  // the WebInstanceHost instance.
+  // TODO(crbug.com/1327587): Remove `outgoing_directory` if and when it is
+  // possible for tests to serve a test-specific outgoing directory via
+  // base::TestComponentContextForProcess on a separate thread.
+  explicit WebInstanceHost(sys::OutgoingDirectory& outgoing_directory);
+
+  // Creates a new web_instance Component using `instance_component_url` and
+  // connects |services_request| to it. Returns ZX_OK if `params` were valid,
+  // and the Component was launched. `extra_args` are included on the command
+  // line when launching the new web_instance. Use
+  // `base::CommandLine(base::CommandLine::NO_PROGRAM)` for empty args.
+  // `services_to_offer` must be non-empty if and only if
+  // `params.service_directory` is present
+  zx_status_t CreateInstanceForContextWithCopiedArgsAndUrl(
+      fuchsia::web::CreateContextParams params,
+      fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
+      base::CommandLine extra_args,
+      base::StringPiece instance_component_url,
+      std::vector<std::string> services_to_offer);
+
  private:
   bool is_initialized() const VALID_CONTEXT_REQUIRED(sequence_checker_) {
     return realm_.is_bound();
@@ -119,4 +137,31 @@
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
+// An instantiable WebInstanceHost where services from this Component are
+// provided to each `WebInstance`.
+class WebInstanceHostWithServicesFromThisComponent : public WebInstanceHost {
+ public:
+  explicit WebInstanceHostWithServicesFromThisComponent(
+      sys::OutgoingDirectory& outgoing_directory);
+
+  zx_status_t CreateInstanceForContextWithCopiedArgs(
+      fuchsia::web::CreateContextParams params,
+      fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
+      const base::CommandLine& extra_args) override;
+};
+
+// An instantiable WebInstanceHost where services must be provided for each
+// `WebInstance` in `params.service_directory` in the call to
+// `CreateInstanceForContextWithCopiedArgs()`.
+class WebInstanceHostWithoutServices : public WebInstanceHost {
+ public:
+  explicit WebInstanceHostWithoutServices(
+      sys::OutgoingDirectory& outgoing_directory);
+
+  zx_status_t CreateInstanceForContextWithCopiedArgs(
+      fuchsia::web::CreateContextParams params,
+      fidl::InterfaceRequest<fuchsia::io::Directory> services_request,
+      const base::CommandLine& extra_args) override;
+};
+
 #endif  // FUCHSIA_WEB_WEBINSTANCE_HOST_WEB_INSTANCE_HOST_H_
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index 76c024f..ece41634 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -55,6 +55,8 @@
     "runner.h",
     "shell_runner.cc",
     "shell_runner.h",
+    "thread_isolation.cc",
+    "thread_isolation.h",
     "time_clamper.cc",
     "time_clamper.h",
     "try_catch.cc",
@@ -82,6 +84,12 @@
       "v8_platform_page_allocator.cc",
       "v8_platform_page_allocator.h",
     ]
+    if (enable_pkeys) {
+      sources += [
+        "v8_platform_thread_isolated_allocator.cc",
+        "v8_platform_thread_isolated_allocator.h",
+      ]
+    }
   }
 
   if (v8_use_external_startup_data) {
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
index fef95f01..fc3f28b2 100644
--- a/gin/gin_features.cc
+++ b/gin/gin_features.cc
@@ -148,6 +148,10 @@
 const base::FeatureParam<base::TimeDelta> kV8MemoryReducerStartDelay{
     &kV8DelayMemoryReducer, "delay", base::Seconds(30)};
 
+BASE_FEATURE(kV8ConcurrentMarkingHighPriorityThreads,
+             "V8ConcurrentMarkingHighPriorityThreads",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kV8UseLibmTrigFunctions,
              "V8UseLibmTrigFunctions",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/gin/gin_features.h b/gin/gin_features.h
index e0cc3c4f..32bf7afc2 100644
--- a/gin/gin_features.h
+++ b/gin/gin_features.h
@@ -20,6 +20,7 @@
 GIN_EXPORT BASE_DECLARE_FEATURE(kV8CodeMemoryWriteProtection);
 GIN_EXPORT BASE_DECLARE_FEATURE(kV8ConcurrentSparkplugHighPriorityThreads);
 GIN_EXPORT BASE_DECLARE_FEATURE(kV8DelayMemoryReducer);
+GIN_EXPORT BASE_DECLARE_FEATURE(kV8ConcurrentMarkingHighPriorityThreads);
 GIN_EXPORT BASE_DECLARE_FEATURE(kV8ExperimentalRegexpEngine);
 GIN_EXPORT extern const base::FeatureParam<int> kV8FlushBytecodeOldAge;
 GIN_EXPORT BASE_DECLARE_FEATURE(kV8FlushBaselineCode);
diff --git a/gin/public/v8_platform.h b/gin/public/v8_platform.h
index 8f14e4a4..565f531 100644
--- a/gin/public/v8_platform.h
+++ b/gin/public/v8_platform.h
@@ -11,6 +11,7 @@
 #include "gin/gin_export.h"
 #include "gin/time_clamper.h"
 #include "gin/v8_platform_page_allocator.h"
+#include "gin/v8_platform_thread_isolated_allocator.h"
 #include "v8/include/v8-platform.h"
 
 namespace gin {
@@ -31,6 +32,9 @@
   // enabling Arm's Branch Target Instructions for executable pages. This is
   // verified in the tests for gin::PageAllocator.
   PageAllocator* GetPageAllocator() override;
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+  ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override;
+#endif
   void OnCriticalMemoryPressure() override;
   v8::ZoneBackingAllocator* GetZoneBackingAllocator() override;
 #endif
diff --git a/gin/thread_isolation.cc b/gin/thread_isolation.cc
new file mode 100644
index 0000000..61ffdd8
--- /dev/null
+++ b/gin/thread_isolation.cc
@@ -0,0 +1,86 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gin/thread_isolation.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include <sys/mman.h>
+#include <cstddef>
+
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/memory/page_size.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
+
+namespace {
+
+int PkeyAlloc(int access_rights) {
+#ifdef SYS_pkey_alloc
+  return syscall(SYS_pkey_alloc, 0, access_rights);
+#else
+  return -1;
+#endif
+}
+
+uint32_t Rdpkru() {
+  uint32_t pkru;
+  asm volatile(".byte 0x0f,0x01,0xee\n" : "=a"(pkru) : "c"(0), "d"(0));
+  return pkru;
+}
+
+void Wrpkru(uint32_t pkru) {
+  asm volatile(".byte 0x0f,0x01,0xef\n" : : "a"(pkru), "c"(0), "d"(0));
+}
+
+static constexpr uint32_t kBitsPerPkey = 2;
+
+void PkeyDisableWriteAccess(int pkey) {
+#ifdef PKEY_DISABLE_WRITE
+  uint32_t pkru = Rdpkru();
+  uint32_t disable_write = static_cast<uint32_t>(PKEY_DISABLE_WRITE)
+                           << (static_cast<uint32_t>(pkey) * kBitsPerPkey);
+  Wrpkru(pkru | disable_write);
+#endif
+}
+
+}  // namespace
+
+namespace gin {
+
+void ThreadIsolationData::InitializeBeforeThreadCreation() {
+  bool page_size_mismatch = PA_THREAD_ISOLATED_ALIGN_SZ < base::GetPageSize();
+  base::UmaHistogramBoolean("V8.CFIPageSizeMismatch", page_size_mismatch);
+  if (page_size_mismatch) {
+    // We write-protect global variables and need to align and pad them to (a
+    // multiple of) the OS page size. But since page size is not a compile time
+    // constant, check at runtime that our value was large enough.
+    return;
+  }
+
+  pkey = PkeyAlloc(0);
+  if (pkey == -1) {
+    return;
+  }
+  allocator->Initialize(pkey);
+  PkeyDisableWriteAccess(pkey);
+}
+
+bool ThreadIsolationData::Initialized() const {
+  return pkey != -1;
+}
+
+ThreadIsolationData& GetThreadIsolationData() {
+  static ThreadIsolationData thread_isolation_data PA_THREAD_ISOLATED_ALIGN;
+  DCHECK_EQ((reinterpret_cast<size_t>(&thread_isolation_data) %
+             PA_THREAD_ISOLATED_ALIGN_SZ),
+            0llu);
+  return thread_isolation_data;
+}
+
+}  // namespace gin
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
diff --git a/gin/thread_isolation.h b/gin/thread_isolation.h
new file mode 100644
index 0000000..97446b8
--- /dev/null
+++ b/gin/thread_isolation.h
@@ -0,0 +1,49 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GIN_THREAD_ISOLATION_H_
+#define GIN_THREAD_ISOLATION_H_
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include "base/allocator/partition_allocator/thread_isolation/alignment.h"
+#include "base/no_destructor.h"
+#include "gin/gin_export.h"
+#include "gin/v8_platform_thread_isolated_allocator.h"
+
+namespace gin {
+
+// All data used for thread isolation needs to live in this struct since we need
+// to write-protect it with the same thread isolation mechanism.
+// The implementation is platform specific, e.g. using pkeys on x64.
+struct GIN_EXPORT ThreadIsolationData {
+  // If we're using pkeys for isolation, we need to allocate the key before
+  // spawning any threads. Otherwise, the other threads will not have read
+  // permissions to memory tagged with this key.
+  void InitializeBeforeThreadCreation();
+
+  // Returns if InitializeBeforeThreadCreation has been called and the
+  // initialization was successful, i.e. the platform supports the isolation
+  // mechanism.
+  bool Initialized() const;
+
+  base::NoDestructor<ThreadIsolatedAllocator> allocator;
+  int pkey = -1;
+
+  // The struct needs to be aligned and padded to a page size since we need to
+  // write-protect the page.
+  char pad[PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(allocator) + sizeof(pkey))];
+};
+static_assert(PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(ThreadIsolationData)) ==
+              0);
+
+GIN_EXPORT ThreadIsolationData& GetThreadIsolationData();
+
+}  // namespace gin
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#endif  // GIN_THREAD_ISOLATION_H_
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 0ea2663..ba3ab6a 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -258,6 +258,9 @@
         static_cast<int>(
             features::kV8MemoryReducerStartDelay.Get().InMilliseconds()));
   }
+  SetV8FlagsIfOverridden(features::kV8ConcurrentMarkingHighPriorityThreads,
+                         "--concurrent-marking-high-priority-threads",
+                         "--no-concurrent-marking-high-priority-threads");
   SetV8FlagsIfOverridden(features::kV8LazyFeedbackAllocation,
                          "--lazy-feedback-allocation",
                          "--no-lazy-feedback-allocation");
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index b56a00d..a0bc00a 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/memory/nonscannable_memory.h"
 #include "base/memory/raw_ptr.h"
+#include "base/no_destructor.h"
 #include "base/system/sys_info.h"
 #include "base/task/post_job.h"
 #include "base/task/task_traits.h"
@@ -25,6 +26,8 @@
 #include "base/tracing_buildflags.h"
 #include "build/build_config.h"
 #include "gin/per_isolate_data.h"
+#include "gin/thread_isolation.h"
+#include "gin/v8_platform_thread_isolated_allocator.h"
 #include "v8_platform_page_allocator.h"
 
 namespace gin {
@@ -326,6 +329,15 @@
   return g_page_allocator.Pointer();
 }
 
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+ThreadIsolatedAllocator* V8Platform::GetThreadIsolatedAllocator() {
+  if (!GetThreadIsolationData().Initialized()) {
+    return nullptr;
+  }
+  return GetThreadIsolationData().allocator.get();
+}
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
 void V8Platform::OnCriticalMemoryPressure() {
 // We only have a reservation on 32-bit Windows systems.
 // TODO(bbudge) Make the #if's in BlinkInitializer match.
diff --git a/gin/v8_platform_page_allocator.h b/gin/v8_platform_page_allocator.h
index 583e912..39e5f84 100644
--- a/gin/v8_platform_page_allocator.h
+++ b/gin/v8_platform_page_allocator.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 GIN_V8_PLATFROM_PAGE_ALLOCATOR_H_
-#define GIN_V8_PLATFROM_PAGE_ALLOCATOR_H_
+#ifndef GIN_V8_PLATFORM_PAGE_ALLOCATOR_H_
+#define GIN_V8_PLATFORM_PAGE_ALLOCATOR_H_
 
 #include "build/build_config.h"
 #include "build/buildflag.h"
@@ -61,4 +61,4 @@
 
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC)
 
-#endif  // GIN_V8_PLATFROM_PAGE_ALLOCATOR_H_
+#endif  // GIN_V8_PLATFORM_PAGE_ALLOCATOR_H_
diff --git a/gin/v8_platform_thread_isolated_allocator.cc b/gin/v8_platform_thread_isolated_allocator.cc
new file mode 100644
index 0000000..4228dfc
--- /dev/null
+++ b/gin/v8_platform_thread_isolated_allocator.cc
@@ -0,0 +1,58 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gin/v8_platform_thread_isolated_allocator.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#include "base/allocator/partition_allocator/thread_isolation/pkey.h"
+#include "gin/thread_isolation.h"
+
+#if BUILDFLAG(ENABLE_PKEYS)
+#else  // BUILDFLAG(ENABLE_PKEYS)
+#error Not implemented for non-pkey thread isolation
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+
+namespace gin {
+
+ThreadIsolatedAllocator::ThreadIsolatedAllocator() = default;
+ThreadIsolatedAllocator::~ThreadIsolatedAllocator() = default;
+
+void ThreadIsolatedAllocator::Initialize(int pkey) {
+  pkey_ = pkey;
+  allocator_.init({
+      partition_alloc::PartitionOptions::AlignedAlloc::kAllowed,
+      partition_alloc::PartitionOptions::ThreadCache::kDisabled,
+      partition_alloc::PartitionOptions::Quarantine::kDisallowed,
+      partition_alloc::PartitionOptions::Cookie::kAllowed,
+      partition_alloc::PartitionOptions::BackupRefPtr::kDisabled,
+      partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
+      partition_alloc::PartitionOptions::UseConfigurablePool::kNo,
+      partition_alloc::ThreadIsolationOption(pkey_),
+  });
+}
+
+void* ThreadIsolatedAllocator::Allocate(size_t size) {
+  return allocator_.root()->AllocWithFlagsNoHooks(
+      0, size, partition_alloc::PartitionPageSize());
+}
+
+void ThreadIsolatedAllocator::Free(void* object) {
+  allocator_.root()->FreeNoHooks(object);
+}
+
+enum ThreadIsolatedAllocator::Type ThreadIsolatedAllocator::Type() const {
+  return Type::kPkey;
+}
+
+int ThreadIsolatedAllocator::Pkey() const {
+  return pkey_;
+}
+
+}  // namespace gin
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
diff --git a/gin/v8_platform_thread_isolated_allocator.h b/gin/v8_platform_thread_isolated_allocator.h
new file mode 100644
index 0000000..0d0f26f
--- /dev/null
+++ b/gin/v8_platform_thread_isolated_allocator.h
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GIN_V8_PLATFORM_THREAD_ISOLATED_ALLOCATOR_H_
+#define GIN_V8_PLATFORM_THREAD_ISOLATED_ALLOCATOR_H_
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+
+#if BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#if !BUILDFLAG(ENABLE_PKEYS)
+#error Not implemented for non-pkey thread isolation
+#endif  // BUILDFLAG(ENABLE_PKEYS)
+
+#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "gin/gin_export.h"
+#include "v8-platform.h"
+
+namespace gin {
+
+// This is a wrapper around PartitionAlloc's ThreadIsolated pool that we pass to
+// v8.
+class GIN_EXPORT ThreadIsolatedAllocator final
+    : public v8::ThreadIsolatedAllocator {
+ public:
+  ThreadIsolatedAllocator();
+  ~ThreadIsolatedAllocator() override;
+
+  void Initialize(int pkey);
+
+  void* Allocate(size_t size) override;
+  void Free(void* object) override;
+  enum Type Type() const override;
+
+  int Pkey() const override;
+
+ private:
+  partition_alloc::PartitionAllocator allocator_;
+  int pkey_ = -1;
+};
+
+}  // namespace gin
+
+#endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
+
+#endif  // GIN_V8_PLATFORM_THREAD_ISOLATED_ALLOCATOR_H_
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index 48f8b8e..d995f00 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -181,9 +181,6 @@
   // Used by OOP raster.
   bool context_supports_distance_field_text = true;
 
-  // Used only by NaCL graphics 3D.
-  bool use_shared_images_swapchain_for_ppapi = false;
-
   GpuMemoryBufferFormatSet gpu_memory_buffer_formats = {
       gfx::BufferFormat::BGR_565,   gfx::BufferFormat::RGBA_4444,
       gfx::BufferFormat::RGBA_8888, gfx::BufferFormat::RGBX_8888,
diff --git a/gpu/ipc/common/gpu_command_buffer_traits_multi.h b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
index 31bdc8f..fac4418 100644
--- a/gpu/ipc/common/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
@@ -137,8 +137,6 @@
   IPC_STRUCT_TRAITS_MEMBER(major_version)
   IPC_STRUCT_TRAITS_MEMBER(minor_version)
 
-  IPC_STRUCT_TRAITS_MEMBER(use_shared_images_swapchain_for_ppapi)
-
   IPC_STRUCT_TRAITS_MEMBER(gpu_memory_buffer_formats)
   IPC_STRUCT_TRAITS_MEMBER(texture_target_exception_list)
   IPC_STRUCT_TRAITS_MEMBER(drm_formats_and_modifiers)
diff --git a/infra/archive_config/android-archive-rel.json b/infra/archive_config/android-archive-rel.json
index 84b7549d..dd7b75b 100644
--- a/infra/archive_config/android-archive-rel.json
+++ b/infra/archive_config/android-archive-rel.json
@@ -4,6 +4,7 @@
             "files": [
                 "apks/ContentShell.apk",
                 "apks/ChromePublic.apk",
+                "apks/SystemWebView.apk",
                 "apks/SystemWebViewShell.apk"
             ],
             "rename_dirs": [
@@ -21,4 +22,4 @@
             }
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/infra/config/generated/builders/ci/GPU Mac Builder/properties.json b/infra/config/generated/builders/ci/GPU Mac Builder/properties.json
index 516c8f7..c215e15 100644
--- a/infra/config/generated/builders/ci/GPU Mac Builder/properties.json
+++ b/infra/config/generated/builders/ci/GPU Mac Builder/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -73,8 +71,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac Builder/properties.json b/infra/config/generated/builders/ci/Mac Builder/properties.json
index 2f78f21..cfaca13 100644
--- a/infra/config/generated/builders/ci/Mac Builder/properties.json
+++ b/infra/config/generated/builders/ci/Mac Builder/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -76,8 +74,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -106,8 +103,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -135,8 +131,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -164,8 +159,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git "a/infra/config/generated/builders/ci/Mac Release \050Intel\051/properties.json" "b/infra/config/generated/builders/ci/Mac Release \050Intel\051/properties.json"
index f67149d..3673863 100644
--- "a/infra/config/generated/builders/ci/Mac Release \050Intel\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Mac Release \050Intel\051/properties.json"
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git "a/infra/config/generated/builders/ci/Mac Retina Release \050AMD\051/properties.json" "b/infra/config/generated/builders/ci/Mac Retina Release \050AMD\051/properties.json"
index a89e92f0..63505597 100644
--- "a/infra/config/generated/builders/ci/Mac Retina Release \050AMD\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Mac Retina Release \050AMD\051/properties.json"
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac10.13 Tests/properties.json b/infra/config/generated/builders/ci/Mac10.13 Tests/properties.json
index 3df545f5..633b10a 100644
--- a/infra/config/generated/builders/ci/Mac10.13 Tests/properties.json
+++ b/infra/config/generated/builders/ci/Mac10.13 Tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac10.14 Tests/properties.json b/infra/config/generated/builders/ci/Mac10.14 Tests/properties.json
index 20b7487..bc46187 100644
--- a/infra/config/generated/builders/ci/Mac10.14 Tests/properties.json
+++ b/infra/config/generated/builders/ci/Mac10.14 Tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac10.15 Tests/properties.json b/infra/config/generated/builders/ci/Mac10.15 Tests/properties.json
index eec3dcc..47d9df0 100644
--- a/infra/config/generated/builders/ci/Mac10.15 Tests/properties.json
+++ b/infra/config/generated/builders/ci/Mac10.15 Tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac11 Tests/properties.json b/infra/config/generated/builders/ci/Mac11 Tests/properties.json
index 91d78b0..2a29d6d 100644
--- a/infra/config/generated/builders/ci/Mac11 Tests/properties.json
+++ b/infra/config/generated/builders/ci/Mac11 Tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -42,8 +41,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/Mac12 Tests/properties.json b/infra/config/generated/builders/ci/Mac12 Tests/properties.json
index 6d718f5..c8019e2 100644
--- a/infra/config/generated/builders/ci/Mac12 Tests/properties.json
+++ b/infra/config/generated/builders/ci/Mac12 Tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -42,8 +41,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/WebKit Win10/properties.json b/infra/config/generated/builders/ci/WebKit Win10/properties.json
index 2c5aae0c..b596f57 100644
--- a/infra/config/generated/builders/ci/WebKit Win10/properties.json
+++ b/infra/config/generated/builders/ci/WebKit Win10/properties.json
@@ -15,7 +15,6 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
@@ -44,7 +43,6 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
diff --git a/infra/config/generated/builders/ci/Win Builder/properties.json b/infra/config/generated/builders/ci/Win Builder/properties.json
index bea3ec3f..eb7f8fd 100644
--- a/infra/config/generated/builders/ci/Win Builder/properties.json
+++ b/infra/config/generated/builders/ci/Win Builder/properties.json
@@ -15,7 +15,6 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
@@ -44,7 +43,6 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
diff --git a/infra/config/generated/builders/ci/mac-archive-rel/properties.json b/infra/config/generated/builders/ci/mac-archive-rel/properties.json
index a7e012b..91eb6d16 100644
--- a/infra/config/generated/builders/ci/mac-archive-rel/properties.json
+++ b/infra/config/generated/builders/ci/mac-archive-rel/properties.json
@@ -23,8 +23,7 @@
               "legacy_chromium_config": {
                 "apply_configs": [
                   "clobber",
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/mac-arm64-archive-rel/properties.json b/infra/config/generated/builders/ci/mac-arm64-archive-rel/properties.json
index 2fecae8..5c0950f 100644
--- a/infra/config/generated/builders/ci/mac-arm64-archive-rel/properties.json
+++ b/infra/config/generated/builders/ci/mac-arm64-archive-rel/properties.json
@@ -23,8 +23,7 @@
               "legacy_chromium_config": {
                 "apply_configs": [
                   "clobber",
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/ci/mac-osxbeta-rel/properties.json b/infra/config/generated/builders/ci/mac-osxbeta-rel/properties.json
index d5a3d73..d4660c460 100644
--- a/infra/config/generated/builders/ci/mac-osxbeta-rel/properties.json
+++ b/infra/config/generated/builders/ci/mac-osxbeta-rel/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/goma/Win Builder Goma RBE ATS Canary/properties.json b/infra/config/generated/builders/goma/Win Builder Goma RBE ATS Canary/properties.json
index 8fe4d04..4a4119f 100644
--- a/infra/config/generated/builders/goma/Win Builder Goma RBE ATS Canary/properties.json
+++ b/infra/config/generated/builders/goma/Win Builder Goma RBE ATS Canary/properties.json
@@ -15,7 +15,6 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb",
                   "goma_canary",
                   "goma_use_local"
diff --git a/infra/config/generated/builders/goma/Win Builder Goma RBE Canary/properties.json b/infra/config/generated/builders/goma/Win Builder Goma RBE Canary/properties.json
index 0ebe90d..971f1d2 100644
--- a/infra/config/generated/builders/goma/Win Builder Goma RBE Canary/properties.json
+++ b/infra/config/generated/builders/goma/Win Builder Goma RBE Canary/properties.json
@@ -15,7 +15,6 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb",
                   "goma_canary",
                   "goma_use_local"
diff --git a/infra/config/generated/builders/goma/mac-archive-rel-goma-rbe-canary/properties.json b/infra/config/generated/builders/goma/mac-archive-rel-goma-rbe-canary/properties.json
index fda4481..bebdfa4 100644
--- a/infra/config/generated/builders/goma/mac-archive-rel-goma-rbe-canary/properties.json
+++ b/infra/config/generated/builders/goma/mac-archive-rel-goma-rbe-canary/properties.json
@@ -17,7 +17,6 @@
                 "apply_configs": [
                   "clobber",
                   "mb",
-                  "goma_use_local",
                   "goma_canary"
                 ],
                 "build_config": "Release",
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient staging untrusted/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient staging untrusted/properties.json
index 7b63e0b..5fd45c4 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient staging untrusted/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient staging untrusted/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient staging/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient staging/properties.json
index f81fb7e2..5a2f3a87 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient staging/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient staging/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
index 6796258..fc660b6e 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
index d556722..3cb305c6 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
index d007aca..f275ce0 100644
--- a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
@@ -60,5 +60,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.fuchsia",
+  "cq": "required",
   "recipe": "chromium/orchestrator"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac-inverse-fieldtrials-fyi-rel/properties.json b/infra/config/generated/builders/try/mac-inverse-fieldtrials-fyi-rel/properties.json
index 3efd4d1d3..6d527d7 100644
--- a/infra/config/generated/builders/try/mac-inverse-fieldtrials-fyi-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-inverse-fieldtrials-fyi-rel/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -71,8 +69,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -101,8 +98,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -130,8 +126,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac-osxbeta-rel/properties.json b/infra/config/generated/builders/try/mac-osxbeta-rel/properties.json
index c70ba3a..fb8597f 100644
--- a/infra/config/generated/builders/try/mac-osxbeta-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-osxbeta-rel/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac-rel-compilator/properties.json b/infra/config/generated/builders/try/mac-rel-compilator/properties.json
index 6bd4f5e..5881ddb 100644
--- a/infra/config/generated/builders/try/mac-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/mac-rel-compilator/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -71,8 +69,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -101,8 +98,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -130,8 +126,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac-rel/properties.json b/infra/config/generated/builders/try/mac-rel/properties.json
index 413e91c..29baca5 100644
--- a/infra/config/generated/builders/try/mac-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-rel/properties.json
@@ -19,8 +19,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -47,8 +46,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -75,8 +73,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -105,8 +102,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -134,8 +130,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac12-tests/properties.json b/infra/config/generated/builders/try/mac12-tests/properties.json
index ac840a8..0b73fbd 100644
--- a/infra/config/generated/builders/try/mac12-tests/properties.json
+++ b/infra/config/generated/builders/try/mac12-tests/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -42,8 +41,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_10.13_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_10.13_rel_ng/properties.json
index 62959f4b..a25f7d6 100644
--- a/infra/config/generated/builders/try/mac_chromium_10.13_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_10.13_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_10.14_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_10.14_rel_ng/properties.json
index 06872e20..5d9d470 100644
--- a/infra/config/generated/builders/try/mac_chromium_10.14_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_10.14_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_10.15_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_10.15_rel_ng/properties.json
index 44c7097..639215c 100644
--- a/infra/config/generated/builders/try/mac_chromium_10.15_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_10.15_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_11.0_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_11.0_rel_ng/properties.json
index f6a3f55..10a9596 100644
--- a/infra/config/generated/builders/try/mac_chromium_11.0_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_11.0_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -42,8 +41,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_archive_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_archive_rel_ng/properties.json
index 1565954..bccd01c 100644
--- a/infra/config/generated/builders/try/mac_chromium_archive_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_archive_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "legacy_chromium_config": {
                 "apply_configs": [
                   "clobber",
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/mac_chromium_compile_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_compile_rel_ng/properties.json
index 7bac97e..eb9f9b5 100644
--- a/infra/config/generated/builders/try/mac_chromium_compile_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_compile_rel_ng/properties.json
@@ -15,8 +15,7 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -43,8 +42,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -76,8 +74,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -106,8 +103,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -135,8 +131,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
@@ -164,8 +159,7 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "mb",
-                  "goma_use_local"
+                  "mb"
                 ],
                 "build_config": "Release",
                 "config": "chromium",
diff --git a/infra/config/generated/builders/try/win_chromium_compile_rel_ng/properties.json b/infra/config/generated/builders/try/win_chromium_compile_rel_ng/properties.json
index e72104e..32b2e51 100644
--- a/infra/config/generated/builders/try/win_chromium_compile_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/win_chromium_compile_rel_ng/properties.json
@@ -15,7 +15,6 @@
               "execution_mode": "TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
@@ -44,7 +43,6 @@
               "execution_mode": "COMPILE_AND_TEST",
               "legacy_chromium_config": {
                 "apply_configs": [
-                  "goma_enable_global_file_stat_cache",
                   "mb"
                 ],
                 "build_config": "Release",
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 4dd4d45..b1fe926b 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -546,6 +546,9 @@
   * [`//third_party/nearby/README.chromium`](https://cs.chromium.org/search?q=+file:third_party/nearby/README.chromium)
 
 ### chromium
+* [fuchsia-x64-cast-receiver-rel](https://ci.chromium.org/p/chromium/builders/try/fuchsia-x64-cast-receiver-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""fuchsia-x64-cast-receiver-rel""))
+  * Experiment percentage: 100.0
+
 * [linux-1mbu-compile-fyi-rel](https://ci.chromium.org/p/chromium/builders/try/linux-1mbu-compile-fyi-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-1mbu-compile-fyi-rel""))
   * Experiment percentage: 5.0
 
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 2ac2472..c498644 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -1853,7 +1853,24 @@
       }
       builders {
         name: "chromium/try/fuchsia-x64-cast-receiver-rel"
-        includable_only: true
+        experiment_percentage: 100
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/.+"
+        }
       }
       builders {
         name: "chromium/try/fuchsia-x64-cast-receiver-rel-compilator"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index d605a4a..8ab92cb1 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -64612,6 +64612,7 @@
         '    }'
         '  },'
         '  "builder_group": "tryserver.chromium.fuchsia",'
+        '  "cq": "required",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium/orchestrator"'
         '}'
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 8b66806..047a63f 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -916,7 +916,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.star b/infra/config/subprojects/chromium/ci/chromium.gpu.star
index 91ee2579..ca04175b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.gpu.star
+++ b/infra/config/subprojects/chromium/ci/chromium.gpu.star
@@ -129,7 +129,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -311,7 +310,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -363,7 +361,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
diff --git a/infra/config/subprojects/chromium/ci/chromium.mac.star b/infra/config/subprojects/chromium/ci/chromium.mac.star
index 19a1c7d..0bb03ee33 100644
--- a/infra/config/subprojects/chromium/ci/chromium.mac.star
+++ b/infra/config/subprojects/chromium/ci/chromium.mac.star
@@ -69,7 +69,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -260,7 +259,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -288,7 +286,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -316,7 +313,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -344,7 +340,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -370,7 +365,6 @@
             config = "chromium",
             apply_configs = [
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935)
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
diff --git a/infra/config/subprojects/chromium/ci/chromium.star b/infra/config/subprojects/chromium/ci/chromium.star
index cc92cfe..e1c03a3 100644
--- a/infra/config/subprojects/chromium/ci/chromium.star
+++ b/infra/config/subprojects/chromium/ci/chromium.star
@@ -549,7 +549,6 @@
             apply_configs = [
                 "clobber",
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935).
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
@@ -611,7 +610,6 @@
             apply_configs = [
                 "clobber",
                 "mb",
-                "goma_use_local",  # to mitigate compile step timeout (crbug.com/1056935).
             ],
             build_config = builder_config.build_config.RELEASE,
             target_bits = 64,
diff --git a/infra/config/subprojects/chromium/ci/chromium.win.star b/infra/config/subprojects/chromium/ci/chromium.win.star
index b2bd02e..441724c 100644
--- a/infra/config/subprojects/chromium/ci/chromium.win.star
+++ b/infra/config/subprojects/chromium/ci/chromium.win.star
@@ -49,7 +49,6 @@
         chromium_config = builder_config.chromium_config(
             config = "chromium",
             apply_configs = [
-                "goma_enable_global_file_stat_cache",
                 "mb",
             ],
             build_config = builder_config.build_config.RELEASE,
@@ -73,7 +72,6 @@
         chromium_config = builder_config.chromium_config(
             config = "chromium",
             apply_configs = [
-                "goma_enable_global_file_stat_cache",
                 "mb",
             ],
             build_config = builder_config.build_config.RELEASE,
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
index 56f5f48..be984a27 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -141,7 +141,9 @@
     },
     main_list_view = "try",
     # TODO(crbug.com/1445005): Restore when runhooks is fixed.
-    #tryjob = try_.job(),
+    tryjob = try_.job(
+        experiment_percentage = 100,
+    ),
     use_clang_coverage = True,
 )
 
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 40fc3a6..e6d14eb 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -617,9 +617,6 @@
       <message name="IDS_IOS_SETTINGS_ADD_PASSWORD_FOOTER_BRANDED" desc="Disclaimer telling users what will happen to their passwords">
         Your password will be saved to Password Manager for <ph name="EMAIL">$1<ex>example@gmail.com</ex></ph>.
       </message>
-      <message name="IDS_IOS_OVERFLOW_MENU_TIP" desc="The text of the tip explaining to the user that the Overflow Menu has new items">
-        Get to know the new Chromium menu
-      </message>
       <message name="IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE" desc="The error message to show in the account table when there is a passphrase error. [iOS only]">
         To use and save Chromium data in your Google Account, enter your passphrase.
       </message>
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1
deleted file mode 100644
index cdd6aec..0000000
--- a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ee6eb1a27baa022d95c01c4cb66791dcbec056de
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index d01ca9b8..b203fda97 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -617,9 +617,6 @@
       <message name="IDS_IOS_SETTINGS_ADD_PASSWORD_FOOTER_BRANDED" desc="Disclaimer telling users what will happen to their passwords">
         Your password will be saved to Google Password Manager for <ph name="EMAIL">$1<ex>example@gmail.com</ex></ph>.
       </message>
-      <message name="IDS_IOS_OVERFLOW_MENU_TIP" desc="The text of the tip explaining to the user that the Overflow Menu has new items">
-        Get to know the new Chrome menu
-      </message>
       <message name="IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE" desc="The error message to show in the account table when there is a passphrase error. [iOS only]">
         To use and save Chrome data in your Google Account, enter your passphrase.
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1
deleted file mode 100644
index 889550b..0000000
--- a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_OVERFLOW_MENU_TIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ce58ffbcc19e53e3991926ac929821d92bedd409
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index aa94890a..17ce026 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -4575,6 +4575,9 @@
       <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL" desc="The label of the verify your account action button in the identity error info bar. [iOS only]">
         Verify
       </message>
+      <message name="IDS_IOS_VIEW_BROWSING_HISTORY_OVERFLOW_MENU_TIP" desc="The text of the tip explaining that browsing history can be viewed from the Overflow Menu.">
+        View browsing history
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_VIEW_BROWSING_HISTORY_OVERFLOW_MENU_TIP.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_VIEW_BROWSING_HISTORY_OVERFLOW_MENU_TIP.png.sha1
new file mode 100644
index 0000000..853a879
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_VIEW_BROWSING_HISTORY_OVERFLOW_MENU_TIP.png.sha1
@@ -0,0 +1 @@
+1fdbfd3d70a183a9eaf728aa708259c399753509
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_lo.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_lo.xtb
index 1a052b63..941d00f 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_lo.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_lo.xtb
@@ -49,6 +49,7 @@
 <translation id="3650632991272923014"><ph name="USER_EMAIL1" /> ກຳລັງໃຊ້ Chromium ຢູ່ ແລະ ເປີດບຸກມາກ, ລະຫັດຜ່ານ ແລະ ການຕັ້ງຄ່າອື່ນໆປະໄວ້ຢູ່ອຸປະກອນນີ້.</translation>
 <translation id="372658070733623520">ເພື່ອໃຊ້ ແລະ ບັນທຶກຂໍ້ມູນ Chromium ໃນບັນຊີ Google ຂອງທ່ານ, ກະລຸນາຢັ້ງຢືນວ່າແມ່ນທ່ານ.</translation>
 <translation id="3805899903892079518">Chromium ບໍ່​ມີ​ການ​ເຂົ້າ​ເຖິງ​ຮູບຖ່າຍ ຫຼື ​ວິ​ດີ​ໂອ​ຂອງ​ທ່ານ. ເປີດ​ໃຊ້​ການ​ເຂົ້າເຖິງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ iOS &gt; Privacy &gt; Photos.</translation>
+<translation id="3955621079070267756">ເປີດ Chromium ຈາກແອັບໃດກໍໄດ້</translation>
 <translation id="4043291146360695975">ລະຫັດຜ່ານແມ່ນຖືກບັນທຶກໄປໃສ່ຕົວຈັດການລະຫັດຜ່ານຢູ່ອຸປະກອນນີ້ເທົ່ານັ້ນ.</translation>
 <translation id="4099085513035183040">ບໍ່ຮອງຮັບໃນ Chromium Beta</translation>
 <translation id="4432744876818348753">ເຂົ້າສູ່ລະບົບເພື່ອໃຊ້ປະໂຫຍດສູງສຸດຈາກ Chromium.</translation>
@@ -143,5 +144,6 @@
 <translation id="9089354809943900324">Chromium ຫຼ້າສະໄໝແລ້ວ</translation>
 <translation id="9110075932708282655">ໃຊ້ Chromium ເປັນຄ່າເລີ່ມຕົ້ນ</translation>
 <translation id="921174536258924340">Chromium ບໍ່ສາມາດກວດລະຫັດຜ່ານທັງໝົດໄດ້. ລອງໃໝ່ໃນມື້ອື່ນ ຫຼື <ph name="BEGIN_LINK" />ກວດລະຫັດຜ່ານໃນບັນຊີ Google ຂອງທ່ານ.<ph name="END_LINK" /></translation>
+<translation id="971488683725792095">ນຳໃຊ້ Chromium ໂດຍອັດຕະໂນມັດເມື່ອທ່ານແຕະລິ້ງໃນຂໍ້ຄວາມ, ເອກະສານ ແລະ ແອັບອື່ນໆ.</translation>
 <translation id="985602178874221306">ຜູ້ຂຽນ Chromium</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_lo.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_lo.xtb
index 363c3f32..ab63939 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_lo.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_lo.xtb
@@ -12,6 +12,7 @@
 <translation id="1554731936187952550">ທ່ານໄດ້ຮັບການດູແລຢ່າງເຂັ້ມງວດທີ່ສຸດຂອງ Chrome ໃຫ້ປອດໄພຈາກເວັບໄຊທີ່ເປັນອັນຕະລາຍ</translation>
 <translation id="1682483655351012182">ຊິ້ງຂໍ້ມູນ Chrome ຂອງທ່ານ</translation>
 <translation id="1759842336958782510">Chrome</translation>
+<translation id="1843217788865538014">ໃຊ້ Chrome ໂດຍອັດຕະໂນມັດເມື່ອທ່ານແຕະລິ້ງໃນຂໍ້ຄວາມ, ເອກະສານ ແລະ ແອັບອື່ນໆ.</translation>
 <translation id="1917964099031477364">ບັນຊີນີ້ ແລະ ຂໍ້ມູນທີ່ບໍ່ໄດ້ບັນທຶກໄວ້ຕ່າງໆຈະຖືກລຶບອອກຈາກ Chrome ແລະ ແອັບອື່ນຂອງ Google ໃນອຸປະກອນນີ້.</translation>
 <translation id="2009224836393115614">Chrome ບໍ່ສາມາດກວດລະຫັດຜ່ານຂອງທ່ານໄດ້. ລອງກວດເບິ່ງການເຊື່ອມຕໍ່ອິນເຕີເນັດຂອງທ່ານ.</translation>
 <translation id="2056123005618757196">ເຮັດສິ່ງຕ່າງໆໃຫ້ແລ້ວຫຼາຍຂຶ້ນດ້ວຍ Google Chrome ທີ່ງ່າຍ, ປອດໄພ ແລະ ໄວກວ່າທີ່ເຄີຍ.</translation>
@@ -58,6 +59,7 @@
 <translation id="4233521129555661685"><ph name="USER_EMAIL1" /> ກຳລັງໃຊ້ Chrome ຢູ່ ແລະ ເປີດບຸກມາກ, ລະຫັດຜ່ານ ແລະ ການຕັ້ງຄ່າອື່ນໆປະໄວ້ຢູ່ອຸປະກອນນີ້.</translation>
 <translation id="424864128008805179">ອອກຈາກລະບົບ Chrome ບໍ?</translation>
 <translation id="4249068189593983585">ເຄັດລັບກ່ຽວກັບ Chrome. ສຳລັບຕົວເລືອກແຖບເພີ່ມເຕີມ, ກະລຸນາແຕະປຸ່ມສະແດງແຖບໃນແຖບເຄື່ອງມືຄ້າງໄວ້ ເຊິ່ງຢູ່ລຸ່ມສຸດ ຫຼື ເທິງສຸດຂອງໜ້າຈໍຂອງທ່ານ.</translation>
+<translation id="4508370294876102450">ເປີດ Chrome ຈາກແອັບໃດກໍໄດ້</translation>
 <translation id="4523886039239821078">ການ​ເພີ່ມ​ໃສ່​ບາງ​ອັນ​ເຮັດ​ໃຫ້ Chrome ເກີດ​ຂັດ​ຂ້ອງ. ກະ​ລຸ​ນາ​ຖອນ​ຕິດ​ຕັ້ງ​.</translation>
 <translation id="4633328489441962921">Chrome ບໍ່ສາມາດກວດຫາການອັບເດດໄດ້</translation>
 <translation id="4636900170638246267">ເຂົ້າສູ່ລະບົບຫາເວັບໄຊນີ້ ແລະ Chrome.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_af.xtb b/ios/chrome/app/strings/resources/ios_strings_af.xtb
index cea91dec..2b477db 100644
--- a/ios/chrome/app/strings/resources/ios_strings_af.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_af.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">Vertaal <ph name="LANGUAGE" /> altyd</translation>
 <translation id="110724200315609752">Wissel na oop venster</translation>
 <translation id="1112015203684611006">Kon nie druk nie.</translation>
+<translation id="1113057722807951993">Wagfrase-enkripsie sluit nie betaalmetodes en adresse van Google Pay af in nie.
+
+<ph name="BEGIN_LINK" />Vee die Chrome-data in jou rekening uit<ph name="END_LINK" /> as jy hierdie instelling wil verander.</translation>
 <translation id="1125564390852150847">Skep nuwe oortjie.</translation>
 <translation id="1126809382673880764">Beskerm jou nie teen gevaarlike webwerwe, aflaaie en uitbreidings nie. Jy sal steeds Veiligblaai-beskerming kry, indien beskikbaar, in ander Google-dienste, soos Gmail en Search.</translation>
 <translation id="1145536944570833626">Vee bestaande data uit.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">Blaai deur</translation>
 <translation id="1990820278544963435">Soek</translation>
 <translation id="199425419756152024">Bekyk wagwoord</translation>
+<translation id="2008357574463816229"><ph name="BEGIN_LINK" />Vee die Chrome-data in jou rekening uit<ph name="END_LINK" /> indien jy jou wagfrase vergeet of hierdie instelling wil verander.</translation>
 <translation id="2010008505735295285">Herlaai</translation>
 <translation id="2015722694326466240">Om wagwoorde te sien, moet jy eers 'n wagkode op jou toestel stel.</translation>
 <translation id="2021670401941426298">Sien jou soekenjin se instruksies om jou soekgeskiedenis uit te vee, indien nodig.</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">Gaan na vorige oortjie</translation>
 <translation id="5755162682436943950">Afgemeld. Maak dialoog oop om aan te meld en sinkronisering aan te skakel.</translation>
 <translation id="5758631781033351321">Jy sal jou leeslys hier kry</translation>
+<translation id="5762370665605786758">Wagfrase-enkripsie sluit nie betaalmetodes en adresse van Google Pay af in nie.
+
+Net iemand met jou wagfrase kan jou geënkripteerde data lees. Die wagfrase word nie na Google toe gestuur of deur hulle gestoor nie. <ph name="BEGIN_LINK" />Vee die Chrome-data in jou rekening uit<ph name="END_LINK" /> indien jy jou wagfrase vergeet of hierdie instelling wil verander.</translation>
 <translation id="5765456154762864099">Kieslys → Instellings → Verstekblaaier</translation>
 <translation id="5777888488419460501">Stoor in rekening</translation>
 <translation id="5782227691023083829">Vertaal tans …</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">Vertaal tans die bladsy in <ph name="LANGUAGE" />. Opsies is naby die onderkant van die skerm beskikbaar.</translation>
 <translation id="648164694371393720">Stawingfout</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> items uitgevee</translation>
+<translation id="6484712497741564393">Aangemeld as <ph name="EMAIL" />.
+
+Jou data is met jou wagfrase geënkripteer. Voer dit in om Chrome-data in jou Google-rekening te gebruik en te stoor.</translation>
 <translation id="6497772452874122664">As jy <ph name="TIME" /> vertrou, kan jy 'n gestoorde wagwoord van 'n ander werf af gebruik.
 
 Probeer 'n unieke wagwoord vir elke werf gebruik.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">Kan nie wagwoorde uitvoer nie</translation>
 <translation id="6732087373923685049">kamera</translation>
 <translation id="6748108480210050150">Vanaf</translation>
+<translation id="6753469262000681876">Snelsluitmodus</translation>
 <translation id="6760509555861141183">Keer terug na onlangse oortjie</translation>
 <translation id="6762812039470893796">Ontkies alles</translation>
 <translation id="6780034285637185932">Poskode</translation>
@@ -1106,6 +1117,7 @@
 <translation id="8197543752516192074">Vertaal bladsy</translation>
 <translation id="8205564605687841303">Kanselleer</translation>
 <translation id="8206354486702514201">Hierdie instelling word deur jou administrateur afgedwing.</translation>
+<translation id="8214293972734702249">Vasgespeld, <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">Gekaste prente en lêers</translation>
 <translation id="8237382152611443140">Maak AutoFill Password Settings oop</translation>
 <translation id="8248969482078657578">Onaktiewe Oortjies help jou om gefokus te bly</translation>
@@ -1120,6 +1132,9 @@
 <translation id="8299417921174340354">Om wagwoorde te gebruik, moet jy eers 'n wagkode op jou toestel stel.</translation>
 <translation id="8299613349954694191">Maak 'n Incognito-oortjie oop om privaat deur die web te blaai.</translation>
 <translation id="8316944564970119719">Voer werf en wagwoord in, en stoor dan</translation>
+<translation id="8317835149433843300">Betaalmetodes en -adresse van Google Pay af sal nie geënkripteer word nie. Blaaigeskiedenis van Chrome af sal nie in jou Google-rekening gestoor word nie.
+
+Net iemand met jou wagfrase kan jou geënkripteerde data lees. Die wagfrase word nie na Google toe gestuur of deur hulle gestoor nie. <ph name="BEGIN_LINK" />Vee die Chrome-data in jou rekening uit<ph name="END_LINK" /> indien jy jou wagfrase vergeet of hierdie instelling wil verander.</translation>
 <translation id="8319076807703933069">Nuwe soektog</translation>
 <translation id="8323906514956095947">Raak en hou vir meer oortjieopsies</translation>
 <translation id="8328777765163860529">Maak almal toe</translation>
@@ -1142,6 +1157,9 @@
 <translation id="8487700953926739672">Vanlyn beskikbaar</translation>
 <translation id="8488923644885757471">Nuwe venster</translation>
 <translation id="8490978609246021741">Stoor veranderinge</translation>
+<translation id="8491300088149538575">Aangemeld as <ph name="EMAIL" />.
+
+Jou data is op <ph name="TIME" /> met jou wagfrase geënkripteer. Voer dit in om Chrome-data in jou Google-rekening te gebruik en te stoor.</translation>
 <translation id="8503813439785031346">Gebruikernaam</translation>
 <translation id="850600235656508448">Maak in Incognito oop</translation>
 <translation id="8517375800490286174">Oopbronlisensies</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_am.xtb b/ios/chrome/app/strings/resources/ios_strings_am.xtb
index aac6abd..894873e4 100644
--- a/ios/chrome/app/strings/resources/ios_strings_am.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_am.xtb
@@ -1106,6 +1106,7 @@
 <translation id="8197543752516192074">ገጽን ተርጉም</translation>
 <translation id="8205564605687841303">ተወው</translation>
 <translation id="8206354486702514201">ይህ ቅንብር በአስተዳዳሪዎ ነው በግዳጅ እንዲፈጸም የተደረገው።</translation>
+<translation id="8214293972734702249">ተሰክቷል፣ <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">የተሸጎጡ ምስሎች እና ፋይሎች</translation>
 <translation id="8237382152611443140">የይለፍ ቃላትን በራስ-ሙላ ቅንብሮችን ይክፈቱ</translation>
 <translation id="8248969482078657578">ገቢር ያልሆኑ ትሮች ትኩረት እንዲያደርጉ ያግዙዎታል</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_as.xtb b/ios/chrome/app/strings/resources/ios_strings_as.xtb
index fe1ee9b..9494b81 100644
--- a/ios/chrome/app/strings/resources/ios_strings_as.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_as.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314"><ph name="LANGUAGE" /> সদাই অনুবাদ কৰক</translation>
 <translation id="110724200315609752">খোলা থকা ৱিণ্ড’লৈ যাওক</translation>
 <translation id="1112015203684611006">প্ৰিণ্টিং কৰিব পৰা নগ'ল।</translation>
+<translation id="1113057722807951993">পাছফ্ৰে’জ এনক্ৰিপশ্বনত Google Payৰ পৰিশোধ পদ্ধতি আৰু ঠিকনা অন্তৰ্ভুক্ত নহয়।
+
+এই ছেটিংটো সলনি কৰিবলৈ, <ph name="BEGIN_LINK" />আপোনাৰ একাউণ্টৰ Chromeৰ ডেটা মচক<ph name="END_LINK" />।</translation>
 <translation id="1125564390852150847">নতুন টেব সৃষ্টি কৰক।</translation>
 <translation id="1126809382673880764">আপোনাক বিপজ্জনক ৱেবছাইট, ডাউনল’ড অথবা এক্সটেনশ্বনসমূহৰ পৰা সুৰক্ষা প্ৰদান নকৰে। Gmail আৰু Searchৰ দৰে অন্য Google সেৱাসমূহ, য’ত সুৰক্ষিত ব্ৰাউজিঙৰ সুবিধাটো উপলব্ধ, সেইবিলাকত আপুনি তথাপি এই সুবিধাটো পাব।</translation>
 <translation id="1145536944570833626">পূর্বে থকা ডেটা মচক।</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">ব্ৰাউজ কৰক</translation>
 <translation id="1990820278544963435">বিচাৰক</translation>
 <translation id="199425419756152024">পাছৱৰ্ড চাওক</translation>
+<translation id="2008357574463816229">আপুনি যদি নিজৰ পাছফ্ৰে’জটো পাহৰে অথবা এই ছেটিংটো সলাব বিচাৰে, <ph name="BEGIN_LINK" />আপোনাৰ একাউণ্টৰ Chromeৰ ডেটা মচক<ph name="END_LINK" />।</translation>
 <translation id="2010008505735295285">পুনৰ ল’ড কৰক</translation>
 <translation id="2015722694326466240">পাছৱৰ্ড চাবলৈ আপুনি প্ৰথমে এই ডিভাইচটোত এটা পাছক‘ড ছেট কৰিব লাগিব।</translation>
 <translation id="2021670401941426298">যদি প্ৰযোজ্য হয়, আপোনাৰ সন্ধানৰ ইতিহাস মচিবলৈ আপোনাৰ সন্ধানৰ ইঞ্জিনৰ নিৰ্দেশাৱলী চাওক।</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">পূৰ্বৱৰ্তী টেবটোলৈ যাওক</translation>
 <translation id="5755162682436943950">ছাইন আউট কৰা আছে। ছাইন ইন আৰু ছিংক অন কৰিবলৈ ডায়লগ খোলে।</translation>
 <translation id="5758631781033351321">ইয়াত আপুনি নিজৰ পঢ়াৰ সূচীখন বিচাৰি পাব</translation>
+<translation id="5762370665605786758">পাছফ্ৰে’জ এনক্ৰিপশ্বনত Google Payৰ পৰিশোধ পদ্ধতি আৰু ঠিকনা অন্তৰ্ভুক্ত নহয়।
+
+আপোনাৰ পাছফ্ৰে’জ থকা লোকেহে আপোনাৰ এনক্ৰিপ্ট কৰা ডেটা পঢ়িব পাৰিব। পাছফ্ৰে’জটো Googleলৈ পঠিওৱা নহয় অথবা Googleএ সেয়া ষ্ট’ৰ নকৰে। আপুনি যদি নিজৰ পাছফ্ৰে’জটো পাহৰে অথবা এই ছেটিংটো সলাব বিচাৰে, <ph name="BEGIN_LINK" />আপোনাৰ একাউণ্টৰ Chromeৰ ডেটা মচক<ph name="END_LINK" />।</translation>
 <translation id="5765456154762864099">মেনু → ছেটিং → ডিফ’ল্ট ব্ৰাউজাৰ</translation>
 <translation id="5777888488419460501">একাউণ্টত ছেভ কৰক</translation>
 <translation id="5782227691023083829">অনুবাদ কাৰ্য্য চলি আছে...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">এই পৃষ্ঠাটো <ph name="LANGUAGE" />লৈ অনুবাদ কৰি থকা হৈছে। বিকল্পসমূহ স্ক্রীণখনৰ একেবাৰে তলৰ কাষত আছে।</translation>
 <translation id="648164694371393720">বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰাত আসোঁৱাহ হৈছে</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> টা সমল মচা হ’ল</translation>
+<translation id="6484712497741564393"><ph name="EMAIL" /> হিচাপে ছাইন ইন কৰিছে।
+
+আপোনাৰ ডেটা নিজৰ পাছফ্ৰে’জৰ জৰিয়তে এনক্ৰিপ্ট কৰা হৈছে। আপোনাৰ Google একাউণ্টত Chromeৰ ডেটা ব্যৱহাৰ আৰু ছেভ কৰিবলৈ এইটো দিয়ক।</translation>
 <translation id="6497772452874122664">যদি আপোনাৰ <ph name="TIME" />ৰ ওপৰত বিশ্বাস আছে, তেন্তে আপুনি অন্য এটা ছাইটৰ বাবে ছেভ কৰি থোৱা এটা পাছৱৰ্ড ব্যৱহাৰ কৰিব পাৰে।
 
 প্ৰতিটো ছাইটৰ বাবে এটা অদ্বিতীয় পাছৱৰ্ড ব্যৱহাৰ কৰিবলৈ চেষ্টা কৰক।</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">পাছৱর্ড ৰপ্তানি কৰিব নোৱাৰি</translation>
 <translation id="6732087373923685049">কেমেৰা</translation>
 <translation id="6748108480210050150">প্ৰেৰক</translation>
+<translation id="6753469262000681876">লকডাউন ম’ড</translation>
 <translation id="6760509555861141183">শেহতীয়া টেবলৈ উভতি যাওক</translation>
 <translation id="6762812039470893796">আটাইবোৰ টেব বাছনি কৰাৰ পৰা আঁতৰাওক</translation>
 <translation id="6780034285637185932">পিন ক’ড</translation>
@@ -1120,6 +1131,9 @@
 <translation id="8299417921174340354">পাছৱৰ্ডসমূহ ব্যৱহাৰ কৰিবলৈ আপুনি প্ৰথমে নিজৰ ডিভাইচত এটা পাছক’ড ছেট কৰিবই লাগিব।</translation>
 <translation id="8299613349954694191">ৱেব ব্যক্তিগতভাৱে ব্ৰাউজ কৰিবলৈ কোনো ইনক’গনিট‘ টেব খোলক।</translation>
 <translation id="8316944564970119719">ছাইট আৰু পাছৱৰ্ডটো দিয়ক, তাৰ পাছত ছেভ কৰক</translation>
+<translation id="8317835149433843300">Google Payৰ পৰা পৰিশোধ পদ্ধতি আৰু ঠিকনা এনক্ৰিপ্ট কৰা নহ’ব। Chromeৰ পৰা ব্ৰাউজিঙৰ ইতিহাস আপোনাৰ Google একাউণ্টত ছেভ কৰা নহ’ব।
+
+আপোনাৰ পাছফ্ৰে’জ থকা লোকেহে আপোনাৰ এনক্ৰিপ্ট কৰা ডেটা পঢ়িব পাৰিব। পাছফ্ৰে’জটো Googleলৈ পঠিওৱা নহয় অথবা Googleএ সেয়া ষ্ট’ৰ নকৰে। আপুনি যদি নিজৰ পাছফ্ৰে’জটো পাহৰে অথবা এই ছেটিংটো সলাব বিচাৰে, <ph name="BEGIN_LINK" />আপোনাৰ একাউণ্টৰ Chromeৰ ডেটা মচক<ph name="END_LINK" />।</translation>
 <translation id="8319076807703933069">নতুন সন্ধান</translation>
 <translation id="8323906514956095947">টেবৰ অধিক বিকল্পৰ বাবে স্পৰ্শ কৰি ধৰি ৰাখক</translation>
 <translation id="8328777765163860529">সকলো বন্ধ কৰক</translation>
@@ -1142,6 +1156,9 @@
 <translation id="8487700953926739672">অফলাইনত উপলব্ধ</translation>
 <translation id="8488923644885757471">নতুন ৱিণ্ড’</translation>
 <translation id="8490978609246021741">সালসলনিবোৰ ছেভ কৰক</translation>
+<translation id="8491300088149538575"><ph name="EMAIL" /> হিচাপে ছাইন ইন কৰিছে।
+
+আপোনাৰ ডেটাখিনি আপোনাৰ পাছফ্ৰে’জৰ জৰিয়তে <ph name="TIME" />ত এনক্ৰিপ্ট কৰা হৈছে। আপোনাৰ Google একাউণ্টত Chromeৰ ডেটা ব্যৱহাৰ আৰু ছেভ কৰিবলৈ এইটো দিয়ক।</translation>
 <translation id="8503813439785031346">ব্যৱহাৰকাৰীৰ নাম</translation>
 <translation id="850600235656508448">ইনক’গনিট’ত খোলক</translation>
 <translation id="8517375800490286174">মুক্ত উৎসৰ অনুজ্ঞাপত্ৰসমূহ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_da.xtb b/ios/chrome/app/strings/resources/ios_strings_da.xtb
index 84ead014..5e0815c2 100644
--- a/ios/chrome/app/strings/resources/ios_strings_da.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_da.xtb
@@ -1106,6 +1106,7 @@
 <translation id="8197543752516192074">Oversæt side</translation>
 <translation id="8205564605687841303">Annuller</translation>
 <translation id="8206354486702514201">Denne indstilling håndhæves af din administrator.</translation>
+<translation id="8214293972734702249"><ph name="TAB_TITLE" /> er fastgjort</translation>
 <translation id="8225985093977202398">Billeder og filer, der er gemt i cache</translation>
 <translation id="8237382152611443140">Åbn indstillingerne for Autoudfyld adgangskoder</translation>
 <translation id="8248969482078657578">Inaktive faner hjælper dig med at holde fokus</translation>
@@ -1236,7 +1237,7 @@
 <translation id="9068336935206019333">Åbn i inkognitotilstand i Chrome</translation>
 <translation id="9079935439869366234">Markér alle som ulæste</translation>
 <translation id="9081058212938299310">Vil du opdatere adgangskoden til <ph name="USERNAME" />?</translation>
-<translation id="9083838294503912307">Aktivér synkronisering for at synkronisere og tilpasse på alle dine enheder.</translation>
+<translation id="9083838294503912307">Aktivér synkronisering for at synkronisere og personligt tilpasse på alle dine enheder.</translation>
 <translation id="9093271241977565440">Tryk på søgeikonet øverst på skærmen</translation>
 <translation id="9094033019050270033">Opdater adgangskoden</translation>
 <translation id="9097506547406246598">"Følg" kan ikke fortrydes. Der gik noget galt.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_fr.xtb b/ios/chrome/app/strings/resources/ios_strings_fr.xtb
index 0ef5d8cc..61b416f 100644
--- a/ios/chrome/app/strings/resources/ios_strings_fr.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_fr.xtb
@@ -63,7 +63,7 @@
 <translation id="1335348992705722518">Gérer les paramètres</translation>
 <translation id="1340643665687018190">Fermer le menu</translation>
 <translation id="1358214951266274152">Consulter le lien copié</translation>
-<translation id="1360432990279830238">Se déconnecter et arrêter la synchro. ?</translation>
+<translation id="1360432990279830238">Se déconnecter et arrêter la synchronisation ?</translation>
 <translation id="1363028406613469049">Titre</translation>
 <translation id="1375321115329958930">Mots de passe enregistrés</translation>
 <translation id="1377255359165588604">La synchronisation s'est arrêtée.</translation>
@@ -618,7 +618,7 @@
 <translation id="5119391094379141756">Sélectionnez Chrome</translation>
 <translation id="5121618895923301719">Vous suivez déjà ce produit. Cette page est enregistrée dans <ph name="BEGIN_LINK" />Favoris sur mobile<ph name="END_LINK" />.</translation>
 <translation id="5126465625664020024">Se connecter et synchroniser</translation>
-<translation id="5132942445612118989">Synchroniser vos mots de passe, votre historique et plus encore sur tous les appareils</translation>
+<translation id="5132942445612118989">Synchronisez vos mots de passe, votre historique et plus encore sur tous les appareils</translation>
 <translation id="5142890110117755815">{COUNT,plural, =1{{COUNT} mot de passe peu sécurisé}one{{COUNT} mot de passe peu sécurisé}other{{COUNT} mots de passe peu sécurisés}}</translation>
 <translation id="5149188072385105201">Ajouter un mot de passe</translation>
 <translation id="5150492518600715772">Envoyer sur votre appareil</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_lo.xtb b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
index 61cb2a7..c52500a 100644
--- a/ios/chrome/app/strings/resources/ios_strings_lo.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">ແປ <ph name="LANGUAGE" /> ຢູ່ສະເໝີ</translation>
 <translation id="110724200315609752">ປ່ຽນເພື່ອເປີດໜ້າຈໍ</translation>
 <translation id="1112015203684611006">ການພິມບໍ່ສຳເລັດ.</translation>
+<translation id="1113057722807951993">ການເຂົ້າລະຫັດດ້ວຍລະຫັດຜ່ານບໍ່ຮວມເຖິງວິທີການຈ່າຍເງິນ ແລະ ທີ່ຢູ່ຈາກ Google Pay.
+
+ເພື່ອປ່ຽນການຕັ້ງຄ່ານີ້, ໃຫ້<ph name="BEGIN_LINK" />ລຶບລ້າງຂໍ້ມູນ Chrome ໃນບັນຊີຂອງທ່ານ<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">ສ້າງ​ແຖບ​ໃໝ່.</translation>
 <translation id="1126809382673880764">ບໍ່ປົກປ້ອງທ່ານຈາກເວັບໄຊ, ການດາວໂຫຼດ ແລະ ສ່ວນຂະຫຍາຍທີ່ເປັນອັນຕະລາຍ. ທ່ານຈະຍັງໄດ້ຮັບການປົກປ້ອງຈາກ Safe Browsing ຢູ່ບ່ອນທີ່ໃຊ້ໄດ້, ຢູ່ໃນການບໍລິການອື່ນຂອງ Google ເຊັ່ນ: Gmail ແລະ ຊອກຫາ.</translation>
 <translation id="1145536944570833626">ລຶບຂໍ້ມູນທີ່ມີຢູ່.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">ເປີດ​ເບິ່ງ</translation>
 <translation id="1990820278544963435">ຊອກຫາ</translation>
 <translation id="199425419756152024">ເບິ່ງລະຫັດຜ່ານ</translation>
+<translation id="2008357574463816229">ຫາກທ່ານລືມລະຫັດຜ່ານຂອງທ່ານ ຫຼື ຕ້ອງການປ່ຽນການຕັ້ງຄ່ານີ້, ໃຫ້<ph name="BEGIN_LINK" />ລຶບລ້າງຂໍ້ມູນ Chrome ໃນບັນຊີຂອງທ່ານ<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">ໂຫຼດໃໝ່</translation>
 <translation id="2015722694326466240">ເພື່ອເບິ່ງລະຫັດຜ່ານ, ກ່ອນອື່ນທາງຕ້ອງຕັ້ງລະຫັດຜ່ານໃນອຸປະກອນຂອງທ່ານ.</translation>
 <translation id="2021670401941426298">ກະລຸນາອ່ານຄຳແນະນຳຂອງໂປຣແກຣມຊອກຫາຂອງທ່ານສຳລັບວິທີການລຶບປະຫວັດການຊອກຫາ, ຖ້າມີ.</translation>
@@ -535,6 +539,7 @@
 <translation id="4592368184551360546">ແປ້ນພິມ</translation>
 <translation id="4606247758155004938">ໂປຣແກຣມທ່ອງເວັບຂອງທ່ານແມ່ນຈັດການໂດຍອົງການຂອງທ່ານ.</translation>
 <translation id="461440297010471931">ກຳລັງຊອກຫາດ້ວຍ Google</translation>
+<translation id="4616391354457235490">ຍົກເລີກ</translation>
 <translation id="4619564267100705184">ຢັ້ງຢືນວ່າແມ່ນທ່ານແທ້</translation>
 <translation id="4619615317237390068">ແຖບຈາກອຸປະກອນອື່ນ</translation>
 <translation id="4620246317052452550">ໜ້າທີ່ທ່ານອ່ານແລ້ວ</translation>
@@ -707,6 +712,9 @@
 <translation id="5745916533876677730">ໄປຫາແຖບກ່ອນໜ້າ</translation>
 <translation id="5755162682436943950">ອອກຈາກລະບົບແລ້ວ. ເປີດກ່ອງໂຕ້ຕອບເພື່ອເຂົ້າສູ່ລະບົບ ແລະ ເປີດການຊິ້ງຂໍ້ມູນ.</translation>
 <translation id="5758631781033351321">ທ່ານຈະເຫັນລາຍການອື່ນຂອງທ່ານຢູ່ບ່ອນນີ້</translation>
+<translation id="5762370665605786758">ການເຂົ້າລະຫັດດ້ວຍລະຫັດຜ່ານບໍ່ຮວມເຖິງວິທີການຈ່າຍເງິນ ແລະ ທີ່ຢູ່ຈາກ Google Pay.
+
+ມີພຽງບຸກຄົນທີ່ມີລະຫັດຜ່ານຂອງທ່ານເທົ່ານັ້ນທີ່ສາມາດອ່ານຂໍ້ມູນທີ່ໄດ້ຖືກເຂົ້າລະຫັດໄວ້ຂອງທ່ານ. Google ຈະບໍ່ໄດ້ຮັບ ຫຼື ຈັດເກັບລະຫັດຜ່ານດັ່ງກ່າວໄວ້. ຫາກທ່ານລືມລະຫັດຜ່ານຂອງທ່ານ ຫຼື ຕ້ອງການປ່ຽນການຕັ້ງຄ່ານີ້, ໃຫ້<ph name="BEGIN_LINK" />ລຶບລ້າງຂໍ້ມູນ Chrome ໃນບັນຊີຂອງທ່ານ<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">ເມນູ → ການຕັ້ງຄ່າ → ໂປຣແກຣມທ່ອງເວັບເລີ່ມຕົ້ນ</translation>
 <translation id="5777888488419460501">ບັນທຶກໃນບັນຊີ</translation>
 <translation id="5782227691023083829">ກໍາລັງແປ...</translation>
@@ -848,10 +856,14 @@
 <translation id="6476800141292307438">ກຳລັງແປໜ້າເວັບເປັນ <ph name="LANGUAGE" />. ມີຕົວເລືອກໃຫ້ນຳໃຊ້ຢູ່ໃກ້ລຸ່ມສຸດຂອງໜ້າຈໍ.</translation>
 <translation id="648164694371393720">ການຮອງຮັບຄວາມຖືກຕ້ອງຜິດພາດ</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ລາຍ​ການ​ຖືກ​ລຶບ​ແລ້ວ</translation>
+<translation id="6484712497741564393">ເຂົ້າສູ່ລະບົບເປັນ <ph name="EMAIL" />.
+
+ຂໍ້ມູນຂອງທ່ານຖືກເຂົ້າລະຫັດໄວ້ດ້ວຍລະຫັດຜ່ານຂອງທ່ານ. ລະບຸລະຫັດຜ່ານເພື່ອໃຊ້ ແລະ ບັນທຶກຂໍ້ມູນ Chrome ໃນບັນຊີ Google ຂອງທ່ານ.</translation>
 <translation id="6497772452874122664">ຖ້າທ່ານເຊື່ອຖື <ph name="TIME" />, ທ່ານສາມາດໃຊ້ລະຫັດຜ່ານທີ່ບັນທຶກໄວ້ຈາກເວັບໄຊອື່ນໄດ້.
 
 ພະຍາຍາມໃຊ້ລະຫັດຜ່ານສະເພາະສຳລັບທຸກໆເວັບໄຊ.</translation>
 <translation id="650279896687777322">ສຶກສາເພີ່ມເຕີມ...</translation>
+<translation id="6507973708545996744">ເຂົ້າສູ່ລະບົບເພື່ອຮັບລາຍຊື່ການອ່ານຂອງທ່ານຢູ່ອຸປະກອນທັງໝົດຂອງທ່ານ.</translation>
 <translation id="6510072653668207258">ແຈ້ງເຕືອນຂ້ອຍພາຍຫຼັງ</translation>
 <translation id="651505212789431520">ຍົກເລີກການຊິ້ງຂໍ້ມູນບໍ? ທ່ານສາມາດເປີດການຊິ້ງຂໍ້ມູນໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າ.</translation>
 <translation id="6518133107902771759">ກວດສອບ</translation>
@@ -894,6 +906,7 @@
 <translation id="6730682669179532099">ບໍ່ສາມາດສົ່ງລະຫັດຜ່ານອອກໄດ້</translation>
 <translation id="6732087373923685049">ກ້ອງຖ່າຍຮູບ</translation>
 <translation id="6748108480210050150">ຈາກ</translation>
+<translation id="6753469262000681876">ໂໝດລັອກໄວ້</translation>
 <translation id="6760509555861141183">ກັບໄປຫາແຖບຫຼ້າສຸດ</translation>
 <translation id="6762812039470893796">ເຊົາເລືອກທັງໝົດ</translation>
 <translation id="6780034285637185932">ລະ​ຫັດ​ໄປສະນີ</translation>
@@ -1106,6 +1119,7 @@
 <translation id="8197543752516192074">ແປໜ້າ</translation>
 <translation id="8205564605687841303">ຍົກເລີກ</translation>
 <translation id="8206354486702514201">ການຕັ້ງຄ່ານີ້ຖືກບັງຄັບໂດຍຜູ້ຄວບຄຸມຂອງທ່ານ.</translation>
+<translation id="8214293972734702249">ປັກໝຸດແລ້ວ, <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">ຮູບ ແລະ ໄຟລ໌ທີ່ຖືກແຄດຊ໌</translation>
 <translation id="8237382152611443140">ເປີດການຕັ້ງຄ່າການຕື່ມຂໍ້ມູນລະຫັດຜ່ານອັດຕະໂນມັດ</translation>
 <translation id="8248969482078657578">ແຖບທີ່ບໍ່ເຄື່ອນໄຫວຊ່ວຍໃຫ້ທ່ານຕັ້ງໃຈຢູ່ສະເໝີ</translation>
@@ -1120,6 +1134,9 @@
 <translation id="8299417921174340354">ເພື່ອໃຊ້ລະຫັດຜ່ານ, ທ່ານຕ້ອງຕັ້ງລະຫັດຜ່ານໃນອຸປະກອນຂອງທ່ານກ່ອນ.</translation>
 <translation id="8299613349954694191">ເປີດແຖບ​ບໍ່ເປີດເຜີຍຕົວຕົນເພື່ອທ່ອງເວັບແບບສ່ວນຕົວ.</translation>
 <translation id="8316944564970119719">ລະບຸເວັບໄຊ ແລະ ລະຫັດ, ຈາກນັ້ນບັນທຶກ</translation>
+<translation id="8317835149433843300">ວິທີການຈ່າຍເງິນ ແລະ ທີ່ຢູ່ຈາກ Google Pay ຈະບໍ່ໄດ້ຖືກເຂົ້າລະຫັດໄວ້. ປະຫວັດການທ່ອງເວັບຈາກ Chrome ຈະບໍ່ຖືກບັນທຶກໄວ້ໃນບັນຊີ Google ຂອງທ່ານ.
+
+ມີພຽງບຸກຄົນທີ່ມີລະຫັດຜ່ານຂອງທ່ານເທົ່ານັ້ນທີ່ສາມາດອ່ານຂໍ້ມູນທີ່ໄດ້ຖືກເຂົ້າລະຫັດໄວ້ຂອງທ່ານ. Google ຈະບໍ່ໄດ້ຮັບ ຫຼື ຈັດເກັບລະຫັດຜ່ານດັ່ງກ່າວໄວ້. ຫາກທ່ານລືມລະຫັດຜ່ານຂອງທ່ານ ຫຼື ຕ້ອງການປ່ຽນການຕັ້ງຄ່ານີ້, ໃຫ້<ph name="BEGIN_LINK" />ລຶບລ້າງຂໍ້ມູນ Chrome ໃນບັນຊີຂອງທ່ານ<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">ຊອກຫາໃໝ່</translation>
 <translation id="8323906514956095947">ແຕະຄ້າງໄວ້ສຳລັບຕົວເລືອກເພີ່ມເຕີມຂອງແຖບ</translation>
 <translation id="8328777765163860529">ປິດທັງໝົດ</translation>
@@ -1142,6 +1159,9 @@
 <translation id="8487700953926739672">ມີອອຟລາຍນ໌ຢູ່</translation>
 <translation id="8488923644885757471">ໜ້າຈໍໃໝ່</translation>
 <translation id="8490978609246021741">ບັນທຶກການປ່ຽນແປງ</translation>
+<translation id="8491300088149538575">ເຂົ້າສູ່ລະບົບເປັນ <ph name="EMAIL" />.
+
+ຂໍ້ມູນຂອງທ່ານໄດ້ຖືກເຂົ້າລະຫັດໄວ້ດ້ວຍລະຫັດຜ່ານຂອງທ່ານເມື່ອ <ph name="TIME" />. ລະບຸລະຫັດຜ່ານເພື່ອໃຊ້ ແລະ ບັນທຶກຂໍ້ມູນ Chrome ໃນບັນຊີ Google ຂອງທ່ານ.</translation>
 <translation id="8503813439785031346">ຊື່​ຜູ້​ໃຊ້</translation>
 <translation id="850600235656508448">ເປີດໃນໂໝດບໍ່ເຜີຍຕົວຕົນ</translation>
 <translation id="8517375800490286174">ໃບ​ອະ​ນຸ​ຍາດ Open source</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ml.xtb b/ios/chrome/app/strings/resources/ios_strings_ml.xtb
index 6d3c82e..3aae1e0 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ml.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ml.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314"><ph name="LANGUAGE" /> എല്ലായ്പ്പോഴും വിവര്‍ത്തനം ചെയ്യുക </translation>
 <translation id="110724200315609752">തുറന്ന വിൻഡോയിലേക്ക് മാറുക</translation>
 <translation id="1112015203684611006">പ്രിന്റിംഗ് പരാജയപ്പെട്ടു.</translation>
+<translation id="1113057722807951993">പാസ്‌ഫ്രെയ്‌സ് എൻക്രിപ്ഷനിൽ Google Pay-ൽ നിന്നുള്ള പേയ്മെന്റ് രീതികളും വിലാസങ്ങളും ഉൾപ്പെടുന്നില്ല.
+
+ഈ ക്രമീകരണം മാറ്റാൻ, <ph name="BEGIN_LINK" />നിങ്ങളുടെ അക്കൗണ്ടിലെ Chrome ഡാറ്റ മായ്ക്കുക<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">പുതിയ ടാബ് സൃഷ്‌ടിക്കുക.</translation>
 <translation id="1126809382673880764">അപകടകരമായ വെബ്‌സൈറ്റുകൾ ഡൗൺലോഡുകൾ, വിപുലീകരണങ്ങൾ എന്നിവയിൽ നിന്ന് നിങ്ങളെ പരിരക്ഷിക്കില്ല. Gmail, Search പോലുള്ള മറ്റ് Google സേവനങ്ങളിൽ ഉള്ള സുരക്ഷിത ബ്രൗസിംഗ് പരിരക്ഷ നിങ്ങൾക്ക് തുടർന്നും ലഭിക്കും.</translation>
 <translation id="1145536944570833626">നിലവിലുള്ള വിവരങ്ങൾ ഇല്ലാതാക്കുക.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">ബ്രൗസ് ചെയ്യുക</translation>
 <translation id="1990820278544963435">കണ്ടെത്തുക</translation>
 <translation id="199425419756152024">പാസ്‌വേഡ് കാണുക</translation>
+<translation id="2008357574463816229">നിങ്ങൾ പാസ്‌ഫ്രെയ്‌സ് മറന്നുപോയെങ്കിലോ ഈ ക്രമീകരണം മാറ്റണമെങ്കിലോ, <ph name="BEGIN_LINK" />നിങ്ങളുടെ അക്കൗണ്ടിലെ Chrome ഡാറ്റ മായ്ക്കുക<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">റീലോഡ് ചെയ്യുക</translation>
 <translation id="2015722694326466240">പാസ്‍വേഡുകൾ കാണാൻ, ആദ്യം നിങ്ങളുടെ ഉപകരണത്തിൽ പാസ്‌കോഡ് സജ്ജീകരിക്കുക.</translation>
 <translation id="2021670401941426298">ബാധകമെങ്കിൽ, നിങ്ങളുടെ തിരയൽ ചരിത്രം ഇല്ലാതാക്കാനുള്ള തിരയൽ യന്ത്രത്തിന്റെ നിർദ്ദേശങ്ങൾ കാണുക.</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">മുമ്പത്തെ ടാബിലേക്ക് പോകുക</translation>
 <translation id="5755162682436943950">സൈൻ ഔട്ട് ചെയ്‌തു. സൈൻ ഇൻ ചെയ്യാനും സമന്വയം ഓണാക്കാനും ഡയലോഗ് തുറക്കുക.</translation>
 <translation id="5758631781033351321">നിങ്ങളുടെ വായനാ ലിസ്‌റ്റ് ഇവിടെ കാണാം</translation>
+<translation id="5762370665605786758">പാസ്‌ഫ്രെയ്‌സ് എൻക്രിപ്ഷനിൽ Google Pay-ൽ നിന്നുള്ള പേയ്മെന്റ് രീതികളും വിലാസങ്ങളും ഉൾപ്പെടുന്നില്ല.
+
+നിങ്ങളുടെ പാസ്‌ഫ്രെയ്‌സ് കൈവശമുള്ള ഒരാൾക്ക് മാത്രമേ നിങ്ങളുടെ എൻക്രിപ്റ്റ് ചെയ്ത ഡാറ്റ വായിക്കാൻ കഴിയൂ. Google-ലേക്ക് പാസ്‌ഫ്രെയ്‌സ് അയയ്‌ക്കുകയോ സൂക്ഷിക്കുകയോ ചെയ്യുന്നില്ല. നിങ്ങൾ പാസ്‌ഫ്രെയ്‌സ് മറന്നുപോയെങ്കിലോ ഈ ക്രമീകരണം മാറ്റണമെങ്കിലോ, <ph name="BEGIN_LINK" />നിങ്ങളുടെ അക്കൗണ്ടിലെ Chrome ഡാറ്റ മായ്ക്കുക<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">മെനു → ക്രമീകരണം → ഡിഫോൾട്ട് ബ്രൗസർ</translation>
 <translation id="5777888488419460501">അക്കൗണ്ടിൽ സംരക്ഷിക്കുക</translation>
 <translation id="5782227691023083829">വിവര്‍‌ത്തനം ചെയ്യുന്നു...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">പേജ് <ph name="LANGUAGE" /> എന്ന ഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യുന്നു. സ്‌ക്രീനിൻ്റെ ചുവടെ ഓപ്‌ഷനുകൾ ലഭ്യമാണ്.</translation>
 <translation id="648164694371393720">പരിശോധിച്ചുറപ്പിക്കൽ പിശക്</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ഇനങ്ങൾ ഇല്ലാതാക്കി</translation>
+<translation id="6484712497741564393"><ph name="EMAIL" /> എന്നയാളായി സൈൻ ഇൻ ചെയ്‌തു.
+
+പാസ്‌ഫ്രെയ്‌സ് ഉപയോഗിച്ച് നിങ്ങളുടെ ഡാറ്റ എൻ‌ക്രിപ്‌റ്റ് ചെയ്‌തു. നിങ്ങളുടെ Google Account-ൽ Chrome ഡാറ്റ ഉപയോഗിക്കാനും സംരക്ഷിക്കാനും അത് നൽകുക.</translation>
 <translation id="6497772452874122664">നിങ്ങൾക്ക് <ph name="TIME" /> -നെ വിശ്വാസമുണ്ടെങ്കിൽ, മറ്റൊരു സൈറ്റിലെ സംരക്ഷിച്ചിരിക്കുന്ന പാസ്‌വേഡ് ഉപയോഗിക്കാം.
 
 ഓരോ സൈറ്റിനും വ്യത്യസ്തമായ പാസ്‌വേഡ് ഉപയോഗിക്കാൻ ശ്രമിക്കുക.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">പാസ്‌വേഡുകൾ എക്‌സ്‌പോർട്ട് ചെയ്യാനാവുന്നില്ല</translation>
 <translation id="6732087373923685049">ക്യാമറ</translation>
 <translation id="6748108480210050150">പ്രേഷിതന്‍</translation>
+<translation id="6753469262000681876">ലോക്ക്‌ഡൌൺ മോഡ്</translation>
 <translation id="6760509555861141183">ഏറ്റവും അവസാനം തുറന്ന ടാബിലേക്ക് മടങ്ങുക</translation>
 <translation id="6762812039470893796">എല്ലാം തിരഞ്ഞെടുത്തത് മാറ്റുക</translation>
 <translation id="6780034285637185932">തപാൽ കോഡ്</translation>
@@ -1120,6 +1131,9 @@
 <translation id="8299417921174340354">പാസ്‍വേഡുകൾ ഉപയോഗിക്കാൻ, ആദ്യം നിങ്ങളുടെ ഉപകരണത്തിൽ പാസ്‌കോഡ് സജ്ജീകരിക്കുക.</translation>
 <translation id="8299613349954694191">സ്വകാര്യമായി വെബ് ബ്രൗസ് ചെയ്യാൻ അദൃശ്യ ടാബ് തുറക്കുക.</translation>
 <translation id="8316944564970119719">സൈറ്റും പാസ്‌വേഡും നൽകുക, തുടർന്ന് സംരക്ഷിക്കുക</translation>
+<translation id="8317835149433843300">Google Pay-യിൽ നിന്നുള്ള പേയ്‌മെന്റ് രീതികളും വിലാസങ്ങളും എൻക്രിപ്റ്റ് ചെയ്യില്ല. Chrome-ൽ നിന്നുള്ള ബ്രൗസിംഗ് ചരിത്രം നിങ്ങളുടെ Google Account-ൽ സംരക്ഷിക്കില്ല.
+
+നിങ്ങളുടെ പാസ്‌ഫ്രെയ്‌സ് കൈവശമുള്ള ഒരാൾക്ക് മാത്രമേ നിങ്ങളുടെ എൻക്രിപ്റ്റ് ചെയ്ത ഡാറ്റ വായിക്കാൻ കഴിയൂ. Google-ലേക്ക് പാസ്‌ഫ്രെയ്‌സ് അയയ്‌ക്കുകയോ സൂക്ഷിക്കുകയോ ചെയ്യുന്നില്ല. നിങ്ങൾ പാസ്‌ഫ്രെയ്‌സ് മറന്നുപോയെങ്കിലോ ഈ ക്രമീകരണം മാറ്റണമെങ്കിലോ, <ph name="BEGIN_LINK" />നിങ്ങളുടെ അക്കൗണ്ടിലെ Chrome ഡാറ്റ മായ്ക്കുക<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">പുതിയ തിരയൽ</translation>
 <translation id="8323906514956095947">കൂടുതൽ ടാബ് ഓപ്‌ഷനുകൾക്കായി സ്‌പർശിച്ച് പിടിക്കുക</translation>
 <translation id="8328777765163860529">എല്ലാം അടയ്‌ക്കുക</translation>
@@ -1142,6 +1156,9 @@
 <translation id="8487700953926739672">ഓഫ്‌ലൈനില്‍ ലഭ്യമാണ്</translation>
 <translation id="8488923644885757471">പുതിയ വിൻഡോ</translation>
 <translation id="8490978609246021741">മാറ്റങ്ങള്‍ സംരക്ഷിക്കുക</translation>
+<translation id="8491300088149538575"><ph name="EMAIL" /> എന്നയാളായി സൈൻ ഇൻ ചെയ്‌തു.
+
+<ph name="TIME" />-ന് നിങ്ങളുടെ സമന്വയ പാസ്‌ഫ്രെയ്സ് ഉപയോഗിച്ച് ഡാറ്റ എൻക്രിപ്റ്റ് ചെയ്‌തു. നിങ്ങളുടെ Google Account-ൽ Chrome ഡാറ്റ ഉപയോഗിക്കാനും സംരക്ഷിക്കാനും അത് നൽകുക.</translation>
 <translation id="8503813439785031346">ഉപയോക്തൃനാമം</translation>
 <translation id="850600235656508448">ആൾമാറാട്ട മോഡിൽ തുറക്കുക</translation>
 <translation id="8517375800490286174">ഓപ്പൺ സോഴ്‌സ് ലൈസൻസുകൾ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ne.xtb b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
index d4538d9..e39d83c4 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ne.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">सँधै अनुवाद गर्नुहोस् <ph name="LANGUAGE" /></translation>
 <translation id="110724200315609752">खुला विन्डोमा जानुहोस्</translation>
 <translation id="1112015203684611006">छाप्न सकिएन।</translation>
+<translation id="1113057722807951993">पासफ्रेज इन्क्रिप्सनमा Google Pay मा भएका भुक्तानी विधि र ठेगानाहरू समावेश हुँदैनन्।
+
+यो सेटिङ परिवर्तन गर्न <ph name="BEGIN_LINK" />आफ्नो खातामा गएर Chrome को डेटा मेटाउनुहोस्<ph name="END_LINK" />।</translation>
 <translation id="1125564390852150847">नयाँ ट्याब सिर्जना गर्नुहोस्।</translation>
 <translation id="1126809382673880764">तपाईंलाई जोखिमपूर्ण वेबसाइट, डाउनलोड वा एक्स्टेन्सनहरूविरुद्ध सुरक्षा प्रदान गर्दैन। उपलब्ध भएसम्म तपाईं अझै पनि Gmail र खोज जस्ता Google का अन्य सेवाहरूमा सुरक्षित ब्राउजिङको सुरक्षा प्राप्त गर्नु हुने छ।</translation>
 <translation id="1145536944570833626">विद्यमान डेटा मेट्नुहोस्।</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">ब्राउज गर्नुहोस्</translation>
 <translation id="1990820278544963435">खोज्नुहोस्</translation>
 <translation id="199425419756152024">पासवर्ड हेर्नुहोस्</translation>
+<translation id="2008357574463816229">तपाईंले आफ्नो पासफ्रेज बिर्सनुभयो वा तपाईं यो सेटिङ परिवर्तन गर्न चाहनुहुन्छ भने <ph name="BEGIN_LINK" />आफ्नो खातामा गएर Chrome को डेटा मेटाउनुहोस्<ph name="END_LINK" />।</translation>
 <translation id="2010008505735295285">रिलोड गर्नुहोस्</translation>
 <translation id="2015722694326466240">पासवर्डहरू हेर्नका लागि सर्वप्रथम तपाईंले अनिवार्य रूपमा आफ्नो यन्त्रमा कुनै पासकोड सेट गर्नुपर्छ।</translation>
 <translation id="2021670401941426298">तपाईंको सर्च इन्जिनमा खोजको इतिहास मेटाउन मिल्छ भने खोज इतिहास मेटाउन सर्च इन्जिनले उपलब्ध गराएका निर्देशनहरू हेर्नुहोस्।</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">अघिल्लो ट्याबमा जानुहोस्</translation>
 <translation id="5755162682436943950">साइन आउट गरिएको छ। साइन इन गर्न र सिंक गर्ने सुविधा अन गर्न डायलग खोल्छ।</translation>
 <translation id="5758631781033351321">तपाईंको अध्ययन सूची यहाँ देखिने छ</translation>
+<translation id="5762370665605786758">पासफ्रेज इन्क्रिप्सनमा Google Pay मा भएका भुक्तानी विधि र ठेगानाहरू समावेश हुँदैनन्।
+
+तपाईंको पासफ्रेज भएको व्यक्ति मात्र तपाईंको इन्क्रिप्ट गरिएको जानकारी पढ्न सक्छ। उक्त पासफ्रेज Google मा पठाइँदैन वा Google ले उक्त पासफ्रेज भण्डारण गरेर राख्दैन। तपाईंले आफ्नो पासफ्रेज बिर्सनुभयो वा तपाईं यो सेटिङ परिवर्तन गर्न चाहनुहुन्छ भने <ph name="BEGIN_LINK" />आफ्नो खातामा गएर Chrome को डेटा मेटाउनुहोस्<ph name="END_LINK" />।</translation>
 <translation id="5765456154762864099">मेनु → सेटिङहरू → डिफल्ट ब्राउजर</translation>
 <translation id="5777888488419460501">खातामा सेभ गर्नुहोस्</translation>
 <translation id="5782227691023083829">अनुवाद गर्दै...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">पृष्ठलाई <ph name="LANGUAGE" /> भाषामा अनुवाद गर्दै। विकल्पहरू स्क्रिनका पुछारमा उपलब्ध छन्।</translation>
 <translation id="648164694371393720">प्रमाणीकरणसम्बन्धी त्रुटि</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> वस्तुहरू मेटाइयो</translation>
+<translation id="6484712497741564393"><ph name="EMAIL" /> का रूपमा साइन इन गरियो।
+
+तपाईंको पासफ्रेज प्रयोग गरी तपाईंको डेटा इन्क्रिप्ट गरिएको छ। उक्त पासफ्रेज हाली आफ्नो Google खातामा Chrome को डेटा प्रयोग र सेभ गर्नुहोस्।</translation>
 <translation id="6497772452874122664">तपाईंलाई <ph name="TIME" /> माथि विश्वास छ भने तपाईं कुनै अर्को साइटको सुरक्षित गरिएको पासवर्ड प्रयोग गर्न सक्नुहुन्छ।
 
 हरेक साइटमा एउटा अद्वितीय पासवर्ड प्रयोग गर्ने प्रयास गर्नुहोस्।</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">पासवर्डहरू निर्यात गर्न सकिएन</translation>
 <translation id="6732087373923685049">क्यामेरा</translation>
 <translation id="6748108480210050150">बाट</translation>
+<translation id="6753469262000681876">लकडाउन मोड</translation>
 <translation id="6760509555861141183">भर्खरै खोलिएको ट्याबमा जानुहोस्</translation>
 <translation id="6762812039470893796">सबै ट्याबको चयन रद्द गर्नुहोस्</translation>
 <translation id="6780034285637185932">जिप कोड</translation>
@@ -1106,6 +1117,7 @@
 <translation id="8197543752516192074">पृष्ठ अनुवाद गर्नुहोस्</translation>
 <translation id="8205564605687841303">रद्द गर्नुहोस्</translation>
 <translation id="8206354486702514201">यो सेटिङ तपाईंको प्रशासकद्वारा जोड दिएको छ।</translation>
+<translation id="8214293972734702249">पिन गरिएको ट्याब: <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">क्यास गरिएका छवि र फाइलहरू</translation>
 <translation id="8237382152611443140">पासवर्ड स्वतः भर्ने सुविधासम्बन्धी सेटिङ खोल्नुहोस्</translation>
 <translation id="8248969482078657578">"निष्क्रिय ट्याबहरू" ले तपाईंलाई ध्यान केन्द्रित गर्न सघाउँछ</translation>
@@ -1120,6 +1132,9 @@
 <translation id="8299417921174340354">पासवर्डहरू प्रयोग गर्न सर्वप्रथम तपाईंले आफ्नो यन्त्रमा अनिवार्य रूपमा कुनै पासकोड सेट गर्नु पर्छ।</translation>
 <translation id="8299613349954694191">गोप्य रूपमा वेब ब्राउज गर्न इन्कोग्निटो ट्याब खोल्नुहोस्।</translation>
 <translation id="8316944564970119719">साइट र पासवर्ड हाल्नुहोस् अनि सेभ गर्नुहोस्</translation>
+<translation id="8317835149433843300">Google Pay मा भएका भुक्तानी विधि र ठेगानाहरू इन्क्रिप्ट गरिने छैनन्। Chrome मा भएको ब्राउजिङ हिस्ट्री तपाईंको Google खातामा सेभ गरिने छैन।
+
+तपाईंको पासफ्रेज भएको व्यक्ति मात्र तपाईंको इन्क्रिप्ट गरिएको जानकारी पढ्न सक्छ। उक्त पासफ्रेज Google मा पठाइँदैन वा Google ले उक्त पासफ्रेज भण्डारण गरेर राख्दैन। तपाईंले आफ्नो पासफ्रेज बिर्सनुभयो वा तपाईं यो सेटिङ परिवर्तन गर्न चाहनुहुन्छ भने <ph name="BEGIN_LINK" />आफ्नो खातामा गएर Chrome को डेटा मेटाउनुहोस्<ph name="END_LINK" />।</translation>
 <translation id="8319076807703933069">नयाँ खोज</translation>
 <translation id="8323906514956095947">ट्याबसम्बन्धी थप विकल्पहरू हेर्न टच एण्ड होल्ड गर्नुहोस्</translation>
 <translation id="8328777765163860529">सबै बन्द गर्नुहोस्</translation>
@@ -1142,6 +1157,9 @@
 <translation id="8487700953926739672">अफलाईन उपलब्ध</translation>
 <translation id="8488923644885757471">नयाँ विन्डो</translation>
 <translation id="8490978609246021741">परिवर्तनहरू सेभ गर्नुहोस्</translation>
+<translation id="8491300088149538575"><ph name="EMAIL" /> का रूपमा साइन इन गरियो।
+
+तपाईंको पासफ्रेज प्रयोग गरेर <ph name="TIME" /> मा तपाईंको डेटा इन्क्रिप्ट गरियो। उक्त पासफ्रेज हाली आफ्नो Google खातामा Chrome को डेटा प्रयोग र सेभ गर्नुहोस्।</translation>
 <translation id="8503813439785031346">एक-पटके टेक्स्ट म्यासेज</translation>
 <translation id="850600235656508448">इन्कोग्निटोमा खोल्नुहोस्</translation>
 <translation id="8517375800490286174">खुला स्रोतका इजाजतपत्रहरू</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_pa.xtb b/ios/chrome/app/strings/resources/ios_strings_pa.xtb
index 2a48de2..9979ae1 100644
--- a/ios/chrome/app/strings/resources/ios_strings_pa.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_pa.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314"><ph name="LANGUAGE" /> ਦਾ ਹਮੇਸ਼ਾਂ ਅਨੁਵਾਦ ਕਰੋ</translation>
 <translation id="110724200315609752">ਖੁੱਲ੍ਹੀ ਵਿੰਡੋ 'ਤੇ ਜਾਓ</translation>
 <translation id="1112015203684611006">ਪ੍ਰਿੰਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ।</translation>
+<translation id="1113057722807951993">ਪਾਸਫਰੇਜ਼ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ Google Pay ਦੀਆਂ ਭੁਗਤਾਨ ਵਿਧੀਆਂ ਅਤੇ ਪਤੇ ਸ਼ਾਮਲ ਨਹੀਂ ਹਨ।
+
+ਇਸ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣ ਲਈ, <ph name="BEGIN_LINK" />ਆਪਣੇ ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਕਲੀਅਰ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="1125564390852150847">ਨਵੀਂ ਟੈਬ ਬਣਾਓ।</translation>
 <translation id="1126809382673880764">ਤੁਹਾਨੂੰ ਖਤਰਨਾਕ ਵੈੱਬਸਾਈਟਾਂ, ਡਾਊਨਲੋਡਾਂ ਅਤੇ ਐਕਸਟੈਂਸ਼ਨਾਂ ਤੋਂ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਰੱਖਿਆ ਜਾਂਦਾ। ਹੋਰ Google ਸੇਵਾਵਾਂ ਜਿਵੇਂ ਕਿ Gmail ਅਤੇ Search ਵਿੱਚ ਜਿੱਥੇ ਵੀ ਉਪਲਬਧ ਹੋਵੇ ਤੁਹਾਨੂੰ ਫਿਰ ਵੀ ਸੁਰੱਖਿਅਤ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸੁਰੱਖਿਆ ਪ੍ਰਾਪਤ ਹੋਵੇਗੀ।</translation>
 <translation id="1145536944570833626">ਮੌਜੂਦਾ ਡਾਟਾ ਮਿਟਾਓ।</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">ਬ੍ਰਾਊਜ਼ ਕਰੋ</translation>
 <translation id="1990820278544963435">ਲੱਭੋ</translation>
 <translation id="199425419756152024">ਪਾਸਵਰਡ ਦੇਖੋ</translation>
+<translation id="2008357574463816229">ਜੇ ਤੁਸੀਂ ਆਪਣਾ ਪਾਸਫਰੇਜ਼ ਭੁੱਲ ਜਾਂਦੇ ਹੋ ਜਾਂ ਇਸ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ <ph name="BEGIN_LINK" />ਆਪਣੇ ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਕਲੀਅਰ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="2010008505735295285">ਰੀਲੋਡ ਕਰੋ</translation>
 <translation id="2015722694326466240">ਪਾਸਵਰਡਾਂ ਨੂੰ ਦੇਖਣ ਲਈ, ਪਹਿਲਾਂ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ 'ਤੇ ਕਿਸੇ ਪਾਸਕੋਡ ਨੂੰ ਸੈੱਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।</translation>
 <translation id="2021670401941426298">ਲਾਗੂ ਹੋਣ 'ਤੇ, ਆਪਣਾ ਖੋਜ ਇਤਿਹਾਸ ਮਿਟਾਉਣ ਲਈ ਆਪਣੇ ਖੋਜ ਇੰਜਣ ਦੀਆਂ ਹਿਦਾਇਤਾਂ ਦੇਖੋ।</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">ਪਿਛਲੀ ਟੈਬ 'ਤੇ ਜਾਓ</translation>
 <translation id="5755162682436943950">ਸਾਈਨ-ਆਊਟ ਕੀਤਾ ਗਿਆ। ਇਸ ਬਟਨ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਾਲੀ ਵਿੰਡੋ ਖੁੱਲ੍ਹਦੀ ਹੈ ਅਤੇ ਸਿੰਕ ਚਾਲੂ ਹੁੰਦਾ ਹੈ।</translation>
 <translation id="5758631781033351321">ਤੁਹਾਨੂੰ ਆਪਣੀ ਪੜ੍ਹਨ-ਸੂਚੀ ਇੱਥੇ ਮਿਲੇਗੀ</translation>
+<translation id="5762370665605786758">ਪਾਸਫਰੇਜ਼ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ Google Pay ਦੀਆਂ ਭੁਗਤਾਨ ਵਿਧੀਆਂ ਅਤੇ ਪਤੇ ਸ਼ਾਮਲ ਨਹੀਂ ਹਨ।
+
+ਸਿਰਫ਼ ਤੁਹਾਡੇ ਪਾਸਫਰੇਜ਼ ਨਾਲ ਹੀ ਕੋਈ ਤੁਹਾਡੇ ਇਨਕ੍ਰਿਪਟਡ ਡਾਟੇ ਨੂੰ ਪੜ੍ਹ ਸਕਦਾ ਹੈ। ਪਾਸਫਰੇਜ਼ Google ਨੂੰ ਨਹੀਂ ਭੇਜਿਆ ਜਾਂਦਾ ਜਾਂ ਇਸ ਵੱਲੋਂ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ। ਜੇ ਤੁਸੀਂ ਆਪਣਾ ਪਾਸਫਰੇਜ਼ ਭੁੱਲ ਜਾਂਦੇ ਹੋ ਜਾਂ ਇਸ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ <ph name="BEGIN_LINK" />ਆਪਣੇ ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਕਲੀਅਰ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="5765456154762864099">ਮੀਨੂ → ਸੈਟਿੰਗਾਂ → ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਬ੍ਰਾਊਜ਼ਰ</translation>
 <translation id="5777888488419460501">ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੋ</translation>
 <translation id="5782227691023083829">ਅਨੁਵਾਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">ਪੰਨੇ ਦਾ <ph name="LANGUAGE" /> ਵਿੱਚ ਅਨੁਵਾਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ। ਵਿਕਲਪ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਪਾਸੇ ਉਪਲਬਧ ਹਨ।</translation>
 <translation id="648164694371393720">ਪ੍ਰਮਾਣੀਕਰਨ ਗੜਬੜ</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ਆਈਟਮਾਂ ਮਿਟਾਈਆਂ ਗਈਆਂ</translation>
+<translation id="6484712497741564393"><ph name="EMAIL" /> ਵਜੋਂ ਸਾਈਨ-ਇਨ ਕੀਤਾ ਗਿਆ।
+
+ਤੁਹਾਡਾ ਡਾਟਾ ਤੁਹਾਡੇ ਪਾਸਫਰੇਜ਼ ਨਾਲ ਇਨਕ੍ਰਿਪਟ ਕੀਤਾ ਗਿਆ ਹੈ। ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਵਰਤਣ ਅਤੇ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਇਸਨੂੰ ਦਾਖਲ ਕਰੋ।</translation>
 <translation id="6497772452874122664">ਜੇ ਤੁਹਾਨੂੰ <ph name="TIME" /> 'ਤੇ ਭਰੋਸਾ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਕਿਸੇ ਹੋਰ ਸਾਈਟ ਤੋਂ ਰੱਖਿਅਤ ਕੀਤਾ ਪਾਸਵਰਡ ਵਰਤ ਸਕਦੇ ਹੋ।
 
 ਹਰੇਕ ਸਾਈਟ ਲਈ ਇੱਕ ਵਿਲੱਖਣ ਪਾਸਵਰਡ ਵਰਤ ਕੇ ਦੇਖੋ।</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">ਪਾਸਵਰਡ ਨਿਰਯਾਤ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ</translation>
 <translation id="6732087373923685049">ਕੈਮਰਾ</translation>
 <translation id="6748108480210050150">ਤੋਂ</translation>
+<translation id="6753469262000681876">ਲਾਕਡਾਊਨ ਮੋਡ</translation>
 <translation id="6760509555861141183">ਹਾਲੀਆ ਟੈਬ 'ਤੇ ਵਾਪਸ ਜਾਓ</translation>
 <translation id="6762812039470893796">ਸਭ ਅਣ-ਚੁਣਿਆ ਕਰੋ</translation>
 <translation id="6780034285637185932">ਜ਼ਿਪ ਕੋਡ</translation>
@@ -1120,6 +1131,9 @@
 <translation id="8299417921174340354">ਪਾਸਵਰਡਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ ਆਪਣੇ ਡੀਵਾਈਸ 'ਤੇ ਪਾਸਕੋਡ ਸੈੱਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ।</translation>
 <translation id="8299613349954694191">ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਵੈੱਬ ਨੂੰ ਬ੍ਰਾਊਜ਼ ਕਰਨ ਲਈ ਇੱਕ ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲ੍ਹੋ।</translation>
 <translation id="8316944564970119719">ਸਾਈਟ ਅਤੇ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰ ਕੇ ਰੱਖਿਅਤ ਕਰੋ</translation>
+<translation id="8317835149433843300">Google Pay 'ਤੇ ਭੁਗਤਾਨ ਵਿਧੀਆਂ ਅਤੇ ਪਤਿਆਂ ਨੂੰ ਇਨਕ੍ਰਿਪਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ। Chrome ਦੇ ਬ੍ਰਾਊਜ਼ਿੰਗ ਇਤਿਹਾਸ ਤੁਹਾਡੇ Google ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ।
+
+ਸਿਰਫ਼ ਤੁਹਾਡੇ ਪਾਸਫਰੇਜ਼ ਨਾਲ ਹੀ ਕੋਈ ਤੁਹਾਡੇ ਇਨਕ੍ਰਿਪਟਡ ਡਾਟੇ ਨੂੰ ਪੜ੍ਹ ਸਕਦਾ ਹੈ। ਪਾਸਫਰੇਜ਼ Google ਨੂੰ ਨਹੀਂ ਭੇਜਿਆ ਜਾਂਦਾ ਜਾਂ ਇਸ ਵੱਲੋਂ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ। ਜੇ ਤੁਸੀਂ ਆਪਣਾ ਪਾਸਫਰੇਜ਼ ਭੁੱਲ ਜਾਂਦੇ ਹੋ ਜਾਂ ਇਸ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ <ph name="BEGIN_LINK" />ਆਪਣੇ ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਕਲੀਅਰ ਕਰੋ<ph name="END_LINK" />।</translation>
 <translation id="8319076807703933069">ਨਵੀਂ ਖੋਜ</translation>
 <translation id="8323906514956095947">ਹੋਰ ਟੈਬ ਵਿਕਲਪਾਂ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ</translation>
 <translation id="8328777765163860529">ਸਭ ਬੰਦ ਕਰੋ</translation>
@@ -1142,6 +1156,9 @@
 <translation id="8487700953926739672">ਆਫ਼ਲਾਈਨ ਉਪਲਬਧ</translation>
 <translation id="8488923644885757471">ਨਵੀਂ ਵਿੰਡੋ</translation>
 <translation id="8490978609246021741">ਤਬਦੀਲੀਆਂ ਰੱਖਿਅਤ ਕਰੋ</translation>
+<translation id="8491300088149538575"><ph name="EMAIL" /> ਵਜੋਂ ਸਾਈਨ-ਇਨ ਕੀਤਾ ਗਿਆ।
+
+ਤੁਹਾਡਾ ਡਾਟਾ ਤੁਹਾਡੇ ਪਾਸਫਰੇਜ਼ ਨਾਲ <ph name="TIME" /> ਨੂੰ ਇਨਕ੍ਰਿਪਟ ਕੀਤਾ ਗਿਆ ਸੀ। ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ Chrome ਡਾਟੇ ਨੂੰ ਵਰਤਣ ਅਤੇ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਇਸਨੂੰ ਦਾਖਲ ਕਰੋ।</translation>
 <translation id="8503813439785031346">ਵਰਤੋਂਕਾਰ ਨਾਮ</translation>
 <translation id="850600235656508448">ਇਨਕੋਗਨਿਟੋ ਵਿੱਚ ਖੋਲ੍ਹੋ</translation>
 <translation id="8517375800490286174">ਖੁੱਲ੍ਹਾ ਸਰੋਤ ਲਾਇਸੰਸ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb b/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
index 273c689..f97f885e 100644
--- a/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">Sempre traduzir do <ph name="LANGUAGE" /></translation>
 <translation id="110724200315609752">Mudar para janela aberta</translation>
 <translation id="1112015203684611006">Falha na impressão.</translation>
+<translation id="1113057722807951993">A criptografia por senha longa não inclui formas de pagamento e endereços do Google Pay.
+
+Para mudar essa configuração, <ph name="BEGIN_LINK" />limpe os dados do Chrome na sua conta<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">Criar nova guia</translation>
 <translation id="1126809382673880764">Não protege você contra sites, downloads e extensões perigosos. Você ainda terá a proteção do "Navegação segura", sempre que possível, em outros Serviços do Google, como o Gmail e a Pesquisa.</translation>
 <translation id="1145536944570833626">Excluir os dados atuais.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">Procurar</translation>
 <translation id="1990820278544963435">Buscar</translation>
 <translation id="199425419756152024">Ver senha</translation>
+<translation id="2008357574463816229">Se você esquecer a senha longa ou quiser mudar essa configuração, <ph name="BEGIN_LINK" />limpe os dados do Chrome na sua conta<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">Atualizar</translation>
 <translation id="2015722694326466240">Para ver as senhas, defina uma senha no dispositivo primeiro.</translation>
 <translation id="2021670401941426298">Veja as instruções do seu mecanismo de pesquisa para excluir o histórico de pesquisa, se aplicável.</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">Ir para a guia anterior</translation>
 <translation id="5755162682436943950">Conta desconectada. Abre a caixa de diálogo para fazer login e ativar a sincronização.</translation>
 <translation id="5758631781033351321">Você encontrará sua lista de leituras aqui</translation>
+<translation id="5762370665605786758">A criptografia por senha longa não inclui formas de pagamento e endereços do Google Pay.
+
+Só uma pessoa com sua senha longa poderá ler os dados criptografados. Essa senha não é enviada ao Google nem armazenada por ele. Se você esquecer a senha longa ou quiser mudar essa configuração, <ph name="BEGIN_LINK" />limpe os dados do Chrome na sua conta<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">Menu → Configurações → Navegador padrão</translation>
 <translation id="5777888488419460501">Salvar na conta</translation>
 <translation id="5782227691023083829">Traduzindo...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">Tradução da página para <ph name="LANGUAGE" />. Opções disponíveis na parte inferior da tela.</translation>
 <translation id="648164694371393720">Erro de autenticação</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> itens excluídos</translation>
+<translation id="6484712497741564393">Login feito como <ph name="EMAIL" />.
+
+Seus dados são criptografados com a senha longa. Digite-a para usar e salvar os dados do Chrome na sua Conta do Google.</translation>
 <translation id="6497772452874122664">Se você confia em <ph name="TIME" />, pode usar uma senha salva de outro site.
 
 Tente usar uma senha exclusiva para cada site.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">Não é possível exportar as senhas</translation>
 <translation id="6732087373923685049">câmera</translation>
 <translation id="6748108480210050150">De</translation>
+<translation id="6753469262000681876">Modo de bloqueio total</translation>
 <translation id="6760509555861141183">Voltar à guia recente</translation>
 <translation id="6762812039470893796">Desmarcar tudo</translation>
 <translation id="6780034285637185932">CEP</translation>
@@ -1120,6 +1131,9 @@
 <translation id="8299417921174340354">Para usar senhas, defina uma no dispositivo primeiro.</translation>
 <translation id="8299613349954694191">Abra uma guia anônima para navegar com privacidade.</translation>
 <translation id="8316944564970119719">Insira o site, a senha e clique em "Salvar"</translation>
+<translation id="8317835149433843300">As formas de pagamento e os endereços do Google Pay não serão criptografados. O histórico de navegação do Chrome não será salvo na sua Conta do Google.
+
+Só uma pessoa com sua senha longa poderá ler os dados criptografados. Essa senha não é enviada ao Google nem armazenada por ele. Se você esquecer a senha longa ou quiser mudar essa configuração, <ph name="BEGIN_LINK" />limpe os dados do Chrome na sua conta<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">Nova pesquisa</translation>
 <translation id="8323906514956095947">Toque no botão e mantenha-o pressionado para ver mais opções da guia</translation>
 <translation id="8328777765163860529">Fechar todos</translation>
@@ -1142,6 +1156,9 @@
 <translation id="8487700953926739672">Disponível off-line</translation>
 <translation id="8488923644885757471">Nova janela</translation>
 <translation id="8490978609246021741">Salvar alterações</translation>
+<translation id="8491300088149538575">Login feito como <ph name="EMAIL" />.
+
+Seus dados foram criptografados com a senha longa em <ph name="TIME" />. Digite-a para usar e salvar os dados do Chrome na sua Conta do Google.</translation>
 <translation id="8503813439785031346">Nome de usuário</translation>
 <translation id="850600235656508448">Abrir em modo de navegação anônima</translation>
 <translation id="8517375800490286174">Licenças de código aberto</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ro.xtb b/ios/chrome/app/strings/resources/ios_strings_ro.xtb
index dea1c70e..8680ac4 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ro.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ro.xtb
@@ -311,7 +311,7 @@
 <translation id="2975121486251958312">Este disponibil numai modul incognito</translation>
 <translation id="2982481275546140226">Șterge datele</translation>
 <translation id="298306318844797842">Adaugă o metodă de plată...</translation>
-<translation id="2989805286512600854">Deschideți într-o filă nouă</translation>
+<translation id="2989805286512600854">Deschide într-o filă nouă</translation>
 <translation id="3020183492814296499">Comenzi rapide</translation>
 <translation id="3037605927509011580">Of, nu mai merge!</translation>
 <translation id="3039722182465315531">Nu mă conectez</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_sk.xtb b/ios/chrome/app/strings/resources/ios_strings_sk.xtb
index c16ceda..f98b9a401 100644
--- a/ios/chrome/app/strings/resources/ios_strings_sk.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_sk.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">Vždy preložiť nasledujúci jazyk: <ph name="LANGUAGE" /></translation>
 <translation id="110724200315609752">Prepnúť na otvorené okno</translation>
 <translation id="1112015203684611006">Tlač zlyhala.</translation>
+<translation id="1113057722807951993">Šifrovanie pomocou prístupovej frázy nezahŕňa spôsoby platby ani adresy zo služby Google Pay.
+
+Ak chcete toto nastavenie zmeniť, <ph name="BEGIN_LINK" />vymažte údaje Chromu vo svojom účte<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">Vytvoriť novú kartu.</translation>
 <translation id="1126809382673880764">Nechráni vás pred nebezpečnými webmi, stiahnutými súbormi ani rozšíreniami. Ochrana Bezpečného prehliadania vám bude poskytovaná v náležitých prípadoch v ďalších službách Googlu, ako sú napríklad Gmail alebo Vyhľadávanie.</translation>
 <translation id="1145536944570833626">Odstrániť existujúce dáta.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">Prehliadať</translation>
 <translation id="1990820278544963435">Nájsť</translation>
 <translation id="199425419756152024">Zobraziť heslo</translation>
+<translation id="2008357574463816229">Ak prístupovú frázu zabudnete alebo budete chcieť toto nastavenie zmeniť, <ph name="BEGIN_LINK" />vymažte údaje Chromu vo svojom účte<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">Opätovné načítanie</translation>
 <translation id="2015722694326466240">Ak si chcete zobraziť heslá, najprv musíte v zariadení nastaviť vstupný kód.</translation>
 <translation id="2021670401941426298">Prečítajte si pokyny vyhľadávača, ako odstrániť históriu vyhľadávania (ak je to možné).</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">Prejsť na predchádzajúcu kartu</translation>
 <translation id="5755162682436943950">Účet je odhlásený. Otvorí dialógové okno, pomocou ktorého sa môžete prihlásiť a zapnúť synchronizáciu.</translation>
 <translation id="5758631781033351321">Tu nájdete svoj čitateľský zoznam</translation>
+<translation id="5762370665605786758">Šifrovanie pomocou prístupovej frázy nezahŕňa spôsoby platby ani adresy zo služby Google Pay.
+
+Šifrované údaje môže čítať iba používateľ s prístupovou frázou. Prístupová fráza sa do Googlu neodosiela a Google ju ani neukladá. Ak prístupovú frázu zabudnete alebo budete chcieť toto nastavenie zmeniť, <ph name="BEGIN_LINK" />vymažte údaje Chromu vo svojom účte<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">Ponuka → Nastavenia → Predvolený prehliadač</translation>
 <translation id="5777888488419460501">Uložiť do účtu</translation>
 <translation id="5782227691023083829">Prebieha preklad...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">Stránka sa prekladá do jazyka <ph name="LANGUAGE" />. Možnosti nájdete v dolnej časti obrazovky.</translation>
 <translation id="648164694371393720">Chyba overenia</translation>
 <translation id="6482629121755362506">Počet odstránených položiek: <ph name="NUMBER_OF_SELECTED_BOOKMARKS" /></translation>
+<translation id="6484712497741564393">Prihlásili ste sa ako <ph name="EMAIL" />.
+
+Údaje sú šifrované pomocou vašej prístupovej frázy. Zadajte ju, ak chcete používať a ukladať údaje Chromu do svojho účtu Google.</translation>
 <translation id="6497772452874122664">Ak webu <ph name="TIME" /> dôverujete, môžete použiť uložené heslo z iného webu.
 
 Pre každý web skúste použiť jedinečné heslo.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">Heslá sa nedajú exportovať</translation>
 <translation id="6732087373923685049">fotoaparát</translation>
 <translation id="6748108480210050150">Od</translation>
+<translation id="6753469262000681876">Režim silnej zámky</translation>
 <translation id="6760509555861141183">Návrat na poslednú kartu</translation>
 <translation id="6762812039470893796">Zrušiť výber všetkého</translation>
 <translation id="6780034285637185932">PSČ</translation>
@@ -1120,6 +1131,9 @@
 <translation id="8299417921174340354">Ak chcete používať heslá, najprv musíte v zariadení nastaviť vstupný kód.</translation>
 <translation id="8299613349954694191">Otvorte kartu inkognito a prehliadajte internet v súkromí.</translation>
 <translation id="8316944564970119719">Zadajte web a heslo a potom kliknite na Uložiť</translation>
+<translation id="8317835149433843300">Spôsoby platby a adresy v službe Google Pay nebudú šifrované. História prehliadania z Chromu sa nebude ukladať do účtu Google.
+
+Šifrované údaje môže čítať iba používateľ s prístupovou frázou. Prístupová fráza sa do Googlu neodosiela a Google ju ani neukladá. Ak prístupovú frázu zabudnete alebo budete chcieť toto nastavenie zmeniť, <ph name="BEGIN_LINK" />vymažte údaje Chromu vo svojom účte<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">Nové vyhľadávanie</translation>
 <translation id="8323906514956095947">Pridržaním zobrazíte ďalšie možnosti karty</translation>
 <translation id="8328777765163860529">Zavrieť všetky</translation>
@@ -1142,6 +1156,9 @@
 <translation id="8487700953926739672">K dispozícii offline</translation>
 <translation id="8488923644885757471">Nové okno</translation>
 <translation id="8490978609246021741">Uložiť zmeny</translation>
+<translation id="8491300088149538575">Prihlásili ste sa ako <ph name="EMAIL" />.
+
+Vaše údaje boli zašifrované pomocou prístupovej frázy <ph name="TIME" />. Zadajte ju, ak chcete používať a ukladať údaje Chromu do svojho účtu Google.</translation>
 <translation id="8503813439785031346">Meno používateľa</translation>
 <translation id="850600235656508448">Otvoriť v režime inkognito</translation>
 <translation id="8517375800490286174">Licencie open source</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_te.xtb b/ios/chrome/app/strings/resources/ios_strings_te.xtb
index 21185f7a..730fd3dcd 100644
--- a/ios/chrome/app/strings/resources/ios_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_te.xtb
@@ -1117,6 +1117,7 @@
 <translation id="8197543752516192074">పేజీని అనువదించు</translation>
 <translation id="8205564605687841303">రద్దు చేయండి</translation>
 <translation id="8206354486702514201">ఈ సెట్టింగ్ మీ నిర్వాహకుడి ద్వారా అమలు చేయబడింది.</translation>
+<translation id="8214293972734702249"><ph name="TAB_TITLE" />, పిన్ చేయబడింది</translation>
 <translation id="8225985093977202398">కాష్ చిత్రాలు, ఫైళ్లు</translation>
 <translation id="8237382152611443140">ఆటోఫిల్ పాస్‌వర్డ్ సెట్టింగ్‌లను తెరవండి</translation>
 <translation id="8248969482078657578">ఇన్‌యాక్టివ్ ట్యాబ్‌లు మీరు ఫోకస్ చేయడంలో సహాయపడతాయి</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ur.xtb b/ios/chrome/app/strings/resources/ios_strings_ur.xtb
index 61d95f5..fb3adfc 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ur.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ur.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314"><ph name="LANGUAGE" /> کو ہمیشہ ترجمہ کریں</translation>
 <translation id="110724200315609752">کھلی ہوئی ونڈو پر سوئچ کریں</translation>
 <translation id="1112015203684611006">پرنٹنگ ناکام۔</translation>
+<translation id="1113057722807951993">‏پاس فریز کی مرموز کاری میں Google Pay سے ادائیگی کے طریقے اور پتے شامل نہیں ہیں۔
+
+اس ترتیب کو تبدیل کرنے کے لیے، <ph name="BEGIN_LINK" />اپنے اکاؤنٹ میں موجود Chrome ڈیٹا کو صاف کریں<ph name="END_LINK" />۔</translation>
 <translation id="1125564390852150847">نیا ٹیب بنائیں۔</translation>
 <translation id="1126809382673880764">‏خطرناک ویب سائٹس، ڈاؤن لوڈز اور ایکسٹینشنز سے آپ کی حفاظت نہیں کرتی ہے۔ آپ کو اب بھی Gmail اور تلاش جیسی Google کی دیگر سروسز میں جہاں بھی دستیاب ہوگا محفوظ براؤزنگ کا تحفظ ملے گا۔</translation>
 <translation id="1145536944570833626">موجودہ ڈیٹا کو حذف کریں۔</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">براؤز کریں</translation>
 <translation id="1990820278544963435">تلاش کریں</translation>
 <translation id="199425419756152024">پاس ورڈ دیکھیں</translation>
+<translation id="2008357574463816229">‏اگر آپ اپنی پاس فریز بھول گئے ہیں یا اس ترتیب کو تبدیل کرنا چاہتے ہیں تو <ph name="BEGIN_LINK" />اپنے اکاؤنٹ میں موجود Chrome ڈیٹا کو صاف کریں<ph name="END_LINK" />۔</translation>
 <translation id="2010008505735295285">دوبارہ لوڈ کریں</translation>
 <translation id="2015722694326466240">پاسورڈز دیکھنے کے لیے، آپ کو اپنے آلے پر پہلے پاس کوڈ سیٹ کرنا چاہئے۔</translation>
 <translation id="2021670401941426298">اگر قابل اطلاق ہو تو اپنی تلاش کی سرگزشت کو حذف کرنے کے لیے اپنے سرچ انجن کی ہدایات دیکھیں۔</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">پچھلے ٹیب پر جائیں</translation>
 <translation id="5755162682436943950">سائن آؤٹ ہوگئے۔ سائن ان کرنے اور مطابقت پذیری کو آن کرنے کے لیے ڈائیلاگ کھولتا ہے۔</translation>
 <translation id="5758631781033351321">آپ اپنی پڑھنے کی فہرست یہاں پائیں گے</translation>
+<translation id="5762370665605786758">‏پاس فریز کی مرموز کاری میں Google Pay سے ادائیگی کے طریقے اور پتے شامل نہیں ہیں۔
+
+صرف وہ شخص جس کے پاس آپ کی پاس فریز ہے آپ کے مرموز کردہ ڈیٹا کو پڑھ سکتا ہے۔ پاس فریز Google کو نہیں بھیجی جاتی ہے اور نہ ہی اس کے ذریعے اسٹور کی جاتی ہے۔ اگر آپ اپنی پاس فریز بھول گئے ہیں یا اس ترتیب کو تبدیل کرنا چاہتے ہیں تو <ph name="BEGIN_LINK" />اپنے اکاؤنٹ میں موجود Chrome ڈیٹا کو صاف کریں<ph name="END_LINK" />۔</translation>
 <translation id="5765456154762864099">مینیو ← ترتیبات ← ڈیفالٹ براؤزر</translation>
 <translation id="5777888488419460501">اکاؤنٹ میں محفوظ کریں</translation>
 <translation id="5782227691023083829">ترجمہ کیا جا رہا ہے...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">صفحہ کا <ph name="LANGUAGE" /> میں ترجمہ کیا جا رہا ہے۔ اسکرین کے نچلے حصے کے قریب اختیارات دستیاب ہیں۔</translation>
 <translation id="648164694371393720">توثیق کی خرابی</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> آئٹم کو حذف کر دیا گیا</translation>
+<translation id="6484712497741564393">‏<ph name="EMAIL" /> کے بطور سائن ان کردہ۔
+
+آپ کا ڈیٹا آپ کی پاس فریز کے ساتھ مرموز کردہ ہے۔ اپنے Google اکاؤنٹ میں Chrome ڈیٹا کو استعمال کرنے اور محفوظ کرنے کے لیے اسے درج کریں۔</translation>
 <translation id="6497772452874122664">اگر آپ کو <ph name="TIME" /> پر اعتماد ہے تو آپ کسی اور سائٹ سے محفوظ کردہ پاس ورڈ استعمال کر سکتے ہیں۔
 
 ہر سائٹ کے لئے ایک منفرد پاس ورڈ استعمال کرنے کی کوشش کریں۔</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">پاسورڈز برآمد نہیں ہو سکے</translation>
 <translation id="6732087373923685049">کیمرا</translation>
 <translation id="6748108480210050150">منجانب</translation>
+<translation id="6753469262000681876">لاک ڈاؤن وضع</translation>
 <translation id="6760509555861141183">حالیہ ٹیب میں واپس جائیں</translation>
 <translation id="6762812039470893796">سبھی غیر منتخب کریں</translation>
 <translation id="6780034285637185932">زپ کوڈ</translation>
@@ -1121,6 +1132,9 @@
 <translation id="8299417921174340354">پاس ورڈز استعمال کرنے کے ليے، آپ کو اپنے آلے پر پہلے پاس کوڈ سیٹ کرنا ہوگا۔</translation>
 <translation id="8299613349954694191">ویب کو نجی طور پر براؤز کرنے کے لیے ایک پوشیدگی ٹیب کھولیں۔</translation>
 <translation id="8316944564970119719">سائٹ اور پاس ورڈ درج کریں، پھر محفوظ کریں</translation>
+<translation id="8317835149433843300">‏Google Pay سے ادائیگی کے طریقے اور پتے مرموز نہیں ہوں گے۔ Chrome سے براؤزنگ کی سرگزشت آپ کے Google اکاؤنٹ میں محفوظ نہیں ہوگی۔
+
+صرف وہ شخص جس کے پاس آپ کی پاس فریز ہے آپ کے مرموز کردہ ڈیٹا کو پڑھ سکتا ہے۔ پاس فریز Google کو نہیں بھیجی جاتی ہے اور نہ ہی اس کے ذریعے اسٹور کی جاتی ہے۔ اگر آپ اپنی پاس فریز بھول گئے ہیں یا اس ترتیب کو تبدیل کرنا چاہتے ہیں تو <ph name="BEGIN_LINK" />اپنے اکاؤنٹ میں موجود Chrome ڈیٹا کو صاف کریں<ph name="END_LINK" />۔</translation>
 <translation id="8319076807703933069">نئی تلاش</translation>
 <translation id="8323906514956095947">ٹیب کے مزید اختیارات کیلئے ٹچ کریں اور دبائے رکھیں</translation>
 <translation id="8328777765163860529">تمام بند کریں</translation>
@@ -1143,6 +1157,9 @@
 <translation id="8487700953926739672">آف لائن دستیاب ہے</translation>
 <translation id="8488923644885757471">نئی ونڈو</translation>
 <translation id="8490978609246021741">تبدیلیاں محفوظ کریں</translation>
+<translation id="8491300088149538575">‏<ph name="EMAIL" /> کے بطور سائن ان کردہ۔
+
+آپ کا ڈیٹا آپ کی پاس فریز کے ساتھ <ph name="TIME" /> کو مرموز کیا گیا تھا۔ اپنے Google اکاؤنٹ میں Chrome ڈیٹا کو استعمال کرنے اور محفوظ کرنے کے لیے اسے درج کریں۔</translation>
 <translation id="8503813439785031346">صارف کا نام</translation>
 <translation id="850600235656508448">پوشیدگی وضع میں کھولیں</translation>
 <translation id="8517375800490286174">اوپن سورس لائسنسز</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_uz.xtb b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
index c99e22f..7bdca6443 100644
--- a/ios/chrome/app/strings/resources/ios_strings_uz.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314"><ph name="LANGUAGE" /> tilidan har doim tarjima qilinsin</translation>
 <translation id="110724200315609752">Yopilmagan oynalarga oʻtish</translation>
 <translation id="1112015203684611006">Chop etilmadi.</translation>
+<translation id="1113057722807951993">Kodli ibora bilan shifrlash ichiga Google Pay xizmatidagi toʻlov usullari va manzillar kirmaydi.
+
+Bu sozlamani oʻzgartirish uchun <ph name="BEGIN_LINK" />hisobingizda Chrome maʼlumotlarini tozalang<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">Yangi sahifa ochish</translation>
 <translation id="1126809382673880764">Zararli sayt, yuklanma va kengaytmalardan himoya qila olmaydi. Gmail va Qidiruv kabi Google xizmatlarida Saytlarni xavfsiz kezish himoyasi ostida boʻlasiz.</translation>
 <translation id="1145536944570833626">Mavjud ma’lumotlarni o‘chirish.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">Tanlash</translation>
 <translation id="1990820278544963435">Qidirish</translation>
 <translation id="199425419756152024">Parolni koʻrish</translation>
+<translation id="2008357574463816229">Agar kodli iborani unutsangiz yoki bu sozlamani oʻzgartirmoqchi boʻlsangiz, <ph name="BEGIN_LINK" />hisobingizda Chrome maʼlumotlarini tozalang<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">Qayta yuklash</translation>
 <translation id="2015722694326466240">Parollarni ko‘rish uchun qurilmangizni maxfiy kod bilan qulflang.</translation>
 <translation id="2021670401941426298">Imkon boʻlsa, qidiruv tarixini qanday tozalash haqidagi qidiruv tizimi koʻrsatmalarini oching.</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">Avvalgi varaqni ochish</translation>
 <translation id="5755162682436943950">Hisobdan chiqqansiz. Kirish va sinxronlashni yoqish uchun oynani ochadi.</translation>
 <translation id="5758631781033351321">Brauzer mutolaa roʻyxati shu yerda chiqadi</translation>
+<translation id="5762370665605786758">Kodli ibora bilan shifrlash ichiga Google Pay xizmatidagi toʻlov usullari va manzillar kirmaydi.
+
+Shifrlangan maʼlumotlarni faqatgina kodli ibora yordamida oʻqish mumkin. Kodli ibora ulashilmaydi va Google serverlarida saqlanmaydi. Agar kodli iborani unutsangiz yoki bu sozlamani oʻzgartirmoqchi boʻlsangiz, <ph name="BEGIN_LINK" />hisobingizda Chrome maʼlumotlarini tozalang<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">Menyu → Sozlamalar → Standart brauzer</translation>
 <translation id="5777888488419460501">Hisobda saqlash</translation>
 <translation id="5782227691023083829">Tarjima qilinmoqda...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">Sahifa <ph name="LANGUAGE" /> tiliga tarjima qilinmoqda. Parametrlar ekranning pastiga yaqin joyda joylashgan.</translation>
 <translation id="648164694371393720">Autentifikatsiya xatosi</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> ta xatcho‘p o‘chirildi</translation>
+<translation id="6484712497741564393"><ph name="EMAIL" /> hisobi bilan kirgansiz.
+
+Maʼlumotlaringiz kodli ibora bilan shifrlangan. Chrome maʼlumotlarini Google hisobingizda saqlash va ulardan foydalanish uchun uni kiriting.</translation>
 <translation id="6497772452874122664"><ph name="TIME" /> saytiga ishonsangiz, saqlangan parolingizni boshqa saytda ishlatishingiz mumkin.
 
 Har bir sayt uchun alohida parol ishlating.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">Parollar eksport qilinmadi</translation>
 <translation id="6732087373923685049">kamera</translation>
 <translation id="6748108480210050150">Kimdan:</translation>
+<translation id="6753469262000681876">Lokdaun rejimi</translation>
 <translation id="6760509555861141183">Oxirgi varaqqa qaytish</translation>
 <translation id="6762812039470893796">Tanlovni bekor qilish</translation>
 <translation id="6780034285637185932">Pochta indeksi</translation>
@@ -1106,6 +1117,7 @@
 <translation id="8197543752516192074">Sahifani tarjima qilish</translation>
 <translation id="8205564605687841303">Bekor qilish</translation>
 <translation id="8206354486702514201">Bu parametr administrator tomonidan yoqilgan.</translation>
+<translation id="8214293972734702249">Mahkamlangan, <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">Keshdagi tasvir va fayllar</translation>
 <translation id="8237382152611443140">Parollarni avtomatik kiritish sozlamalarini oching</translation>
 <translation id="8248969482078657578">Nofaol varaqlar tufayli diqqatni jamlaysiz</translation>
@@ -1120,6 +1132,9 @@
 <translation id="8299417921174340354">Parollarni ishlatish uchun qurilmangizni maxfiy kod bilan qulflang.</translation>
 <translation id="8299613349954694191">Brauzer tarixi saqlanmasligi uchun inkognito tab oching.</translation>
 <translation id="8316944564970119719">Sayt va parolni kiritib, keyin Saqlang</translation>
+<translation id="8317835149433843300">Google Pay xizmatidagi toʻlov usullari va manzillar shifrlanmaydi. Chrome brauzerida ochilgan veb-sahifalar tarixi Google hisobingizda saqlanmaydi.
+
+Shifrlangan maʼlumotlarni faqatgina kodli ibora yordamida oʻqish mumkin. Kodli ibora ulashilmaydi va Google serverlarida saqlanmaydi. Agar kodli iborani unutsangiz yoki bu sozlamani oʻzgartirmoqchi boʻlsangiz, <ph name="BEGIN_LINK" />hisobingizda Chrome maʼlumotlarini tozalang<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">Yangi qidiruv</translation>
 <translation id="8323906514956095947">Varaqqa oid boshqa amallar uchun bosib turing</translation>
 <translation id="8328777765163860529">Hammasini yopish</translation>
@@ -1142,6 +1157,9 @@
 <translation id="8487700953926739672">Internetsiz foydalanish mumkin</translation>
 <translation id="8488923644885757471">Yangi oyna</translation>
 <translation id="8490978609246021741">Oʻzgarishlarni saqlash</translation>
+<translation id="8491300088149538575"><ph name="EMAIL" /> hisobi bilan kirgansiz.
+
+Maʼlumotlaringiz <ph name="TIME" /> sanasida kodli ibora bilan shifrlangan. Chrome maʼlumotlarini Google hisobingizda saqlash va ulardan foydalanish uchun uni kiriting.</translation>
 <translation id="8503813439785031346">Foydalanuvchi nomi</translation>
 <translation id="850600235656508448">Inkognito rejimida ochish</translation>
 <translation id="8517375800490286174">Ochiq kodli DT litsenziyalari</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_vi.xtb b/ios/chrome/app/strings/resources/ios_strings_vi.xtb
index 9ab734d..a180fd3 100644
--- a/ios/chrome/app/strings/resources/ios_strings_vi.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_vi.xtb
@@ -1243,7 +1243,7 @@
 <translation id="9098541895599151034">Xoá <ph name="NUMBER_OF_ACCOUNTS" /> mật khẩu?</translation>
 <translation id="9100610230175265781">Yêu cầu cụm mật khẩu</translation>
 <translation id="9107664647686727385">Kiểm tra để tìm mật khẩu bị lộ</translation>
-<translation id="9120217828624527905">Chuyển sang Dịch toàn bộ trang</translation>
+<translation id="9120217828624527905">Chuyển sang chế độ Dịch toàn bộ trang</translation>
 <translation id="9124387962554796433">Google có thể sử dụng nhật ký hoạt động của bạn để điều chỉnh tính năng Tìm kiếm và các dịch vụ khác của Google cho phù hợp hơn với bạn.</translation>
 <translation id="9137526406337347448">Dịch vụ của Google</translation>
 <translation id="9148126808321036104">Đăng nhập lại</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zu.xtb b/ios/chrome/app/strings/resources/ios_strings_zu.xtb
index 6afbdfe..e454847 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zu.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zu.xtb
@@ -21,6 +21,9 @@
 <translation id="1103523840287552314">Humusha njalo i-<ph name="LANGUAGE" /></translation>
 <translation id="110724200315609752">Shintshela Kuwindi Elivuliwe</translation>
 <translation id="1112015203684611006">Ukuphrinta kwehlulekile.</translation>
+<translation id="1113057722807951993">Ukubethelwa komushwana wokungena akubandakanyi izindlela zokukhokha namakheli kusuka ku-Google Pay.
+
+Ukuze ushintshel lawa masethingi, <ph name="BEGIN_LINK" />sula idatha yakho ye-Chrome ku-akhawunti yakho<ph name="END_LINK" />.</translation>
 <translation id="1125564390852150847">Dala ithebhu entsha</translation>
 <translation id="1126809382673880764">Akukuvikeli kumawebusayithi ayingozi, okulandwayo, kanye nezandiso. Usazokuthola ukuvikelwa kokuphequlula okuphephile, lapho kutholakala, kwamanye amasevisi we-Google, njenge-Gmail. nokuSesha.</translation>
 <translation id="1145536944570833626">Susa idatha ekhona.</translation>
@@ -158,6 +161,7 @@
 <translation id="1989112275319619282">Dlulisa amehlo</translation>
 <translation id="1990820278544963435">Thola</translation>
 <translation id="199425419756152024">Buka iphasiwedi</translation>
+<translation id="2008357574463816229">Uma ukhohlwa umushwana wakho wokungena noma ufuna ukushintsha leli sethingi, <ph name="BEGIN_LINK" />sula idatha ye-Chrome ku-akhawunti yakho<ph name="END_LINK" />.</translation>
 <translation id="2010008505735295285">Layisha kabusha</translation>
 <translation id="2015722694326466240">Ukuze ubone amaphasiwedi, kufanele uqale ngokusetha ikhodi yokudlula kudivayisi yakho.</translation>
 <translation id="2021670401941426298">Bona imiyalelo yenjini yakho yokusesha yokusula umlando wakho wosesho, uma kusebenza.</translation>
@@ -707,6 +711,9 @@
 <translation id="5745916533876677730">Iya Kuthebhu Yangaphambilini</translation>
 <translation id="5755162682436943950">Uphume ngemvume. Ivula ibhokisi ukuze ungene ngemvume futhi uvule ukuvumelanisa.</translation>
 <translation id="5758631781033351321">Uzothola uhlu lwakho lokufunda lapha</translation>
+<translation id="5762370665605786758">Ukubethelwa komushwana wokungena akubandakanyi izindlela zokukhokha namakheli kusuka ku-Google Pay.
+
+Kuphela othile onomushwana wokungena ongafunda idatha yakho ebethelwe. Umshwana wokungena awuthunyelwa noma ulondolozwe i-Google. Uma ukhohlwa umushwana wakho wokungena noma ufuna ukushintsha leli sethingi, <ph name="BEGIN_LINK" />sula idatha ye-Chrome ku-akhawunti yakho<ph name="END_LINK" />.</translation>
 <translation id="5765456154762864099">Imeny → Amasethingi → Ibhrawuza Ezenzakalelayo</translation>
 <translation id="5777888488419460501">Londoloza ku-akhawunti</translation>
 <translation id="5782227691023083829">Iyahumusha...</translation>
@@ -848,6 +855,9 @@
 <translation id="6476800141292307438">Ukuhumushela ikhasi kusi-<ph name="LANGUAGE" />. Izinketho ziyatholakala eduzane naphansi kwesikrini.</translation>
 <translation id="648164694371393720">Iphutha lokufakazela ubuqiniso</translation>
 <translation id="6482629121755362506"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> izinto zisusiwe</translation>
+<translation id="6484712497741564393">Ungene ngemvume njengo-<ph name="EMAIL" />.
+
+Idatha yakho ibethelwe ngomushwana wokungena. Ifake ukuze usebenzise futhi wonge idatha ye-Chrome ku-akhawunti yakho ye-Google.</translation>
 <translation id="6497772452874122664">Uma wethemba i-<ph name="TIME" />, ungase usebenzise iphasiwedi elondoloziwe kusuka kwelinye isayithi.
 
 Zama ukusebenzisa iphasiwedi eyingqayizivele kusayithi ngayinye.</translation>
@@ -894,6 +904,7 @@
 <translation id="6730682669179532099">Ayikwazi ukuthumela amaphasiwedi</translation>
 <translation id="6732087373923685049">ikhamera</translation>
 <translation id="6748108480210050150">Kusuka ku-</translation>
+<translation id="6753469262000681876">Imodi Yokukhiya</translation>
 <translation id="6760509555861141183">Buyela Kuthebhu Yakamuva</translation>
 <translation id="6762812039470893796">Ungakhethi konke</translation>
 <translation id="6780034285637185932">Ikhodi ye-Zip</translation>
@@ -1106,6 +1117,7 @@
 <translation id="8197543752516192074">Humusha ikhasi</translation>
 <translation id="8205564605687841303">Khansela</translation>
 <translation id="8206354486702514201">Lokhu kulungiselelwa kusetshenziswa umlawuli wakho.</translation>
+<translation id="8214293972734702249">Kuphiniwe, <ph name="TAB_TITLE" /></translation>
 <translation id="8225985093977202398">Izithombe ezifakwe kunqolobane namafayela</translation>
 <translation id="8237382152611443140">Vula Amasethingi Wokugcwalisa Iphasiwedi Okuzenzakalelayo</translation>
 <translation id="8248969482078657578">Amathebhu Angasebenzi Akusiza Ukuthi Uhlale Ugxilile</translation>
@@ -1120,6 +1132,9 @@
 <translation id="8299417921174340354">Ukuze usebenzise amaphasiwedi, kuzomele uqale usethe ikhodi yokudlula kudivayisi yakho.</translation>
 <translation id="8299613349954694191">Vula i ithebhu ye-incognito ukuze uphequlule iwebhu ngokuyimfihlo.</translation>
 <translation id="8316944564970119719">Faka Isayithi Nephasiwedi, Bese Uyalondoloza</translation>
+<translation id="8317835149433843300">Izindlela zokukhokha namakheli kusuka ku-Google Pay ngeke kubethelwe. Ukuphequlula umlando kusuka ku-Chrome ngeke kulondolozwe ku-akhawunti yakho ye-Google.
+
+Kuphela othile onomushwana wokungena ongafunda idatha yakho ebethelwe. Umshwana wokungena awuthunyelwa noma ulondolozwe i-Google. Uma ukhohlwa umushwana wakho wokungena noma ufuna ukushintsha leli sethingi, <ph name="BEGIN_LINK" />sula idatha ye-Chrome ku-akhawunti yakho<ph name="END_LINK" />.</translation>
 <translation id="8319076807703933069">Ukusesha okusha</translation>
 <translation id="8323906514956095947">Thinta uphinde ubambe ukuze uthole okunye okungakhethwa zethebhu</translation>
 <translation id="8328777765163860529">Vala konke</translation>
@@ -1142,6 +1157,9 @@
 <translation id="8487700953926739672">Itholakala kokungaxhunyiwe ku-inthanethi</translation>
 <translation id="8488923644885757471">Iwindi Elisha</translation>
 <translation id="8490978609246021741">Londoloza izinguquko</translation>
+<translation id="8491300088149538575">Ungene ngemvume njengo-<ph name="EMAIL" />.
+
+Idatha yakho ibethelwe ngomushwana wakho wokungena ngo-<ph name="TIME" />. Ifake ukuze usebenzise futhi wonge idatha ye-Chrome ku-akhawunti yakho ye-Google.</translation>
 <translation id="8503813439785031346">Igama lomsebenzisi</translation>
 <translation id="850600235656508448">Vula ku-incognito</translation>
 <translation id="8517375800490286174">Amalayisense womthombo ovulekile</translation>
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index f22edcce..572eb4c 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -86,7 +86,6 @@
     "//base",
     "//components/autofill/core/browser",
     "//components/autofill/ios/browser",
-    "//ios/chrome/browser/autofill/bottom_sheet",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/web/public",
     "//ios/web/public/js_messaging",
diff --git a/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
index 85b1003..7cd66778 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
+++ b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
@@ -15,7 +15,6 @@
   deps = [
     ":bottom_sheet_ts",
     "//base",
-    "//components/autofill/core/browser",
     "//components/autofill/core/common",
     "//components/autofill/ios/form_util",
     "//components/password_manager/core/common:features",
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h
index 36d282e..92ce0b1 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h
@@ -26,11 +26,6 @@
   // the field that had originally triggered the bottom sheet.
   void DetachListenersAndRefocus(web::WebFrame* frame);
 
-  // This function will result in detaching listeners from the username
-  // and password fields, which will prevent the bottom sheet from showing
-  // up until the form reloads.
-  void DetachListeners(web::WebFrame* frame);
-
  private:
   friend class base::NoDestructor<BottomSheetJavaScriptFeature>;
 
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
index 1244080..1b36274 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
@@ -65,7 +65,3 @@
     web::WebFrame* frame) {
   CallJavaScriptFunction(frame, "bottomSheet.detachListenersAndRefocus", {});
 }
-
-void BottomSheetJavaScriptFeature::DetachListeners(web::WebFrame* frame) {
-  CallJavaScriptFunction(frame, "bottomSheet.detachListeners", {});
-}
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
index f05b152..9b94e53d 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
@@ -5,9 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
 #define IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
 
-#import "components/autofill/core/browser/ui/popup_types.h"
 #import "components/autofill/core/common/unique_ids.h"
-#import "ios/web/public/web_state_observer.h"
 #import "ios/web/public/web_state_user_data.h"
 
 namespace web {
@@ -21,8 +19,7 @@
 
 // TODO(crbug.com/1422361): Rename this class to include the notion of autofill.
 class BottomSheetTabHelper
-    : public web::WebStateObserver,
-      public web::WebStateUserData<BottomSheetTabHelper> {
+    : public web::WebStateUserData<BottomSheetTabHelper> {
  public:
   BottomSheetTabHelper(const BottomSheetTabHelper&) = delete;
   BottomSheetTabHelper& operator=(const BottomSheetTabHelper&) = delete;
@@ -48,17 +45,6 @@
   // Detach the listeners, which will deactivate the bottom sheet.
   void DetachListenersAndRefocus(web::WebFrame* frame);
 
-  // Notification that the keyboard accessory will be shown with a specific type
-  // of suggestions. May be called multiple times before showing the keyboard
-  // accessory.
-  void WillShowKeyboardAccessory(autofill::PopupType suggestionType,
-                                 web::WebFrame* frame);
-
-  // WebStateObserver:
-  void DidFinishNavigation(web::WebState* web_state,
-                           web::NavigationContext* navigation_context) override;
-  void WebStateDestroyed(web::WebState* web_state) override;
-
  private:
   friend class web::WebStateUserData<BottomSheetTabHelper>;
 
@@ -83,11 +69,6 @@
   // The WebState with which this object is associated.
   web::WebState* const web_state_;
 
-  // Whether the bottom sheet is currently enabled. This prevents receiving
-  // async messages or commands to attach listeners once any request to disable
-  // the bottom sheet has been made.
-  bool enabled_;
-
   WEB_STATE_USER_DATA_KEY_DECL();
 };
 
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
index dc9c030..bf3fba5c 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
@@ -30,10 +30,7 @@
         password_account_storage_notice_handler)
     : password_account_storage_notice_handler_(
           password_account_storage_notice_handler),
-      web_state_(web_state),
-      enabled_(true) {
-  web_state->AddObserver(this);
-}
+      web_state_(web_state) {}
 
 // Public methods
 
@@ -52,7 +49,7 @@
 void BottomSheetTabHelper::OnFormMessageReceived(
     const web::ScriptMessage& message) {
   autofill::FormActivityParams params;
-  if (!enabled_ || !password_bottom_sheet_commands_handler_ ||
+  if (!password_bottom_sheet_commands_handler_ ||
       !password_account_storage_notice_handler_ ||
       !autofill::FormActivityParams::FromMessage(message, &params)) {
     return;
@@ -78,8 +75,7 @@
     web::WebFrame* frame) {
   // Verify that the password bottom sheet feature is enabled and that it hasn't
   // been dismissed too many times.
-  if (!enabled_ ||
-      !base::FeatureList::IsEnabled(
+  if (!base::FeatureList::IsEnabled(
           password_manager::features::kIOSPasswordBottomSheet) ||
       HasReachedDismissLimit()) {
     return;
@@ -91,43 +87,9 @@
 }
 
 void BottomSheetTabHelper::DetachListenersAndRefocus(web::WebFrame* frame) {
-  if (!enabled_) {
-    return;
-  }
-
-  enabled_ = false;
   BottomSheetJavaScriptFeature::GetInstance()->DetachListenersAndRefocus(frame);
 }
 
-void BottomSheetTabHelper::WillShowKeyboardAccessory(
-    autofill::PopupType suggestionType,
-    web::WebFrame* frame) {
-  // If the keyboard accessory is being shown with a specific type of suggestion
-  // for which a bottom sheet exists, disable that bottom sheet in order to
-  // provide a consistent experience for the user.
-  if (enabled_ && (suggestionType == autofill::PopupType::kPasswords)) {
-    enabled_ = false;
-    BottomSheetJavaScriptFeature::GetInstance()->DetachListeners(frame);
-  }
-}
-
-// WebStateObserver
-
-void BottomSheetTabHelper::DidFinishNavigation(
-    web::WebState* web_state,
-    web::NavigationContext* navigation_context) {
-  if (navigation_context->IsSameDocument()) {
-    return;
-  }
-
-  // Re-enable the bottom sheet when loading a new page
-  enabled_ = true;
-}
-
-void BottomSheetTabHelper::WebStateDestroyed(web::WebState* web_state) {
-  web_state->RemoveObserver(this);
-}
-
 // Private methods
 
 bool BottomSheetTabHelper::HasReachedDismissLimit() {
diff --git a/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts b/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts
index 23c0af01..adc7794 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts
+++ b/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts
@@ -14,13 +14,52 @@
 /**
  * The last HTML element that was blurred.
  */
-let lastBlurredElement_: HTMLElement|null;
+let lastBlurredElement_: HTMLElement|null = null;
 
 /**
  * The list of observed elements.
  */
 let observedElements_: Element[] = [];
 
+/*
+ * Prepare and send message to show bottom sheet.
+ * @private
+ */
+function showBottomSheet_(hasUserGesture: boolean): void {
+  let field = null;
+  let fieldType = '';
+  let fieldValue = '';
+  let form = null;
+
+  if (lastBlurredElement_ instanceof HTMLInputElement) {
+    field = lastBlurredElement_;
+    fieldType = lastBlurredElement_.type;
+    fieldValue = lastBlurredElement_.value;
+    form = lastBlurredElement_.form;
+  } else if (lastBlurredElement_ instanceof HTMLFormElement) {
+    form = lastBlurredElement_;
+  }
+
+  // TODO(crbug.com/1427221): convert these "gCrWeb.fill" and "gCrWeb.form"
+  // calls to import and call the functions directly once the conversion to
+  // TypeScript is done.
+  gCrWeb.fill.setUniqueIDIfNeeded(field);
+  gCrWeb.fill.setUniqueIDIfNeeded(form);
+
+  const msg = {
+    'frameID': gCrWeb.message.getFrameId(),
+    'formName': gCrWeb.form.getFormIdentifier(form),
+    'uniqueFormID': gCrWeb.fill.getUniqueID(form),
+    'fieldIdentifier': gCrWeb.form.getFieldIdentifier(field),
+    'uniqueFieldID': gCrWeb.fill.getUniqueID(field),
+    'fieldType': fieldType,
+    'type': 'focus',
+    'value': fieldValue,
+    'hasUserGesture': hasUserGesture,
+  };
+  sendWebKitMessage('BottomSheetMessage', msg);
+}
+
 /**
  * Focus events for observed input elements are messaged to the main
  * application for broadcast to WebStateObservers.
@@ -36,54 +75,25 @@
   event.target.blur();
   lastBlurredElement_ = event.target;
 
-  let field = null;
-  let fieldType = '';
-  let fieldValue = '';
-  let form = null;
-
-  if (event.target instanceof HTMLInputElement) {
-    field = event.target;
-    fieldType = event.target.type;
-    fieldValue = event.target.value;
-    form = event.target.form;
-  } else if (event.target instanceof HTMLFormElement) {
-    form = event.target;
-  }
-
-  // TODO(crbug.com/1427221): convert these "gCrWeb.fill" and "gCrWeb.form"
-  // calls to import and call the functions directly once the conversion to
-  // TypeScript is done.
-  gCrWeb.fill.setUniqueIDIfNeeded(field);
-  gCrWeb.fill.setUniqueIDIfNeeded(form);
-
-  const msg = {
-    'frameID': gCrWeb.message.getFrameId(),
-    'formName': gCrWeb.form.getFormIdentifier(form),
-    'uniqueFormID': gCrWeb.fill.getUniqueID(form),
-    'fieldIdentifier': gCrWeb.form.getFieldIdentifier(field),
-    'uniqueFieldID': gCrWeb.fill.getUniqueID(field),
-    'fieldType': fieldType,
-    'type': event.type,
-    'value': fieldValue,
-    'hasUserGesture': event.isTrusted,
-  };
-  sendWebKitMessage('BottomSheetMessage', msg);
+  showBottomSheet_(event.isTrusted);
 }
 
 /**
  * Attach event listeners for relevant elements on the focus event.
  * @private
  */
-function attachListeners_(): void {
-  for (const element of observedElements_) {
+function doAttachListeners_(elementsToObserve: Element[]): void {
+  for (const element of elementsToObserve) {
     element.addEventListener('focus', focusEventHandler_, true);
+    observedElements_.push(element);
   }
 }
 
 /**
  * Removes all listeners and clears the list of observed elements
+ * @private
  */
-function detachListeners(): void {
+function detachListeners_(): void {
   for (const element of observedElements_) {
     element.removeEventListener('focus', focusEventHandler_, true);
   }
@@ -96,15 +106,36 @@
  */
 function attachListeners(renderer_ids: number[]): void {
   // Build list of elements
+  let blurredElement: HTMLElement|null = null;
+  let elementsToObserve: Element[] = [];
   for (const renderer_id of renderer_ids) {
     const element = gCrWeb.fill.getElementByUniqueID(renderer_id);
-    if (element) {
-      observedElements_.push(element);
+    // Only add element to list of observed elements if we aren't already
+    // observing it.
+    if (element && !observedElements_.find(elem => elem === element)) {
+      elementsToObserve.push(element);
+      if (document.activeElement === element) {
+        if (element.value != '') {
+          // The user has already started filling the active field, so bail out
+          // without attaching listeners.
+          return;
+        }
+        // Remove the focus on an element if it already has focus and we want to
+        // listen for the focus event on it.
+        element.blur();
+        blurredElement = element;
+      }
     }
   }
 
   // Attach the listeners once the IDs are set.
-  attachListeners_();
+  doAttachListeners_(elementsToObserve);
+
+  // Restore focus if it was removed.
+  if (blurredElement) {
+    lastBlurredElement_ = blurredElement;
+    showBottomSheet_(/*hasUserGesture=*/ false);
+  }
 }
 
 /**
@@ -114,7 +145,7 @@
 function detachListenersAndRefocus(): void {
   // If the form was dismissed, we don't need to show it anymore on this page,
   // so remove the event listeners.
-  detachListeners();
+  detachListeners_();
 
   // Re-focus the previously blurred element
   if (lastBlurredElement_) {
@@ -124,6 +155,5 @@
 
 gCrWeb.bottomSheet = {
   attachListeners,
-  detachListenersAndRefocus,
-  detachListeners
+  detachListenersAndRefocus
 };
diff --git a/ios/chrome/browser/autofill/form_input_accessory_view_handler.h b/ios/chrome/browser/autofill/form_input_accessory_view_handler.h
index b240b52c..d8e0e404 100644
--- a/ios/chrome/browser/autofill/form_input_accessory_view_handler.h
+++ b/ios/chrome/browser/autofill/form_input_accessory_view_handler.h
@@ -21,11 +21,6 @@
 // Sets the frameId of the frame containing the form with the latest focus.
 - (void)setLastFocusFormActivityWebFrameID:(NSString*)frameID;
 
-// Notification that the keyboard accessory will be shown with a specific type
-// of suggestions. May be called multiple times before showing the keyboard
-// accessory.
-- (void)willShowKeyboardAccessory:(autofill::PopupType)suggestionType;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_FORM_INPUT_ACCESSORY_VIEW_HANDLER_H_
diff --git a/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm b/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm
index b69bd75d..b37529da 100644
--- a/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm
+++ b/ios/chrome/browser/autofill/form_input_accessory_view_handler.mm
@@ -11,7 +11,6 @@
 #import "base/notreached.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/autofill/ios/browser/suggestion_controller_java_script_feature.h"
-#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
 #import "ios/web/public/web_state.h"
@@ -166,21 +165,6 @@
   _lastFocusFormActivityWebFrameID = frameID;
 }
 
-- (void)willShowKeyboardAccessory:(autofill::PopupType)suggestionType {
-  if (!_webState) {
-    return;
-  }
-
-  web::WebFrame* frame = [self webFrame];
-
-  if (frame) {
-    BottomSheetTabHelper* bottomSheetTabHelper =
-        BottomSheetTabHelper::FromWebState(_webState);
-    CHECK(bottomSheetTabHelper);
-    bottomSheetTabHelper->WillShowKeyboardAccessory(suggestionType, frame);
-  }
-}
-
 // Attempts to execute/tap/send-an-event-to the iOS built-in "next" and
 // "previous" form assist controls. Returns NO if this attempt failed, YES
 // otherwise. [HACK] Because the buttons on the assist controls can change any
diff --git a/ios/chrome/browser/bookmarks/account_bookmark_sync_service_factory.cc b/ios/chrome/browser/bookmarks/account_bookmark_sync_service_factory.cc
index 177d7f7..b71073e 100644
--- a/ios/chrome/browser/bookmarks/account_bookmark_sync_service_factory.cc
+++ b/ios/chrome/browser/bookmarks/account_bookmark_sync_service_factory.cc
@@ -51,8 +51,8 @@
       ChromeBrowserState::FromBrowserState(context);
   std::unique_ptr<sync_bookmarks::BookmarkSyncService> bookmark_sync_service(
       new sync_bookmarks::BookmarkSyncService(
-          BookmarkUndoServiceFactory::GetForBrowserStateIfExists(
-              browser_state)));
+          BookmarkUndoServiceFactory::GetForBrowserStateIfExists(browser_state),
+          /*wipe_model_on_stopping_sync_with_clear_data=*/true));
   return bookmark_sync_service;
 }
 
diff --git a/ios/chrome/browser/bookmarks/local_or_syncable_bookmark_sync_service_factory.cc b/ios/chrome/browser/bookmarks/local_or_syncable_bookmark_sync_service_factory.cc
index fb2ec3f..06a67ada 100644
--- a/ios/chrome/browser/bookmarks/local_or_syncable_bookmark_sync_service_factory.cc
+++ b/ios/chrome/browser/bookmarks/local_or_syncable_bookmark_sync_service_factory.cc
@@ -46,8 +46,8 @@
       ChromeBrowserState::FromBrowserState(context);
   std::unique_ptr<sync_bookmarks::BookmarkSyncService> bookmark_sync_service(
       new sync_bookmarks::BookmarkSyncService(
-          BookmarkUndoServiceFactory::GetForBrowserStateIfExists(
-              browser_state)));
+          BookmarkUndoServiceFactory::GetForBrowserStateIfExists(browser_state),
+          /*wipe_model_on_stopping_sync_with_clear_data=*/false));
   return bookmark_sync_service;
 }
 
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 2cc9528..a22e07b 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -873,10 +873,6 @@
     {"new-overflow-menu", flag_descriptions::kNewOverflowMenuName,
      flag_descriptions::kNewOverflowMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kNewOverflowMenu)},
-    {"new-overflow-menu-alternate-iph",
-     flag_descriptions::kNewOverflowMenuAlternateIPHName,
-     flag_descriptions::kNewOverflowMenuAlternateIPHDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kNewOverflowMenuAlternateIPH)},
     {"enable-lens-in-home-screen-widget",
      flag_descriptions::kEnableLensInHomeScreenWidgetName,
      flag_descriptions::kEnableLensInHomeScreenWidgetDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index f906175..00ef689 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -641,11 +641,6 @@
 const char kNewOverflowMenuName[] = "New Overflow Menu";
 const char kNewOverflowMenuDescription[] = "Enables the new overflow menu";
 
-const char kNewOverflowMenuAlternateIPHName[] =
-    "New Overflow Menu Alternative IPH";
-const char kNewOverflowMenuAlternateIPHDescription[] =
-    "Uses the alternative IPH flow for the new overflow menu";
-
 const char kNTPViewHierarchyRepairName[] = "NTP View Hierarchy Repair";
 const char kNTPViewHierarchyRepairDescription[] =
     "Checks if NTP view hierarchy is broken and fixes it if necessary.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index ffac8b7..1306de0 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -568,11 +568,6 @@
 extern const char kNewOverflowMenuName[];
 extern const char kNewOverflowMenuDescription[];
 
-// Title and description for the flag to enable the new overflow menu alternate
-// IPH flow.
-extern const char kNewOverflowMenuAlternateIPHName[];
-extern const char kNewOverflowMenuAlternateIPHDescription[];
-
 // Title and description for temporary bug fix to broken NTP view hierarhy.
 // TODO(crbug.com/1262536): Remove this when fixed.
 extern const char kNTPViewHierarchyRepairName[];
diff --git a/ios/chrome/browser/shared/public/commands/BUILD.gn b/ios/chrome/browser/shared/public/commands/BUILD.gn
index 5d95522..96182c00 100644
--- a/ios/chrome/browser/shared/public/commands/BUILD.gn
+++ b/ios/chrome/browser/shared/public/commands/BUILD.gn
@@ -8,8 +8,6 @@
   sources = [
     "activity_service_commands.h",
     "application_commands.h",
-    "bookmark_add_command.h",
-    "bookmark_add_command.mm",
     "bookmarks_commands.h",
     "bring_android_tabs_commands.h",
     "browser_commands.h",
diff --git a/ios/chrome/browser/shared/public/commands/bookmark_add_command.h b/ios/chrome/browser/shared/public/commands/bookmark_add_command.h
deleted file mode 100644
index 6cfb220..0000000
--- a/ios/chrome/browser/shared/public/commands/bookmark_add_command.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_BOOKMARK_ADD_COMMAND_H_
-#define IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_BOOKMARK_ADD_COMMAND_H_
-
-#import <Foundation/Foundation.h>
-
-class GURL;
-@class URLWithTitle;
-namespace web {
-class WebState;
-}
-
-// An object of this class will contain the data needed to execute any bookmark
-// command for one or more pages.
-@interface BookmarkAddCommand : NSObject
-
-// Initializes a command object with the page's `URL` and `title`.
-// If `presentFolderChooser` is true, the user will be prompted to choose
-// a destination for the bookmarks first. If false, the item will be bookmarked
-// immediately and the displayed snackbar message will allow editing to change
-// the location if desired.
-- (instancetype)initWithURL:(const GURL&)URL
-                      title:(NSString*)title
-       presentFolderChooser:(BOOL)presentFolderChooser
-    NS_DESIGNATED_INITIALIZER;
-
-// Initializes a command object with the `webState`'s URL and title.
-// If `presentFolderChooser` is true, the user will be prompted to choose
-// a destination for the bookmarks first. If false, the item will be bookmarked
-// immediately and the displayed snackbar message will allow editing to change
-// the location if desired.
-- (instancetype)initWithWebState:(web::WebState*)webState
-            presentFolderChooser:(BOOL)presentFolderChooser;
-
-// Initializes a command object with multiple pages `UrlWithTitle`.
-// This implies `presentFolderChooser` is `true` and the user will need
-// to select a destination folder before the bookmarks are saved.
-- (instancetype)initWithURLs:(NSArray<URLWithTitle*>*)URLs
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-// The URL and title pairs to bookmark.
-@property(nonatomic, readonly) NSArray<URLWithTitle*>* URLs;
-// Whether or not the user needs to select the destination folder before the
-// bookmarks are saved.
-@property(nonatomic, readonly) BOOL presentFolderChooser;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_BOOKMARK_ADD_COMMAND_H_
diff --git a/ios/chrome/browser/shared/public/commands/bookmark_add_command.mm b/ios/chrome/browser/shared/public/commands/bookmark_add_command.mm
deleted file mode 100644
index a6cef35..0000000
--- a/ios/chrome/browser/shared/public/commands/bookmark_add_command.mm
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
-
-#import "ios/chrome/browser/shared/ui/util/url_with_title.h"
-#import "ios/chrome/browser/tabs/tab_title_util.h"
-#import "ios/web/public/web_state.h"
-#import "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface BookmarkAddCommand ()
-
-@property(nonatomic, strong) NSArray<URLWithTitle*>* URLs;
-@property(nonatomic, assign) BOOL presentFolderChooser;
-
-@end
-
-@implementation BookmarkAddCommand
-
-@synthesize URLs = _URLs;
-@synthesize presentFolderChooser = _presentFolderChooser;
-
-- (instancetype)initWithURL:(const GURL&)URL
-                      title:(NSString*)title
-       presentFolderChooser:(BOOL)presentFolderChooser {
-  if (self = [super init]) {
-    _URLs = @[ [[URLWithTitle alloc] initWithURL:URL title:title] ];
-    _presentFolderChooser = presentFolderChooser;
-  }
-  return self;
-}
-
-- (instancetype)initWithWebState:(web::WebState*)webState
-            presentFolderChooser:(BOOL)presentFolderChooser {
-  GURL URL = webState->GetLastCommittedURL();
-  NSString* title = tab_util::GetTabTitle(webState);
-  return [self initWithURL:URL
-                     title:title
-      presentFolderChooser:presentFolderChooser];
-}
-
-- (instancetype)initWithURLs:(NSArray<URLWithTitle*>*)URLs {
-  if (self = [super init]) {
-    _URLs = [URLs copy];
-    _presentFolderChooser = YES;
-  }
-  return self;
-}
-
-@end
diff --git a/ios/chrome/browser/shared/public/commands/bookmarks_commands.h b/ios/chrome/browser/shared/public/commands/bookmarks_commands.h
index 35dcc4d..207b046 100644
--- a/ios/chrome/browser/shared/public/commands/bookmarks_commands.h
+++ b/ios/chrome/browser/shared/public/commands/bookmarks_commands.h
@@ -8,22 +8,30 @@
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
-
 class GURL;
 @class ReadingListAddCommand;
+@class URLWithTitle;
+namespace web {
+class WebState;
+}  // namespace web
 
+// TODO(crbug.com/1445428): Remove this commands.
 // Protocol for commands arounds Bookmarks manipulation.
 @protocol BookmarksCommands <NSObject>
 
-// Adds bookmarks for the given list of URLs in `command`.
-// If `command.presentFolderChooser` is true:
-// - the user will be prompted to choose a location to store the bookmarks.
-// Otherwise, only a single URL must be provided:
+// Adds bookmarks for the given list of URLs.
+// The user will be prompted to choose a location to store the bookmarks.
+- (void)bookmarkWithFolderChooser:(NSArray<URLWithTitle*>*)URLs;
+
+// Adds bookmark for the last committed URL, and tab title.
+// Behaves as `-(void)bookmark:(URLWithTitle*)` otherwise.
+- (void)bookmarkWithWebState:(web::WebState*)webState;
+
+// Adds bookmark for the URL.
 // - If it is already bookmarked, the "edit bookmark" flow will begin.
 // - If it is not already bookmarked, it will be bookmarked automatically and an
 //   "Edit" button will be provided in the displayed snackbar message.
-- (void)bookmark:(BookmarkAddCommand*)command;
+- (void)createOrEditBookmarkWithURL:(URLWithTitle*)URLWithTitle;
 
 // Opens the Bookmarks UI in edit mode and selects the bookmark node
 // corresponding to `URL`.
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index 07950ba7..cd7649b4 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -52,6 +52,7 @@
     "//ios/chrome/browser/shared/model/browser_state",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/commands",
+    "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/signin",
@@ -62,7 +63,6 @@
     "//ios/chrome/browser/ui/authentication/cells",
     "//ios/chrome/browser/ui/authentication/signin:signin_headers",
     "//ios/chrome/browser/ui/authentication/unified_consent/identity_chooser",
-    "//ios/chrome/browser/ui/infobars/resources:infobar_warning",
     "//ios/chrome/browser/ui/ntp:feature_flags",
     "//ios/chrome/browser/ui/settings:settings_root",
     "//ios/chrome/browser/unified_consent",
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
index f3e275a..b647b54 100644
--- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
+++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
@@ -18,6 +18,7 @@
 #import "ios/chrome/browser/infobars/infobar_utils.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/shared/public/commands/show_signin_command.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/ui/authentication/signin_presenter.h"
@@ -99,7 +100,8 @@
     ChromeBrowserState* browser_state,
     id<SigninPresenter> presenter)
     : browser_state_(browser_state),
-      icon_([UIImage imageNamed:@"infobar_warning"]),
+      icon_(DefaultSymbolWithPointSize(kWarningFillSymbol,
+                                       kInfobarSymbolPointSize)),
       presenter_(presenter) {
   DCHECK(browser_state_);
   DCHECK(!browser_state_->IsOffTheRecord());
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
index 32e647f8..e68f2082 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
@@ -529,15 +529,6 @@
   // If suggestions are enabled, update `currentProvider`.
   self.currentProvider = provider;
 
-  // Notify that we are showing the keyboard accessory for a given type of
-  // suggestion. Note that this is called here so that it does get called when
-  // the keyboard accessory is about to show a set of suggestions, but this
-  // notification should NOT get propagated if the suggestions are accessed
-  // by clicking the key icon on the keyboard. This is specifically for the
-  // keyboard accessory.
-  [self.formNavigationHandler
-      willShowKeyboardAccessory:provider.suggestionType];
-
   // Post it to the consumer.
   self.consumer.suggestionType = provider.suggestionType;
   self.consumer.currentFieldId = _lastSeenParams.unique_field_id;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
index bc99112..a9f6b1fc 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
@@ -39,7 +39,7 @@
 - (void)shutdown;
 
 // Adds a bookmark for `URL` with the given `title`.
-- (void)bookmarkURL:(const GURL&)URL title:(NSString*)title;
+- (void)createBookmarkURL:(const GURL&)URL title:(NSString*)title;
 
 // Presents the bookmark UI to edit an existing bookmark with `URL`.
 - (void)presentBookmarkEditorForURL:(const GURL&)URL;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
index 9da8e0b..aedbcc0 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
@@ -226,7 +226,7 @@
   return _snackbarCommandsHandler;
 }
 
-- (void)bookmarkURL:(const GURL&)URL title:(NSString*)title {
+- (void)createBookmarkURL:(const GURL&)URL title:(NSString*)title {
   if (!_profileBookmarkModel->loaded()) {
     return;
   }
@@ -541,30 +541,39 @@
 
 #pragma mark - BookmarksCommands
 
-- (void)bookmark:(BookmarkAddCommand*)command {
-  DCHECK(command.URLs.count > 0) << "URLs are missing " << [self description];
+- (void)bookmarkWithWebState:(web::WebState*)webState {
+  GURL URL = webState->GetLastCommittedURL();
+  NSString* title = tab_util::GetTabTitle(webState);
+  [self createOrEditBookmarkWithURL:[[URLWithTitle alloc] initWithURL:URL
+                                                                title:title]];
+}
+
+- (void)createOrEditBookmarkWithURL:(URLWithTitle*)URLWithTitle {
+  DCHECK(URLWithTitle) << [self description];
+  NSString* title = URLWithTitle.title;
+  GURL URL = URLWithTitle.URL;
+  if (!_profileBookmarkModel->loaded()) {
+    return;
+  }
+
+  const BookmarkNode* existingBookmark =
+      _profileBookmarkModel->GetMostRecentlyAddedUserNodeForURL(URL);
+
+  if (existingBookmark) {
+    [self presentBookmarkEditorForURL:URL];
+  } else {
+    [self createBookmarkURL:URL title:title];
+  }
+}
+
+- (void)bookmarkWithFolderChooser:(NSArray<URLWithTitle*>*)URLs {
+  DCHECK(URLs.count > 0) << "URLs are missing " << [self description];
 
   if (!_profileBookmarkModel->loaded()) {
     return;
   }
 
-  if (command.URLs.count == 1 && !command.presentFolderChooser) {
-    URLWithTitle* URLWithTitle = command.URLs.firstObject;
-    DCHECK(URLWithTitle) << [self description];
-
-    const BookmarkNode* existingBookmark =
-        _profileBookmarkModel->GetMostRecentlyAddedUserNodeForURL(
-            URLWithTitle.URL);
-
-    if (existingBookmark) {
-      [self presentBookmarkEditorForURL:URLWithTitle.URL];
-    } else {
-      [self bookmarkURL:URLWithTitle.URL title:URLWithTitle.title];
-    }
-    return;
-  }
-
-  _URLs = command.URLs;
+  _URLs = URLs;
   [self presentFolderChooser];
 }
 
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
index c27e04a0..807d8f2 100644
--- a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
@@ -21,7 +21,6 @@
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/shared/public/commands/reading_list_add_command.h"
@@ -29,6 +28,7 @@
 #import "ios/chrome/browser/shared/ui/util/layout_guide_names.h"
 #import "ios/chrome/browser/shared/ui/util/rtl_geometry.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/shared/ui/util/url_with_title.h"
 #import "ios/chrome/browser/shared/ui/util/util_swift.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
@@ -409,10 +409,9 @@
   }
 
   NSString* title = tab_util::GetTabTitle(currentWebState);
-  BookmarkAddCommand* command = [[BookmarkAddCommand alloc] initWithURL:URL
-                                                                  title:title
-                                                   presentFolderChooser:NO];
-  [_bookmarksCommandsHandler bookmark:command];
+  [_bookmarksCommandsHandler
+      createOrEditBookmarkWithURL:[[URLWithTitle alloc] initWithURL:URL
+                                                              title:title]];
 }
 
 - (void)keyCommand_reload {
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
index c459419..b88e985f 100644
--- a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
@@ -686,10 +686,11 @@
   id handler = OCMStrictProtocolMock(@protocol(BookmarksCommands));
   provider_.bookmarksCommandsHandler = handler;
   GURL url = GURL("https://e.test");
-  id addCommand = [OCMArg checkWithBlock:^BOOL(BookmarkAddCommand* command) {
-    return command.URLs.count == 1 && command.URLs.firstObject.URL == url;
+  id addCommand = [OCMArg checkWithBlock:^BOOL(URLWithTitle* URL) {
+    return URL.URL == url;
   }];
-  OCMExpect([provider_.bookmarksCommandsHandler bookmark:addCommand]);
+  OCMExpect([provider_.bookmarksCommandsHandler
+      createOrEditBookmarkWithURL:addCommand]);
   web::FakeWebState* web_state = InsertNewWebState(0);
   web_state->SetCurrentURL(url);
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
index ec77b5e..26405755 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
@@ -17,6 +17,7 @@
 
 namespace {
 const CGFloat kContentViewCornerRadius = 12.0f;
+const CGFloat kMagicStackContentViewCornerRadius = 24.0f;
 const CGFloat kContentViewBorderWidth = 1.0f;
 const CGFloat kIconCornerRadius = 4.0f;
 const CGFloat kContentViewSubviewSpacing = 12.0f;
@@ -31,8 +32,13 @@
     [self.layer
         setBorderColor:[UIColor colorNamed:kTertiaryBackgroundColor].CGColor];
     [self.layer setBorderWidth:kContentViewBorderWidth];
-    self.layer.cornerRadius = kContentViewCornerRadius;
+    self.layer.cornerRadius = IsMagicStackEnabled()
+                                  ? kMagicStackContentViewCornerRadius
+                                  : kContentViewCornerRadius;
     self.layer.masksToBounds = YES;
+    if (IsMagicStackEnabled()) {
+      self.backgroundColor = [UIColor colorNamed:kBackgroundColor];
+    }
 
     _titleLabel = [[UILabel alloc] init];
     _titleLabel.isAccessibilityElement = NO;
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm b/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm
index 92c6af12..09d0af2 100644
--- a/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm
@@ -26,6 +26,7 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
 typedef NS_ENUM(NSInteger, SectionIdentifier) {
   SectionIdentifierContent = kSectionIdentifierEnumZero,
 };
@@ -38,6 +39,9 @@
   ItemTypeCancel,
 };
 
+const CGFloat kSymbolSize = 15;
+}  // namespace
+
 @interface InfobarPasswordTableViewController () <UITextFieldDelegate>
 // Properties backing InfobarPasswordModalConsumer interface.
 @property(nonatomic, copy) NSString* username;
@@ -183,7 +187,7 @@
       l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
   self.passwordItem.textFieldValue = self.maskedPassword;
   self.passwordItem.identifyingIcon =
-      [UIImage imageNamed:@"infobar_reveal_password_icon"];
+      DefaultSymbolWithPointSize(kShowActionSymbol, kSymbolSize);
   self.passwordItem.identifyingIconEnabled = YES;
   self.passwordItem.hideIcon = YES;
   self.passwordItem.identifyingIconAccessibilityLabel = l10n_util::GetNSString(
@@ -366,7 +370,7 @@
   self.passwordMasked = !self.passwordMasked;
   if (self.passwordMasked) {
     self.passwordItem.identifyingIcon =
-        [UIImage imageNamed:@"infobar_reveal_password_icon"];
+        DefaultSymbolWithPointSize(kShowActionSymbol, kSymbolSize);
     self.passwordItem.textFieldValue = self.maskedPassword;
     self.passwordItem.identifyingIconAccessibilityLabel =
         l10n_util::GetNSString(
@@ -375,7 +379,7 @@
         recordModalEvent:MobileMessagesPasswordsModalEvent::MaskedPassword];
   } else {
     self.passwordItem.identifyingIcon =
-        [UIImage imageNamed:@"infobar_hide_password_icon"];
+        DefaultSymbolWithPointSize(kHideActionSymbol, kSymbolSize);
     self.passwordItem.textFieldValue = self.unmaskedPassword;
     self.passwordItem.identifyingIconAccessibilityLabel =
         l10n_util::GetNSString(
diff --git a/ios/chrome/browser/ui/infobars/resources/BUILD.gn b/ios/chrome/browser/ui/infobars/resources/BUILD.gn
deleted file mode 100644
index a9e611f..0000000
--- a/ios/chrome/browser/ui/infobars/resources/BUILD.gn
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ios/asset_catalog.gni")
-
-imageset("infobar_warning") {
-  sources = [
-    "infobar_warning.imageset/Contents.json",
-    "infobar_warning.imageset/infobar_warning.png",
-    "infobar_warning.imageset/infobar_warning@2x.png",
-    "infobar_warning.imageset/infobar_warning@3x.png",
-  ]
-}
-
-imageset("infobar_reveal_password_icon") {
-  sources = [
-    "infobar_reveal_password_icon.imageset/Contents.json",
-    "infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png",
-    "infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png",
-  ]
-}
-
-imageset("infobar_hide_password_icon") {
-  sources = [
-    "infobar_hide_password_icon.imageset/Contents.json",
-    "infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png",
-    "infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json
deleted file mode 100644
index acbff6c5..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "infobar_hide_password_icon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "infobar_hide_password_icon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png
deleted file mode 100644
index 4827898..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png
deleted file mode 100644
index 8863188a..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json
deleted file mode 100644
index 7d8697c..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "infobar_reveal_password_icon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "infobar_reveal_password_icon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png
deleted file mode 100644
index d421f539..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png
deleted file mode 100644
index 63cea42..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/Contents.json b/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/Contents.json
deleted file mode 100644
index 8143b07..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "infobar_warning.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "infobar_warning@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "infobar_warning@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning.png b/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning.png
deleted file mode 100644
index 16a4069..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@2x.png b/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@2x.png
deleted file mode 100644
index 26a72fb..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@3x.png b/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@3x.png
deleted file mode 100644
index 14d4b317..0000000
--- a/ios/chrome/browser/ui/infobars/resources/infobar_warning.imageset/infobar_warning@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/main/default_browser_promo_scene_agent.mm b/ios/chrome/browser/ui/main/default_browser_promo_scene_agent.mm
index 0b29d09..f130b76 100644
--- a/ios/chrome/browser/ui/main/default_browser_promo_scene_agent.mm
+++ b/ios/chrome/browser/ui/main/default_browser_promo_scene_agent.mm
@@ -35,12 +35,6 @@
 
 - (void)sceneState:(SceneState*)sceneState
     transitionedToActivationLevel:(SceneActivationLevel)level {
-  // Don't show Default Browser promo for users not on the stable 14.0.1 iOS
-  // version yet.
-  if (!base::ios::IsRunningOnOrLater(14, 0, 1)) {
-    return;
-  }
-
   // Register default browser promo manager to the promo manager.
   if (IsDefaultBrowserInPromoManagerEnabled()) {
     if (level == SceneActivationLevelForegroundActive) {
diff --git a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
index 319d5fa..7b76e0f 100644
--- a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
+++ b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
@@ -78,7 +78,7 @@
     // call to `animationFinished` after the toolbar animations finished was
     // interrupted and cleanup still needs to occur.
     if (self.inProgressAnimationCount == 0 && self.isAnimating) {
-      [self animationFinished];
+      [self cleanupAfterAnimations];
     }
   });
 }
@@ -331,6 +331,10 @@
 
 - (void)animationFinished {
   self.inProgressAnimationCount -= 1;
+  [self cleanupAfterAnimations];
+}
+
+- (void)cleanupAfterAnimations {
   // Make sure all the animations have been queued and finished.
   if (!self.areOmniboxChangesQueued || self.inProgressAnimationCount > 0) {
     return;
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h
index f564dc2..3c064de 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h
@@ -17,9 +17,6 @@
 // Feature to add a "Share Chrome App" action to the overflow menu
 BASE_DECLARE_FEATURE(kNewOverflowMenuShareChromeAction);
 
-// Feature to use the alternate overflow IPH flow.
-BASE_DECLARE_FEATURE(kNewOverflowMenuAlternateIPH);
-
 // Whether the NewOverflowMenu feature is enabled.
 bool IsNewOverflowMenuEnabled();
 
@@ -33,7 +30,4 @@
 // Whether or not the NewOverflowMenuShareChromeAction is enabled.
 bool IsNewOverflowMenuShareChromeActionEnabled();
 
-// Whether or not the alternate overflow menu IPH flow is enabled.
-bool IsNewOverflowMenuAlternateIPHEnabled();
-
 #endif  // IOS_CHROME_BROWSER_UI_POPUP_MENU_OVERFLOW_MENU_FEATURE_FLAGS_H_
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
index 69003895..ad2a3ed 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
@@ -22,10 +22,6 @@
              "kNewOverflowMenuShareChromeAction",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kNewOverflowMenuAlternateIPH,
-             "NewOverflowMenuAlternateIPH",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 bool IsNewOverflowMenuEnabled() {
   if (@available(iOS 15, *)) {
     return base::FeatureList::IsEnabled(kNewOverflowMenu);
@@ -43,8 +39,3 @@
   return IsNewOverflowMenuEnabled() &&
          base::FeatureList::IsEnabled(kNewOverflowMenuShareChromeAction);
 }
-
-bool IsNewOverflowMenuAlternateIPHEnabled() {
-  return IsNewOverflowMenuEnabled() &&
-         base::FeatureList::IsEnabled(kNewOverflowMenuAlternateIPH);
-}
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
index 2619c6b..b733c4a 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -1510,10 +1510,7 @@
   if (!currentWebState) {
     return;
   }
-  BookmarkAddCommand* command =
-      [[BookmarkAddCommand alloc] initWithWebState:currentWebState
-                              presentFolderChooser:NO];
-  [self.bookmarksCommandsHandler bookmark:command];
+  [self.bookmarksCommandsHandler bookmarkWithWebState:currentWebState];
 }
 
 // Dismisses the menu and adds the current page to the reading list.
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
index 8beae78..0ca1a30 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
@@ -86,10 +86,7 @@
       if (!currentWebState) {
         return;
       }
-      BookmarkAddCommand* command =
-          [[BookmarkAddCommand alloc] initWithWebState:currentWebState
-                                  presentFolderChooser:NO];
-      [self.bookmarksCommandsHandler bookmark:command];
+      [self.bookmarksCommandsHandler bookmarkWithWebState:currentWebState];
       break;
     }
     case PopupMenuActionTranslate:
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
index df9a593..29733b2 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_egtest.mm
@@ -219,7 +219,7 @@
 }
 
 // Tests that the overflow menu IPH shows up when triggered.
-- (void)testOverflowMenuIPH {
+- (void)testOverflowMenuIPHForHistory {
   if (![ChromeEarlGrey isNewOverflowMenuEnabled]) {
     EARL_GREY_TEST_SKIPPED(
         @"The overflow menu IPH only exists when the overflow menu is enabled.")
@@ -228,7 +228,7 @@
   // Enable the IPH Demo Mode feature to ensure the IPH triggers
   AppLaunchConfiguration config = [self appConfigurationForTestCase];
   config.additional_args.push_back(base::StringPrintf(
-      "--enable-features=%s:chosen_feature/IPH_OverflowMenuTip",
+      "--enable-features=%s:chosen_feature/IPH_iOSHistoryOnOverflowMenuFeature",
       feature_engagement::kIPHDemoMode.name));
 
   // The IPH appears immediately on startup, so don't open a new tab when the
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm
index 4087c1c3..1c42c3c 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm
@@ -51,9 +51,9 @@
 // potential IPH bubble.
 @property(nonatomic, strong) UILayoutGuide* layoutGuide;
 
-// Whether the user is still in the same session as when the popup menu IPH was
-// triggered
-@property(nonatomic, assign) BOOL inSessionWithPopupMenuIPH;
+// Whether the user is still in the same session as when the history menu item
+// IPH was triggered
+@property(nonatomic, assign) BOOL inSessionWithHistoryMenuItemIPH;
 
 // The tracker for feature engagement. May return null after the coordinator has
 // been stopped (thus the returned value must be checked for null).
@@ -100,13 +100,9 @@
 }
 
 - (void)showOverflowMenuIPHInViewController:(UIViewController*)menu {
-  // There are 2 reasons to show the IPH in the overflow menu:
-  // 1. The alternate flow is enabled and the feature tracker says it can show.
-  // 2. The user is still in a session where they saw the initial IPH.
-  BOOL shouldShowIPH =
-      (IsNewOverflowMenuAlternateIPHEnabled() && [self canShowIPH]) ||
-      self.inSessionWithPopupMenuIPH;
-  if (!shouldShowIPH) {
+  // Show the IPH in the overflow menu only if user is still in a session where
+  // they saw the initial IPH.
+  if (!self.inSessionWithHistoryMenuItemIPH) {
     return;
   }
 
@@ -122,7 +118,7 @@
     return;
   }
 
-  self.inSessionWithPopupMenuIPH = NO;
+  self.inSessionWithHistoryMenuItemIPH = NO;
   self.uiConfiguration.highlightDestinationsRow = YES;
   [self.overflowMenuBubblePresenter presentInViewController:menu
                                                        view:menu.view
@@ -132,7 +128,8 @@
 #pragma mark - Popup Menu Button Bubble/IPH methods
 
 - (BubbleViewControllerPresenter*)newPopupMenuBubblePresenter {
-  NSString* text = l10n_util::GetNSString(IDS_IOS_OVERFLOW_MENU_TIP);
+  NSString* text =
+      l10n_util::GetNSString(IDS_IOS_VIEW_BROWSING_HISTORY_OVERFLOW_MENU_TIP);
 
   // Prepare the dismissal callback.
   __weak __typeof(self) weakSelf = self;
@@ -164,11 +161,6 @@
 }
 
 - (void)prepareToShowPopupMenuBubble {
-  // The alternate IPH flow only shows the IPH when entering the menu.
-  if (IsNewOverflowMenuAlternateIPHEnabled()) {
-    return;
-  }
-
   // If the Feature Engagement Tracker isn't ready, queue up and re-show when
   // it has finished initializing.
   if (!self.featureEngagementTracker->IsInitialized()) {
@@ -227,7 +219,7 @@
 
   // Present the bubble after the delay.
   self.popupMenuBubblePresenter = bubblePresenter;
-  self.inSessionWithPopupMenuIPH = YES;
+  self.inSessionWithHistoryMenuItemIPH = YES;
   [self.popupMenuBubblePresenter
       presentInViewController:self.baseViewController
                          view:self.baseViewController.view
@@ -263,9 +255,6 @@
 
 - (void)overflowMenuIPHDidDismissWithSnoozeAction:
     (feature_engagement::Tracker::SnoozeAction)snoozeAction {
-  if (IsNewOverflowMenuAlternateIPHEnabled()) {
-    [self trackerIPHDidDismissWithSnoozeAction:snoozeAction];
-  }
   self.overflowMenuBubblePresenter = nil;
   self.uiConfiguration.highlightDestinationsRow = NO;
 }
@@ -275,7 +264,7 @@
 - (void)sceneState:(SceneState*)sceneState
     transitionedToActivationLevel:(SceneActivationLevel)level {
   if (level <= SceneActivationLevelBackground) {
-    self.inSessionWithPopupMenuIPH = NO;
+    self.inSessionWithHistoryMenuItemIPH = NO;
   } else if (level >= SceneActivationLevelForegroundActive) {
     [self prepareToShowPopupMenuBubble];
   }
@@ -287,7 +276,8 @@
 // displayed. Once this is called, the IPH MUST be shown and dismissed.
 - (BOOL)canShowIPH {
   feature_engagement::Tracker* tracker = self.featureEngagementTracker;
-  const base::Feature& feature = feature_engagement::kIPHOverflowMenuTipFeature;
+  const base::Feature& feature =
+      feature_engagement::kIPHiOSHistoryOnOverflowMenuFeature;
   return tracker && tracker->ShouldTriggerHelpUI(feature);
 }
 
@@ -297,7 +287,7 @@
   feature_engagement::Tracker* tracker = self.featureEngagementTracker;
   if (tracker) {
     const base::Feature& feature =
-        feature_engagement::kIPHOverflowMenuTipFeature;
+        feature_engagement::kIPHiOSHistoryOnOverflowMenuFeature;
     tracker->DismissedWithSnooze(feature, snoozeAction);
   }
 }
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
index f8eb5a6..2d9cbfed 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
@@ -199,8 +199,7 @@
 // but sync is off.
 TEST_F(ClearBrowsingDataManagerTest, TestModelSignedInSyncOff) {
   // Ensure that sync is not running.
-  test_sync_service_->SetDisableReasons(
-      {syncer::SyncService::DISABLE_REASON_USER_CHOICE});
+  test_sync_service_->SetHasSyncConsent(false);
 
   AuthenticationServiceFactory::GetForBrowserState(browser_state_.get())
       ->SignIn(fake_identity(),
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm
index b53d076..0064ee21 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm
@@ -64,8 +64,7 @@
   sync_service->SetAccountInfo(account);
   sync_service->SetHasSyncConsent(false);
   sync_service->SetTransportState(syncer::SyncService::TransportState::ACTIVE);
-  sync_service->SetDisableReasons(
-      {syncer::SyncService::DisableReason::DISABLE_REASON_USER_CHOICE});
+  sync_service->SetDisableReasons({});
   ASSERT_FALSE(sync_service->IsSyncFeatureEnabled());
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
index 5e2e6d97d..5732499 100644
--- a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
@@ -304,16 +304,7 @@
   if (self.signOutFlowInProgress) {
     return;
   }
-  syncer::SyncService::DisableReasonSet disableReasons =
-      self.syncService->GetDisableReasons();
-  syncer::SyncService::DisableReasonSet userChoiceDisableReason =
-      syncer::SyncService::DisableReasonSet(
-          syncer::SyncService::DISABLE_REASON_USER_CHOICE);
-  // Manage sync settings needs to stay opened if sync is disabled with
-  // DISABLE_REASON_USER_CHOICE. Manage sync settings is the only way for a
-  // user to turn on the sync engine (and remove DISABLE_REASON_USER_CHOICE).
-  // The sync engine turned back on automatically by enabling any datatype.
-  if (!disableReasons.Empty() && disableReasons != userChoiceDisableReason) {
+  if (!self.syncService->GetDisableReasons().Empty()) {
     [self closeManageSyncSettings];
   }
 }
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
index 67b590e..816a181 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -93,8 +93,6 @@
     "//ios/chrome/browser/shared/ui/table_view:utils",
     "//ios/chrome/browser/shared/ui/table_view/cells",
     "//ios/chrome/browser/shared/ui/util",
-    "//ios/chrome/browser/ui/infobars/resources:infobar_hide_password_icon",
-    "//ios/chrome/browser/ui/infobars/resources:infobar_reveal_password_icon",
     "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/settings:settings_root",
     "//ios/chrome/browser/ui/settings/autofill",
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/BUILD.gn b/ios/chrome/browser/ui/sharing/activity_services/activities/BUILD.gn
index 9e91fee..4799a73 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/BUILD.gn
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/BUILD.gn
@@ -33,6 +33,7 @@
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/util",
+    "//ios/chrome/browser/shared/ui/util:url_with_title",
     "//ios/chrome/browser/ui/sharing/activity_services/data",
     "//ios/chrome/browser/web",
     "//ios/web/common:user_agent",
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity.mm b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity.mm
index 814fe016..bf86d01 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity.mm
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity.mm
@@ -9,9 +9,9 @@
 #import "components/bookmarks/browser/bookmark_model.h"
 #import "components/bookmarks/common/bookmark_pref_names.h"
 #import "components/prefs/pref_service.h"
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/ui/symbols/symbols.h"
+#import "ios/chrome/browser/shared/ui/util/url_with_title.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 #import "url/gurl.h"
@@ -99,11 +99,9 @@
   // presented by the bookmark command below.
   [self activityDidFinish:YES];
 
-  BookmarkAddCommand* command =
-      [[BookmarkAddCommand alloc] initWithURL:self.URL
-                                        title:self.title
-                         presentFolderChooser:NO];
-  [self.handler bookmark:command];
+  [self.handler createOrEditBookmarkWithURL:[[URLWithTitle alloc]
+                                                initWithURL:self.URL
+                                                      title:self.title]];
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
index 2b7e53e..5f88750 100644
--- a/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/activity_services/activities/bookmark_activity_unittest.mm
@@ -10,7 +10,6 @@
 #import "components/prefs/pref_registry_simple.h"
 #import "components/prefs/testing_pref_service.h"
 #import "ios/chrome/browser/bookmarks/bookmark_ios_unit_test_support.h"
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/ui/util/url_with_title.h"
 #import "ios/chrome/grit/ios_strings.h"
@@ -121,11 +120,12 @@
   BookmarkActivity* activity = CreateActivity(testUrl);
 
   [[mocked_handler_ expect]
-      bookmark:[OCMArg checkWithBlock:^BOOL(BookmarkAddCommand* value) {
-        EXPECT_EQ(testUrl, value.URLs.firstObject.URL);
-        EXPECT_EQ(kTestTitle, value.URLs.firstObject.title);
-        return YES;
-      }]];
+      createOrEditBookmarkWithURL:[OCMArg
+                                      checkWithBlock:^BOOL(URLWithTitle* URL) {
+                                        EXPECT_EQ(testUrl, URL.URL);
+                                        EXPECT_EQ(kTestTitle, URL.title);
+                                        return YES;
+                                      }]];
 
   id activity_partial_mock = OCMPartialMock(activity);
   [[activity_partial_mock expect] activityDidFinish:YES];
diff --git a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
index 0293f8a..b0b3a3a 100644
--- a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
@@ -22,7 +22,6 @@
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/generate_qr_code_command.h"
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index f68622c..2531e87e 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -1308,7 +1308,7 @@
   } else {
     base::RecordAction(base::UserMetricsAction(
         "MobileTabGridOpenedBookmarkEditorForNewBookmark"));
-    [self.bookmarksCoordinator bookmarkURL:URL title:title];
+    [self.bookmarksCoordinator createBookmarkURL:URL title:title];
   }
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
index 9edcfc0..cd1e6f3 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
@@ -36,7 +36,6 @@
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer_bridge.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
-#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h"
 #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/reading_list_add_command.h"
@@ -1087,8 +1086,7 @@
 
   NSArray<URLWithTitle*>* URLs = [self urlsWithTitleFromItemIDs:items];
 
-  BookmarkAddCommand* command = [[BookmarkAddCommand alloc] initWithURLs:URLs];
-  [bookmarkHandler bookmark:command];
+  [bookmarkHandler bookmarkWithFolderChooser:URLs];
 }
 
 - (NSArray<URLWithTitle*>*)urlsWithTitleFromItemIDs:(NSArray<NSString*>*)items {
diff --git a/ios/chrome/browser/web/chrome_web_client.h b/ios/chrome/browser/web/chrome_web_client.h
index 9bdb7b2..9e545ab 100644
--- a/ios/chrome/browser/web/chrome_web_client.h
+++ b/ios/chrome/browser/web/chrome_web_client.h
@@ -55,7 +55,7 @@
                                          const GURL& url) const override;
   void LogDefaultUserAgent(web::WebState* web_state,
                            const GURL& url) const override;
-  bool RestoreSessionFromCache(web::WebState* web_state) const override;
+  NSData* FetchSessionFromCache(web::WebState* web_state) const override;
   void CleanupNativeRestoreURLs(web::WebState* web_state) const override;
   void WillDisplayMediaCapturePermissionPrompt(
       web::WebState* web_state) const override;
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index 522756e..0f54574 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -436,10 +436,13 @@
                             !use_desktop_agent);
 }
 
-bool ChromeWebClient::RestoreSessionFromCache(web::WebState* web_state) const {
-  return web::UseNativeSessionRestorationCache() &&
-         WebSessionStateTabHelper::FromWebState(web_state)
-             ->RestoreSessionFromCache();
+NSData* ChromeWebClient::FetchSessionFromCache(web::WebState* web_state) const {
+  if (!web::UseNativeSessionRestorationCache()) {
+    return nil;
+  }
+
+  return WebSessionStateTabHelper::FromWebState(web_state)
+      ->FetchSessionFromCache();
 }
 
 void ChromeWebClient::CleanupNativeRestoreURLs(web::WebState* web_state) const {
diff --git a/ios/chrome/browser/web/session_state/web_session_state_tab_helper.h b/ios/chrome/browser/web/session_state/web_session_state_tab_helper.h
index 750d04f5..6b2eb38 100644
--- a/ios/chrome/browser/web/session_state/web_session_state_tab_helper.h
+++ b/ios/chrome/browser/web/session_state/web_session_state_tab_helper.h
@@ -32,10 +32,9 @@
 
   ~WebSessionStateTabHelper() override;
 
-  // If kRestoreSessionFromCache is enabled restore `web_state`'s WKWebView
-  // using the previously saved sessionState data via the WebSessionStateCache.
-  // Returns true if the session could be restored.
-  bool RestoreSessionFromCache();
+  // Returns the WKWebView session data blob from cache or nil if the feature
+  // is disabled or the data not found in the cache.
+  NSData* FetchSessionFromCache();
 
   // Calls SaveSessionState if the tab helper is stale.
   void SaveSessionStateIfStale();
diff --git a/ios/chrome/browser/web/session_state/web_session_state_tab_helper.mm b/ios/chrome/browser/web/session_state/web_session_state_tab_helper.mm
index e1108b1..3d624d0 100644
--- a/ios/chrome/browser/web/session_state/web_session_state_tab_helper.mm
+++ b/ios/chrome/browser/web/session_state/web_session_state_tab_helper.mm
@@ -90,22 +90,11 @@
   return ChromeBrowserState::FromBrowserState(web_state_->GetBrowserState());
 }
 
-bool WebSessionStateTabHelper::RestoreSessionFromCache() {
+NSData* WebSessionStateTabHelper::FetchSessionFromCache() {
   WebSessionStateCache* cache =
       WebSessionStateCacheFactory::GetForBrowserState(GetBrowserState());
   NSData* data = [cache sessionStateDataForWebState:web_state_];
-  if (!data.length)
-    return false;
-
-  bool restore_session_succeeded = web_state_->SetSessionStateData(data);
-  UMA_HISTOGRAM_BOOLEAN("Session.WebStates.NativeRestoreSessionFromCache",
-                        restore_session_succeeded);
-  if (!restore_session_succeeded)
-    return false;
-
-  DCHECK(web_state_->GetNavigationItemCount());
-  web::GetWebClient()->CleanupNativeRestoreURLs(web_state_);
-  return true;
+  return data.length ? data : nil;
 }
 
 void WebSessionStateTabHelper::SaveSessionStateIfStale() {
diff --git a/ios/chrome/browser/web/session_state/web_session_state_tab_helper_unittest.mm b/ios/chrome/browser/web/session_state/web_session_state_tab_helper_unittest.mm
index 4200a20e..0797623 100644
--- a/ios/chrome/browser/web/session_state/web_session_state_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/session_state/web_session_state_tab_helper_unittest.mm
@@ -128,8 +128,10 @@
   EXPECT_TRUE(base::CopyFile(filePath, newFilePath));
 
   // Only restore for session restore URLs.
-  ASSERT_TRUE(WebSessionStateTabHelper::FromWebState(web_state.get())
-                  ->RestoreSessionFromCache());
+  NSData* data = WebSessionStateTabHelper::FromWebState(web_state.get())
+                     ->FetchSessionFromCache();
+  ASSERT_TRUE(data);
+  EXPECT_TRUE(web_state->SetSessionStateData(data));
 
   // kChromeUIAboutNewTabURL should get rewritten to kChromeUINewTabURL.
   ASSERT_EQ(web_state->GetLastCommittedURL(), GURL(kChromeUINewTabURL));
diff --git a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
index 5e0ca24..3de79c9 100644
--- a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
+++ b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
@@ -75,10 +75,6 @@
                              "info_plist",
                              "info_plist_target",
                              "output_name",
-                           ],
-                           [
-                             "deps",
-                             "public_deps",
                            ])
 
     testonly = true
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 70497e3..fda479ee 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-40df72f86c025c2be70f70562eb7e1c333009314
\ No newline at end of file
+fe76e8105cbd146304444cdfd9675f21d2cea68c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 3b646ce..dfefa14 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-01c05ebb6d71b8b35f958a3f8c44385b33fcb9c0
\ No newline at end of file
+bdc52de02739e0fd432549ef105f622770c745a7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 0beb8b34..35dd43e 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-27a581a4e45d4c73ced2e1192ffcef3d74d95a0b
\ No newline at end of file
+e223c5cb16f2fe199436fd9df7e7ded3ec4f6d51
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 0bb7ef32..1b0396a 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-4c0cebf0a5fd93c53cda9b72fc3f3f8cb90235c9
\ No newline at end of file
+eb7022a2d3589c7d543540f8bf7819a1b13fad3d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index c774bdf..6827f52 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f75595eb9dc31941389d8b919440f6908a5f6990
\ No newline at end of file
+413d9c745aebf523c09bac0940dc719a2b1711db
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index f1f3c91..19c2359 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fde1f5a1f5caa9277af2bb1402719aabd8e1000b
\ No newline at end of file
+3c3e1bbb1e3f57a2af8021c19bc742ac985832d4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index f36f16a..b06402a 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-95354d89f0015a78d2a1c49d254a39ac100e1770
\ No newline at end of file
+d3a83c900c0ce79337955494a533112a346986fa
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index dc2ae8fe..4238d5c 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-c8815c32becdfb5d33416ba2498229803920571f
\ No newline at end of file
+97b568f09129c795d88c02029fadce383229fb4f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 1fcb648..29aed46 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-6b0e09c0ac118c7f1cd6e2b861e9537c60e0b23d
\ No newline at end of file
+9c4617e8781182350377ab3bce40f15ab76650f6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index fe2770e..d9a15690 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-671b881473a992b2eb3c9e14042441a7d79f9d15
\ No newline at end of file
+9686decf1a238a1fe40426da478a9cfa5fcd7c0a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index d374e01..60b460c5 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-54ed55c461a952f0915c12baa2bbd42627681a17
\ No newline at end of file
+48610ea0edd4119ed0f96ca54b2331b3e5fc7675
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index d3188775..ca58b27 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-84bd1fe304ad507810a08b8cbab8fe02710125a8
\ No newline at end of file
+7f32bb5267bacc84ec940a75b3cf0409c6289f8d
\ No newline at end of file
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index e136704e..b45aa12 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -303,6 +303,7 @@
   "src/components/ScalableFontDescriptor/src/MDCScalableFontDescriptor.h",
   "src/components/ScalableFontDescriptor/src/MaterialScalableFontDescriptor.h",
   "src/components/Shadow/src/Animations/UIView+MDCShadowAnimations.h",
+  "src/components/Shadow/src/M3CAnimationActions.h",
   "src/components/Shadow/src/MDCShadow.h",
   "src/components/Shadow/src/MDCShadowsCollection.h",
   "src/components/Shadow/src/MaterialShadow.h",
@@ -1174,6 +1175,8 @@
   "src/components/ScalableFontDescriptor/src/MaterialScalableFontDescriptor.h",
   "src/components/Shadow/src/Animations/UIView+MDCShadowAnimations.h",
   "src/components/Shadow/src/Animations/UIView+MDCShadowAnimations.m",
+  "src/components/Shadow/src/M3CAnimationActions.h",
+  "src/components/Shadow/src/M3CAnimationActions.m",
   "src/components/Shadow/src/MDCShadow.h",
   "src/components/Shadow/src/MDCShadow.m",
   "src/components/Shadow/src/MDCShadowsCollection.h",
diff --git a/ios/web/annotations/annotations_inttest.mm b/ios/web/annotations/annotations_inttest.mm
index faaa4801b..ecb9a3f 100644
--- a/ios/web/annotations/annotations_inttest.mm
+++ b/ios/web/annotations/annotations_inttest.mm
@@ -251,7 +251,7 @@
                          "<p>Enjoy</p>"
                          "</body></html>");
 
-  EXPECT_EQ("\nYou'll find it on"
+  EXPECT_EQ("You'll find it on"
             "\nCastro Street, Mountain View, CA"
             "\nEnjoy",
             observer()->extracted_text());
@@ -266,7 +266,7 @@
                          "<p>text</p>"
                          "</body></html>");
 
-  std::string text = "\ntext"
+  std::string text = "text"
                      "\nannotation"
                      "\ntext";
   EXPECT_EQ(text, observer()->extracted_text());
@@ -297,7 +297,7 @@
                          "<p>text</p>"
                          "</body></html>");
 
-  std::string text = "\ntext"
+  std::string text = "text"
                      "annotation1"
                      "annotation2"
                      "\ntext";
diff --git a/ios/web/annotations/resources/annotations.ts b/ios/web/annotations/resources/annotations.ts
index 9308c30..87ba2fc 100644
--- a/ios/web/annotations/resources/annotations.ts
+++ b/ios/web/annotations/resources/annotations.ts
@@ -299,6 +299,7 @@
     filterInvisibles: boolean = false): void {
   const nodes: Node[] = [root];
   let index = 0;
+  let isPreviousSpace = true;
 
   while (nodes.length > 0) {
     let node = nodes.pop();
@@ -313,8 +314,11 @@
         continue;
       }
       if (node.nodeName === 'BR') {
+        if (isPreviousSpace)
+          continue;
         if (!process(node, index, '\n'))
           break;
+        isPreviousSpace = true;
         index += 1;
         continue;
       }
@@ -326,9 +330,10 @@
       }
       // No need to add a line break before `body` as it is the first element.
       if (node.nodeName.toUpperCase() !== 'BODY' &&
-          style.display !== 'inline') {
+          style.display !== 'inline' && !isPreviousSpace) {
         if (!process(node, index, '\n'))
           break;
+        isPreviousSpace = true;
         index += 1;
       }
 
@@ -347,8 +352,12 @@
         nodes.push(node.childNodes[childIdx]!);
       }
     } else if (node.nodeType === Node.TEXT_NODE && node.textContent) {
+      const isSpace = node.textContent.trim() === '';
+      if (isSpace && isPreviousSpace)
+        continue;
       if (!process(node, index, node.textContent))
         break;
+      isPreviousSpace = isSpace;
       index += node.textContent.length;
     }
   }
diff --git a/ios/web/js_features/context_menu/context_menu_js_unittest.mm b/ios/web/js_features/context_menu/context_menu_js_unittest.mm
index 2174ec0b..0de8c2b9 100644
--- a/ios/web/js_features/context_menu/context_menu_js_unittest.mm
+++ b/ios/web/js_features/context_menu/context_menu_js_unittest.mm
@@ -218,13 +218,13 @@
  protected:
   // Returns details of the DOM element at the given `point` in the web view
   // viewport's coordinate space.
-  base::Value FindElementAtPoint(CGPoint point) {
+  base::Value::Dict FindElementAtPoint(CGPoint point) {
     bool gCrWeb_injected = web::test::WaitForInjectedScripts(web_view());
     if (!gCrWeb_injected) {
       // This EXPECT_TRUE call will always fail. However, add the conditional to
       // also return null and prevent further execution of this method.
       EXPECT_TRUE(gCrWeb_injected);
-      return base::Value();
+      return base::Value::Dict();
     }
 
     // Force layout
@@ -242,11 +242,12 @@
     }));
 
     if (!script_message_handler_.lastReceivedScriptMessage) {
-      return base::Value();
+      return base::Value::Dict();
     }
-    return web::ValueResultFromWKResult(
-               script_message_handler_.lastReceivedScriptMessage.body)
-        ->Clone();
+    return std::move(
+               *web::ValueResultFromWKResult(
+                   script_message_handler_.lastReceivedScriptMessage.body))
+        .TakeDict();
   }
 
   // Finds the element at the given `point` and compares it against
@@ -260,13 +261,13 @@
   // TODO(crbug.com/1219869): Find a better "ready" signal for the webview and
   // remove this retry logic.
   void CheckElementResult(CGPoint point,
-                          const base::Value& expected_result,
-                          const std::vector<const char*>& ignored_keys) {
+                          const base::Value::Dict& expected_result,
+                          const std::vector<const char*>& ignored_keys = {}) {
     constexpr int kNumTries = 13;
     for (int i = 0; i < kNumTries; ++i) {
-      base::Value result = FindElementAtPoint(point);
+      base::Value::Dict result = FindElementAtPoint(point);
       for (const char* key : ignored_keys) {
-        result.RemoveKey(key);
+        result.Remove(key);
       }
       if (result == expected_result) {
         return;
@@ -276,11 +277,6 @@
     }
   }
 
-  void CheckElementResult(CGPoint point, const base::Value& expected_result) {
-    return CheckElementResult(point, expected_result,
-                              std::vector<const char*>());
-  }
-
   // Returns web view's content size from the current web state.
   CGSize GetWebViewContentSize() { return web_view().scrollView.contentSize; }
 
@@ -321,13 +317,14 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementTagName, "P");
-  expected_value.SetStringKey(
-      kContextMenuElementSurroundingText,
-      "This is the address's first line Lorem ipsum dolor sit amet. 49 WEST "
-      "27TH STREET reprehenderit sed cumque magni ut omnis sint est deserunt");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementTagName, "P")
+                            .Set(kContextMenuElementSurroundingText,
+                                 "This is the address's first line Lorem ipsum "
+                                 "dolor sit amet. 49 WEST "
+                                 "27TH STREET reprehenderit sed cumque magni "
+                                 "ut omnis sint est deserunt");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementInnerText);
@@ -371,12 +368,12 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForImage());
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -393,12 +390,12 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, html_for_picture);
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -412,11 +409,11 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, html_for_div);
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -432,12 +429,12 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, html_for_div);
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -454,9 +451,9 @@
   ASSERT_TRUE(LoadHtml(html));
 
   // Check that the paragraph was caught instead.
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementTagName, "DIV");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementTagName, "DIV");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementTextOffset);
@@ -473,13 +470,13 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTitle, image_title);
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTitle, image_title)
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -490,12 +487,12 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForImage());
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -507,8 +504,8 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForImage());
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
+  auto expected_value =
+      base::Value::Dict().Set(kContextMenuElementRequestId, kRequestId);
 
   CheckElementResult(kPointOutsideDocument, expected_value);
 }
@@ -519,8 +516,8 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForImage());
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
+  auto expected_value =
+      base::Value::Dict().Set(kContextMenuElementRequestId, kRequestId);
 
   CheckElementResult(kPointOutsideImage, expected_value);
 }
@@ -535,13 +532,13 @@
       /*head=*/nil, GetHtmlForLink(image_link, GetHtmlForImage()));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, image_link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, image_link)
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -555,8 +552,8 @@
       /*head=*/nil, GetHtmlForLink(image_link, GetHtmlForImage()));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
+  auto expected_value =
+      base::Value::Dict().Set(kContextMenuElementRequestId, kRequestId);
 
   CheckElementResult(kPointOutsideDocument, expected_value);
 }
@@ -570,8 +567,8 @@
       /*head=*/nil, GetHtmlForLink(image_link, GetHtmlForImage()));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
+  auto expected_value =
+      base::Value::Dict().Set(kContextMenuElementRequestId, kRequestId);
 
   CheckElementResult(kPointOutsideImage, expected_value);
 }
@@ -590,13 +587,13 @@
   std::string image_source =
       base::StringPrintf("%s%s", kTestUrl, relative_image_path);
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, image_source);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, image_link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, image_source)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, image_link)
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -616,13 +613,13 @@
   std::string image_source =
       base::StringPrintf("%s%s", kTestUrl, relative_image_path);
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, image_source);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, image_link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, image_source)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, image_link)
+                            .Set(kContextMenuElementTagName, "img");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -642,12 +639,12 @@
   std::string image_source =
       base::StringPrintf("%s%s", kTestUrl, relative_image_path);
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, image_source);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, image_source)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   // Make sure the returned JSON does not have an 'href' key.
   CheckElementResult(kPointOnImage, expected_value);
@@ -667,12 +664,12 @@
   std::string image_source =
       base::StringPrintf("%s%s", kTestUrl, relative_image_path);
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, image_source);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, image_source)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   // Make sure the returned JSON does not have an 'href' key.
   CheckElementResult(kPointOnImage, expected_value);
@@ -687,12 +684,12 @@
       /*head=*/nil, GetHtmlForLink(image_link, GetHtmlForImage()));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementSource, kImageSource);
-  expected_value.SetStringKey(kContextMenuElementAlt, kImageAlt);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementTagName, "img");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementSource, kImageSource)
+                            .Set(kContextMenuElementAlt, kImageAlt)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementTagName, "img");
 
   // Make sure the returned JSON does not have an 'href' key.
   CheckElementResult(kPointOnImage, expected_value);
@@ -710,13 +707,12 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  base::Value bounding_box_expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementHyperlink, image_link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, image_link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -729,11 +725,11 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForSvgLink(link));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnSvgLink, expected_value);
 }
@@ -744,11 +740,11 @@
   NSString* html = GetHtmlForPage(/*head=*/nil, GetHtmlForSvgXlink(link));
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnSvgLink, expected_value);
 }
@@ -761,9 +757,9 @@
   ASSERT_TRUE(LoadHtml(html));
 
   // Check that the paragraph was caught instead.
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementTagName, "P");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementTagName, "P");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementTextOffset);
@@ -787,8 +783,8 @@
   ASSERT_TRUE(web::test::LoadHtml(
       web_view(), GetHtmlForPage(/*head=*/nil, body), GetTestURL()));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
+  auto expected_value =
+      base::Value::Dict().Set(kContextMenuElementRequestId, kRequestId);
 
   CheckElementResult(kPointOnImage, expected_value);
 }
@@ -803,10 +799,8 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value result = FindElementAtPoint(kPointOnImage);
-  const auto* dict = result.GetIfDict();
-  ASSERT_TRUE(dict);
-  auto* policy = dict->FindString(kContextMenuElementReferrerPolicy);
+  base::Value::Dict result = FindElementAtPoint(kPointOnImage);
+  auto* policy = result.FindString(kContextMenuElementReferrerPolicy);
   ASSERT_TRUE(policy);
   EXPECT_STREQ("never", policy->c_str());
 }
@@ -841,12 +835,12 @@
   CGFloat offset = content_height - scroll_view_height;
   web_view().scrollView.contentOffset = CGPointMake(0.0, offset);
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   // Link is at bottom of the page content.
   CheckElementResult(CGPointMake(50.0, content_height - 100), expected_value);
@@ -861,12 +855,12 @@
       GetHtmlForPage(/*head=*/nil, GetHtmlForShadowDomLink(link, @"link")),
       GetTestURL()));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnShadowDomLink, expected_value);
 }
@@ -881,9 +875,9 @@
       GetTestURL()));
 
   // Check that the paragraph was caught instead.
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementTagName, "DIV");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementTagName, "DIV");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementTextOffset);
@@ -900,12 +894,12 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnLink, expected_value);
 }
@@ -921,12 +915,12 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnLink, expected_value);
 }
@@ -943,11 +937,11 @@
   ASSERT_TRUE(LoadHtml(html));
 
   // Check that the paragraph was caught instead.
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementSurroundingText, "link");
-  expected_value.SetStringKey(kContextMenuElementTagName, "P");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementSurroundingText, "link")
+                            .Set(kContextMenuElementTagName, "P");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementTextOffset);
@@ -967,11 +961,11 @@
   ASSERT_TRUE(LoadHtml(html));
 
   // Check that the paragraph was caught instead.
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementSurroundingText, "link");
-  expected_value.SetStringKey(kContextMenuElementTagName, "P");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementSurroundingText, "link")
+                            .Set(kContextMenuElementTagName, "P");
 
   std::vector<const char*> ignored_keys;
   ignored_keys.push_back(kContextMenuElementTextOffset);
@@ -992,12 +986,12 @@
 
   ASSERT_TRUE(LoadHtml(html));
 
-  base::Value expected_value(base::Value::Type::DICT);
-  expected_value.SetStringKey(kContextMenuElementRequestId, kRequestId);
-  expected_value.SetStringKey(kContextMenuElementInnerText, "link");
-  expected_value.SetStringKey(kContextMenuElementReferrerPolicy, "default");
-  expected_value.SetStringKey(kContextMenuElementHyperlink, link);
-  expected_value.SetStringKey(kContextMenuElementTagName, "a");
+  auto expected_value = base::Value::Dict()
+                            .Set(kContextMenuElementRequestId, kRequestId)
+                            .Set(kContextMenuElementInnerText, "link")
+                            .Set(kContextMenuElementReferrerPolicy, "default")
+                            .Set(kContextMenuElementHyperlink, link)
+                            .Set(kContextMenuElementTagName, "a");
 
   CheckElementResult(kPointOnLink, expected_value);
 }
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index dc69045..67d85f8 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -95,6 +95,15 @@
 //   attached state when a new navigation starts.
 class NavigationManagerImpl : public NavigationManager {
  public:
+  // Callback used to fetch WKWebView session data blob.
+  using SessionDataBlobFetcher = base::OnceCallback<NSData*()>;
+
+  // Enumeration representing the source of a WKWebView session data blob.
+  enum class SessionDataBlobSource {
+    kSessionCache,
+    kSynthesized,
+  };
+
   NavigationManagerImpl();
   ~NavigationManagerImpl() override;
 
@@ -105,6 +114,10 @@
   void SetDelegate(NavigationManagerDelegate* delegate);
   void SetBrowserState(BrowserState* browser_state);
 
+  // Setter for the callback used to fetch the native session data blob from
+  // the session cache.
+  void SetNativeSessionFetcher(SessionDataBlobFetcher native_session_fetcher);
+
   // Helper functions for notifying WebStateObservers of changes.
   // TODO(stuartmorgan): Make these private once the logic triggering them moves
   // into this layer.
@@ -318,6 +331,10 @@
     kForwardList,
   };
 
+  // Appends a new session blob fetcher with given source.
+  void AppendSessionDataBlobFetcher(SessionDataBlobFetcher loader,
+                                    SessionDataBlobSource source);
+
   // Restores the state of the `items_restored` in the navigation items
   // associated with the WKBackForwardList. `back_list` is used to specify if
   // the items passed are the list containing the back list or the forward list.
@@ -376,10 +393,10 @@
   void FinalizeSessionRestore();
 
   // The primary delegate for this manager.
-  NavigationManagerDelegate* delegate_;
+  NavigationManagerDelegate* delegate_ = nullptr;
 
   // The BrowserState that is associated with this instance.
-  BrowserState* browser_state_;
+  BrowserState* browser_state_ = nullptr;
 
   // List of transient url rewriters added by `AddTransientURLRewriter()`.
   std::vector<BrowserURLRewriter::URLRewriter> transient_url_rewriters_;
@@ -392,11 +409,11 @@
   // -1 if pending_item_ represents a new navigation or there is no pending
   // navigation. Otherwise, this is the index of the pending_item in the
   // back-forward list.
-  int pending_item_index_;
+  int pending_item_index_ = -1;
 
   // Index of the last committed item in the main frame. If there is none, this
   // field will equal to -1.
-  int last_committed_item_index_;
+  int last_committed_item_index_ = -1;
 
   // The NavigationItem that corresponds to the empty window open navigation. It
   // has to be stored separately because it has no WKBackForwardListItem. It is
@@ -417,7 +434,7 @@
   // have to be lazily created on read, this is the only workaround.
   mutable TimeSmoother time_smoother_;
 
-  WKWebViewCache web_view_cache_;
+  WKWebViewCache web_view_cache_{this};
 
   // Whether this navigation manager is in the process of restoring session
   // history into WKWebView. It is set in Restore() and unset in
@@ -450,10 +467,11 @@
   // FinalizeSessionRestore().
   std::vector<base::OnceClosure> restore_session_completion_callbacks_;
 
-  // Used to trigger a WKWebView native session restore with a synthesized
-  // data blob (rather than a cached one). This is useful for when there is a
-  // cache miss, or when syncing tabs between devices.
-  SynthesizedSessionRestore synthesized_restore_helper_;
+  // Stores the different WKWebView session data blob loaders. Loaders are
+  // tried in the order they are registered, and the native session loading
+  // code stops at the first session successfully loaded.
+  std::vector<std::pair<SessionDataBlobFetcher, SessionDataBlobSource>>
+      session_data_blob_fetchers_;
 };
 
 }  // namespace web
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm
index d49706b..0024b503 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -55,6 +55,22 @@
       navigationItem];
 }
 
+// Records metrics about session restoration `success` from `source`.
+void RecordSessionRestorationResultForSource(
+    bool success,
+    web::NavigationManagerImpl::SessionDataBlobSource source) {
+  switch (source) {
+    case web::NavigationManagerImpl::SessionDataBlobSource::kSessionCache:
+      UMA_HISTOGRAM_BOOLEAN("Session.WebStates.NativeRestoreSessionFromCache",
+                            success);
+      break;
+
+    case web::NavigationManagerImpl::SessionDataBlobSource::kSynthesized:
+      UMA_HISTOGRAM_BOOLEAN("Session.WebStates.NativeRestoreSession", success);
+      break;
+  }
+}
+
 }  // namespace
 
 namespace web {
@@ -95,12 +111,7 @@
   return *this;
 }
 
-NavigationManagerImpl::NavigationManagerImpl()
-    : delegate_(nullptr),
-      browser_state_(nullptr),
-      pending_item_index_(-1),
-      last_committed_item_index_(-1),
-      web_view_cache_(this) {}
+NavigationManagerImpl::NavigationManagerImpl() = default;
 
 NavigationManagerImpl::~NavigationManagerImpl() = default;
 
@@ -112,6 +123,13 @@
   browser_state_ = browser_state;
 }
 
+void NavigationManagerImpl::SetNativeSessionFetcher(
+    SessionDataBlobFetcher native_session_fetcher) {
+  CHECK(session_data_blob_fetchers_.empty());
+  AppendSessionDataBlobFetcher(std::move(native_session_fetcher),
+                               SessionDataBlobSource::kSessionCache);
+}
+
 void NavigationManagerImpl::OnNavigationItemCommitted() {
   NavigationItem* item = GetLastCommittedItemInCurrentOrRestoredSession();
   DCHECK(item);
@@ -435,8 +453,21 @@
     return false;
   }
 
-  if (!web::GetWebClient()->RestoreSessionFromCache(GetWebState()) &&
-      !synthesized_restore_helper_.Restore(GetWebState())) {
+  // Try to load session data blob from each registered source in order,
+  // stopping at the first that is successfully loaded.
+  bool success = false;
+  for (auto& [fetcher, source] : session_data_blob_fetchers_) {
+    NSData* data = std::move(fetcher).Run();
+    if (data.length != 0) {
+      success = GetWebState()->SetSessionStateData(data);
+      RecordSessionRestorationResultForSource(success, source);
+      if (success) {
+        break;
+      }
+    }
+  }
+
+  if (!success) {
     return false;
   }
 
@@ -1033,6 +1064,13 @@
       index, true /* create_if_missing */);
 }
 
+void NavigationManagerImpl::AppendSessionDataBlobFetcher(
+    SessionDataBlobFetcher fetcher,
+    SessionDataBlobSource source) {
+  session_data_blob_fetchers_.push_back(
+      std::make_pair(std::move(fetcher), source));
+}
+
 void NavigationManagerImpl::RestoreItemsState(
     RestoreItemListType list_type,
     std::vector<std::unique_ptr<NavigationItem>> items_restored) {
@@ -1085,16 +1123,19 @@
     RewriteItemURLIfNecessary(items[index].get());
   }
 
+  NSData* synthesized_data = SynthesizedSessionRestore(
+      last_committed_item_index, items, browser_state_->IsOffTheRecord());
+  if (synthesized_data != nil) {
+    AppendSessionDataBlobFetcher(
+        base::BindOnce([](NSData* data) { return data; }, synthesized_data),
+        SessionDataBlobSource::kSynthesized);
+  }
+
   // TODO(crbug.com/771200): Retain these original NavigationItems restored from
   // storage and associate them with new WKBackForwardListItems created after
   // history restore so information such as scroll position is restored.
-  int first_index = -1;
   GURL url;
-
-  bool off_the_record = browser_state_->IsOffTheRecord();
-  synthesized_restore_helper_.Init(last_committed_item_index, items,
-                                   off_the_record);
-
+  int first_index = -1;
   wk_navigation_util::CreateRestoreSessionUrl(last_committed_item_index, items,
                                               &url, &first_index);
   DCHECK_GE(first_index, 0);
@@ -1283,7 +1324,7 @@
 
 void NavigationManagerImpl::FinalizeSessionRestore() {
   is_restore_session_in_progress_ = false;
-  synthesized_restore_helper_.Clear();
+  session_data_blob_fetchers_.clear();
 
   for (base::OnceClosure& callback : restore_session_completion_callbacks_) {
     std::move(callback).Run();
diff --git a/ios/web/navigation/synthesized_session_restore.h b/ios/web/navigation/synthesized_session_restore.h
index 57e83c6a..7292e319 100644
--- a/ios/web/navigation/synthesized_session_restore.h
+++ b/ios/web/navigation/synthesized_session_restore.h
@@ -13,45 +13,18 @@
 namespace web {
 
 class NavigationItem;
-class WebState;
 
-// Class used to generate an NSData blob similar to what WKWebView uses in
-// -interactionState. This can be used to use native restore when the otherwise
-// cached `interactionState` is unavailable (for example, tab syncing).
+// Generates an NSData blob similar to what WKWebView uses in -interactionState.
+// This can be used to use native restore when the cached -interactionState is
+// missing (e.g. tab syncing).
+//
 // See
 // https://github.com/WebKit/WebKit/blob/674bd0ec/Source/WebKit/UIProcess/mac/LegacySessionStateCoding.cpp
 // for the basis of this implementation.
-class SynthesizedSessionRestore {
- public:
-  SynthesizedSessionRestore();
-  ~SynthesizedSessionRestore();
-
-  SynthesizedSessionRestore(const SynthesizedSessionRestore&) = delete;
-  SynthesizedSessionRestore& operator=(const SynthesizedSessionRestore&) =
-      delete;
-
-  // Generate and cache an NSData blob that can be later passed to WKWebView
-  // -interactionState.
-  void Init(int last_committed_item_index,
-            const std::vector<std::unique_ptr<NavigationItem>>& items,
-            bool off_the_record);
-
-  // Pass the archived NSData blob to WKWebView via the WebState API. Returns
-  // false if restore fails.
-  bool Restore(WebState* web_state);
-
-  // Release the cached NSData blob. This is called automatically on Restore,
-  // but may also be called if the synthesized data is not used (such as if a
-  // cached restore is successful).
-  void Clear() { cached_data_ = nil; }
-
- private:
-  // Returns true when running on iOS15 and when the kSynthesizedRestoreSession
-  // feature is enabled.
-  static bool IsEnabled();
-
-  NSData* cached_data_ = nil;
-};
+NSData* SynthesizedSessionRestore(
+    int last_committed_item_index,
+    const std::vector<std::unique_ptr<NavigationItem>>& items,
+    bool off_the_record);
 
 }  // namespace web
 
diff --git a/ios/web/navigation/synthesized_session_restore.mm b/ios/web/navigation/synthesized_session_restore.mm
index f71f84de..19aee7c 100644
--- a/ios/web/navigation/synthesized_session_restore.mm
+++ b/ios/web/navigation/synthesized_session_restore.mm
@@ -42,20 +42,18 @@
 
 namespace web {
 
-SynthesizedSessionRestore::SynthesizedSessionRestore() {}
-SynthesizedSessionRestore::~SynthesizedSessionRestore() {}
-
-void SynthesizedSessionRestore::Init(
+NSData* SynthesizedSessionRestore(
     int last_committed_item_index,
     const std::vector<std::unique_ptr<NavigationItem>>& items,
     bool off_the_record) {
-  if (!IsEnabled()) {
-    return;
+  if (!base::FeatureList::IsEnabled(
+          web::features::kSynthesizedRestoreSession)) {
+    return nil;
   }
 
   DCHECK(last_committed_item_index >= 0 &&
          last_committed_item_index < static_cast<int>(items.size()));
-  int external_url_policy = off_the_record ? 0 : 1;
+  NSNumber* const external_url_policy = off_the_record ? @0 : @1;
   NSMutableArray* entries =
       [[NSMutableArray alloc] initWithCapacity:items.size()];
   for (size_t i = 0; i < items.size(); i++) {
@@ -68,7 +66,7 @@
     [entries addObject:@{
       kEntryData : entry_data.AsNSData(),
       kEntryOriginalURL : base::SysUTF8ToNSString(item->GetURL().spec()),
-      kEntryExternalURLPolicy : @(external_url_policy),
+      kEntryExternalURLPolicy : external_url_policy,
       kEntryTitle : base::SysUTF16ToNSString(item->GetTitle()),
       kEntryURL : base::SysUTF8ToNSString(item->GetURL().spec()),
     }];
@@ -93,34 +91,7 @@
                    options:0
                      error:nil];
   [interaction_data appendData:property_list_data];
-  cached_data_ = interaction_data;
-}
-
-bool SynthesizedSessionRestore::Restore(WebState* web_state) {
-  if (!IsEnabled() || cached_data_.length == 0)
-    return false;
-  NSData* data = cached_data_;
-  cached_data_ = nil;
-
-  bool restore_session_succeeded = web_state->SetSessionStateData(data);
-  UMA_HISTOGRAM_BOOLEAN("Session.WebStates.NativeRestoreSession",
-                        restore_session_succeeded);
-  if (!restore_session_succeeded)
-    return false;
-
-  DCHECK(web_state->GetNavigationItemCount());
-  web::GetWebClient()->CleanupNativeRestoreURLs(web_state);
-  return true;
-}
-
-// static
-bool SynthesizedSessionRestore::IsEnabled() {
-  if (!base::FeatureList::IsEnabled(
-          web::features::kSynthesizedRestoreSession)) {
-    return false;
-  }
-
-  return base::ios::IsRunningOnIOS15OrLater();
+  return interaction_data;
 }
 
 }  // namespace web
diff --git a/ios/web/navigation/synthesized_session_restore_unittest.mm b/ios/web/navigation/synthesized_session_restore_unittest.mm
index b3514e4..3def122d 100644
--- a/ios/web/navigation/synthesized_session_restore_unittest.mm
+++ b/ios/web/navigation/synthesized_session_restore_unittest.mm
@@ -60,27 +60,19 @@
 
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<WebStateImpl> web_state_;
-  SynthesizedSessionRestore synthesized_restore_helper_;
 };
 
-TEST_F(SynthesizedSessionRestoreTest, TestLessThaniOS15) {
-  if (base::ios::IsRunningOnIOS15OrLater())
-    return;
-
-  std::vector<std::unique_ptr<NavigationItem>> items;
-  CreateTestNavigationItems(3, items);
-  synthesized_restore_helper_.Init(0, items, false);
-  EXPECT_FALSE(synthesized_restore_helper_.Restore(web_state_.get()));
-}
-
+// Test that the synthetic session data blob can be successfully loaded
+// by WebStateImpl and correctly restores the session.
 TEST_F(SynthesizedSessionRestoreTest, TestRestore) {
-  if (!base::ios::IsRunningOnIOS15OrLater())
-    return;
   std::vector<std::unique_ptr<NavigationItem>> items;
   CreateTestNavigationItems(100, items);
-  synthesized_restore_helper_.Init(0, items, false);
 
-  EXPECT_TRUE(synthesized_restore_helper_.Restore(web_state_.get()));
+  NSData* synthesized_data = SynthesizedSessionRestore(
+      /*last_committed_item_index=*/0, items, /*off_the_record=*/false);
+  EXPECT_GT(synthesized_data.length, 0u);
+
+  EXPECT_TRUE(web_state_->SetSessionStateData(synthesized_data));
   EXPECT_EQ(web_state_->GetNavigationItemCount(), 100);
 }
 
diff --git a/ios/web/public/web_client.h b/ios/web/public/web_client.h
index a22c838..46db4f2 100644
--- a/ios/web/public/web_client.h
+++ b/ios/web/public/web_client.h
@@ -27,6 +27,7 @@
 @protocol CRWFindSession;
 @protocol UITraitEnvironment;
 @class NSString;
+@class NSData;
 
 namespace net {
 class SSLInfo;
@@ -179,8 +180,9 @@
   virtual void LogDefaultUserAgent(web::WebState* web_state,
                                    const GURL& url) const;
 
-  // Returns true if URL was restored via session restoration cache.
-  virtual bool RestoreSessionFromCache(web::WebState* web_state) const;
+  // Fetches the session data blob from cache for `web_state`. Returns nil if
+  // the blob could not be loaded (missing, feature disabled, ...).
+  virtual NSData* FetchSessionFromCache(web::WebState* web_state) const;
 
   // Correct missing NTP and reading list virtualURLs and titles. Native session
   // restoration may not properly restore these items.
diff --git a/ios/web/web_client.mm b/ios/web/web_client.mm
index 9ff7a9e6..634ea5f 100644
--- a/ios/web/web_client.mm
+++ b/ios/web/web_client.mm
@@ -106,8 +106,8 @@
   return false;
 }
 
-bool WebClient::RestoreSessionFromCache(web::WebState* web_state) const {
-  return false;
+NSData* WebClient::FetchSessionFromCache(web::WebState* web_state) const {
+  return nil;
 }
 
 void WebClient::CleanupNativeRestoreURLs(web::WebState* web_state) const {}
diff --git a/ios/web/web_state/web_state_impl_realized_web_state.mm b/ios/web/web_state/web_state_impl_realized_web_state.mm
index 017c33a..7226c40 100644
--- a/ios/web/web_state/web_state_impl_realized_web_state.mm
+++ b/ios/web/web_state/web_state_impl_realized_web_state.mm
@@ -49,6 +49,19 @@
 #import "url/url_constants.h"
 
 namespace web {
+namespace {
+
+// Returns the session data blob from the cache for `weak_web_state`.
+NSData* FetchSessionDataBlob(base::WeakPtr<WebState> weak_web_state) {
+  web::WebState* web_state = weak_web_state.get();
+  if (!web_state) {
+    return nil;
+  }
+
+  return GetWebClient()->FetchSessionFromCache(web_state);
+}
+
+}  // namespace
 
 #pragma mark - WebStateImpl::RealizedWebState public methods
 
@@ -81,6 +94,11 @@
   // Restore session history last because NavigationManagerImpl relies on
   // CRWWebController to restore history into the web view.
   if (session_storage) {
+    // Set the callback used to load the native session data blob from the
+    // session cache.
+    navigation_manager_->SetNativeSessionFetcher(
+        base::BindOnce(&FetchSessionDataBlob, owner_->GetWeakPtr()));
+
     // Session storage restore is asynchronous because it involves a page
     // load in WKWebView. Temporarily cache the restored session so it can
     // be returned if BuildSessionStorage() or GetTitle() is called before
@@ -804,6 +822,8 @@
           failedNavigationURLFromErrorPageFileURL:item->GetURL()]);
     }
   }
+
+  web::GetWebClient()->CleanupNativeRestoreURLs(owner_);
   return true;
 }
 
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index f9b0f15..953b6acb 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -238,6 +238,12 @@
     "lacros-use-chromeos-protected-media";
 MEDIA_EXPORT extern const char kLacrosUseChromeosProtectedAv1[] =
     "lacros-use-chromeos-protected-av1";
+
+// Allows remote attestation (RA) in dev mode for testing purpose. Usually RA
+// is disabled in dev mode because it will always fail. However, there are cases
+// in testing where we do want to go through the permission flow even in dev
+// mode. This can be enabled by this flag.
+const char kAllowRAInDevMode[] = "allow-ra-in-dev-mode";
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace autoplay {
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index c61d765..d1b8902 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -97,6 +97,7 @@
 MEDIA_EXPORT extern const char kLacrosEnablePlatformHevc[];
 MEDIA_EXPORT extern const char kLacrosUseChromeosProtectedMedia[];
 MEDIA_EXPORT extern const char kLacrosUseChromeosProtectedAv1[];
+MEDIA_EXPORT extern const char kAllowRAInDevMode[];
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace autoplay {
diff --git a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
index 500e338..86aba162 100644
--- a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
+++ b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
@@ -31,7 +31,7 @@
 #define V4L2_REQUEST_CODE_AND_STRING(x) \
   { x, #x }
 
-constexpr uint32_t kMaximumDeviceNumber = 20;
+constexpr uint32_t kMaximumDeviceNumber = 40;
 
 constexpr base::StringPiece kDecoderDevicePrefix = "/dev/video";
 constexpr base::StringPiece kMediaDevicePrefix = "/dev/media";
diff --git a/net/dns/public/doh_provider_entry.cc b/net/dns/public/doh_provider_entry.cc
index e6671d8..eee76a4 100644
--- a/net/dns/public/doh_provider_entry.cc
+++ b/net/dns/public/doh_provider_entry.cc
@@ -128,7 +128,7 @@
       new DohProviderEntry(
           "Cox",
           MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(
-              DohProviderCox, base::FEATURE_DISABLED_BY_DEFAULT),
+              DohProviderCox, base::FEATURE_ENABLED_BY_DEFAULT),
           /*provider_id_for_histogram=*/absl::nullopt,
           {"68.105.28.11", "68.105.28.12", "2001:578:3f::30"},
           /*dns_over_tls_hostnames=*/{"dot.cox.net"},
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 8455853..bb86ea9 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2023-05-09 12:54 UTC
+# Last updated: 2023-05-14 12:55 UTC
 PinsListTimestamp
-1683636841
+1684068917
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -184,29 +184,6 @@
 USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg==
 -----END CERTIFICATE-----
 
-GeoTrustGlobal
------BEGIN CERTIFICATE-----
-MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
-MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
-aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
-WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
-AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
-OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
-T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
-JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
-Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
-PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
-aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
-TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
-LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
-BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
-dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
-AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
-NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
-b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
------END CERTIFICATE-----
-
 RapidSSL
 -----BEGIN CERTIFICATE-----
 MIID1TCCAr2gAwIBAgIDAjbRMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
@@ -561,28 +538,6 @@
 PQIDAQAB
 -----END PUBLIC KEY-----
 
-SpiderOak2
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1ACdmloAbzQugdO44I7l
-N5QHEeZIPpYE8W6T0u2bdcQLNKKbl6SzF7p1KcxGnUGYYSKoMTX+6FqQFxngUZlO
-KZL5NuDeHrtx5tACMFqJeMQcfyPufaerV7M7Qr6aMeNCaORVzt5VXHrl+quhSy7I
-kcxo7RSEnpX7v6+MEaRPlTF5ravRd88b/FH9DBwSGjGky3cap4DC0IxSN+QbEjLj
-BcoOPQa79q1UkgmD/5BkhxfMBGczT7VudfArKKyZNEeYmP6itrGy2BdIBSkw+XPL
-Hs5+68eGpG74cdV3HjvhDPTD/OP+hgGHRQOmcOd0Y1vayW9i3+B7qiUvCngzfiIt
-ZQIDAQAB
------END PUBLIC KEY-----
-
-SpiderOak3
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3uV1DNSAfxGyfqhF2XkD
-F/ADpxyl11guzjBlsVyaAXByxV72rPR2a09XlLiobFrp/9jF9om9lEtujBsaVDjg
-ga8EqVxGV++RxJalAnk3KsKrGQAS6IiOMvkZ2jm0F7+77+oSW8+FQB4NjdMH2lfg
-ysqpS9SqP8zQoypnUZalR89ZGf6pjCbKM1ZQWGjBC03B5JRdEoPjULzzBB/e2igM
-Vchpq1U6WS8/WGgtiDNXS43Bx0Nka41KLIk4Pv8VSy7Jfxu6i33+SuA7cDP1oTK9
-aFE/tQpQ/YVB8aQ9+2vGoBDv9bFF+bxMmQyFtST3SUvKLhgeRqLraEd8OPfEizYl
-PwIDAQAB
------END PUBLIC KEY-----
-
 # From https://letsencrypt.org/certificates/
 # The key is shared by Let's Encrypt Authority X1 and X3.
 LetsEncryptAuthorityPrimary_X1_X3
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json
index ad83d6e..b85d210 100644
--- a/net/http/transport_security_state_static_pins.json
+++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@
 // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets'
 // refer to, and the timestamp at which the pins list was last updated.
 //
-// Last updated: 2023-05-09 12:54 UTC
+// Last updated: 2023-05-14 12:55 UTC
 //
 {
   "pinsets": [
@@ -84,15 +84,6 @@
       ]
     },
     {
-      "name": "spideroak",
-      "static_spki_hashes": [
-        "GeoTrustGlobal",
-        "DigiCertEVRoot",
-        "SpiderOak2",
-        "SpiderOak3"
-      ]
-    },
-    {
       "name": "yahoo",
       "static_spki_hashes": [
         "DigiCertAssuredIDRoot",
@@ -2412,11 +2403,6 @@
       "name": "dist.torproject.org",
       "include_subdomains": true,
       "pins": "tor"
-    },
-    {
-      "name": "spideroak.com",
-      "include_subdomains": true,
-      "pins": "spideroak"
     }
   ]
 }
\ No newline at end of file
diff --git a/net/socket/connect_job.h b/net/socket/connect_job.h
index 35c0f499..2f810362 100644
--- a/net/socket/connect_job.h
+++ b/net/socket/connect_job.h
@@ -110,7 +110,7 @@
 // ConnectJob synchronously, but may signal the ConnectJob may be destroyed
 // asynchronously. See OnHostResolutionCallbackResult above.
 //
-// |address_list| is the list of addresses the host being connected to was
+// `endpoint_results` is the list of endpoints the host being connected to was
 // resolved to, with the port fields populated to the port being connected to.
 using OnHostResolutionCallback =
     base::RepeatingCallback<OnHostResolutionCallbackResult(
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 74df33f..b7c031ab9 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -758,11 +758,10 @@
                            int32_t /* id */)
 // The receiver of this message takes ownership of the front buffer of the GL
 // context. Each call to PpapiHostMsg_PPBGraphics3D_SwapBuffers must be preceded
-// by exactly one call to PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer. The
-// SyncToken passed to PpapiHostMsg_PPBGraphics3D_SwapBuffers must be generated
-// after this message is sent.
-IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer,
-                    ppapi::HostResource /* graphics_3d */)
+// by exactly one call to
+// PpapiHostMsg_PPBGraphics3D_ResolveAndDetachFramebuffer. The SyncToken passed
+// to PpapiHostMsg_PPBGraphics3D_SwapBuffers must be generated after this
+// message is sent.
 IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
                     ppapi::HostResource /* graphics_3d */,
                     gpu::SyncToken /* sync_token */,
diff --git a/ppapi/proxy/ppb_graphics_3d_proxy.cc b/ppapi/proxy/ppb_graphics_3d_proxy.cc
index 50a63e8..3b07865 100644
--- a/ppapi/proxy/ppb_graphics_3d_proxy.cc
+++ b/ppapi/proxy/ppb_graphics_3d_proxy.cc
@@ -46,17 +46,8 @@
 
 }  // namespace
 
-Graphics3D::Graphics3D(const HostResource& resource,
-                       const gfx::Size& size,
-                       const bool single_buffer,
-                       bool use_shared_images_swapchain)
-    : PPB_Graphics3D_Shared(resource, size, use_shared_images_swapchain),
-      single_buffer(single_buffer) {
-  // This log is to make diagnosing any outages for Enterprise customers
-  // easier.
-  LOG(WARNING) << "Graphics3D initialized. use_shared_images_swapchain: "
-               << use_shared_images_swapchain_;
-}
+Graphics3D::Graphics3D(const HostResource& resource, const gfx::Size& size)
+    : PPB_Graphics3D_Shared(resource, size) {}
 
 Graphics3D::~Graphics3D() {
   DestroyGLES2Impl();
@@ -115,10 +106,6 @@
   NOTREACHED();
 }
 
-void Graphics3D::TakeFrontBuffer() {
-  NOTREACHED();
-}
-
 void Graphics3D::ResolveAndDetachFramebuffer() {
   NOTREACHED();
 }
@@ -138,23 +125,13 @@
 
   gpu::gles2::GLES2Implementation* gl = gles2_impl();
 
-  if (use_shared_images_swapchain_) {
-    // Flush current GL commands.
-    gl->ShallowFlushCHROMIUM();
+  // Flush current GL commands.
+  gl->ShallowFlushCHROMIUM();
 
-    // Make sure we resolved and detached our frame buffer
-    PluginDispatcher::GetForResource(this)->Send(
-        new PpapiHostMsg_PPBGraphics3D_ResolveAndDetachFramebuffer(
-            API_ID_PPB_GRAPHICS_3D, host_resource()));
-  } else {
-    gl->SwapBuffers(swap_id_++);
-
-    if (!single_buffer || swap_id_ == 1) {
-      PluginDispatcher::GetForResource(this)->Send(
-          new PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer(API_ID_PPB_GRAPHICS_3D,
-                                                         host_resource()));
-    }
-  }
+  // Make sure we resolved and detached our frame buffer
+  PluginDispatcher::GetForResource(this)->Send(
+      new PpapiHostMsg_PPBGraphics3D_ResolveAndDetachFramebuffer(
+          API_ID_PPB_GRAPHICS_3D, host_resource()));
 
   gpu::SyncToken new_sync_token;
   gl->GenSyncTokenCHROMIUM(new_sync_token.GetData());
@@ -168,7 +145,6 @@
 }
 
 void Graphics3D::DoResize(gfx::Size size) {
-  DCHECK(use_shared_images_swapchain_);
   // Flush current GL commands.
   gles2_impl()->ShallowFlushCHROMIUM();
   PluginDispatcher::GetForResource(this)->Send(
@@ -275,9 +251,7 @@
     return 0;
 
   scoped_refptr<Graphics3D> graphics_3d(
-      new Graphics3D(result, attrib_helper.offscreen_framebuffer_size,
-                     attrib_helper.single_buffer,
-                     capabilities.use_shared_images_swapchain_for_ppapi));
+      new Graphics3D(result, attrib_helper.offscreen_framebuffer_size));
   if (!graphics_3d->Init(share_gles2, capabilities, std::move(shared_state),
                          command_buffer_id)) {
     return 0;
@@ -304,8 +278,6 @@
                         OnMsgDestroyTransferBuffer)
     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
                         OnMsgSwapBuffers)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer,
-                        OnMsgTakeFrontBuffer)
     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_ResolveAndDetachFramebuffer,
                         OnMsgResolveAndDetachFramebuffer)
     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Resize, OnMsgResize)
@@ -438,12 +410,6 @@
         enter.callback(), sync_token, size));
 }
 
-void PPB_Graphics3D_Proxy::OnMsgTakeFrontBuffer(const HostResource& context) {
-  EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
-  if (enter.succeeded())
-    enter.object()->TakeFrontBuffer();
-}
-
 void PPB_Graphics3D_Proxy::OnMsgResolveAndDetachFramebuffer(
     const HostResource& context) {
   EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
diff --git a/ppapi/proxy/ppb_graphics_3d_proxy.h b/ppapi/proxy/ppb_graphics_3d_proxy.h
index 8543a45f..5cba0779 100644
--- a/ppapi/proxy/ppb_graphics_3d_proxy.h
+++ b/ppapi/proxy/ppb_graphics_3d_proxy.h
@@ -36,10 +36,7 @@
 
 class PPAPI_PROXY_EXPORT Graphics3D : public PPB_Graphics3D_Shared {
  public:
-  Graphics3D(const HostResource& resource,
-             const gfx::Size& size,
-             const bool single_buffer,
-             bool use_shared_images_swapchain);
+  Graphics3D(const HostResource& resource, const gfx::Size& size);
 
   Graphics3D(const Graphics3D&) = delete;
   Graphics3D& operator=(const Graphics3D&) = delete;
@@ -64,7 +61,6 @@
       int32_t start,
       int32_t end) override;
   void EnsureWorkVisible() override;
-  void TakeFrontBuffer() override;
   void ResolveAndDetachFramebuffer() override;
 
  private:
@@ -76,9 +72,6 @@
   void DoResize(gfx::Size size) override;
 
   std::unique_ptr<PpapiCommandBufferProxy> command_buffer_;
-
-  uint64_t swap_id_ = 0;
-  bool single_buffer = false;
 };
 
 class PPB_Graphics3D_Proxy : public InterfaceProxy {
@@ -130,7 +123,6 @@
   void OnMsgSwapBuffers(const HostResource& context,
                         const gpu::SyncToken& sync_token,
                         const gfx::Size& size);
-  void OnMsgTakeFrontBuffer(const HostResource& context);
   void OnMsgEnsureWorkVisible(const HostResource& context);
   void OnMsgResolveAndDetachFramebuffer(const HostResource& context);
   void OnMsgResize(const HostResource& context, gfx::Size size);
diff --git a/ppapi/proxy/video_decoder_resource_unittest.cc b/ppapi/proxy/video_decoder_resource_unittest.cc
index 5414245..c4fdd50 100644
--- a/ppapi/proxy/video_decoder_resource_unittest.cc
+++ b/ppapi/proxy/video_decoder_resource_unittest.cc
@@ -96,8 +96,7 @@
     HostResource host_resource;
     host_resource.SetHostResource(pp_instance(), kGraphics3D);
     scoped_refptr<ppapi::proxy::Graphics3D> graphics_3d(
-        new ppapi::proxy::Graphics3D(host_resource, gfx::Size(640, 480), false,
-                                     false));
+        new ppapi::proxy::Graphics3D(host_resource, gfx::Size(640, 480)));
 
     return graphics_3d->GetReference();
   }
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
index 29e2f66..bb566b6 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
@@ -15,17 +15,12 @@
 
 namespace ppapi {
 
-PPB_Graphics3D_Shared::PPB_Graphics3D_Shared(PP_Instance instance,
-                                             bool use_shared_images_swapchain)
-    : Resource(OBJECT_IS_IMPL, instance),
-      use_shared_images_swapchain_(use_shared_images_swapchain) {}
+PPB_Graphics3D_Shared::PPB_Graphics3D_Shared(PP_Instance instance)
+    : Resource(OBJECT_IS_IMPL, instance) {}
 
 PPB_Graphics3D_Shared::PPB_Graphics3D_Shared(const HostResource& host_resource,
-                                             const gfx::Size& size,
-                                             bool use_shared_images_swapchain)
-    : Resource(OBJECT_IS_PROXY, host_resource),
-      use_shared_images_swapchain_(use_shared_images_swapchain),
-      size_(size) {}
+                                             const gfx::Size& size)
+    : Resource(OBJECT_IS_PROXY, host_resource), size_(size) {}
 
 PPB_Graphics3D_Shared::~PPB_Graphics3D_Shared() {
   // Make sure that GLES2 implementation has already been destroyed.
@@ -59,11 +54,8 @@
 
   size_ = gfx::Size(width, height);
 
-  if (use_shared_images_swapchain_) {
-    DoResize(size_);
-  } else {
-    gles2_impl()->ResizeCHROMIUM(width, height, 1.f, nullptr, true);
-  }
+  DoResize(size_);
+
   // TODO(alokp): Check if resize succeeded and return appropriate error code.
   return PP_OK;
 }
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.h b/ppapi/shared_impl/ppb_graphics_3d_shared.h
index 2fcd635c..78dc774 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.h
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.h
@@ -68,10 +68,9 @@
   void SwapBuffersACK(int32_t pp_error);
 
  protected:
-  PPB_Graphics3D_Shared(PP_Instance instance, bool use_shared_images_swapchain);
+  explicit PPB_Graphics3D_Shared(PP_Instance instance);
   PPB_Graphics3D_Shared(const HostResource& host_resource,
-                        const gfx::Size& size,
-                        bool use_shared_images_swapchain);
+                        const gfx::Size& size);
   ~PPB_Graphics3D_Shared() override;
 
   virtual gpu::CommandBuffer* GetCommandBuffer() = 0;
@@ -84,8 +83,6 @@
   bool CreateGLES2Impl(gpu::gles2::GLES2Implementation* share_gles2);
   void DestroyGLES2Impl();
 
-  const bool use_shared_images_swapchain_;
-
  private:
   std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
   std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
diff --git a/ppapi/thunk/ppb_graphics_3d_api.h b/ppapi/thunk/ppb_graphics_3d_api.h
index a44adcb..487d1792 100644
--- a/ppapi/thunk/ppb_graphics_3d_api.h
+++ b/ppapi/thunk/ppb_graphics_3d_api.h
@@ -69,7 +69,6 @@
   virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) = 0;
 
   virtual void EnsureWorkVisible() = 0;
-  virtual void TakeFrontBuffer() = 0;
   virtual void ResolveAndDetachFramebuffer() = 0;
 };
 
diff --git a/remoting/base/file_host_settings.cc b/remoting/base/file_host_settings.cc
index 392a0f7..f6d2c064 100644
--- a/remoting/base/file_host_settings.cc
+++ b/remoting/base/file_host_settings.cc
@@ -7,7 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
 #include "base/json/json_file_value_serializer.h"
-#include "base/json/json_string_value_serializer.h"
+#include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/values.h"
@@ -33,12 +33,19 @@
   JSONFileValueDeserializer deserializer(settings_file_);
   int error_code;
   std::string error_message;
-  settings_ = deserializer.Deserialize(&error_code, &error_message);
-  if (!settings_) {
+  std::unique_ptr<base::Value> settings =
+      deserializer.Deserialize(&error_code, &error_message);
+  if (!settings) {
     LOG(WARNING) << "Failed to load " << settings_file_
                  << ". Code: " << error_code << ", message: " << error_message;
     return;
   }
+  if (!settings->is_dict()) {
+    LOG(WARNING) << "Settings loaded from " << settings_file_
+                 << " are not a valid json dictionary.";
+    return;
+  }
+  settings_ = std::move(*settings).TakeDict();
   HOST_LOG << "Host settings loaded.";
 }
 
@@ -56,7 +63,7 @@
                "doesn't exist.";
     return default_value;
   }
-  std::string* string_value = settings_->GetDict().FindString(key);
+  const std::string* string_value = settings_->FindString(key);
   if (!string_value) {
     return default_value;
   }
@@ -76,17 +83,16 @@
 
   if (!settings_) {
     VLOG(1) << "Settings file didn't exist. New file will be created.";
-    settings_ = std::make_unique<base::Value>(base::Value::Type::DICT);
+    settings_ = base::Value::Dict();
   }
-  settings_->SetStringKey(key, value);
+  settings_->Set(key, value);
 
-  std::string json;
-  JSONStringValueSerializer serializer(&json);
-  if (!serializer.Serialize(*settings_)) {
+  auto json = base::WriteJson(*settings_);
+  if (!json) {
     LOG(ERROR) << "Failed to serialize host settings JSON";
     return;
   }
-  if (!base::ImportantFileWriter::WriteFileAtomically(settings_file_, json)) {
+  if (!base::ImportantFileWriter::WriteFileAtomically(settings_file_, *json)) {
     LOG(ERROR) << "Can't write host settings file to " << settings_file_;
   }
 }
diff --git a/remoting/base/file_host_settings.h b/remoting/base/file_host_settings.h
index ad8bbd0..26cebb1 100644
--- a/remoting/base/file_host_settings.h
+++ b/remoting/base/file_host_settings.h
@@ -9,12 +9,9 @@
 
 #include "base/files/file_path.h"
 #include "base/task/sequenced_task_runner.h"
+#include "base/values.h"
 #include "remoting/base/host_settings.h"
 
-namespace base {
-class Value;
-}
-
 namespace remoting {
 
 // An implementation of HostSettings that reads settings from a JSON file.
@@ -45,7 +42,7 @@
 
   // TODO(yuweih): This needs to be guarded with a lock if we detect changes of
   // the settings file.
-  std::unique_ptr<base::Value> settings_;
+  absl::optional<base::Value::Dict> settings_;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc b/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
index d50f25e8..1c1e7e41 100644
--- a/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
+++ b/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
@@ -26,15 +26,15 @@
 
 namespace {
 
-base::Value CreateWebAuthnExceptionDetailsDict(const std::string& name,
-                                               const std::string& message) {
-  base::Value details(base::Value::Type::DICT);
-  details.SetStringKey(kWebAuthnErrorNameKey, name);
-  details.SetStringKey(kWebAuthnErrorMessageKey, message);
-  return details;
+base::Value::Dict CreateWebAuthnExceptionDetailsDict(
+    const std::string& name,
+    const std::string& message) {
+  return base::Value::Dict()
+      .Set(kWebAuthnErrorNameKey, name)
+      .Set(kWebAuthnErrorMessageKey, message);
 }
 
-base::Value MojoErrorToErrorDict(
+base::Value::Dict MojoErrorToErrorDict(
     const mojom::WebAuthnExceptionDetailsPtr& mojo_error) {
   return CreateWebAuthnExceptionDetailsDict(mojo_error->name,
                                             mojo_error->message);
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 2315df4..c1421d8 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -347,6 +347,10 @@
   }
 
   if (is_android) {
+    sources += [
+      "empty_network_service.cc",
+      "empty_network_service.h",
+    ]
     deps += [
       "//crypto",
       "//third_party/boringssl",
diff --git a/services/network/empty_network_service.cc b/services/network/empty_network_service.cc
new file mode 100644
index 0000000..0b642a2
--- /dev/null
+++ b/services/network/empty_network_service.cc
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/empty_network_service.h"
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/service_factory.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+
+namespace network {
+namespace {
+
+class EmptyNetworkService : public network::mojom::EmptyNetworkService {
+ public:
+  explicit EmptyNetworkService(
+      mojo::PendingReceiver<network::mojom::EmptyNetworkService> receiver) {
+    receiver_.Bind(std::move(receiver));
+  }
+
+ private:
+  // network::mojom::EmptyNetworkService implementation:
+  void Ping(int32_t value, PingCallback callback) override {
+    std::move(callback).Run(value);
+  }
+  mojo::Receiver<network::mojom::EmptyNetworkService> receiver_{this};
+};
+
+std::unique_ptr<network::mojom::EmptyNetworkService> RunEmptyNetworkService(
+    mojo::PendingReceiver<network::mojom::EmptyNetworkService> receiver) {
+  return std::make_unique<EmptyNetworkService>(std::move(receiver));
+}
+}  // namespace
+
+void RegisterEmptyNetworkService(mojo::ServiceFactory& services) {
+  services.Add(RunEmptyNetworkService);
+}
+}  // namespace network
diff --git a/services/network/empty_network_service.h b/services/network/empty_network_service.h
new file mode 100644
index 0000000..d0dc4efc
--- /dev/null
+++ b/services/network/empty_network_service.h
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_EMPTY_NETWORK_SERVICE_H_
+#define SERVICES_NETWORK_EMPTY_NETWORK_SERVICE_H_
+
+#include "base/component_export.h"
+
+namespace mojo {
+class ServiceFactory;
+}  // namespace mojo
+
+namespace network {
+COMPONENT_EXPORT(NETWORK_SERVICE)
+void RegisterEmptyNetworkService(mojo::ServiceFactory& services);
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_EMPTY_NETWORK_SERVICE_H_
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 648dc6395..b9e9b30 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/system/sys_info.h"
-#include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "net/base/mime_sniffer.h"
 
@@ -322,5 +321,9 @@
 BASE_FEATURE(kLessChattyNetworkService,
              "LessChattyNetworkService",
              base::FEATURE_DISABLED_BY_DEFAULT);
-
+#if BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kNetworkServiceEmptyOutOfProcess,
+             "NetworkServiceEmptyOutOfProcess",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
 }  // namespace network::features
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index c5b2d09..50ed51a 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 
 namespace network {
 namespace features {
@@ -135,6 +136,12 @@
 // Decrease Mojo calls from network service to browser.
 COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kLessChattyNetworkService);
 
+#if BUILDFLAG(IS_ANDROID)
+// Create empty network service out of process only if canonical network service
+// is in process to see process overhead on Android.
+COMPONENT_EXPORT(NETWORK_CPP)
+BASE_DECLARE_FEATURE(kNetworkServiceEmptyOutOfProcess);
+#endif
 }  // namespace features
 }  // namespace network
 
diff --git a/services/network/public/cpp/request_destination.cc b/services/network/public/cpp/request_destination.cc
index 648c827..518b3d6 100644
--- a/services/network/public/cpp/request_destination.cc
+++ b/services/network/public/cpp/request_destination.cc
@@ -61,6 +61,8 @@
       return "fencedframe";
     case network::mojom::RequestDestination::kWebIdentity:
       return "webidentity";
+    case network::mojom::RequestDestination::kDictionary:
+      return "dictionary";
   }
 }
 
diff --git a/services/network/public/mojom/fetch_api.mojom b/services/network/public/mojom/fetch_api.mojom
index 85617eb..2782f348 100644
--- a/services/network/public/mojom/fetch_api.mojom
+++ b/services/network/public/mojom/fetch_api.mojom
@@ -66,6 +66,8 @@
   // Requests from the federated credential management API,
   // https://fedidcg.github.io/FedCM/
   kWebIdentity = 23,
+  // Requests for compression dictionary
+  kDictionary = 24,
 };
 
 // Corresponds to Fetch request's "redirect mode":
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 84d73ea..63a0180 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -374,3 +374,12 @@
   // enabled.
   EnableDataUseUpdates(bool enable);
 };
+
+// Service that tests new process overhead on Android.
+// TODO(http://crbug.com/1395707): Remove this once
+// --disable-features=NetworkServiceInProcess2 is launched stable.
+[EnableIf=is_android, ServiceSandbox=sandbox.mojom.Sandbox.kNetwork]
+interface EmptyNetworkService {
+  // Test function to check if the service is available. Returns same `value`.
+  Ping(int32 value) => (int32 value);
+};
diff --git a/services/test/echo/BUILD.gn b/services/test/echo/BUILD.gn
index 2bc5cb7..35d91bb 100644
--- a/services/test/echo/BUILD.gn
+++ b/services/test/echo/BUILD.gn
@@ -1,6 +1,8 @@
 # Copyright 2017 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+import("//build/config/compiler/compiler.gni")
+import("//testing/test.gni")
 
 source_set("lib") {
   sources = [
@@ -15,3 +17,27 @@
     "//services/test/echo/public/mojom",
   ]
 }
+
+if (is_win) {
+  shared_library("echo_preload_library") {
+    testonly = true
+
+    sources = [
+      "echo_preload_library.def",
+      "echo_preload_library_win.cc",
+    ]
+
+    if (!is_asan && !use_clang_profiling) {
+      no_default_deps = true
+    }
+
+    # Keep this a tiny dll as it does very little.
+    assert_no_deps = [
+      "//third_party/abseil-cpp:absl",
+      "//third_party/perfetto:libperfetto",
+    ]
+
+    libs = [ "secur32.lib" ]
+    ldflags = [ "/delayload:secur32.dll" ]
+  }
+}
diff --git a/services/test/echo/echo_preload_library.def b/services/test/echo/echo_preload_library.def
new file mode 100644
index 0000000..f0da9a4b
--- /dev/null
+++ b/services/test/echo/echo_preload_library.def
@@ -0,0 +1,8 @@
+; Copyright 2023 The Chromium Authors
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+LIBRARY  "echo_preload_library.dll"
+
+EXPORTS
+  ; These are required for the echo service test.
+  FnCallsDelayloadFn
diff --git a/services/test/echo/echo_preload_library_win.cc b/services/test/echo/echo_preload_library_win.cc
new file mode 100644
index 0000000..6d02191
--- /dev/null
+++ b/services/test/echo/echo_preload_library_win.cc
@@ -0,0 +1,27 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a small file to make a loadable dll for the echo service tests.
+#include <windows.h>
+
+#define SECURITY_WIN32
+#include <security.h>
+
+extern "C" {
+BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
+  return true;
+}
+
+BOOL FnCallsDelayloadFn() {
+  // Calls xyz which is delayloaded but in a library already in
+  // utility processes.
+  ULONG sz = 0;
+  wchar_t buf[1];
+  // This call should happen, we don't actually care about the return.
+  if (::GetUserNameExW(NameSamCompatible, buf, &sz)) {
+    return false;
+  }
+  return true;
+}
+}  // extern "C"
diff --git a/services/test/echo/echo_service.cc b/services/test/echo/echo_service.cc
index 2baaa1fe..069cb1d0 100644
--- a/services/test/echo/echo_service.cc
+++ b/services/test/echo/echo_service.cc
@@ -11,6 +11,8 @@
 #if BUILDFLAG(IS_WIN)
 #include <windows.h>
 #include <winevt.h>
+
+#include "base/native_library.h"
 #endif
 
 #include <string>
@@ -49,6 +51,41 @@
   EVT_HANDLE handle = ::EvtCreateRenderContext(0, nullptr, 0);
   ::EvtClose(handle);
 }
+
+void EchoService::LoadNativeLibrary(const ::base::FilePath& library,
+                                    bool call_sec32_delayload,
+                                    LoadNativeLibraryCallback callback) {
+  // This attempts to load a library inside the sandbox - it should fail unless
+  // the library was in `ServiceProcessHostOptions::WithPreloadedLibraries()`.
+  base::NativeLibraryLoadError error;
+  // We leak the module as preloading already leaked it.
+  HMODULE hmod = base::LoadNativeLibrary(library, &error);
+  if (!hmod) {
+    std::move(callback).Run(LoadStatus::kFailedLoadLibrary, error.code);
+    return;
+  }
+
+  // Calls an exported function that calls a delayloaded function that should
+  // be loaded in the utility (as secur32.dll is imported by chrome.dll).
+  if (call_sec32_delayload) {
+    BOOL(WINAPI * fn)() = nullptr;
+    fn = reinterpret_cast<decltype(fn)>(
+        GetProcAddress(hmod, "FnCallsDelayloadFn"));
+    if (!fn) {
+      std::move(callback).Run(LoadStatus::kFailedGetProcAddress,
+                              GetLastError());
+      return;
+    }
+    BOOL ret = fn();
+    if (!ret) {
+      std::move(callback).Run(LoadStatus::kFailedCallingDelayLoad,
+                              GetLastError());
+      return;
+    }
+  }
+  std::move(callback).Run(LoadStatus::kSuccess, ERROR_SUCCESS);
+}
+
 #endif  // BUILDFLAG(IS_WIN)
 
 }  // namespace echo
diff --git a/services/test/echo/echo_service.h b/services/test/echo/echo_service.h
index 8351508a..6edccfd 100644
--- a/services/test/echo/echo_service.h
+++ b/services/test/echo/echo_service.h
@@ -31,6 +31,9 @@
   void Crash() override;
 #if BUILDFLAG(IS_WIN)
   void DelayLoad() override;
+  void LoadNativeLibrary(const ::base::FilePath& library,
+                         bool call_sec32_fn,
+                         LoadNativeLibraryCallback callback) override;
 #endif
 
   mojo::Receiver<mojom::EchoService> receiver_;
diff --git a/services/test/echo/public/mojom/echo.mojom b/services/test/echo/public/mojom/echo.mojom
index ff14a761..1b8e3f2 100644
--- a/services/test/echo/public/mojom/echo.mojom
+++ b/services/test/echo/public/mojom/echo.mojom
@@ -4,6 +4,7 @@
 
 module echo.mojom;
 
+import "mojo/public/mojom/base/file_path.mojom";
 import "mojo/public/mojom/base/shared_memory.mojom";
 import "sandbox/policy/mojom/sandbox.mojom";
 
@@ -26,4 +27,23 @@
   // Delay Load a DLL.
   [EnableIf=is_win]
   DelayLoad();
+
+  // Helper to validate that the right failure happens in some tests.
+  enum LoadStatus {
+    kSuccess,
+    kFailedLoadLibrary,
+    kFailedGetProcAddress,
+    kFailedCallingDelayLoad,
+  };
+  // Attempts to load a library by path - kService should prevent this unless it
+  // was preloaded into the utility at service startup.
+  // `library` is a library path or module name to attempt to load.
+  // `call_sec32_delayload` - if true will attempt to call the function
+  // `FnCallsDelayloadFn` in the library, which in turn attempts to call a
+  // delayloaded function in secur32.dll.
+  // `status` indicates where a failure occurred, or kSuccess.
+  // `error_code` is the last error, or 0 on success.
+  [EnableIf=is_win]
+  LoadNativeLibrary(mojo_base.mojom.FilePath library, bool call_sec32_delayload)
+   => (LoadStatus status, uint32 error_code);
 };
diff --git a/styleguide/c++/c++-dos-and-donts.md b/styleguide/c++/c++-dos-and-donts.md
index 341ed59..a9b156d 100644
--- a/styleguide/c++/c++-dos-and-donts.md
+++ b/styleguide/c++/c++-dos-and-donts.md
@@ -68,8 +68,9 @@
 
 ## Variable initialization
 
-There are myriad ways to initialize variables in C++11.  Prefer the following
+There are myriad ways to initialize variables in C++. Prefer the following
 general rules:
+
 1. Use assignment syntax when performing "simple" initialization with one or
    more literal values which will simply be composed into the object:
 
@@ -126,6 +127,9 @@
    auto x{1};  // Until C++17, decltype(x) is std::initializer_list<int>, not int!
    ```
 
+For more reading, please see abseil's [Tip of the Week #88: Initialization: =,
+(), and {}](https://abseil.io/tips/88).
+
 ## Initialize members in the declaration where possible
 
 If possible, initialize class members in their declarations, except where a
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8965f2c..0dd4685 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5730,9 +5730,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5743,8 +5743,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -5895,9 +5895,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5908,8 +5908,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -6042,9 +6042,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6055,8 +6055,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 42639fa5..8425afe 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25491,9 +25491,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25504,8 +25504,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -25656,9 +25656,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25669,8 +25669,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -25803,9 +25803,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25816,8 +25816,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index e676520..ad01fe4 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41382,9 +41382,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41394,8 +41394,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -41547,9 +41547,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41559,8 +41559,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -41694,9 +41694,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41706,8 +41706,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -43171,9 +43171,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43183,8 +43183,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -43336,9 +43336,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43348,8 +43348,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -43483,9 +43483,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43495,8 +43495,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -44231,9 +44231,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44243,8 +44243,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index db344f8..bb30e60 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18080,12 +18080,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18096,8 +18096,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -18265,12 +18265,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18281,8 +18281,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
@@ -18427,12 +18427,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 115.0.5767.0",
+        "description": "Run with ash-chrome version 115.0.5772.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18443,8 +18443,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v115.0.5767.0",
-              "revision": "version:115.0.5767.0"
+              "location": "lacros_version_skew_tests_v115.0.5772.0",
+              "revision": "version:115.0.5772.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/filters/pixel_tests.filter b/testing/buildbot/filters/pixel_tests.filter
index fb63e9b..cfb7364f 100644
--- a/testing/buildbot/filters/pixel_tests.filter
+++ b/testing/buildbot/filters/pixel_tests.filter
@@ -70,6 +70,7 @@
 RelaunchRecommendedBubbleViewDialogTest.*
 RelaunchRequiredDialogViewDialogTest.*
 ReopenTabPromoControllerDialogBrowserTest.*
+SAAEnabledPermissionPromptBubbleViewBrowserTest.*
 SafetyTipPageInfoBubbleViewDialogTest.*
 ScreenCaptureNotificationUiBrowserTest.*
 SecurePaymentConfirmationDialogViewTest.InvokeUi_*
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 9f0b59a6..e52d97ce 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5767.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5772.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 115.0.5767.0',
+    'description': 'Run with ash-chrome version 115.0.5772.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v115.0.5767.0',
-          'revision': 'version:115.0.5767.0',
+          'location': 'lacros_version_skew_tests_v115.0.5772.0',
+          'revision': 'version:115.0.5772.0',
         },
       ],
     },
diff --git a/testing/scripts/run_variations_smoke_tests.py b/testing/scripts/run_variations_smoke_tests.py
index 0c5c21d..8a4d7e2c 100755
--- a/testing/scripts/run_variations_smoke_tests.py
+++ b/testing/scripts/run_variations_smoke_tests.py
@@ -22,21 +22,24 @@
 from pkg_resources import packaging
 from threading import Thread
 
+_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+_CHROMIUM_SRC_DIR = os.path.realpath(os.path.join(_THIS_DIR, '..', '..'))
+# Needed for skia_gold_common import.
+sys.path.append(os.path.join(_CHROMIUM_SRC_DIR, 'build'))
+# Needed to import common without pylint errors.
+sys.path.append(os.path.join(_CHROMIUM_SRC_DIR, 'testing'))
+
 import pkg_resources
 from skia_gold_common.skia_gold_properties import SkiaGoldProperties
 from skia_gold_infra import finch_skia_gold_utils
 
 import variations_seed_access_helper as seed_helper
 
-_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 _VARIATIONS_TEST_DATA = 'variations_smoke_test_data'
 _VERSION_STRING = 'PRODUCT_VERSION'
 _FLAG_RELEASE_VERSION = packaging.version.parse('105.0.5176.3')
 
 
-# Add src/testing/ into sys.path for importing common without pylint errors.
-sys.path.append(
-    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
 from scripts import common
 
 from selenium import webdriver
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index e7c4138d..9ff080a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3675,6 +3675,21 @@
             ]
         }
     ],
+    "CrashOnInProcessANGLEContextLoss": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CrashOnInProcessANGLEContextLoss"
+                    ]
+                }
+            ]
+        }
+    ],
     "CrashReportBreadcrumbs": [
         {
             "platforms": [
@@ -4603,27 +4618,6 @@
             ]
         }
     ],
-    "DnsOverHttpsCox": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DohProviderCox"
-                    ]
-                }
-            ]
-        }
-    ],
     "DnsOverHttpsUi": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 69aee5d..8f5fff0 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1547,7 +1547,7 @@
 
 BASE_FEATURE(kWebRtcEncoderAsyncEncode,
              "WebRtcEncoderAsyncEncode",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kWebRtcInitializeEncoderOnFirstFrame,
              "WebRtcInitializeEncoderOnFirstFrame",
diff --git a/third_party/blink/public/common/origin_trials/origin_trials.h b/third_party/blink/public/common/origin_trials/origin_trials.h
index 88da27e..a91105d9 100644
--- a/third_party/blink/public/common/origin_trials/origin_trials.h
+++ b/third_party/blink/public/common/origin_trials/origin_trials.h
@@ -31,9 +31,9 @@
 BLINK_COMMON_EXPORT bool IsTrialEnabledForThirdPartyOrigins(
     base::StringPiece trial_name);
 
-// Return true if |trial_name| can be enabled for read/write access by the
-// browser process.
-BLINK_COMMON_EXPORT bool IsTrialEnabledForBrowserProcessReadWriteAccess(
+// Return true if |trial_name| can be enabled for read access by the browser
+// process.
+BLINK_COMMON_EXPORT bool IsTrialEnabledForBrowserProcessReadAccess(
     base::StringPiece trial_name);
 
 // Returns true if |trial_name| should be enabled until the next response
diff --git a/third_party/blink/public/common/service_worker/service_worker_subresource_load_metrics.h b/third_party/blink/public/common/service_worker/service_worker_subresource_load_metrics.h
index 1c9a73e4..51f38a1e 100644
--- a/third_party/blink/public/common/service_worker/service_worker_subresource_load_metrics.h
+++ b/third_party/blink/public/common/service_worker/service_worker_subresource_load_metrics.h
@@ -107,6 +107,13 @@
   // i.e. the service worker did not call `respondWith`, and network fallback.
   bool mock_fallback = false;
 
+  // True if dictionary subresource is handled by a service worker.
+  // i.e. the service worker called `respondWith` to return the resource.
+  bool dictionary_handled = false;
+  // True if dictionary subresource is not handled by a service worker.
+  // i.e. the service worker did not call `respondWith`, and network fallback.
+  bool dictionary_fallback = false;
+
   bool operator==(const ServiceWorkerSubresourceLoadMetrics& other) const {
     return image_handled == other.image_handled &&
            image_fallback == other.image_fallback &&
@@ -135,7 +142,9 @@
            speculation_rules_handled == other.speculation_rules_handled &&
            speculation_rules_fallback == other.speculation_rules_fallback &&
            mock_handled == other.mock_handled &&
-           mock_fallback == other.mock_fallback;
+           mock_fallback == other.mock_fallback &&
+           dictionary_handled == other.dictionary_handled &&
+           dictionary_fallback == other.dictionary_fallback;
   }
 };
 
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 27336c2..812d38b 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -919,6 +919,12 @@
       # Whether to report WCAG AAA level issues. Default is false.
       optional boolean reportAAA
 
+  # Runs the form issues check for the target page. Found issues are reported
+  # using Audits.issueAdded event.
+  command checkFormsIssues
+    returns
+      array of GenericIssueDetails formIssues
+
   event issueAdded
     parameters
       InspectorIssue issue
@@ -944,6 +950,8 @@
     parameters
       # Identifies a field that serves as an anchor for autofill.
       DOM.BackendNodeId fieldId
+      # Identifies the frame that field belongs to.
+      optional Page.FrameId frameId
       # Credit card information to fill out the form. Credit card data is not saved.
       CreditCard card
 
@@ -10996,6 +11004,9 @@
       SameSiteCrossOriginNavigationNotOptInInMainFrameNavigation
       MemoryPressureOnTrigger
       MemoryPressureAfterTriggered
+      SpeculationRuleRemoved
+      TriggerPageNavigated
+      OtherPrerenderedPageActivated
 
   # Fired when a prerender attempt is completed.
   event prerenderAttemptCompleted
diff --git a/third_party/blink/public/web/web_autofill_client.h b/third_party/blink/public/web/web_autofill_client.h
index 28c2166..bb49b0d 100644
--- a/third_party/blink/public/web/web_autofill_client.h
+++ b/third_party/blink/public/web/web_autofill_client.h
@@ -31,6 +31,9 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_AUTOFILL_CLIENT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_AUTOFILL_CLIENT_H_
 
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+
 namespace blink {
 
 class WebFormControlElement;
@@ -39,9 +42,29 @@
 class WebKeyboardEvent;
 class WebNode;
 class WebString;
+class WebElement;
 
 class WebAutofillClient {
  public:
+  struct FormIssue {
+    FormIssue(blink::WebString frame,
+              blink::mojom::GenericIssueErrorType type,
+              int node,
+              blink::WebString attribute)
+        : frame_id(frame),
+          issue_type(type),
+          violating_node(node),
+          violating_node_attribute(attribute) {}
+    FormIssue(blink::WebString frame,
+              blink::mojom::GenericIssueErrorType type,
+              int node)
+        : frame_id(frame), issue_type(type), violating_node(node) {}
+
+    blink::WebString frame_id;
+    blink::mojom::GenericIssueErrorType issue_type;
+    int violating_node;
+    blink::WebString violating_node_attribute;
+  };
   // These methods are called when the users edits a text-field.
   virtual void TextFieldDidEndEditing(const WebInputElement&) {}
   virtual void TextFieldDidChange(const WebFormControlElement&) {}
@@ -86,6 +109,11 @@
   // Called when the given form element is reset.
   virtual void FormElementReset(const WebFormElement&) {}
 
+  // Processes the current forms and returns an array of issues found.
+  virtual std::vector<FormIssue> ProccessFormsAndReturnIssues() {
+    return std::vector<FormIssue>();
+  }
+
   // Called when the empty value is set for the given input element, which is
   // or has been a password field.
   virtual void PasswordFieldReset(const WebInputElement& element) {}
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
index 1f80dfba..c5f03351 100644
--- a/third_party/blink/renderer/bindings/core/v8/binding_security.cc
+++ b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -70,9 +70,8 @@
 }  // namespace
 
 void BindingSecurity::Init() {
-  BindingSecurityForPlatform::
-      SetShouldAllowAccessToV8ContextWithErrorReportOption(
-          ShouldAllowAccessToV8Context);
+  BindingSecurityForPlatform::SetShouldAllowAccessToV8Context(
+      ShouldAllowAccessToV8Context);
   BindingSecurityForPlatform::SetShouldAllowWrapperCreationOrThrowException(
       ShouldAllowWrapperCreationOrThrowException);
   BindingSecurityForPlatform::SetRethrowWrapperCreationException(
@@ -81,38 +80,22 @@
 
 namespace {
 
-void ReportOrThrowSecurityError(
+void ThrowSecurityError(
     const LocalDOMWindow* accessing_window,
     const DOMWindow* target_window,
     DOMWindow::CrossDocumentAccessPolicy cross_document_access,
-    ExceptionState& exception_state) {
+    ExceptionState* exception_state) {
+  if (!exception_state) {
+    return;
+  }
   if (target_window) {
-    exception_state.ThrowSecurityError(
+    exception_state->ThrowSecurityError(
         target_window->SanitizedCrossDomainAccessErrorMessage(
             accessing_window, cross_document_access),
         target_window->CrossDomainAccessErrorMessage(accessing_window,
                                                      cross_document_access));
   } else {
-    exception_state.ThrowSecurityError("Cross origin access was denied.");
-  }
-}
-
-void ReportOrThrowSecurityError(
-    const LocalDOMWindow* accessing_window,
-    const DOMWindow* target_window,
-    DOMWindow::CrossDocumentAccessPolicy cross_document_access,
-    BindingSecurity::ErrorReportOption reporting_option) {
-  if (reporting_option == BindingSecurity::ErrorReportOption::kDoNotReport)
-    return;
-
-  if (accessing_window && target_window) {
-    accessing_window->PrintErrorMessage(
-        target_window->CrossDomainAccessErrorMessage(accessing_window,
-                                                     cross_document_access));
-  } else if (accessing_window) {
-    accessing_window->PrintErrorMessage("Cross origin access was denied.");
-  } else {
-    // Nowhere to report the error.
+    exception_state->ThrowSecurityError("Cross origin access was denied.");
   }
 }
 
@@ -203,18 +186,18 @@
   return true;
 }
 
-template <typename ExceptionStateOrErrorReportOption>
 bool CanAccessWindow(const LocalDOMWindow* accessing_window,
                      const DOMWindow* target_window,
-                     ExceptionStateOrErrorReportOption& error_report) {
+                     ExceptionState* exception_state) {
   DOMWindow::CrossDocumentAccessPolicy cross_document_access =
       DOMWindow::CrossDocumentAccessPolicy::kAllowed;
   if (CanAccessWindowInternal(accessing_window, target_window,
-                              &cross_document_access))
+                              &cross_document_access)) {
     return true;
+  }
 
-  ReportOrThrowSecurityError(accessing_window, target_window,
-                             cross_document_access, error_report);
+  ThrowSecurityError(accessing_window, target_window, cross_document_access,
+                     exception_state);
   return false;
 }
 
@@ -236,10 +219,9 @@
 
 bool BindingSecurity::ShouldAllowAccessTo(
     const LocalDOMWindow* accessing_window,
-    const DOMWindow* target,
-    ErrorReportOption reporting_option) {
+    const DOMWindow* target) {
   DCHECK(target);
-  bool can_access = CanAccessWindow(accessing_window, target, reporting_option);
+  bool can_access = CanAccessWindow(accessing_window, target, nullptr);
 
   if (!can_access && accessing_window) {
     UseCounter::Count(accessing_window->document(),
@@ -255,11 +237,10 @@
 
 bool BindingSecurity::ShouldAllowAccessTo(
     const LocalDOMWindow* accessing_window,
-    const Location* target,
-    ErrorReportOption reporting_option) {
+    const Location* target) {
   DCHECK(target);
   bool can_access =
-      CanAccessWindow(accessing_window, target->DomWindow(), reporting_option);
+      CanAccessWindow(accessing_window, target->DomWindow(), nullptr);
 
   if (!can_access && accessing_window) {
     UseCounter::Count(accessing_window->document(),
@@ -275,21 +256,19 @@
 
 bool BindingSecurity::ShouldAllowAccessTo(
     const LocalDOMWindow* accessing_window,
-    const Node* target,
-    ErrorReportOption reporting_option) {
+    const Node* target) {
   if (!target)
     return false;
   return CanAccessWindow(accessing_window, target->GetDocument().domWindow(),
-                         reporting_option);
+                         nullptr);
 }
 
 namespace {
 
-template <typename ExceptionStateOrErrorReportOption>
 bool ShouldAllowAccessToV8ContextInternal(
     v8::Local<v8::Context> accessing_context,
     v8::MaybeLocal<v8::Context> maybe_target_context,
-    ExceptionStateOrErrorReportOption& error_report) {
+    ExceptionState* exception_state) {
   // Workers and worklets do not support multiple contexts, so both of
   // |accessing_context| and |target_context| must be windows at this point.
 
@@ -297,9 +276,9 @@
   // contexts are unconditionally treated as cross origin.
   v8::Local<v8::Context> target_context;
   if (!maybe_target_context.ToLocal(&target_context)) {
-    ReportOrThrowSecurityError(ToLocalDOMWindow(accessing_context), nullptr,
-                               DOMWindow::CrossDocumentAccessPolicy::kAllowed,
-                               error_report);
+    ThrowSecurityError(ToLocalDOMWindow(accessing_context), nullptr,
+                       DOMWindow::CrossDocumentAccessPolicy::kAllowed,
+                       exception_state);
     return false;
   }
   // Fast path for the most likely case.
@@ -312,25 +291,16 @@
   CHECK_EQ(accessing_world.GetWorldId(), target_world.GetWorldId());
   return !accessing_world.IsMainWorld() ||
          CanAccessWindow(ToLocalDOMWindow(accessing_context),
-                         ToLocalDOMWindow(target_context), error_report);
+                         ToLocalDOMWindow(target_context), exception_state);
 }
 
 }  // namespace
 
 bool BindingSecurity::ShouldAllowAccessToV8Context(
     v8::Local<v8::Context> accessing_context,
-    v8::MaybeLocal<v8::Context> target_context,
-    ExceptionState& exception_state) {
+    v8::MaybeLocal<v8::Context> target_context) {
   return ShouldAllowAccessToV8ContextInternal(accessing_context, target_context,
-                                              exception_state);
-}
-
-bool BindingSecurity::ShouldAllowAccessToV8Context(
-    v8::Local<v8::Context> accessing_context,
-    v8::MaybeLocal<v8::Context> target_context,
-    ErrorReportOption reporting_option) {
-  return ShouldAllowAccessToV8ContextInternal(accessing_context, target_context,
-                                              reporting_option);
+                                              nullptr);
 }
 
 bool BindingSecurity::ShouldAllowWrapperCreationOrThrowException(
@@ -352,8 +322,8 @@
   ExceptionState exception_state(accessing_context->GetIsolate(),
                                  ExceptionState::kConstructionContext,
                                  wrapper_type_info->interface_name);
-  return ShouldAllowAccessToV8Context(accessing_context, creation_context,
-                                      exception_state);
+  return ShouldAllowAccessToV8ContextInternal(
+      accessing_context, creation_context, &exception_state);
 }
 
 void BindingSecurity::RethrowWrapperCreationException(
@@ -365,8 +335,8 @@
   v8::Isolate* isolate = creation_context.ToLocalChecked()->GetIsolate();
   ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
                                  wrapper_type_info->interface_name);
-  if (!ShouldAllowAccessToV8Context(accessing_context, creation_context,
-                                    exception_state)) {
+  if (!ShouldAllowAccessToV8ContextInternal(accessing_context, creation_context,
+                                            &exception_state)) {
     // A cross origin exception has turned into a SecurityError.
     CHECK(exception_state.HadException());
     return;
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.h b/third_party/blink/renderer/bindings/core/v8/binding_security.h
index eb2c6286..98c26574 100644
--- a/third_party/blink/renderer/bindings/core/v8/binding_security.h
+++ b/third_party/blink/renderer/bindings/core/v8/binding_security.h
@@ -39,7 +39,6 @@
 namespace blink {
 
 class DOMWindow;
-class ExceptionState;
 class LocalDOMWindow;
 class Location;
 class Node;
@@ -52,8 +51,6 @@
   STATIC_ONLY(BindingSecurity);
 
  public:
-  using ErrorReportOption = BindingSecurityForPlatform::ErrorReportOption;
-
   static void Init();
 
   // Checks if the caller (|accessing_window|) is allowed to access the JS
@@ -65,13 +62,11 @@
   //
   // DOMWindow
   static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window,
-                                  const DOMWindow* target,
-                                  ErrorReportOption);
+                                  const DOMWindow* target);
 
   // Location
   static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window,
-                                  const Location* target,
-                                  ErrorReportOption);
+                                  const Location* target);
 
   // Checks if the caller (|accessing_window|) is allowed to access the JS
   // returned object (|target|), where the returned object is the JS object
@@ -85,20 +80,14 @@
   //
   // Node
   static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window,
-                                  const Node* target,
-                                  ErrorReportOption);
+                                  const Node* target);
 
-  // These overloads should be used only when checking a general access from
-  // one context to another context.  For access to a receiver object or
+  // This function should be used only when checking a general access from
+  // one context to another context. For access to a receiver object or
   // returned object, you should use the above overloads.
   static bool ShouldAllowAccessToV8Context(
       v8::Local<v8::Context> accessing_context,
-      v8::MaybeLocal<v8::Context> target_context,
-      ExceptionState&);
-  static bool ShouldAllowAccessToV8Context(
-      v8::Local<v8::Context> accessing_context,
-      v8::MaybeLocal<v8::Context> target_context,
-      ErrorReportOption);
+      v8::MaybeLocal<v8::Context> target_context);
 
   static void FailedAccessCheckFor(v8::Isolate*,
                                    const WrapperTypeInfo*,
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
index c56b4c8..10da2f95 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
@@ -115,9 +115,8 @@
   LocalDOMWindow* impl = To<LocalDOMWindow>(V8Window::ToImpl(info.Holder()));
   Element* frameElement = impl->frameElement();
 
-  if (!BindingSecurity::ShouldAllowAccessTo(
-          CurrentDOMWindow(info.GetIsolate()), frameElement,
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+  if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()),
+                                            frameElement)) {
     V8SetReturnValueNull(info);
     return;
   }
@@ -232,9 +231,8 @@
 
   // This is a cross-origin interceptor. Check that the caller has access to the
   // named results.
-  if (!BindingSecurity::ShouldAllowAccessTo(
-          CurrentDOMWindow(info.GetIsolate()), window,
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+  if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()),
+                                            window)) {
     // HTML 7.2.3.3 CrossOriginGetOwnPropertyHelper ( O, P )
     // https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-)
     // step 3. If P is "then", @@toStringTag, @@hasInstance, or
diff --git a/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
index 7efb8cf8..9864d8e 100644
--- a/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
+++ b/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
@@ -103,13 +103,23 @@
   if (v8_context_of_event_target.IsEmpty())
     return;
 
+  // Step 6: Let |global| be listener callback’s associated Realm’s global
+  // object.
+  LocalDOMWindow* window =
+      ToLocalDOMWindow(script_state_of_listener->GetContext());
+
   // Check if the current context, which is set to the listener's relevant
   // context by creating |listener_script_state_scope|, has access to the
   // event target's relevant context before creating |js_event|. SecurityError
   // is thrown if it doesn't have access.
   if (!BindingSecurity::ShouldAllowAccessToV8Context(
-          script_state_of_listener->GetContext(), v8_context_of_event_target,
-          BindingSecurity::ErrorReportOption::kReport)) {
+          script_state_of_listener->GetContext(), v8_context_of_event_target)) {
+    LocalDOMWindow* target_window =
+        DynamicTo<LocalDOMWindow>(execution_context_of_event_target);
+    if (window && target_window) {
+      window->PrintErrorMessage(target_window->CrossDomainAccessErrorMessage(
+          window, DOMWindow::CrossDocumentAccessPolicy::kDisallowed));
+    }
     return;
   }
 
@@ -118,11 +128,6 @@
   if (js_event.IsEmpty())
     return;
 
-  // Step 6: Let |global| be listener callback’s associated Realm’s global
-  // object.
-  LocalDOMWindow* window =
-      ToLocalDOMWindow(script_state_of_listener->GetContext());
-
   // Step 7: Let |current_event| be undefined.
   Event* current_event = nullptr;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc b/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
index b5dc20a..a7e159e 100644
--- a/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
+++ b/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
@@ -59,8 +59,7 @@
   if (script_state->World().IsWorkerWorld() ||
       BindingSecurity::ShouldAllowAccessTo(
           EnteredDOMWindow(script_state->GetIsolate()),
-          To<LocalDOMWindow>(target),
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+          To<LocalDOMWindow>(target))) {
     function_ = handler;
     arguments_ = arguments;
     auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
@@ -81,8 +80,7 @@
   if (script_state->World().IsWorkerWorld() ||
       BindingSecurity::ShouldAllowAccessTo(
           EnteredDOMWindow(script_state->GetIsolate()),
-          To<LocalDOMWindow>(target),
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+          To<LocalDOMWindow>(target))) {
     code_ = handler;
     auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
     if (tracker && script_state->World().IsMainWorld()) {
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
index d8120da..141eebf 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -730,8 +730,7 @@
 
   DCHECK(!window || !window->GetFrame() ||
          BindingSecurity::ShouldAllowAccessTo(
-             ToLocalDOMWindow(function->GetCreationContextChecked()), window,
-             BindingSecurity::ErrorReportOption::kDoNotReport));
+             ToLocalDOMWindow(function->GetCreationContextChecked()), window));
   v8::Isolate::SafeForTerminationScope safe_for_termination(isolate);
   v8::MicrotasksScope microtasks_scope(isolate, microtask_queue,
                                        v8::MicrotasksScope::kRunMicrotasks);
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 97a6f644..5376eba 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -1006,8 +1006,7 @@
     use_counter = _format(
         "UseCounter::Count(${current_execution_context}, {});", web_feature)
     cond = T("!BindingSecurity::ShouldAllowAccessTo("
-             "ToLocalDOMWindow(${current_context}), ${return_value}, "
-             "BindingSecurity::ErrorReportOption::kDoNotReport)")
+             "ToLocalDOMWindow(${current_context}), ${return_value})")
     body = [
         T(use_counter),
         T("bindings::V8SetReturnValue(${info}, nullptr);\n"
@@ -4027,8 +4026,7 @@
                 blink_class=blink_class)),
         TextNode("return BindingSecurity::ShouldAllowAccessTo("
                  "ToLocalDOMWindow(${accessing_context}), "
-                 "blink_accessed_object, "
-                 "BindingSecurity::ErrorReportOption::kDoNotReport);"),
+                 "blink_accessed_object);"),
     ])
 
     return func_def
diff --git a/third_party/blink/renderer/build/scripts/PRESUBMIT.py b/third_party/blink/renderer/build/scripts/PRESUBMIT.py
index 9777e96..3340426 100644
--- a/third_party/blink/renderer/build/scripts/PRESUBMIT.py
+++ b/third_party/blink/renderer/build/scripts/PRESUBMIT.py
@@ -20,12 +20,13 @@
                                        file_name)
     cmd = [input_api.python3_executable, test_path]
 
-    # Adds "//third_party" to the path, so that the jinja2 module can be found
-    # during import.
+    # Adds paths for jinja2 and pyjson5
     env = input_api.environ.copy()
     import_path = [
         input_api.os_path.join(input_api.change.RepositoryRoot(),
-                               'third_party')
+                               'third_party'),
+        input_api.os_path.join(input_api.change.RepositoryRoot(),
+                               'third_party', 'pyjson5', 'src')
     ]
     if env.get('PYTHONPATH'):
         import_path.append(env.get('PYTHONPATH'))
diff --git a/third_party/blink/renderer/build/scripts/json5_generator.py b/third_party/blink/renderer/build/scripts/json5_generator.py
index ca29f4e..42a953c 100644
--- a/third_party/blink/renderer/build/scripts/json5_generator.py
+++ b/third_party/blink/renderer/build/scripts/json5_generator.py
@@ -55,8 +55,8 @@
 """
 
 import argparse
-import ast
 import copy
+import json5
 import os
 import os.path
 import re
@@ -64,20 +64,6 @@
 from blinkbuild.name_style_converter import NameStyleConverter
 
 
-def _json5_load(lines):
-    # Use json5.loads when json5 is available. Currently we use simple
-    # regexs to convert well-formed JSON5 to PYL format.
-    # Strip away comments and quote unquoted keys.
-    re_comment = re.compile(r"^\s*//.*$|//+ .*$", re.MULTILINE)
-    re_map_keys = re.compile(r"^\s*([$A-Za-z_][\w]*)\s*:", re.MULTILINE)
-    pyl = re.sub(re_map_keys, r"'\1':", re.sub(re_comment, "", lines))
-    # Convert map values of true/false to Python version True/False.
-    re_true = re.compile(r":\s*true\b")
-    re_false = re.compile(r":\s*false\b")
-    pyl = re.sub(re_true, ":True", re.sub(re_false, ":False", pyl))
-    return ast.literal_eval(pyl)
-
-
 def _merge_doc(doc, doc2):
     def _merge_dict(key):
         if key in doc or key in doc2:
@@ -131,7 +117,7 @@
         for path in file_paths:
             assert path.endswith(".json5")
             with open(os.path.abspath(path)) as json5_file:
-                doc = _json5_load(json5_file.read())
+                doc = json5.loads(json5_file.read())
                 if not merged_doc:
                     merged_doc = doc
                 else:
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_feature_state_contexts_headers.py b/third_party/blink/renderer/build/scripts/make_runtime_feature_state_contexts_headers.py
index 093edc5..0b1d056 100755
--- a/third_party/blink/renderer/build/scripts/make_runtime_feature_state_contexts_headers.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_feature_state_contexts_headers.py
@@ -55,6 +55,8 @@
             self._features)
         self._browser_write_access_features = util.browser_write_access(
             self._features)
+        self._browser_read_access_with_third_party_features = util.browser_read_access_with_third_party(
+            self._features)
 
     def _template_inputs(self):
         return {
@@ -62,6 +64,8 @@
             'browser_read_access_features': self._browser_read_access_features,
             'browser_write_access_features':
             self._browser_write_access_features,
+            'browser_read_access_with_third_party_features':
+            self._browser_read_access_with_third_party_features,
             'platforms': self._platforms(),
             'input_files': self._input_files,
             'header_guard': self._header_guard,
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py b/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
index ffd14b8..dc96787 100644
--- a/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
@@ -97,6 +97,14 @@
     ]
 
 
+def browser_read_access_with_third_party(features):
+    return [
+        f for f in features if (f['browser_process_read_access']
+                                or f['browser_process_read_write_access'])
+        and f['origin_trial_allows_third_party']
+    ]
+
+
 def browser_write_access(features):
     return [f for f in features if f['browser_process_read_write_access']]
 
diff --git a/third_party/blink/renderer/build/scripts/scripts.gni b/third_party/blink/renderer/build/scripts/scripts.gni
index 54fa152..db7a810 100644
--- a/third_party/blink/renderer/build/scripts/scripts.gni
+++ b/third_party/blink/renderer/build/scripts/scripts.gni
@@ -19,6 +19,7 @@
   # dependency for whole jinja2 package
   "//third_party/jinja2/__init__.py",
   "//third_party/markupsafe/__init__.py",  # jinja2 dep
+  "//third_party/pyjson5/src/json5/__init__.py",
   "$_scripts_dir/blinkbuild/name_style_converter.py",
   "$_scripts_dir/hasher.py",
   "$_scripts_dir/json5_generator.py",
@@ -93,6 +94,8 @@
 # then run invoker.script.
 #  - //third_party/blink/renderer/build/scripts
 #  - //third_party
+#  - //third_party/pyjson5/src
+#  - //tools
 template("blink_python_runner") {
   action(target_name) {
     script = "$_scripts_dir/run_with_pythonpath.py"
@@ -113,6 +116,8 @@
              "-I",
              rebase_path("//third_party", root_build_dir),
              "-I",
+             rebase_path("//third_party/pyjson5/src", root_build_dir),
+             "-I",
              rebase_path("//tools", root_build_dir),
              rebase_path(invoker.script, root_build_dir),
            ] + invoker.args
diff --git a/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
index d299e8e..1eff209 100644
--- a/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
@@ -60,13 +60,15 @@
   return base::Contains(kEnabledForThirdPartyOrigins, trial_name);
 }
 
-bool origin_trials::IsTrialEnabledForBrowserProcessReadWriteAccess(base::StringPiece trial_name) {
+bool origin_trials::IsTrialEnabledForBrowserProcessReadAccess(base::StringPiece trial_name) {
   // Select all features that represent origin trials and have
   // browser_process_read_write_access enabled. Determine if that list of
   // features contains the  `trial_name` provided.
   static const char* const kEnabledForBrowserProcessReadWriteAccess[] = {
-  {% for trial in origin_trial_features|selectattr('browser_process_read_write_access')|map(attribute='origin_trial_feature_name')|unique %}
-      "{{trial}}",
+  {% for trial in origin_trial_features %}
+    {% if trial.browser_process_read_access or trial.browser_process_read_write_access  %}
+      "{{trial.origin_trial_feature_name}}",
+    {% endif %}
   {% endfor %}
   };
   return base::Contains(kEnabledForBrowserProcessReadWriteAccess, trial_name);
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_read_context.h.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_read_context.h.tmpl
index 5f0b69b..8374b97 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_read_context.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_read_context.h.tmpl
@@ -7,9 +7,14 @@
 #define {{header_guard}}
 
 #include "base/containers/flat_map.h"
+#include "base/containers/span.h"
 #include "base/notreached.h"
 #include "third_party/blink/public/common/common_export.h"
+#include "third_party/blink/public/common/origin_trials/origin_trials.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_result.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 #include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature_state.mojom-shared.h"
+#include "url/origin.h"
 
 namespace content {
 class RuntimeFeatureStateControllerImpl;
@@ -41,6 +46,16 @@
   }
   {% endfor %}
 
+  // TODO(https://crbug.com/1410784): Validate the list of `third_party_origins`
+  // against the ones the renderer process believes were active.
+  {% for feature in browser_read_access_with_third_party_features %}
+  bool Is{{feature.name}}EnabledForThirdParty(const url::Origin& first_party_origin,
+                                              const base::span<url::Origin>& third_party_origins) const {
+    return IsEnabledForThirdParty(
+        blink::mojom::RuntimeFeatureState::k{{feature.name}}, first_party_origin, third_party_origins);
+  }
+  {% endfor %}
+
  protected:
   bool IsEnabled(blink::mojom::RuntimeFeatureState feature) const {
     auto override_it = feature_overrides_.find(feature);
@@ -52,10 +67,35 @@
     return initial_it->second;
   }
 
+  bool IsEnabledForThirdParty(blink::mojom::RuntimeFeatureState feature,
+                              const url::Origin& first_party_origin,
+                              const base::span<url::Origin>& third_party_origins) const {
+    auto override_it = possible_third_party_feature_overrides_.find(feature);
+    if (override_it == possible_third_party_feature_overrides_.end())
+      return false;
+
+    blink::TrialTokenValidator validator;
+    for (const auto& token : override_it->second) {
+      blink::TrialTokenResult result = validator.ValidateTokenAndTrial(
+          token, first_party_origin, third_party_origins, base::Time::Now());
+      if (result.Status() == blink::OriginTrialTokenStatus::kSuccess) {
+        return blink::origin_trials::IsTrialValid(result.ParsedToken()->feature_name()) &&
+          blink::origin_trials::IsTrialEnabledForBrowserProcessReadAccess(
+              result.ParsedToken()->feature_name());
+      }
+    }
+    return false;
+  }
+
   // Sparse map of overrides collected during initial navigation. This map
   // will be attached to the navigation on commit.
   base::flat_map<blink::mojom::RuntimeFeatureState, bool> feature_overrides_;
 
+  // Sparse map of overrides that might be needed for third-party contexts.
+  // Tokens must be validated once the attempting third-party origin is known.
+  base::flat_map<blink::mojom::RuntimeFeatureState,
+                 std::vector<std::string>> possible_third_party_feature_overrides_;
+
   // Values for all read/write features on context creation.
   base::flat_map<blink::mojom::RuntimeFeatureState, bool> initial_values_;
 
@@ -73,12 +113,17 @@
   // the renderer process.
   void ApplyFeatureChange(
     const base::flat_map<blink::mojom::RuntimeFeatureState,
-                                       bool>& modified_features) {
+                                       bool>& modified_features,
+    const base::flat_map<blink::mojom::RuntimeFeatureState,
+                                       std::vector<std::string>>& possible_third_party_features) {
     // Feature values sent from the renderer process take precedence over state
     // held currently in the browser process, so insert_or_assign is used.
     for(auto const& feature : modified_features) {
       feature_overrides_.insert_or_assign(feature.first, feature.second);
     }
+    for(auto const& feature : possible_third_party_features) {
+      possible_third_party_feature_overrides_.insert_or_assign(feature.first, feature.second);
+    }
   }
 };
 
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
index a6c7619..785945af 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
+++ b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
@@ -772,4 +772,55 @@
   EXPECT_EQ(cache.size(), 2u);
 }
 
+TEST_F(ContainerQueryEvaluatorTest, DisplayContentsStyleQueryInvalidation) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      /* Register --foo to avoid recalc due to inheritance. */
+      @property --foo {
+        syntax: "none|bar";
+        inherits: false;
+        initial-value: none;
+      }
+      #container.contents {
+        --foo: bar;
+        display: contents;
+      }
+      @container style(--foo: bar) {
+        #container > div.bar {
+          --match: true;
+        }
+      }
+    </style>
+    <div id="container">
+      <div></div>
+      <div></div>
+      <div></div>
+      <div class="bar"></div>
+      <div></div>
+      <div></div>
+    </div>
+  )HTML");
+
+  Element* container = GetDocument().getElementById("container");
+  ASSERT_TRUE(container);
+  ContainerQueryEvaluator* evaluator = container->GetContainerQueryEvaluator();
+  ASSERT_TRUE(evaluator);
+
+  container->setAttribute(html_names::kClassAttr, "contents");
+
+  unsigned before_count = GetStyleEngine().StyleForElementCount();
+
+  UpdateAllLifecyclePhasesForTest();
+
+  unsigned after_count = GetStyleEngine().StyleForElementCount();
+
+  // #container and div.bar should be affected. In particular, we should not
+  // recalc style for other <div> children of #container.
+  EXPECT_EQ(2u, after_count - before_count);
+
+  // The ContainerQueryEvaluator should still be the same. No need to re-create
+  // the evaluator if when the display changes.
+  EXPECT_EQ(evaluator, container->GetContainerQueryEvaluator());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_properties_ranking.json5 b/third_party/blink/renderer/core/css/css_properties_ranking.json5
index 9e308101..93cd3d26 100644
--- a/third_party/blink/renderer/core/css/css_properties_ranking.json5
+++ b/third_party/blink/renderer/core/css/css_properties_ranking.json5
@@ -736,7 +736,7 @@
         "origin-trial-test-property",
         "subtree-visibility",
         "math-superscript-shift-style",
-        "start"
+        "start",
         "accent-color",
     ],
     "properties": {}
diff --git a/third_party/blink/renderer/core/css/popover.css b/third_party/blink/renderer/core/css/popover.css
index fc2b2c4..e5d2a09 100644
--- a/third_party/blink/renderer/core/css/popover.css
+++ b/third_party/blink/renderer/core/css/popover.css
@@ -38,7 +38,7 @@
 
 /* Popovers using anchor positioning get their inset and anchor-scroll properties
    reset, to make it easier to position them. */
-[anchor]:popover-open {
+[popover][anchor] {
   inset:auto;
   anchor-scroll: implicit;
 }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index b639179d..61fad032 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3947,11 +3947,11 @@
   if (!before_unload_event.defaultPrevented())
     DefaultEventHandler(before_unload_event);
 
-  if (before_unload_event.returnValue().empty()) {
+  if (before_unload_event.returnValue().IsNull()) {
     RecordBeforeUnloadUse(BeforeUnloadUse::kNoDialogNoText);
   }
   bool cancelled_by_script =
-      !before_unload_event.returnValue().empty() ||
+      !before_unload_event.returnValue().IsNull() ||
       (RuntimeEnabledFeatures::
            BeforeunloadEventCancelByPreventDefaultEnabled() &&
        before_unload_event.defaultPrevented());
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 1a76116..cc76dfc 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3431,19 +3431,10 @@
       return nullptr;
     }
   }
-  // If we're switching to display:contents, any existing results cached on
-  // ContainerQueryEvaluator are no longer valid, since any style recalc
-  // based on that information would *not* be corrected by a subsequent
-  // interleaved style recalc, since the element has no layout object.
-  if (old_style && !element.LayoutObjectIsNeeded(new_style) &&
-      element.LayoutObjectIsNeeded(*old_style)) {
-    return MakeGarbageCollected<ContainerQueryEvaluator>();
+  if (evaluator) {
+    return evaluator;
   }
-  // Otherwise, the existing ContainerQueryEvaluator can be used, if any.
-  if (!evaluator) {
-    evaluator = MakeGarbageCollected<ContainerQueryEvaluator>();
-  }
-  return evaluator;
+  return MakeGarbageCollected<ContainerQueryEvaluator>();
 }
 
 static const StyleRecalcChange ApplyComputedStyleDiff(
diff --git a/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index 43e625c..918bb6d3 100644
--- a/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -294,7 +294,14 @@
                                  paint_rect.bottom_left(), false};
   PaintedSelectionBound end = start;
 
-  context.GetPaintController().RecordSelection(start, end);
+  // Get real world data to help debug crbug.com/1441243.
+#if DCHECK_IS_ON()
+  String debug_info = drawing_rect.ToString();
+#else
+  String debug_info = "";
+#endif
+
+  context.GetPaintController().RecordSelection(start, end, debug_info);
 }
 
 String CaretDisplayItemClient::DebugName() const {
diff --git a/third_party/blink/renderer/core/events/event_target_names.json5 b/third_party/blink/renderer/core/events/event_target_names.json5
index 4571010..b4cb8a3 100644
--- a/third_party/blink/renderer/core/events/event_target_names.json5
+++ b/third_party/blink/renderer/core/events/event_target_names.json5
@@ -4,9 +4,9 @@
     export: "CORE_EXPORT",
   },
 
-  # You don't need to specify ImplementedAs even though an interface name and
-  # its C++ class name don't match.  You need to specify ImplementedAs only if
-  # you'd like to change recorded names in ActivityLogger.
+  // You don't need to specify ImplementedAs even though an interface name and
+  // its C++ class name don't match.  You need to specify ImplementedAs only if
+  // you'd like to change recorded names in ActivityLogger.
   data: [
     "AccessibleNode",
     "Animation",
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
index 58cee85..125a3c8 100644
--- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -316,7 +316,7 @@
   session->CreateAndAppend<InspectorAuditsAgent>(
       network_agent,
       &inspected_frames->Root()->GetPage()->GetInspectorIssueStorage(),
-      inspected_frames);
+      inspected_frames, web_local_frame_impl_->AutofillClient());
 
   session->CreateAndAppend<InspectorMediaAgent>(
       inspected_frames, /*worker_global_scope=*/nullptr);
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index e3d2f13..b5599c98 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2171,9 +2171,7 @@
   // entered realm should be same origin-domain. However, to be on the safe
   // side and add some defense in depth, we'll check against the entry realm
   // as well here.
-  if (!BindingSecurity::ShouldAllowAccessTo(
-          entered_window, this,
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+  if (!BindingSecurity::ShouldAllowAccessTo(entered_window, this)) {
     // Trigger DCHECK() failure, while gracefully failing on release builds.
     NOTREACHED();
     UseCounter::Count(GetExecutionContext(),
@@ -2317,9 +2315,7 @@
   // entered realm should be same origin-domain. However, to be on the safe
   // side and add some defense in depth, we'll check against the entry realm
   // as well here.
-  if (!BindingSecurity::ShouldAllowAccessTo(
-          entered_window, this,
-          BindingSecurity::ErrorReportOption::kDoNotReport)) {
+  if (!BindingSecurity::ShouldAllowAccessTo(entered_window, this)) {
     // Trigger DCHECK() failure, while gracefully failing on release builds.
     NOTREACHED();
     UseCounter::Count(GetExecutionContext(),
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 66aad25..1d09672 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -388,8 +388,6 @@
         !GetFrame()->GetDocument()->GetLayoutView())
       return;
 
-    ComputePageRects(page_size_in_pixels);
-
     gfx::RectF all_pages_rect(spool_size_in_pixels);
 
     auto* builder = MakeGarbageCollected<PaintRecordBuilder>();
@@ -532,7 +530,11 @@
     ChromePrintContext::Trace(visitor);
   }
 
-  void BeginPrintMode(float width, float height) override {}
+  void BeginPrintMode(float width, float height) override {
+    gfx::Rect rect(gfx::ToFlooredSize(gfx::SizeF(width, height)));
+    print_params_.print_content_area = rect;
+    page_rects_.Fill(rect, plugin_->PrintBegin(print_params_));
+  }
 
   void EndPrintMode() override {
     plugin_->PrintEnd();
@@ -553,17 +555,6 @@
     return 1.0;
   }
 
-  void ComputePageRects(const gfx::SizeF& print_size) override {
-    gfx::Rect rect(gfx::ToFlooredSize(print_size));
-    print_params_.print_content_area = rect;
-    page_rects_.Fill(rect, plugin_->PrintBegin(print_params_));
-  }
-
-  void ComputePageRectsWithPageSize(
-      const gfx::SizeF& page_size_in_pixels) override {
-    NOTREACHED();
-  }
-
  protected:
   void SpoolPage(GraphicsContext& context, int page_number) override {
     auto* builder = MakeGarbageCollected<PaintRecordBuilder>(context);
@@ -1188,8 +1179,7 @@
 bool WebFrame::ScriptCanAccess(WebFrame* target) {
   return BindingSecurity::ShouldAllowAccessTo(
       CurrentDOMWindow(V8PerIsolateData::MainThreadIsolate()),
-      ToCoreFrame(*target)->DomWindow(),
-      BindingSecurity::ErrorReportOption::kDoNotReport);
+      ToCoreFrame(*target)->DomWindow());
 }
 
 void WebLocalFrameImpl::StartReload(WebFrameLoadType frame_load_type) {
@@ -1884,7 +1874,6 @@
 
   gfx::SizeF size(print_params.print_content_area.size());
   print_context_->BeginPrintMode(size.width(), size.height());
-  print_context_->ComputePageRects(size);
 
   return print_context_->PageCount();
 }
diff --git a/third_party/blink/renderer/core/html/html_frame_element_base.cc b/third_party/blink/renderer/core/html/html_frame_element_base.cc
index 9d72e50..9d54ae2 100644
--- a/third_party/blink/renderer/core/html/html_frame_element_base.cc
+++ b/third_party/blink/renderer/core/html/html_frame_element_base.cc
@@ -57,42 +57,18 @@
       margin_width_(-1),
       margin_height_(-1) {}
 
-bool HTMLFrameElementBase::IsURLAllowed() const {
-  if (url_.empty())
-    return true;
-
-  const KURL& complete_url = GetDocument().CompleteURL(url_);
-
-  if (contentWindow() && complete_url.ProtocolIsJavaScript()) {
-    // Check if the caller can execute script in the context of the content
-    // frame. NB: This check can be invoked without any JS on the stack for some
-    // parser operations. In such case, we use the origin of the frame element's
-    // containing document as the caller context.
-    v8::Isolate* isolate = GetExecutionContext()->GetIsolate();
-    LocalDOMWindow* accessing_window = isolate->InContext()
-                                           ? CurrentDOMWindow(isolate)
-                                           : GetDocument().domWindow();
-    if (!BindingSecurity::ShouldAllowAccessTo(
-            accessing_window, contentWindow(),
-            BindingSecurity::ErrorReportOption::kReport)) {
-      return false;
-    }
-  }
-  return true;
-}
-
 void HTMLFrameElementBase::OpenURL(bool replace_current_item) {
-  if (!IsURLAllowed())
+  LocalFrame* parent_frame = GetDocument().GetFrame();
+  if (!parent_frame) {
     return;
+  }
 
   if (url_.empty())
     url_ = AtomicString(BlankURL().GetString());
-
-  LocalFrame* parent_frame = GetDocument().GetFrame();
-  if (!parent_frame)
-    return;
-
   KURL url = GetDocument().CompleteURL(url_);
+  if (ContentFrame() && !parent_frame->CanNavigate(*ContentFrame(), url)) {
+    return;
+  }
 
   // There is no (easy) way to tell if |url_| is relative at this point. That
   // is determined in the KURL constructor. If we fail to create an absolute
diff --git a/third_party/blink/renderer/core/html/html_frame_element_base.h b/third_party/blink/renderer/core/html/html_frame_element_base.h
index e5248df..1168536 100644
--- a/third_party/blink/renderer/core/html/html_frame_element_base.h
+++ b/third_party/blink/renderer/core/html/html_frame_element_base.h
@@ -80,7 +80,6 @@
 
   void SetLocation(const String&);
   void SetNameAndOpenURL();
-  bool IsURLAllowed() const;
   void OpenURL(bool replace_current_item = true);
 
   mojom::blink::ScrollbarMode scrollbar_mode_;
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.cc b/third_party/blink/renderer/core/html/link_rel_attribute.cc
index 1f377d7..6cc591e 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute.cc
+++ b/third_party/blink/renderer/core/html/link_rel_attribute.cc
@@ -48,7 +48,8 @@
       is_module_preload_(false),
       is_service_worker_(false),
       is_canonical_(false),
-      is_monetization_(false) {}
+      is_monetization_(false),
+      is_dictionary_(false) {}
 
 LinkRelAttribute::LinkRelAttribute(const String& rel) : LinkRelAttribute() {
   if (rel.empty())
@@ -93,7 +94,10 @@
       is_canonical_ = true;
     } else if (EqualIgnoringASCIICase(link_type, "monetization")) {
       is_monetization_ = true;
+    } else if (EqualIgnoringASCIICase(link_type, "dictionary")) {
+      is_dictionary_ = true;
     }
+
     // Adding or removing a value here requires you to update
     // RelList::supportedTokens()
   }
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.h b/third_party/blink/renderer/core/html/link_rel_attribute.h
index 96a4278..40b855a 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute.h
+++ b/third_party/blink/renderer/core/html/link_rel_attribute.h
@@ -60,6 +60,7 @@
   bool IsServiceWorker() const { return is_service_worker_; }
   bool IsCanonical() const { return is_canonical_; }
   bool IsMonetization() const { return is_monetization_; }
+  bool IsDictionary() const { return is_dictionary_; }
 
  private:
   mojom::blink::FaviconIconType icon_type_;
@@ -76,6 +77,7 @@
   bool is_service_worker_ : 1;
   bool is_canonical_ : 1;
   bool is_monetization_ : 1;
+  bool is_dictionary_ : 1;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
index 8afb570a..f2453de8 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
+++ b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
@@ -42,7 +42,8 @@
                                         bool is_dns_prefetch,
                                         bool is_link_prerender,
                                         bool is_preconnect = false,
-                                        bool is_canonical = false) {
+                                        bool is_canonical = false,
+                                        bool is_dictionary = false) {
   SCOPED_TRACE(value.Utf8());
   LinkRelAttribute link_rel_attribute(value);
   ASSERT_EQ(is_style_sheet, link_rel_attribute.IsStyleSheet());
@@ -52,6 +53,7 @@
   ASSERT_EQ(is_link_prerender, link_rel_attribute.IsLinkPrerender());
   ASSERT_EQ(is_preconnect, link_rel_attribute.IsPreconnect());
   ASSERT_EQ(is_canonical, link_rel_attribute.IsCanonical());
+  ASSERT_EQ(is_dictionary, link_rel_attribute.IsDictionary());
 }
 
 TEST(LinkRelAttributeTest, Constructor) {
@@ -136,6 +138,15 @@
   TestLinkRelAttribute("caNONiCAL", false,
                        mojom::blink::FaviconIconType::kInvalid, false, false,
                        false, /*is_preconnect=*/false, /*is_canonical=*/true);
+
+  TestLinkRelAttribute("dictionary", false,
+                       mojom::blink::FaviconIconType::kInvalid, false, false,
+                       false, /*is_preconnect=*/false, /*is_canonical=*/false,
+                       /*is_dictionary=*/true);
+  TestLinkRelAttribute("diCtIonAry", false,
+                       mojom::blink::FaviconIconType::kInvalid, false, false,
+                       false, /*is_preconnect=*/false, /*is_canonical=*/false,
+                       /*is_dictionary=*/true);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc b/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
index ae243e5..8a2a5b6 100644
--- a/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
+++ b/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
@@ -134,6 +134,8 @@
                  features::kLightweightNoStatePrefetch, "skip_async_script",
                  true) ||
              preload->DeferOption() == FetchParameters::DeferOption::kNoDefer;
+    case ResourceType::kDictionary:
+      return false;
   }
 }
 
diff --git a/third_party/blink/renderer/core/html/rel_list.cc b/third_party/blink/renderer/core/html/rel_list.cc
index cc8333e7..d0a101d 100644
--- a/third_party/blink/renderer/core/html/rel_list.cc
+++ b/third_party/blink/renderer/core/html/rel_list.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
@@ -20,6 +21,7 @@
   // There is a use counter for <link rel="monetization"> but the feature is
   // actually not implemented yet, so "monetization" is not included in the
   // list below. See https://crbug.com/1031476
+  // clang-format off
   DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tokens,
                       ({
                           "preload",
@@ -38,6 +40,7 @@
                           "modulepreload",
                           "allowed-alt-sxg",
                       }));
+  // clang-format on
 
   return tokens;
 }
@@ -54,11 +57,16 @@
 }
 
 bool RelList::ValidateTokenValue(const AtomicString& token_value,
-                                 ExceptionState&) const {
+                                 ExceptionState& state) const {
   //  https://html.spec.whatwg.org/C/#linkTypes
+  ExecutionContext* execution_context =
+      GetElement().GetDocument().GetExecutionContext();
   if (GetElement().HasTagName(html_names::kLinkTag)) {
     if (SupportedTokensLink().Contains(token_value)) {
       return true;
+    } else if (CompressionDictionaryTransportFullyEnabled(execution_context) &&
+               token_value == "dictionary") {
+      return true;
     }
   } else if ((GetElement().HasTagName(html_names::kATag) ||
               GetElement().HasTagName(html_names::kAreaTag) ||
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
index 440c745..1140a00 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/web/web_autofill_client.h"
 #include "third_party/blink/public/web/web_image.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/dom/dom_token_list.h"
@@ -15,8 +16,10 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
 #include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/core/inspector/inspector_audits_issue.h"
 #include "third_party/blink/renderer/core/inspector/inspector_issue_storage.h"
 #include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
+#include "third_party/blink/renderer/core/inspector/protocol/audits.h"
 #include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -115,13 +118,16 @@
   InspectorBaseAgent::Trace(visitor);
 }
 
-InspectorAuditsAgent::InspectorAuditsAgent(InspectorNetworkAgent* network_agent,
-                                           InspectorIssueStorage* storage,
-                                           InspectedFrames* inspected_frames)
+InspectorAuditsAgent::InspectorAuditsAgent(
+    InspectorNetworkAgent* network_agent,
+    InspectorIssueStorage* storage,
+    InspectedFrames* inspected_frames,
+    WebAutofillClient* web_autofill_client)
     : inspector_issue_storage_(storage),
       enabled_(&agent_state_, false),
       network_agent_(network_agent),
-      inspected_frames_(inspected_frames) {
+      inspected_frames_(inspected_frames),
+      web_autofill_client_(web_autofill_client) {
   DCHECK(network_agent);
 }
 
@@ -207,6 +213,33 @@
   return protocol::Response::Success();
 }
 
+protocol::Response InspectorAuditsAgent::checkFormsIssues(
+    std::unique_ptr<protocol::Array<protocol::Audits::GenericIssueDetails>>*
+        out_formIssues) {
+  *out_formIssues = std::make_unique<
+      protocol::Array<protocol::Audits::GenericIssueDetails>>();
+  if (web_autofill_client_) {
+    std::vector<WebAutofillClient::FormIssue> form_issues =
+        web_autofill_client_->ProccessFormsAndReturnIssues();
+    for (const WebAutofillClient::FormIssue& form_issue : form_issues) {
+      std::unique_ptr<protocol::Audits::GenericIssueDetails>
+          generic_issue_details =
+              protocol::Audits::GenericIssueDetails::create()
+                  .setErrorType(AuditsIssue::GenericIssueErrorTypeToProtocol(
+                      form_issue.issue_type))
+                  .setFrameId(form_issue.frame_id)
+                  .setViolatingNodeAttribute(
+                      form_issue.violating_node_attribute)
+                  .setViolatingNodeId(form_issue.violating_node)
+                  .build();
+
+      (*out_formIssues)->emplace_back(std::move(generic_issue_details));
+    }
+  }
+
+  return protocol::Response::Success();
+}
+
 protocol::Response InspectorAuditsAgent::disable() {
   if (!enabled_.Get()) {
     return protocol::Response::Success();
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_agent.h b/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
index cf182c8..569fb14 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
@@ -16,13 +16,15 @@
 
 class InspectorIssue;
 class InspectorIssueStorage;
+class WebAutofillClient;
 
 class CORE_EXPORT InspectorAuditsAgent final
     : public InspectorBaseAgent<protocol::Audits::Metainfo> {
  public:
   explicit InspectorAuditsAgent(InspectorNetworkAgent*,
                                 InspectorIssueStorage*,
-                                InspectedFrames*);
+                                InspectedFrames*,
+                                WebAutofillClient*);
   InspectorAuditsAgent(const InspectorAuditsAgent&) = delete;
   InspectorAuditsAgent& operator=(const InspectorAuditsAgent&) = delete;
   ~InspectorAuditsAgent() override;
@@ -35,6 +37,9 @@
   protocol::Response enable() override;
   protocol::Response disable() override;
   protocol::Response checkContrast(protocol::Maybe<bool> report_aaa) override;
+  protocol::Response checkFormsIssues(
+      std::unique_ptr<protocol::Array<protocol::Audits::GenericIssueDetails>>*
+          out_formIssues) override;
 
   void Restore() override;
 
@@ -55,6 +60,7 @@
   InspectorAgentState::Boolean enabled_;
   Member<InspectorNetworkAgent> network_agent_;
   Member<InspectedFrames> inspected_frames_;
+  WebAutofillClient* const web_autofill_client_ = nullptr;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
index 212ab6a..e03ca24 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -76,8 +76,23 @@
       return protocol::Network::CorsErrorEnum::DisallowedByMode;
   }
 }
+}  // namespace
 
-protocol::Audits::GenericIssueErrorType GenericIssueErrorTypeToProtocol(
+std::unique_ptr<protocol::Audits::SourceCodeLocation> CreateProtocolLocation(
+    const SourceLocation& location) {
+  auto protocol_location = protocol::Audits::SourceCodeLocation::create()
+                               .setUrl(location.Url())
+                               .setLineNumber(location.LineNumber() - 1)
+                               .setColumnNumber(location.ColumnNumber())
+                               .build();
+  if (location.ScriptId()) {
+    protocol_location->setScriptId(WTF::String::Number(location.ScriptId()));
+  }
+  return protocol_location;
+}
+
+protocol::Audits::GenericIssueErrorType
+AuditsIssue::GenericIssueErrorTypeToProtocol(
     mojom::blink::GenericIssueErrorType error_type) {
   switch (error_type) {
     case mojom::blink::GenericIssueErrorType::
@@ -123,21 +138,6 @@
   }
 }
 
-}  // namespace
-
-std::unique_ptr<protocol::Audits::SourceCodeLocation> CreateProtocolLocation(
-    const SourceLocation& location) {
-  auto protocol_location = protocol::Audits::SourceCodeLocation::create()
-                               .setUrl(location.Url())
-                               .setLineNumber(location.LineNumber() - 1)
-                               .setColumnNumber(location.ColumnNumber())
-                               .build();
-  if (location.ScriptId()) {
-    protocol_location->setScriptId(WTF::String::Number(location.ScriptId()));
-  }
-  return protocol_location;
-}
-
 void AuditsIssue::ReportCorsIssue(
     ExecutionContext* execution_context,
     int64_t identifier,
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
index 03a6c64b..cb7293a 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy_violation_type.h"
+#include "third_party/blink/renderer/core/inspector/protocol/audits.h"
 
 namespace WTF {
 class String;
@@ -165,6 +166,10 @@
       SourceLocation* source_location,
       absl::optional<base::UnguessableToken> issue_id);
 
+  static protocol::Audits::GenericIssueErrorType
+  GenericIssueErrorTypeToProtocol(
+      mojom::blink::GenericIssueErrorType error_type);
+
   static void ReportGenericIssue(LocalFrame* frame,
                                  mojom::blink::GenericIssueErrorType error_type,
                                  int violating_node_id);
diff --git a/third_party/blink/renderer/core/inspector/resolve_node.cc b/third_party/blink/renderer/core/inspector/resolve_node.cc
index ae4f923..560a8e11 100644
--- a/third_party/blink/renderer/core/inspector/resolve_node.cc
+++ b/third_party/blink/renderer/core/inspector/resolve_node.cc
@@ -16,10 +16,10 @@
 
 v8::Local<v8::Value> NodeV8Value(v8::Local<v8::Context> context, Node* node) {
   v8::Isolate* isolate = context->GetIsolate();
-  if (!node || !BindingSecurity::ShouldAllowAccessTo(
-                   CurrentDOMWindow(isolate), node,
-                   BindingSecurity::ErrorReportOption::kDoNotReport))
+  if (!node ||
+      !BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(isolate), node)) {
     return v8::Null(isolate);
+  }
   return ToV8(node, context->Global(), isolate);
 }
 
diff --git a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
index e6952a6..0110ebf7 100644
--- a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
+++ b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -127,7 +127,8 @@
     session->CreateAndAppend<InspectorEmulationAgent>(nullptr,
                                                       *virtual_time_controller);
     session->CreateAndAppend<InspectorAuditsAgent>(
-        network_agent, thread_->GetInspectorIssueStorage(), nullptr);
+        network_agent, thread_->GetInspectorIssueStorage(),
+        /*inspected_frames=*/nullptr, /*web_autofill_client=*/nullptr);
     session->CreateAndAppend<InspectorMediaAgent>(inspected_frames_.Get(),
                                                   scope);
   }
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index 185fd127..a8dc97f 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -305,6 +305,9 @@
   "ng/inline/ng_line_box_fragment_builder.h",
   "ng/inline/ng_line_breaker.cc",
   "ng/inline/ng_line_breaker.h",
+  "ng/inline/ng_line_break_candidate.cc",
+  "ng/inline/ng_line_break_candidate.h",
+  "ng/inline/ng_line_break_point.h",
   "ng/inline/ng_line_info.cc",
   "ng/inline/ng_line_info.h",
   "ng/inline/ng_line_info_list.h",
@@ -741,6 +744,7 @@
   "ng/inline/ng_inline_layout_algorithm_test.cc",
   "ng/inline/ng_inline_node_test.cc",
   "ng/inline/ng_line_breaker_test.cc",
+  "ng/inline/ng_line_break_candidate_test.cc",
   "ng/inline/ng_line_info_list_test.cc",
   "ng/inline/ng_offset_mapping_test.cc",
   "ng/inline/ng_paragraph_line_breaker_test.cc",
diff --git a/third_party/blink/renderer/core/layout/ng/inline/hyphen_result.h b/third_party/blink/renderer/core/layout/ng/inline/hyphen_result.h
index e846814..f0ab74e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/hyphen_result.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/hyphen_result.h
@@ -16,6 +16,9 @@
 
 class CORE_EXPORT HyphenResult {
  public:
+  HyphenResult() = default;
+  explicit HyphenResult(const ComputedStyle& style) { Shape(style); }
+
   explicit operator bool() const { return !text_.IsNull(); }
 
   const String& Text() const { return text_; }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h
index 8067cf1..50c6405 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h
@@ -18,9 +18,20 @@
   bool operator==(const NGInlineItemTextIndex& other) const {
     return text_offset == other.text_offset && item_index == other.item_index;
   }
+  bool operator!=(const NGInlineItemTextIndex& other) const {
+    return !operator==(other);
+  }
+  bool operator>(const NGInlineItemTextIndex& other) const {
+    return text_offset > other.text_offset || item_index > other.item_index;
+  }
+  bool operator<(const NGInlineItemTextIndex& other) const {
+    return text_offset < other.text_offset || item_index < other.item_index;
+  }
   bool operator>=(const NGInlineItemTextIndex& other) const {
-    return text_offset > other.text_offset ||
-           (text_offset == other.text_offset && item_index >= other.item_index);
+    return !operator<(other);
+  }
+  bool operator<=(const NGInlineItemTextIndex& other) const {
+    return !operator>(other);
   }
 
   // The index of `NGInlineItemsData::items`.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h
index 0fd5b524..4adfaba 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h
@@ -24,6 +24,10 @@
  public:
   virtual ~NGInlineItemsData() = default;
 
+  NGInlineItemTextIndex End() const {
+    return {items.size(), text_content.length()};
+  }
+
   // Text content for all inline items represented by a single NGInlineNode.
   // Encoded either as UTF-16 or latin-1 depending on the content.
   String text_content;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.cc
new file mode 100644
index 0000000..002ea77
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.cc
@@ -0,0 +1,198 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h"
+
+namespace blink {
+
+void NGLineBreakCandidateContext::Append(State new_state,
+                                         NGInlineItemTextIndex offset,
+                                         NGInlineItemTextIndex end,
+                                         float pos_no_break,
+                                         float pos_if_break,
+                                         float penalty,
+                                         bool is_hyphenated) {
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  DCHECK_GE(offset, end);
+  if (!candidates_.empty()) {
+    const NGLineBreakCandidate& last_candidate = candidates_.back();
+    if (state_ == NGLineBreakCandidateContext::kBreak) {
+      DCHECK_GT(offset, last_candidate.offset);
+    } else {
+      DCHECK_GE(offset, last_candidate.offset);
+    }
+    DCHECK_GE(end, last_candidate.end);
+    if (std::isnan(position_no_snap_)) {
+      DCHECK(std::isnan(last_candidate.pos_no_break));
+    } else if (position_no_snap_ < LayoutUnit::NearlyMax()) {
+      DCHECK_EQ(position_no_snap_, last_candidate.pos_no_break);
+      DCHECK_GE(pos_no_break, last_candidate.pos_no_break);
+    }
+  }
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+
+  switch (state_) {
+    case State::kBreak:
+      candidates_.emplace_back(offset, end, pos_no_break, pos_if_break, penalty,
+                               is_hyphenated);
+      break;
+    case State::kMidWord: {
+      NGLineBreakCandidate& last_candidate = candidates_.back();
+      last_candidate.offset = offset;
+      last_candidate.end = end;
+      last_candidate.pos_no_break = pos_no_break;
+      last_candidate.pos_if_break = pos_if_break;
+      last_candidate.penalty = penalty;
+      last_candidate.is_hyphenated = is_hyphenated;
+      break;
+    }
+  }
+  position_no_snap_ = pos_no_break;
+  state_ = new_state;
+}
+
+void NGLineBreakCandidateContext::Append(State new_state,
+                                         const NGInlineItemTextIndex& offset,
+                                         float position) {
+  Append(new_state, offset, offset, position, position);
+}
+
+void NGLineBreakCandidateContext::AppendTrailingSpaces(
+    State new_state,
+    const NGInlineItemTextIndex& offset,
+    float pos_no_break) {
+  DCHECK(!candidates_.empty());
+  NGLineBreakCandidate& last_candidate = candidates_.back();
+  DCHECK_GE(offset, last_candidate.offset);
+  DCHECK_EQ(position_no_snap_, last_candidate.pos_no_break);
+  last_candidate.offset = offset;
+  last_candidate.pos_no_break = pos_no_break;
+  position_no_snap_ = pos_no_break;
+  state_ = new_state;
+}
+
+bool NGLineBreakCandidateContext::AppendLine(const NGLineInfo& line_info,
+                                             NGLineBreaker& line_breaker) {
+  const NGInlineItemResult& last_item_result = line_info.Results().back();
+  if (!last_item_result.can_break_after) {
+    // TODO(kojii): `last_item_result.can_break_after` should be true, but there
+    // are cases where it is not set. The line breaker never uses it because
+    // `can_break_after` is used for rewinding, but it helps simplifying this
+    // logic.
+    const_cast<NGInlineItemResult&>(last_item_result).can_break_after = true;
+  }
+
+  for (const NGInlineItemResult& item_result : line_info.Results()) {
+    if (UNLIKELY(item_result.inline_size < LayoutUnit())) {
+      // Negative margins are not supported, break opportunities must increase
+      // monotonically. See `NGScoreLineBreaker::ComputeScores`.
+      return false;
+    }
+    DCHECK(item_result.item);
+    const NGInlineItem& item = *item_result.item;
+    switch (item.Type()) {
+      case NGInlineItem::kText:
+        line_breaker.AppendCandidates(item_result, line_info, *this);
+        break;
+      case NGInlineItem::kControl:
+        AppendTrailingSpaces(item_result.can_break_after ? kBreak : kMidWord,
+                             {item_result.item_index, item_result.EndOffset()},
+                             SnappedPosition() + item_result.inline_size);
+        SetLast(&item, item_result.EndOffset());
+        break;
+      default: {
+        State new_state;
+        if (item_result.can_break_after) {
+          new_state = kBreak;
+        } else if (state_ == kBreak) {
+          new_state = kMidWord;
+        } else {
+          new_state = state_;
+        }
+        const NGInlineItemTextIndex offset{item_result.item_index + 1,
+                                           item_result.EndOffset()};
+        const float end_position = SnappedPosition() + item_result.inline_size;
+        if (!item.Length()) {
+          // Oopaque items such as open/close don't change `pos_if_break`,
+          // similar to trailing spaces.
+          const NGLineBreakCandidate& last_candidate = candidates_.back();
+          Append(new_state, offset, last_candidate.end, end_position,
+                 last_candidate.pos_if_break);
+        } else {
+          Append(new_state, offset, end_position);
+        }
+        SetLast(&item, item_result.EndOffset());
+        break;
+      }
+    }
+  }
+
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  CheckConsistency();
+  DCHECK_EQ(state_, kBreak);
+  const NGLineBreakCandidate& last_candidate = candidates_.back();
+  DCHECK_GE(last_candidate.offset.item_index, last_item_result.item_index);
+  DCHECK_LE(last_candidate.offset.item_index, last_item_result.item_index + 1);
+  DCHECK_GE(last_candidate.offset.text_offset, last_item_result.EndOffset());
+  DCHECK_LE(last_candidate.offset.text_offset, line_info.EndTextOffset());
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+  return true;
+}
+
+void NGLineBreakCandidateContext::EnsureFirstSentinel(
+    const NGLineInfo& first_line_info) {
+  DCHECK(candidates_.empty());
+  const NGInlineItemResult& first_item_result =
+      first_line_info.Results().front();
+  candidates_.push_back(NGLineBreakCandidate{first_item_result.Start(), 0});
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  first_offset_ = first_item_result.Start();
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+}
+
+void NGLineBreakCandidateContext::EnsureLastSentinel(
+    const NGLineInfo& last_line_info) {
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  const NGInlineItemResult& last_item_result = last_line_info.Results().back();
+  DCHECK(last_item_result.can_break_after);
+  DCHECK_EQ(state_, NGLineBreakCandidateContext::kBreak);
+  CheckConsistency();
+  DCHECK_GE(candidates_.size(), 2u);
+  DCHECK_EQ(candidates_.front().offset, first_offset_);
+  DCHECK(candidates_.back().offset == last_item_result.End() ||
+         candidates_.back().offset == last_line_info.End());
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+}
+
+#if EXPENSIVE_DCHECKS_ARE_ON()
+void NGLineBreakCandidateContext::CheckConsistency() const {
+  for (wtf_size_t i = 1; i < candidates_.size(); ++i) {
+    const NGLineBreakCandidate& candidate = candidates_[i];
+    DCHECK_GE(candidate.offset, candidate.end);
+    const NGLineBreakCandidate& prev_candidate = candidates_[i - 1];
+    DCHECK_GT(candidate.offset, prev_candidate.offset);
+    DCHECK_GE(candidate.end, prev_candidate.end);
+    if (std::isnan(candidate.pos_no_break) ||
+        candidate.pos_no_break >= LayoutUnit::NearlyMax()) {
+      continue;
+    }
+    DCHECK_GE(candidate.pos_no_break, prev_candidate.pos_no_break);
+  }
+}
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+
+std::ostream& operator<<(std::ostream& ostream,
+                         const NGLineBreakCandidate& candidate) {
+  return ostream << candidate.offset << "/" << candidate.end << " "
+                 << candidate.pos_no_break << "/" << candidate.pos_if_break
+                 << " penalty=" << candidate.penalty
+                 << (candidate.is_hyphenated ? " (hyphenated)" : "");
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h
new file mode 100644
index 0000000..f95d3b4
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h
@@ -0,0 +1,136 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_CANDIDATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_CANDIDATE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_break_point.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class NGInlineItem;
+class NGLineBreaker;
+class NGLineInfo;
+
+//
+// Represents a break candidate (break opportunity).
+//
+struct CORE_EXPORT NGLineBreakCandidate : public NGLineBreakPoint {
+  DISALLOW_NEW();
+
+ public:
+  NGLineBreakCandidate() = default;
+  NGLineBreakCandidate(const NGInlineItemTextIndex& offset,
+                       const NGInlineItemTextIndex& end,
+                       float pos_no_break,
+                       float pos_if_break,
+                       float penalty = .0f,
+                       bool is_hyphenated = false)
+      : NGLineBreakPoint(offset, end, is_hyphenated),
+        pos_no_break(pos_no_break),
+        pos_if_break(pos_if_break),
+        penalty(penalty) {}
+  NGLineBreakCandidate(const NGInlineItemTextIndex& offset, float position)
+      : NGLineBreakCandidate(offset, offset, position, position) {}
+
+  bool operator==(const NGLineBreakCandidate& other) const {
+    return NGLineBreakPoint::operator==(other) &&
+           pos_no_break == other.pos_no_break &&
+           pos_if_break == other.pos_if_break && penalty == other.penalty;
+  }
+
+  // The position when the line doesn't break offset the `offset`.
+  float pos_no_break = 0;
+  // The position if the line breaks here. This is different from `pos_no_break`
+  // if there are trailing spaces, kernings, hyphens, etc.
+  float pos_if_break = 0;
+  // The line break penalty of this candidate.
+  float penalty = 0;
+
+  static constexpr wtf_size_t kInlineCapacity = 128;
+};
+
+CORE_EXPORT std::ostream& operator<<(std::ostream& ostream,
+                                     const NGLineBreakCandidate& candidate);
+
+//
+// A vector of `NGLineBreakCandidate`.
+//
+using NGLineBreakCandidates =
+    Vector<NGLineBreakCandidate, NGLineBreakCandidate::kInlineCapacity>;
+
+//
+// Provides a context for computing `NGLineBreakCandidate` from multiple
+// `NGLineInfo` and `NGInlineItemResult`.
+//
+class CORE_EXPORT NGLineBreakCandidateContext {
+  STACK_ALLOCATED();
+
+ public:
+  explicit NGLineBreakCandidateContext(NGLineBreakCandidates& candidates)
+      : candidates_(candidates) {}
+
+  enum State : uint8_t { kBreak, kMidWord };
+  State GetState() const { return state_; }
+
+  float Position() const { return position_no_snap_; }
+  LayoutUnit SnappedPosition() const {
+    return LayoutUnit::FromFloatCeil(position_no_snap_);
+  }
+
+  const NGLineBreakCandidates& Candidates() const { return candidates_; }
+
+  const NGInlineItem* LastItem() const { return last_item_; }
+  wtf_size_t LastEndOffset() const { return last_end_offset_; }
+  void SetLast(const NGInlineItem* item, wtf_size_t offset) {
+    last_item_ = item;
+    last_end_offset_ = offset;
+  }
+
+  // Append a `NGLineInfo` to this context.
+  bool AppendLine(const NGLineInfo& line_info, NGLineBreaker& line_breaker);
+
+  // Append a new `NGLineBreakCandidate`. This modifies the last candidate if
+  // `state` is `kMidWord`, instead of adding a new candidate.
+  void Append(State new_state,
+              NGInlineItemTextIndex offset,
+              NGInlineItemTextIndex end,
+              float pos_no_break,
+              float pos_if_break,
+              float penalty = .0f,
+              bool is_hyphenated = false);
+  void Append(State new_state,
+              const NGInlineItemTextIndex& offset,
+              float position);
+  void AppendTrailingSpaces(State new_state,
+                            const NGInlineItemTextIndex& offset,
+                            float pos_no_break);
+
+  // Append the first/last sentinel. `NGScoreLineBreaker` requires these two
+  // sentinels.
+  void EnsureFirstSentinel(const NGLineInfo& first_line_info);
+  void EnsureLastSentinel(const NGLineInfo& last_line_info);
+
+ private:
+  float position_no_snap_ = .0f;
+  State state_ = State::kBreak;
+  const NGInlineItem* last_item_ = nullptr;
+  wtf_size_t last_end_offset_ = 0;
+  NGLineBreakCandidates& candidates_;
+
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  void CheckConsistency() const;
+
+  NGInlineItemTextIndex first_offset_;
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_CANDIDATE_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate_test.cc
new file mode 100644
index 0000000..abf0ec6
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate_test.cc
@@ -0,0 +1,342 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
+
+namespace blink {
+
+class NGLineBreakCandidateTest : public RenderingTest {
+ public:
+  bool ComputeCandidates(const NGInlineNode& node,
+                         LayoutUnit available_width,
+                         NGLineBreakCandidates& candidates) {
+    NGConstraintSpace space = ConstraintSpaceForAvailableSize(available_width);
+    NGExclusionSpace exclusion_space;
+    NGPositionedFloatVector leading_floats;
+    NGLineLayoutOpportunity line_opportunity(available_width);
+    const NGInlineBreakToken* break_token = nullptr;
+    NGLineInfo line_info;
+    NGLineBreakCandidateContext context(candidates);
+    bool is_first = true;
+    do {
+      NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, space,
+                                 line_opportunity, leading_floats, 0u,
+                                 break_token, /* column_spanner_path */ nullptr,
+                                 &exclusion_space);
+      line_breaker.NextLine(&line_info);
+      if (is_first) {
+        context.EnsureFirstSentinel(line_info);
+        is_first = false;
+      }
+      if (!context.AppendLine(line_info, line_breaker)) {
+        return false;
+      }
+      break_token = line_info.BreakToken();
+    } while (break_token);
+    context.EnsureLastSentinel(line_info);
+    return true;
+  }
+};
+
+TEST_F(NGLineBreakCandidateTest, Text) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      01 345
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (int width : {800, 50, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({0, 3}, {0, 2}, 30, 20),
+                                NGLineBreakCandidate({0, 6}, 60)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, SoftHyphen) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      01&shy;345&shy;7890
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (int width : {800, 70, 60, 50, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates,
+                testing::ElementsAre(
+                    NGLineBreakCandidate({0, 0}, 0),
+                    NGLineBreakCandidate({0, 3}, {0, 3}, 20, 30, 0, true),
+                    NGLineBreakCandidate({0, 7}, {0, 7}, 50, 60, 0, true),
+                    NGLineBreakCandidate({0, 11}, 90)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, Span) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      01 <span>345</span> 7890
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 60, 50, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({0, 3}, {0, 2}, 30, 20),
+                                NGLineBreakCandidate({4, 7}, {2, 6}, 70, 60),
+                                NGLineBreakCandidate({4, 11}, 110)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, SpanMidWord) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      0<span>12</span>345 7890
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 80, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({4, 7}, {4, 6}, 70, 60),
+                                NGLineBreakCandidate({4, 11}, 110)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, SpanCloseAfterSpace) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      01 <span>345 </span>7890
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 50, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({0, 3}, {0, 2}, 30, 20),
+                                NGLineBreakCandidate({4, 7}, {2, 6}, 70, 60),
+                                NGLineBreakCandidate({4, 11}, 110)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, TrailingSpacesCollapsed) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      012 <span style="font-size: 20px"> </span>456
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 50, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    // TODO(kojii): There shouldn't be a break opportunity before `<span>`, but
+    // `item_results[0].can_break_after` is set.
+    if (width < 70) {
+      EXPECT_THAT(candidates, testing::ElementsAre(
+                                  NGLineBreakCandidate({0, 0}, 0),
+                                  NGLineBreakCandidate({0, 4}, {0, 3}, 40, 30),
+                                  NGLineBreakCandidate({4, 4}, {0, 3}, 40, 30),
+                                  NGLineBreakCandidate({4, 7}, 70)))
+          << String::Format("Width=%d", width);
+      continue;
+    }
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({0, 4}, {0, 3}, 40, 30),
+                                NGLineBreakCandidate({4, 7}, 70)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, AtomicInline) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    span {
+      display: inline-block;
+      width: 1em;
+    }
+    </style>
+    <div id="target"><span></span><span></span></div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates,
+                testing::ElementsAre(NGLineBreakCandidate({0, 0}, 0),
+                                     NGLineBreakCandidate({1, 1}, 10),
+                                     NGLineBreakCandidate({2, 2}, 20)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+// fast/borders/border-image-border-radius.html
+TEST_F(NGLineBreakCandidateTest, AtomicInlineBr) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    span {
+      display: inline-block;
+      width: 1em;
+    }
+    </style>
+    <div id="target">
+      <span></span>
+      <br>
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                NGLineBreakCandidate({2, 2}, {1, 1}, 10, 10)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+// All/VisualRectMappingTest.LayoutTextContainerFlippedWritingMode/6
+TEST_F(NGLineBreakCandidateTest, AtomicInlineTrailingSpaces) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    inline-block {
+      display: inline-block;
+      width: 1em;
+    }
+    </style>
+    <div id="target">
+      <span><inline-block></inline-block></span>
+      <span>23</span>
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(candidates, testing::ElementsAre(
+                                NGLineBreakCandidate({0, 0}, 0),
+                                // TODO(kojii): {3,2} should be {4,2}.
+                                NGLineBreakCandidate({3, 2}, {2, 1}, 20, 10),
+                                NGLineBreakCandidate({7, 4}, {5, 4}, 40, 40)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+TEST_F(NGLineBreakCandidateTest, ForcedBreak) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+    }
+    </style>
+    <div id="target">
+      01 345<br>
+      01 3456 <br>
+    </div>
+  )HTML");
+  const NGInlineNode target = GetInlineNodeByElementId("target");
+  for (const int width : {800, 40, 10}) {
+    NGLineBreakCandidates candidates;
+    EXPECT_TRUE(ComputeCandidates(target, LayoutUnit(width), candidates));
+    EXPECT_THAT(
+        candidates,
+        testing::ElementsAre(NGLineBreakCandidate({0, 0}, 0),
+                             NGLineBreakCandidate({0, 3}, {0, 2}, 30, 20),
+                             NGLineBreakCandidate({1, 7}, {0, 6}, 60, 60),
+                             NGLineBreakCandidate({2, 10}, {2, 9}, 90, 80),
+                             NGLineBreakCandidate({3, 15}, {2, 14}, 130, 130)))
+        << String::Format("Width=%d", width);
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_point.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_point.h
new file mode 100644
index 0000000..2e9cb52
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_break_point.h
@@ -0,0 +1,60 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_POINT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_POINT_H_
+
+#include "base/check_op.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_text_index.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+//
+// Represents a determined break point.
+//
+struct CORE_EXPORT NGLineBreakPoint {
+  DISALLOW_NEW();
+
+ public:
+  NGLineBreakPoint() = default;
+  NGLineBreakPoint(const NGInlineItemTextIndex& offset,
+                   const NGInlineItemTextIndex& end,
+                   bool is_hyphenated = false)
+      : offset(offset), end(end), is_hyphenated(is_hyphenated) {}
+  explicit NGLineBreakPoint(const NGInlineItemTextIndex& offset,
+                            bool is_hyphenated = false)
+      : NGLineBreakPoint(offset, offset, is_hyphenated) {}
+
+  explicit operator bool() const { return offset.text_offset; }
+
+  bool operator==(const NGLineBreakPoint& other) const {
+    return offset == other.offset && end == other.end &&
+           is_hyphenated == other.is_hyphenated;
+  }
+
+  // The line breaks before `offset`. The `offset` is also the start of the next
+  // line, includes trailing spaces, while `end` doesn't.
+  //
+  // In the following example, the line should break before `next`:
+  // ```
+  // end <span> </span> next
+  // ```
+  // Then `offset` is at `n`, while `end` is at the next space of `end`.
+  NGInlineItemTextIndex offset;
+  NGInlineItemTextIndex end;
+
+  // True when this break point has a hyphen.
+  bool is_hyphenated = false;
+
+#if EXPENSIVE_DCHECKS_ARE_ON()
+  LayoutUnit line_width;
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BREAK_POINT_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index c9e64388e..ecefd10 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_break_candidate.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
@@ -164,6 +165,20 @@
       .IsAllSpecialCharacters<IsBreakableSpace>();
 }
 
+inline LayoutUnit HyphenAdvance(const ComputedStyle& style,
+                                bool is_ltr,
+                                const HyphenResult& hyphen_result,
+                                absl::optional<LayoutUnit>& cache) {
+  if (cache) {
+    return *cache;
+  }
+  const LayoutUnit size = hyphen_result ? hyphen_result.InlineSize()
+                                        : HyphenResult(style).InlineSize();
+  const LayoutUnit advance = is_ltr ? size : -size;
+  cache = advance;
+  return advance;
+}
+
 // True if the item is "trailable". Trailable items should be included in the
 // line if they are after the soft wrap point.
 //
@@ -836,8 +851,12 @@
 bool NGLineBreaker::CanBreakAfterAtomicInline(const NGInlineItem& item) const {
   DCHECK(item.Type() == NGInlineItem::kAtomicInline ||
          item.Type() == NGInlineItem::kInitialLetterBox);
-  if (!auto_wrap_ || item.EndOffset() == Text().length())
+  if (!auto_wrap_) {
     return false;
+  }
+  if (item.EndOffset() == Text().length()) {
+    return true;
+  }
   // We can not break before sticky images quirk was applied.
   if (item.IsImage())
     return !sticky_images_quirk_;
@@ -1594,6 +1613,258 @@
   return shape_result;
 }
 
+void NGLineBreaker::AppendCandidates(const NGInlineItemResult& item_result,
+                                     const NGLineInfo& line_info,
+                                     NGLineBreakCandidateContext& context) {
+  DCHECK(item_result.item);
+  const NGInlineItem& item = *item_result.item;
+  const wtf_size_t item_index = item_result.item_index;
+  DCHECK(context.GetState() == NGLineBreakCandidateContext::kBreak ||
+         !context.Candidates().empty());
+
+  DCHECK_EQ(item.Type(), NGInlineItem::kText);
+  if (!item.Length()) {
+    // Fully collapsed spaces don't have break opportunities.
+    context.AppendTrailingSpaces(
+        item_result.can_break_after ? NGLineBreakCandidateContext::kBreak
+                                    : context.GetState(),
+        {item_result.item_index, item.EndOffset()}, context.Position());
+    context.SetLast(&item, item.EndOffset());
+    return;
+  }
+
+  DCHECK(item.TextShapeResult());
+  struct ShapeResultWrapper {
+    explicit ShapeResultWrapper(const ShapeResult* shape_result)
+        : shape_result(shape_result),
+          shape_result_start_index(shape_result->StartIndex()),
+          is_ltr(shape_result->IsLtr()) {
+      shape_result->EnsurePositionData();
+    }
+
+    bool IsLtr() const { return is_ltr; }
+
+    // The returned position is in the external coordinate system set by
+    // `SetBasePosition`, not the internal one of the `ShapeResult`.
+    float PositionForOffset(unsigned offset) const {
+      DCHECK_GE(offset, shape_result_start_index);
+      const float position = shape_result->CachedPositionForOffset(
+          offset - shape_result_start_index);
+      return IsLtr() ? base_position + position : base_position - position;
+    }
+
+    // Adjusts the internal coordinate system of the `ShapeResult` to the
+    // specified one.
+    void SetBasePosition(wtf_size_t offset, float adjusted) {
+      DCHECK_GE(offset, shape_result_start_index);
+      const float position = shape_result->CachedPositionForOffset(
+          offset - shape_result_start_index);
+      base_position = IsLtr() ? adjusted - position : adjusted + position;
+      DCHECK_EQ(adjusted, PositionForOffset(offset));
+    }
+
+    unsigned PreviousSafeToBreakOffset(unsigned offset) const {
+      // Unlike `PositionForOffset`, `PreviousSafeToBreakOffset` takes the
+      // "external" offset that takes care of `StartIndex()`.
+      return shape_result->CachedPreviousSafeToBreakOffset(offset);
+    }
+
+    const ShapeResult* const shape_result;
+    const wtf_size_t shape_result_start_index;
+    float base_position = .0f;
+    const bool is_ltr;
+  } shape_result(item.TextShapeResult());
+  const String& text_content = Text();
+
+  // Extend the end offset to the end of the item or the end of this line,
+  // whichever earlier. This is not only for performance but also to include
+  // trailing spaces that may be removed by the line breaker.
+  NGTextOffsetRange offset = item_result.TextOffset();
+  offset.end = std::max(offset.end,
+                        std::min(item.EndOffset(), line_info.EndTextOffset()));
+
+  // Extend the start offset to `context.last_end_offset`. Trailing spaces may
+  // be skipped, or leading spaces may be already handled.
+  if (context.LastItem()) {
+    DCHECK_GE(context.LastEndOffset(), item.StartOffset());
+    if (context.LastEndOffset() >= offset.end) {
+      return;  // Return if all characters were already handled.
+    }
+    offset.start = context.LastEndOffset();
+    offset.AssertNotEmpty();
+    shape_result.SetBasePosition(offset.start, context.Position());
+
+    // Handle leading/trailing spaces if they were skipped.
+    if (IsBreakableSpace(text_content[offset.start])) {
+      DCHECK_GE(offset.start, item.StartOffset());
+      do {
+        ++offset.start;
+      } while (offset.start < offset.end &&
+               IsBreakableSpace(text_content[offset.start]));
+      const float end_position = shape_result.PositionForOffset(offset.start);
+      if (!offset.Length()) {
+        context.AppendTrailingSpaces(
+            item_result.can_break_after ? NGLineBreakCandidateContext::kBreak
+                                        : NGLineBreakCandidateContext::kMidWord,
+            {item_index, offset.start}, end_position);
+        context.SetLast(&item, offset.end);
+        return;
+      }
+      context.AppendTrailingSpaces(auto_wrap_
+                                       ? NGLineBreakCandidateContext::kBreak
+                                       : NGLineBreakCandidateContext::kMidWord,
+                                   {item_index, offset.start}, end_position);
+    }
+  } else {
+    shape_result.SetBasePosition(offset.start, context.Position());
+  }
+  offset.AssertNotEmpty();
+  DCHECK_GE(offset.start, item.StartOffset());
+  DCHECK_GE(offset.start, context.LastEndOffset());
+  DCHECK_LE(offset.end, item.EndOffset());
+  context.SetLast(&item, offset.end);
+
+  // Setup the style and its derived fields for this `item`.
+  if (offset.start < break_iterator_.StartOffset()) {
+    break_iterator_.SetStartOffset(offset.start);
+  }
+  DCHECK(item.Style());
+  SetCurrentStyle(*item.Style());
+
+  // Find all break opportunities in `item_result`.
+  absl::optional<LayoutUnit> hyphen_advance_cache;
+  for (;;) {
+    // Compute the offset of the next break opportunity.
+    wtf_size_t next_offset;
+    if (auto_wrap_) {
+      next_offset = break_iterator_.NextBreakOpportunity(
+          offset.start + 1, std::min(offset.end + 1, text_content.length()));
+    } else {
+      next_offset = offset.end + 1;
+    }
+    if (next_offset > offset.end && item_result.can_break_after) {
+      // If `can_break_after`, honor it over `next_offset`. CSS can allow the
+      // break at the end. E.g., fast/inline/line-break-atomic-inline.html
+      next_offset = offset.end;
+    }
+
+    // Compute the position of the break opportunity and the end of the word.
+    wtf_size_t end_offset;
+    float next_position;
+    float end_position;
+    NGLineBreakCandidateContext::State next_state =
+        NGLineBreakCandidateContext::kBreak;
+    bool is_hyphenated = false;
+    if (next_offset > offset.end) {
+      // If the next break opportunity is beyond this item, stop at the end of
+      // this item and set `is_middle_word`.
+      end_offset = next_offset = offset.end;
+      end_position = next_position =
+          shape_result.PositionForOffset(next_offset);
+      next_state = NGLineBreakCandidateContext::kMidWord;
+    } else {
+      if (next_offset == offset.end && !item_result.can_break_after) {
+        // Can't break at `next_offset` by higher level protocols.
+        // E.g., `<span>1 </span>2`.
+        next_state = NGLineBreakCandidateContext::kMidWord;
+      }
+      next_position = shape_result.PositionForOffset(next_offset);
+
+      // Exclude trailing spaces if any.
+      end_offset = next_offset;
+      DCHECK_GT(end_offset, offset.start);
+      UChar last_ch = text_content[end_offset - 1];
+      while (IsBreakableSpace(last_ch)) {
+        --end_offset;
+        if (end_offset == offset.start) {
+          last_ch = 0;
+          break;
+        }
+        last_ch = text_content[end_offset - 1];
+      }
+      DCHECK_LE(end_offset, offset.end);
+
+      if (UNLIKELY(hyphenation_)) {
+        const LayoutUnit hyphen_advance =
+            HyphenAdvance(*current_style_, shape_result.IsLtr(),
+                          item_result.hyphen, hyphen_advance_cache);
+        DCHECK_GT(end_offset, offset.start);
+        const wtf_size_t word_len = end_offset - offset.start;
+        const StringView word(text_content, offset.start, word_len);
+        Vector<wtf_size_t, 8> locations = hyphenation_->HyphenLocations(word);
+        // |locations| is a list of hyphenation points in the descending order.
+#if EXPENSIVE_DCHECKS_ARE_ON()
+        DCHECK(!locations.Contains(0u));
+        DCHECK(!locations.Contains(word_len));
+        DCHECK(std::is_sorted(locations.rbegin(), locations.rend()));
+#endif  // EXPENSIVE_DCHECKS_ARE_ON()
+        NGInlineItemTextIndex hyphen_offset = {item_index, 0};
+        for (const wtf_size_t location : base::Reversed(locations)) {
+          hyphen_offset.text_offset = offset.start + location;
+          const float position =
+              shape_result.PositionForOffset(hyphen_offset.text_offset);
+          float penalty = 0;  // TODO(kojii): penalty not implemented yet.
+          context.Append(NGLineBreakCandidateContext::kBreak, hyphen_offset,
+                         hyphen_offset, position, position + hyphen_advance,
+                         penalty,
+                         /*is_hyphenated*/ true);
+        }
+      }
+
+      // Compute the end position of this word, excluding trailing spaces.
+      wtf_size_t end_safe_offset;
+      switch (next_state) {
+        case NGLineBreakCandidateContext::kBreak:
+          end_safe_offset = shape_result.PreviousSafeToBreakOffset(end_offset);
+          if (end_safe_offset < offset.start) {
+            DCHECK_EQ(context.Candidates().back().offset.text_offset,
+                      offset.start);
+            end_safe_offset = offset.start;
+          }
+          break;
+        case NGLineBreakCandidateContext::kMidWord:
+          end_safe_offset = end_offset;
+          break;
+      }
+      if (end_safe_offset == end_offset) {
+        if (end_offset == next_offset) {
+          end_position = next_position;
+        } else {
+          end_position = shape_result.PositionForOffset(end_offset);
+        }
+      } else {
+        DCHECK_LT(end_safe_offset, end_offset);
+        end_position = shape_result.PositionForOffset(end_safe_offset);
+        scoped_refptr<ShapeResult> end_shape_result =
+            ShapeText(item, end_safe_offset, end_offset);
+        end_position += end_shape_result->Width();
+      }
+
+      DCHECK(!is_hyphenated);
+      if (end_offset == item_result.EndOffset()) {
+        is_hyphenated = item_result.is_hyphenated;
+      } else if (last_ch == kSoftHyphenCharacter) {
+        is_hyphenated = true;
+      }
+      if (is_hyphenated) {
+        end_position += HyphenAdvance(*current_style_, shape_result.IsLtr(),
+                                      item_result.hyphen, hyphen_advance_cache);
+      }
+    }
+
+    // TODO(kojii): Increase the penalty if `last_ch` is not a space in
+    // space-delimiting lang? Or if '-', '/', etc.?
+    float penalty = 0;  // TODO(kojii): penalty not implemented yet.
+    context.Append(next_state, {item_index, next_offset},
+                   {item_index, end_offset}, next_position, end_position,
+                   penalty, is_hyphenated);
+    if (next_offset >= offset.end) {
+      break;
+    }
+    offset.start = next_offset;
+  }
+}
+
 // Compute a new ShapeResult for the specified end offset.
 // The end is re-shaped if it is not safe-to-break.
 scoped_refptr<ShapeResultView> NGLineBreaker::TruncateLineEndResult(
@@ -1944,6 +2215,7 @@
     NGInlineItemResult* item_result = AddItem(*item, line_info);
     item_result->should_create_line_box = true;
     item_result->has_only_trailing_spaces = true;
+    item_result->can_break_after = true;
     MoveToNextOf(*item);
 
     // Include following close tags. The difference is visible when they have
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 856ddca1..d5e539f8 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -23,6 +23,7 @@
 class NGColumnSpannerPath;
 class NGInlineBreakToken;
 class NGInlineItem;
+class NGLineBreakCandidateContext;
 class NGLineInfo;
 class ResolvedTextLayoutAttributesIterator;
 
@@ -88,6 +89,12 @@
     return trailing_whitespace_;
   }
 
+  // Find break candidates in the `item_result` and append to `context`. See
+  // `NGLineBreakCandidate` and `NGLineBreakCandidateContext` for more details.
+  void AppendCandidates(const NGInlineItemResult& item_result,
+                        const NGLineInfo& line_info,
+                        NGLineBreakCandidateContext& context);
+
  private:
   const String& Text() const { return text_content_; }
   const HeapVector<NGInlineItem>& Items() const { return items_data_.items; }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 087f186..f060583 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -49,18 +49,9 @@
       void (*callback)(const NGLineBreaker&, const NGLineInfo&) = nullptr,
       bool fill_first_space_ = false) {
     DCHECK(node);
-
     node.PrepareLayoutIfNeeded();
-
-    NGConstraintSpaceBuilder builder(
-        WritingMode::kHorizontalTb,
-        {WritingMode::kHorizontalTb, TextDirection::kLtr},
-        /* is_new_fc */ false);
-    builder.SetAvailableSize({available_width, kIndefiniteSize});
-    NGConstraintSpace space = builder.ToConstraintSpace();
-
+    NGConstraintSpace space = ConstraintSpaceForAvailableSize(available_width);
     const NGInlineBreakToken* break_token = nullptr;
-
     Vector<std::pair<String, unsigned>> lines;
     trailing_whitespaces_.resize(0);
     NGExclusionSpace exclusion_space;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.cc
index 3c5f08c..4125fe5 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/adapters.h"
 #include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 
@@ -136,6 +137,15 @@
   return false;
 }
 
+NGInlineItemTextIndex NGLineInfo::End() const {
+  return BreakToken() ? BreakToken()->Start() : ItemsData().End();
+}
+
+unsigned NGLineInfo::EndTextOffset() const {
+  return BreakToken() ? BreakToken()->StartTextOffset()
+                      : ItemsData().text_content.length();
+}
+
 unsigned NGLineInfo::InflowEndOffset() const {
   for (const auto& item_result : base::Reversed(Results())) {
     DCHECK(item_result.item);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
index 4d2dd968..abb6b70 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
@@ -158,10 +158,14 @@
     width_ = width;
   }
 
-  // Start text offset of this line.
+  // Start offset of this line.
   const NGInlineItemTextIndex& Start() const { return start_; }
   unsigned StartOffset() const { return start_.text_offset; }
   void SetStart(const NGInlineItemTextIndex& index) { start_ = index; }
+  // End offset of this line. This is the same as the start offset of the next
+  // line, or the end of block if this is the last line.
+  NGInlineItemTextIndex End() const;
+  unsigned EndTextOffset() const;
   // End text offset of this line, excluding out-of-flow objects such as
   // floating or positioned.
   unsigned InflowEndOffset() const;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc
index b3be556..c233377 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc
@@ -18,13 +18,7 @@
     const NGPhysicalBoxFragment* fragment =
         node.GetLayoutBox()->GetPhysicalFragment(0);
     const LayoutUnit width = fragment->Size().width;
-
-    NGConstraintSpaceBuilder builder(
-        WritingMode::kHorizontalTb,
-        {WritingMode::kHorizontalTb, TextDirection::kLtr},
-        /* is_new_fc */ false);
-    builder.SetAvailableSize(LogicalSize(width, LayoutUnit::Max()));
-    NGConstraintSpace space = builder.ToConstraintSpace();
+    NGConstraintSpace space = ConstraintSpaceForAvailableSize(width);
     NGLineLayoutOpportunity line_opportunity(width);
     return NGParagraphLineBreaker::AttemptParagraphBalancing(node, space,
                                                              line_opportunity);
diff --git a/third_party/blink/renderer/core/loader/build.gni b/third_party/blink/renderer/core/loader/build.gni
index ad193bf..4941a2c 100644
--- a/third_party/blink/renderer/core/loader/build.gni
+++ b/third_party/blink/renderer/core/loader/build.gni
@@ -121,6 +121,8 @@
   "resource/image_resource_content.h",
   "resource/image_resource_info.h",
   "resource/image_resource_observer.h",
+  "resource/link_dictionary_resource.cc",
+  "resource/link_dictionary_resource.h",
   "resource/link_prefetch_resource.cc",
   "resource/link_prefetch_resource.h",
   "resource/multipart_image_resource_parser.cc",
diff --git a/third_party/blink/renderer/core/loader/link_loader.cc b/third_party/blink/renderer/core/loader/link_loader.cc
index fdf4137..5e96e83f 100644
--- a/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/third_party/blink/renderer/core/loader/link_loader.cc
@@ -141,6 +141,7 @@
     PreloadHelper::PrefetchIfNeeded(params, document, pending_preload_);
   PreloadHelper::ModulePreloadIfNeeded(
       params, document, nullptr /* viewport_description */, pending_preload_);
+  PreloadHelper::FetchDictionaryIfNeeded(params, document, pending_preload_);
 
   absl::optional<mojom::blink::PrerenderTriggerType> trigger_type =
       PrerenderTriggerTypeFromRelAttribute(params.rel, document);
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index 2808413b..75fae178 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -8,10 +8,13 @@
 
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_mock_time_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/loader/referrer_utils.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_prescient_networking.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
@@ -22,6 +25,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/link_loader_client.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
+#include "third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h"
 #include "third_party/blink/renderer/core/testing/dummy_modulator.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h"
@@ -29,6 +33,9 @@
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
+#include "third_party/blink/renderer/platform/scheduler/public/main_thread_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/testing/url_loader_mock_factory.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -780,6 +787,71 @@
   EXPECT_TRUE(resource->IsLinkPreload());
 }
 
-}  // namespace
+class DictionaryLinkTest : public testing::Test,
+                           public testing::WithParamInterface<bool> {
+ public:
+  DictionaryLinkTest()
+      : dictionary_scoped_feature_(GetParam()),
+        backend_scoped_feature_(GetParam()) {}
 
+  void SetUp() override {
+    test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  }
+
+  void RunIdleTasks() {
+    ThreadScheduler::Current()
+        ->ToMainThreadScheduler()
+        ->StartIdlePeriodForTesting();
+    platform_->RunUntilIdle();
+  }
+
+ protected:
+  ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
+  scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
+
+ private:
+  ScopedCompressionDictionaryTransportForTest dictionary_scoped_feature_;
+  ScopedCompressionDictionaryTransportBackendForTest backend_scoped_feature_;
+};
+
+INSTANTIATE_TEST_SUITE_P(DictionaryLinkTest,
+                         DictionaryLinkTest,
+                         testing::Bool());
+
+TEST_P(DictionaryLinkTest, LoadDictionaryFromLink) {
+  bool is_dictionary_load_enabled = GetParam();
+  static constexpr char href[] = "http://example.test/test.dict";
+
+  // Test the cases with a single header
+  auto dummy_page_holder =
+      std::make_unique<DummyPageHolder>(gfx::Size(500, 500));
+  dummy_page_holder->GetFrame().GetSettings()->SetScriptEnabled(true);
+  Persistent<MockLinkLoaderClient> loader_client =
+      MakeGarbageCollected<MockLinkLoaderClient>(is_dictionary_load_enabled);
+  auto* loader = MakeGarbageCollected<LinkLoader>(loader_client.Get());
+  KURL href_url = KURL(NullURL(), href);
+  // TODO(crbug.com/751425): We should use the mock functionality
+  // via |dummy_page_holder|.
+  url_test_helpers::RegisterMockedErrorURLLoad(href_url);
+  LinkLoadParameters params(
+      LinkRelAttribute("dictionary"), kCrossOriginAttributeNotSet,
+      String() /* type */, String() /* as */, String() /* media */,
+      String() /* nonce */, String() /* integrity */,
+      String() /* fetch_priority_hint */,
+      network::mojom::ReferrerPolicy::kDefault, href_url,
+      String() /* image_srcset */, String() /* image_sizes */,
+      String() /* blocking */);
+  loader->LoadLink(params, dummy_page_holder->GetDocument());
+  RunIdleTasks();
+  Resource* resource = loader->GetResourceForTesting();
+  if (is_dictionary_load_enabled) {
+    EXPECT_TRUE(resource);
+  } else {
+    EXPECT_FALSE(resource);
+  }
+  URLLoaderMockFactory::GetSingletonInstance()
+      ->UnregisterAllURLsAndClearMemoryCache();
+}
+
+}  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index b82cfe57..c0cfd355 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -9,10 +9,12 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_prescient_networking.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_idle_request_options.h"
 #include "third_party/blink/renderer/core/css/media_list.h"
 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
 #include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/scripted_idle_task_controller.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -35,6 +37,7 @@
 #include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/font_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/link_prefetch_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/script_resource.h"
 #include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
@@ -50,11 +53,41 @@
 #include "third_party/blink/renderer/platform/loader/link_header.h"
 #include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
 namespace {
 
+class LoadDictionaryWhenIdleTask final : public IdleTask {
+ public:
+  LoadDictionaryWhenIdleTask(FetchParameters fetch_params,
+                             ResourceFetcher* fetcher,
+                             PendingLinkPreload* pending_preload)
+      : fetch_params_(std::move(fetch_params)),
+        resource_fetcher_(fetcher),
+        pending_preload_(pending_preload) {}
+
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(resource_fetcher_);
+    visitor->Trace(pending_preload_);
+    IdleTask::Trace(visitor);
+  }
+
+ private:
+  void invoke(IdleDeadline* deadline) override {
+    Resource* resource =
+        LinkDictionaryResource::Fetch(fetch_params_, resource_fetcher_);
+    if (pending_preload_) {
+      pending_preload_->AddResource(resource);
+    }
+  }
+
+  FetchParameters fetch_params_;
+  Member<ResourceFetcher> resource_fetcher_;
+  Member<PendingLinkPreload> pending_preload_;
+};
+
 void SendMessageToConsoleForPossiblyNullDocument(
     ConsoleMessage* console_message,
     Document* document,
@@ -796,6 +829,47 @@
   }
 }
 
+void PreloadHelper::FetchDictionaryIfNeeded(
+    const LinkLoadParameters& params,
+    Document& document,
+    PendingLinkPreload* pending_preload) {
+  if (!CompressionDictionaryTransportFullyEnabled(
+          document.GetExecutionContext())) {
+    return;
+  }
+
+  if (!document.Loader() || document.Loader()->Archive()) {
+    return;
+  }
+
+  if (!params.rel.IsDictionary() || !params.href.IsValid() ||
+      !document.GetFrame()) {
+    return;
+  }
+
+  DVLOG(1) << "PreloadHelper::FetchDictionaryIfNeeded "
+           << params.href.GetString().Utf8();
+  ResourceRequest resource_request(params.href);
+
+  resource_request.SetReferrerString(Referrer::NoReferrer());
+  resource_request.SetCredentialsMode(network::mojom::CredentialsMode::kOmit);
+  resource_request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever);
+  resource_request.SetMode(network::mojom::RequestMode::kCors);
+  resource_request.SetRequestDestination(
+      network::mojom::RequestDestination::kDictionary);
+
+  ResourceLoaderOptions options(
+      document.GetExecutionContext()->GetCurrentWorld());
+  options.initiator_info.name = fetch_initiator_type_names::kLink;
+
+  FetchParameters link_fetch_params(std::move(resource_request), options);
+  IdleRequestOptions* idle_options = IdleRequestOptions::Create();
+  document.RequestIdleCallback(
+      MakeGarbageCollected<LoadDictionaryWhenIdleTask>(
+          std::move(link_fetch_params), document.Fetcher(), pending_preload),
+      idle_options);
+}
+
 Resource* PreloadHelper::StartPreload(ResourceType type,
                                       FetchParameters& params,
                                       Document& document) {
diff --git a/third_party/blink/renderer/core/loader/preload_helper.h b/third_party/blink/renderer/core/loader/preload_helper.h
index 15bd4e75..62c972d3 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.h
+++ b/third_party/blink/renderer/core/loader/preload_helper.h
@@ -71,6 +71,9 @@
                                     Document&,
                                     const ViewportDescription*,
                                     PendingLinkPreload*);
+  static void FetchDictionaryIfNeeded(const LinkLoadParameters&,
+                                      Document&,
+                                      PendingLinkPreload*);
 
   static absl::optional<ResourceType> GetResourceTypeFromAsAttribute(
       const String& as);
diff --git a/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.cc b/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.cc
new file mode 100644
index 0000000..eb87b7b
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.cc
@@ -0,0 +1,42 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h"
+
+#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+bool CompressionDictionaryTransportFullyEnabled(
+    const FeatureContext* feature_context) {
+  return RuntimeEnabledFeatures::CompressionDictionaryTransportEnabled(
+             feature_context) &&
+         RuntimeEnabledFeatures::CompressionDictionaryTransportBackendEnabled();
+}
+
+Resource* LinkDictionaryResource::Fetch(FetchParameters& params,
+                                        ResourceFetcher* fetcher) {
+  return fetcher->RequestResource(params, Factory(), nullptr);
+}
+
+LinkDictionaryResource::LinkDictionaryResource(
+    const ResourceRequest& request,
+    const ResourceLoaderOptions& options)
+    : Resource(request, ResourceType::kDictionary, options) {}
+
+LinkDictionaryResource::~LinkDictionaryResource() = default;
+
+LinkDictionaryResource::Factory::Factory()
+    : NonTextResourceFactory(ResourceType::kDictionary) {}
+
+Resource* LinkDictionaryResource::Factory::Create(
+    const ResourceRequest& request,
+    const ResourceLoaderOptions& options) const {
+  return MakeGarbageCollected<LinkDictionaryResource>(request, options);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h b/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h
new file mode 100644
index 0000000..eaee87e4
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/resource/link_dictionary_resource.h
@@ -0,0 +1,38 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_LINK_DICTIONARY_RESOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_LINK_DICTIONARY_RESOURCE_H_
+
+#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+
+namespace blink {
+
+class FetchParameters;
+class ResourceFetcher;
+class FeatureContext;
+
+bool CompressionDictionaryTransportFullyEnabled(const FeatureContext*);
+
+// This is the implementation of Resource for <link rel='dictionary'>.
+class LinkDictionaryResource final : public Resource {
+ public:
+  static Resource* Fetch(FetchParameters&, ResourceFetcher*);
+
+  LinkDictionaryResource(const ResourceRequest&, const ResourceLoaderOptions&);
+  ~LinkDictionaryResource() override;
+
+ private:
+  class Factory final : public NonTextResourceFactory {
+   public:
+    Factory();
+
+    Resource* Create(const ResourceRequest& request,
+                     const ResourceLoaderOptions& options) const override;
+  };
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_LINK_DICTIONARY_RESOURCE_H_
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index a143b06..0294667 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -80,12 +80,6 @@
   ComputePageRectsWithPageSizeInternal(page_size);
 }
 
-void PrintContext::ComputePageRectsWithPageSize(
-    const gfx::SizeF& page_size_in_pixels) {
-  page_rects_.clear();
-  ComputePageRectsWithPageSizeInternal(page_size_in_pixels);
-}
-
 void PrintContext::ComputePageRectsWithPageSizeInternal(
     const gfx::SizeF& page_size_in_pixels) {
   if (!IsFrameValid())
@@ -166,6 +160,8 @@
   frame_->StartPrinting(
       floored_min_layout_size, aspect_ratio,
       printingMaximumShrinkFactor / kPrintingMinimumShrinkFactor);
+
+  ComputePageRects(gfx::SizeF(width, height));
 }
 
 void PrintContext::EndPrintMode() {
@@ -198,12 +194,6 @@
   if (!box)
     return -1;
 
-  gfx::SizeF scaled_page_size = page_size_in_pixels;
-  scaled_page_size.Scale(
-      frame->View()->LayoutViewport()->ContentsSize().width() /
-      page_rect.width());
-  print_context->ComputePageRectsWithPageSize(scaled_page_size);
-
   int top = box->OffsetTop(box->OffsetParent()).ToInt();
   int left = box->OffsetLeft(box->OffsetParent()).ToInt();
   for (wtf_size_t page_number = 0; page_number < print_context->PageCount();
@@ -323,17 +313,9 @@
                                 const gfx::SizeF& page_size_in_pixels) {
   frame->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kPrinting);
 
-  gfx::RectF page_rect(page_size_in_pixels);
   ScopedPrintContext print_context(frame);
-  print_context->BeginPrintMode(page_rect.width(), page_rect.height());
-  // Account for shrink-to-fit.
-  gfx::SizeF scaled_page_size = page_size_in_pixels;
-  const LayoutView* layout_view = frame->View()->GetLayoutView();
-  bool is_horizontal = layout_view->StyleRef().IsHorizontalWritingMode();
-  scaled_page_size.Scale(
-      layout_view->PageLogicalHeight() /
-      (is_horizontal ? page_rect.height() : page_rect.width()));
-  print_context->ComputePageRectsWithPageSize(scaled_page_size);
+  print_context->BeginPrintMode(page_size_in_pixels.width(),
+                                page_size_in_pixels.height());
   return print_context->PageCount();
 }
 
diff --git a/third_party/blink/renderer/core/page/print_context.h b/third_party/blink/renderer/core/page/print_context.h
index c372bb3..eca281fed 100644
--- a/third_party/blink/renderer/core/page/print_context.h
+++ b/third_party/blink/renderer/core/page/print_context.h
@@ -55,17 +55,6 @@
 
   LocalFrame* GetFrame() const { return frame_; }
 
-  // Break up a page into rects without relayout.
-  // FIXME: This means that CSS page breaks won't be on page boundary if the
-  // size is different than what was passed to BeginPrintMode(). That's probably
-  // not always desirable.
-  virtual void ComputePageRects(const gfx::SizeF& print_size);
-
-  // Deprecated. Page size computation is already in this class, clients
-  // shouldn't be copying it.
-  virtual void ComputePageRectsWithPageSize(
-      const gfx::SizeF& page_size_in_pixels);
-
   // These are only valid after page rects are computed.
   wtf_size_t PageCount() const { return page_rects_.size(); }
   const gfx::Rect& PageRect(wtf_size_t page_number) const {
@@ -114,6 +103,7 @@
   Vector<gfx::Rect> page_rects_;
 
  private:
+  void ComputePageRects(const gfx::SizeF& print_size);
   void ComputePageRectsWithPageSizeInternal(
       const gfx::SizeF& page_size_in_pixels);
   void CollectLinkedDestinations(Node*);
diff --git a/third_party/blink/renderer/core/page/print_context_test.cc b/third_party/blink/renderer/core/page/print_context_test.cc
index e6c7d3c9..40bca9b 100644
--- a/third_party/blink/renderer/core/page/print_context_test.cc
+++ b/third_party/blink/renderer/core/page/print_context_test.cc
@@ -138,7 +138,6 @@
     GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
         DocumentUpdateReason::kTest);
 
-    GetPrintContext().ComputePageRects(gfx::SizeF(kPageWidth, kPageHeight));
     gfx::Rect page_rect = GetPrintContext().PageRect(page_number);
 
     auto* builder = MakeGarbageCollected<PaintRecordBuilder>();
diff --git a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
index f911351e..f67b5fc1 100644
--- a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
+++ b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
@@ -159,7 +159,7 @@
                    PhysicalOffset(end->edge_end));
   }
 
-  paint_controller_.RecordSelection(start, end);
+  paint_controller_.RecordSelection(start, end, "");
 }
 
 bool SelectionBoundsRecorder::ShouldRecordSelection(
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 09dfa724..bff51f2c 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -1447,11 +1447,12 @@
                                const gfx::RectF& bounding_box,
                                CoordBox coord_box) {
   if (box) {
-    // In SVG contexts, all values behave as view-box.
-    if (box->IsSVG()) {
-      return SVGLengthContext(To<SVGElement>(box->GetNode())).ResolveViewport();
-    }
     if (const LayoutBlock* containing_block = box->ContainingBlock()) {
+      // In SVG contexts, all values behave as view-box.
+      if (box->IsSVG()) {
+        return SVGLengthContext(To<SVGElement>(box->GetNode()))
+            .ResolveViewport();
+      }
       // https://drafts.csswg.org/css-box-4/#typedef-coord-box
       switch (coord_box) {
         case CoordBox::kFillBox:
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
index 72dce2a..329e04c 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -159,4 +160,14 @@
   ChildDocument().View()->BeginLifecycleUpdates();
 }
 
+NGConstraintSpace RenderingTest::ConstraintSpaceForAvailableSize(
+    LayoutUnit inline_size) const {
+  NGConstraintSpaceBuilder builder(
+      WritingMode::kHorizontalTb,
+      {WritingMode::kHorizontalTb, TextDirection::kLtr},
+      /* is_new_fc */ false);
+  builder.SetAvailableSize(LogicalSize(inline_size, LayoutUnit::Max()));
+  return builder.ToConstraintSpace();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.h b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
index f48aece..7545f65 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.h
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
@@ -173,6 +173,11 @@
     return GetDisplayItemClientFromLayoutObject(GetLayoutObjectByElementId(id));
   }
 
+  // Create a `NGConstraintSpace` for the given available inline size. The
+  // available block sizes is `LayoutUnit::Max()`.
+  NGConstraintSpace ConstraintSpaceForAvailableSize(
+      LayoutUnit inline_size) const;
+
  private:
   Persistent<LocalFrameClient> local_frame_client_;
 };
diff --git a/third_party/blink/renderer/extensions/chromeos/event_target_chromeos_names.json5 b/third_party/blink/renderer/extensions/chromeos/event_target_chromeos_names.json5
index 694931ea..27427726 100644
--- a/third_party/blink/renderer/extensions/chromeos/event_target_chromeos_names.json5
+++ b/third_party/blink/renderer/extensions/chromeos/event_target_chromeos_names.json5
@@ -3,9 +3,9 @@
     namespace: "event_target_names",
     suffix: "ChromeOS",
   },
-  # You don't need to specify ImplementedAs even though an interface name and
-  # its C++ class name don't match.  You need to specify ImplementedAs only if
-  # you'd like to change recorded names in ActivityLogger.
+  // You don't need to specify ImplementedAs even though an interface name and
+  // its C++ class name don't match.  You need to specify ImplementedAs only if
+  // you'd like to change recorded names in ActivityLogger.
   data: [
     "CrosWindowManagement",
   ]
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index b054bb0..199752cd5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -546,17 +546,11 @@
   }
 
   // Ignore a block flow (display:block, display:inline-block), unless it
-  // directly parents inline children and can have a caret inside of it.
+  // directly parents inline children.
   // This effectively trims a lot of uninteresting divs out of the tree.
   auto* block_flow = DynamicTo<LayoutBlockFlow>(*layout_object_);
   if (block_flow && block_flow->ChildrenInline() && block_flow->FirstChild()) {
-    // Require the ability to contain a caret -- this requirement is not
-    // strictly necessary, and could be removed, but caused about 20 test
-    // changes on each platform.
-    NGInlineCursor cursor(*block_flow);
-    if (cursor.HasRoot()) {
-      return false;
-    }
+    return false;
   }
 
   // By default, objects should be ignored so that the AX hierarchy is not
diff --git a/third_party/blink/renderer/modules/event_target_modules_names.json5 b/third_party/blink/renderer/modules/event_target_modules_names.json5
index 787d6af..3eda536 100644
--- a/third_party/blink/renderer/modules/event_target_modules_names.json5
+++ b/third_party/blink/renderer/modules/event_target_modules_names.json5
@@ -4,9 +4,9 @@
     suffix: "Modules",
   },
 
-  # You don't need to specify ImplementedAs even though an interface name and
-  # its C++ class name don't match.  You need to specify ImplementedAs only if
-  # you'd like to change recorded names in ActivityLogger.
+  // You don't need to specify ImplementedAs even though an interface name and
+  // its C++ class name don't match.  You need to specify ImplementedAs only if
+  // you'd like to change recorded names in ActivityLogger.
   data: [
     "BackgroundFetchRegistration",
     "BatteryManager",
diff --git a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc
index 2a233dd..eaa44ab 100644
--- a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc
+++ b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc
@@ -6,11 +6,8 @@
 
 namespace blink {
 
-BindingSecurityForPlatform::
-    ShouldAllowAccessToV8ContextWithErrorReportOptionFunction
-        BindingSecurityForPlatform::
-            should_allow_access_to_v8context_with_error_report_option_ =
-                nullptr;
+BindingSecurityForPlatform::ShouldAllowAccessToV8ContextFunction
+    BindingSecurityForPlatform::should_allow_access_to_v8context_ = nullptr;
 BindingSecurityForPlatform::ShouldAllowWrapperCreationOrThrowExceptionFunction
     BindingSecurityForPlatform::
         should_allow_wrapper_creation_or_throw_exception_ = nullptr;
@@ -20,10 +17,9 @@
 // static
 bool BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
     v8::Local<v8::Context> accessing_context,
-    v8::MaybeLocal<v8::Context> target_context,
-    ErrorReportOption reporting_option) {
-  return (*should_allow_access_to_v8context_with_error_report_option_)(
-      accessing_context, target_context, reporting_option);
+    v8::MaybeLocal<v8::Context> target_context) {
+  return (*should_allow_access_to_v8context_)(accessing_context,
+                                              target_context);
 }
 
 // static
@@ -47,12 +43,11 @@
 }
 
 // static
-void BindingSecurityForPlatform::
-    SetShouldAllowAccessToV8ContextWithErrorReportOption(
-        ShouldAllowAccessToV8ContextWithErrorReportOptionFunction func) {
-  DCHECK(!should_allow_access_to_v8context_with_error_report_option_);
+void BindingSecurityForPlatform::SetShouldAllowAccessToV8Context(
+    ShouldAllowAccessToV8ContextFunction func) {
+  DCHECK(!should_allow_access_to_v8context_);
   DCHECK(func);
-  should_allow_access_to_v8context_with_error_report_option_ = func;
+  should_allow_access_to_v8context_ = func;
 }
 
 // static
diff --git a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h
index eec96d3..b21269d 100644
--- a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h
+++ b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h
@@ -22,18 +22,12 @@
   STATIC_ONLY(BindingSecurityForPlatform);
 
  public:
-  enum class ErrorReportOption {
-    kDoNotReport,
-    kReport,
-  };
-
   // This should be used only when checking a general access from one context to
   // another context. For access to a receiver object or returned object, you
   // should use BindingSecurity::ShouldAllowAccessTo family.
   static bool ShouldAllowAccessToV8Context(
       v8::Local<v8::Context> accessing_context,
-      v8::MaybeLocal<v8::Context> target_context,
-      ErrorReportOption);
+      v8::MaybeLocal<v8::Context> target_context);
 
   // Checks if a wrapper creation of the given wrapper type associated with
   // |creation_context| is allowed in |accessing_context|.
@@ -51,10 +45,9 @@
       v8::Local<v8::Value> cross_context_exception);
 
  private:
-  using ShouldAllowAccessToV8ContextWithErrorReportOptionFunction =
+  using ShouldAllowAccessToV8ContextFunction =
       bool (*)(v8::Local<v8::Context> accessing_context,
-               v8::MaybeLocal<v8::Context> target_context,
-               ErrorReportOption);
+               v8::MaybeLocal<v8::Context> target_context);
   using ShouldAllowWrapperCreationOrThrowExceptionFunction =
       bool (*)(v8::Local<v8::Context> accessing_context,
                v8::MaybeLocal<v8::Context> creation_context,
@@ -65,15 +58,14 @@
                const WrapperTypeInfo* wrapper_type_info,
                v8::Local<v8::Value> cross_context_exception);
 
-  static void SetShouldAllowAccessToV8ContextWithErrorReportOption(
-      ShouldAllowAccessToV8ContextWithErrorReportOptionFunction);
+  static void SetShouldAllowAccessToV8Context(
+      ShouldAllowAccessToV8ContextFunction);
   static void SetShouldAllowWrapperCreationOrThrowException(
       ShouldAllowWrapperCreationOrThrowExceptionFunction);
   static void SetRethrowWrapperCreationException(
       RethrowWrapperCreationExceptionFunction);
 
-  static ShouldAllowAccessToV8ContextWithErrorReportOptionFunction
-      should_allow_access_to_v8context_with_error_report_option_;
+  static ShouldAllowAccessToV8ContextFunction should_allow_access_to_v8context_;
   static ShouldAllowWrapperCreationOrThrowExceptionFunction
       should_allow_wrapper_creation_or_throw_exception_;
   static RethrowWrapperCreationExceptionFunction
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.cc b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
index 85bf6a8..91a39ed 100644
--- a/third_party/blink/renderer/platform/bindings/callback_function_base.cc
+++ b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
@@ -40,8 +40,7 @@
     v8::MaybeLocal<v8::Context> creation_context =
         callback_function->GetCreationContext();
     if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
-            incumbent_script_state->GetContext(), creation_context,
-            BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) {
+            incumbent_script_state->GetContext(), creation_context)) {
       ScriptState* callback_relevant_script_state =
           ScriptState::From(creation_context.ToLocalChecked());
       MakeCachedData(callback_relevant_script_state, incumbent_script_state);
diff --git a/third_party/blink/renderer/platform/bindings/callback_interface_base.cc b/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
index 4efc5ab..933dee3 100644
--- a/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
+++ b/third_party/blink/renderer/platform/bindings/callback_interface_base.cc
@@ -37,8 +37,7 @@
     v8::MaybeLocal<v8::Context> creation_context =
         callback_object->GetCreationContext();
     if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context(
-            incumbent_script_state_->GetContext(), creation_context,
-            BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) {
+            incumbent_script_state_->GetContext(), creation_context)) {
       callback_relevant_script_state_ =
           ScriptState::From(creation_context.ToLocalChecked());
     }
diff --git a/third_party/blink/renderer/platform/bindings/enumeration_base.h b/third_party/blink/renderer/platform/bindings/enumeration_base.h
index 14b4b23..3f615f4 100644
--- a/third_party/blink/renderer/platform/bindings/enumeration_base.h
+++ b/third_party/blink/renderer/platform/bindings/enumeration_base.h
@@ -35,7 +35,7 @@
   }
 
   // Migration adapter
-  operator AtomicString() const { return string_literal_; }
+  operator AtomicString() const { return AtomicString(string_literal_); }
   operator String() const { return string_literal_; }
 
   // Returns true if the value is invalid.  The instance in this state must be
diff --git a/third_party/blink/renderer/platform/fonts/font_description.cc b/third_party/blink/renderer/platform/fonts/font_description.cc
index bc27da5..90e3778 100644
--- a/third_party/blink/renderer/platform/fonts/font_description.cc
+++ b/third_party/blink/renderer/platform/fonts/font_description.cc
@@ -289,7 +289,7 @@
 #if BUILDFLAG(IS_ANDROID)
   if (const LayoutLocale* locale = Locale()) {
     if (FontCache::GetLocaleSpecificFamilyName(creation_params.Family()))
-      cache_key.SetLocale(locale->LocaleForSkFontMgr());
+      cache_key.SetLocale(AtomicString(locale->LocaleForSkFontMgr()));
   }
 #endif  // BUILDFLAG(IS_ANDROID)
   return cache_key;
diff --git a/third_party/blink/renderer/platform/fonts/font_face_creation_params.h b/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
index c748f1c1..f0673f7b 100644
--- a/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
+++ b/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
@@ -115,7 +115,7 @@
           sizeof(fontconfig_interface_id_));
       return hasher.GetHash();
     }
-    return CaseFoldingHash::GetHash(family_.empty() ? "" : family_);
+    return CaseFoldingHash::GetHash(family_.empty() ? g_empty_atom : family_);
   }
 
   bool operator==(const FontFaceCreationParams& other) const {
diff --git a/third_party/blink/renderer/platform/fonts/font_family_names.json5 b/third_party/blink/renderer/platform/fonts/font_family_names.json5
index 11d7e7ae..c0d8e4c1 100644
--- a/third_party/blink/renderer/platform/fonts/font_family_names.json5
+++ b/third_party/blink/renderer/platform/fonts/font_family_names.json5
@@ -13,11 +13,13 @@
     "Courier New",
     "Courier",
     "Helvetica",
+    "Helvetica Neue",
     "Lucida Grande",
     "Microsoft Sans Serif",
     "MS Sans Serif",
     "MS Serif",
     "MS UI Gothic",
+    "Roboto",
     "Sans",
     "Segoe UI",
     "Times New Roman",
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 7b6ce26..f5a4b50 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -1880,7 +1880,7 @@
     unsigned offset) const {
   DCHECK_LE(start_offset_, offset);
   unsigned adjusted_offset = offset - start_offset_;
-  DCHECK_LT(adjusted_offset, data_.size());
+  DCHECK_LE(adjusted_offset, data_.size());
 
   // Assume it is always safe to break at the end of the run.
   if (adjusted_offset >= data_.size())
diff --git a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
index 6dddd16..943d5cf 100644
--- a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
+++ b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
@@ -95,7 +95,7 @@
     const FontFallbackPriority& fallback_priority,
     const UChar32 codepoint) {
   if (fallback_priority == FontFallbackPriority::kEmojiEmoji)
-    return LayoutLocale::Get(kColorEmojiLocale);
+    return LayoutLocale::Get(AtomicString(kColorEmojiLocale));
 
   UErrorCode error_code = U_ZERO_ERROR;
   const UScriptCode char_script = uscript_getScript(codepoint, &error_code);
@@ -107,7 +107,8 @@
     // ambiguous locale for Han fallback requests.
     const LayoutLocale* han_locale =
         LayoutLocale::LocaleForHan(font_description.Locale());
-    return han_locale ? han_locale : LayoutLocale::Get(kChineseSimplified);
+    return han_locale ? han_locale
+                      : LayoutLocale::Get(AtomicString(kChineseSimplified));
   }
 
   return font_description.Locale() ? font_description.Locale()
@@ -186,7 +187,8 @@
       &script, fallback_priority, font_manager_.get());
 
   if (legacy_fallback_family) {
-    FontFaceCreationParams create_by_family(legacy_fallback_family);
+    FontFaceCreationParams create_by_family =
+        FontFaceCreationParams(AtomicString(legacy_fallback_family));
     FontPlatformData* data =
         GetFontPlatformData(font_description, create_by_family);
     if (data && data->FontContainsCharacter(codepoint)) {
@@ -236,8 +238,8 @@
   // critical enough for non-Latin scripts (especially Han) to
   // warrant an additional (real coverage) check with fontCotainsCharacter.
   for (int i = 0; i < num_fonts; ++i) {
-    legacy_fallback_family = pan_uni_fonts[i];
-    FontFaceCreationParams create_by_family(legacy_fallback_family);
+    FontFaceCreationParams create_by_family =
+        FontFaceCreationParams(AtomicString(pan_uni_fonts[i]));
     FontPlatformData* data =
         GetFontPlatformData(font_description, create_by_family);
     if (data && data->FontContainsCharacter(codepoint))
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index c08d7fa7..e12a12a 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -254,8 +254,7 @@
 }
 
 viz::SharedImageFormat CanvasResource::GetSharedImageFormat() const {
-  return viz::SharedImageFormat::SinglePlane(
-      viz::SkColorTypeToResourceFormat(info_.colorType()));
+  return viz::SkColorTypeToSinglePlaneSharedImageFormat(info_.colorType());
 }
 
 gfx::BufferFormat CanvasResource::GetBufferFormat() const {
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index a4d0c78..1985e3da 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -191,8 +191,7 @@
     *out_resource = viz::TransferableResource::MakeGpu(
         mailbox_holder.mailbox, mailbox_holder.texture_target,
         mailbox_holder.sync_token, size,
-        viz::SharedImageFormat::SinglePlane(
-            viz::SkColorTypeToResourceFormat(color_type)),
+        viz::SkColorTypeToSinglePlaneSharedImageFormat(color_type),
         is_overlay_candidate);
 
     // If the transferred ImageBitmap contained in this ImageLayerBridge was
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
index 2c0f24810..103684a 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
@@ -195,7 +195,8 @@
 
 void PaintChunker::AddSelectionToCurrentChunk(
     absl::optional<PaintedSelectionBound> start,
-    absl::optional<PaintedSelectionBound> end) {
+    absl::optional<PaintedSelectionBound> end,
+    String debug_info) {
   // We should have painted the selection when calling this method.
   DCHECK(chunks_);
   DCHECK(!chunks_->empty());
@@ -207,14 +208,14 @@
     gfx::Rect edge_rect = gfx::BoundingRect(start->edge_start, start->edge_end);
     DCHECK(chunk.bounds.Contains(edge_rect))
         << chunk.bounds.ToString() << " does not contain "
-        << edge_rect.ToString();
+        << edge_rect.ToString() << ", original bounds: " << debug_info;
   }
 
   if (end) {
     gfx::Rect edge_rect = gfx::BoundingRect(end->edge_start, end->edge_end);
     DCHECK(chunk.bounds.Contains(edge_rect))
         << chunk.bounds.ToString() << " does not contain "
-        << edge_rect.ToString();
+        << edge_rect.ToString() << ", original bounds: " << debug_info;
   }
 #endif
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
index d157e40..c5008a4a 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
@@ -91,7 +91,8 @@
   // The id will be used when we need to create a new current chunk.
   // Otherwise it's ignored. Returns true if a new chunk is added.
   void AddSelectionToCurrentChunk(absl::optional<PaintedSelectionBound> start,
-                                  absl::optional<PaintedSelectionBound> end);
+                                  absl::optional<PaintedSelectionBound> end,
+                                  String debug_info);
   void RecordAnySelectionWasPainted();
 
   // Returns true if a new chunk is created.
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
index 1b2c9e4..dd231c2d 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -115,9 +115,10 @@
 
 void PaintController::RecordSelection(
     absl::optional<PaintedSelectionBound> start,
-    absl::optional<PaintedSelectionBound> end) {
+    absl::optional<PaintedSelectionBound> end,
+    String debug_info) {
   DCHECK(start.has_value() || end.has_value());
-  paint_chunker_.AddSelectionToCurrentChunk(start, end);
+  paint_chunker_.AddSelectionToCurrentChunk(start, end, debug_info);
 }
 
 bool PaintController::UseCachedItemIfPossible(const DisplayItemClient& client,
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
index 333bb7d..1a0d59729 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -136,7 +136,8 @@
       const gfx::Rect&);
 
   void RecordSelection(absl::optional<PaintedSelectionBound> start,
-                       absl::optional<PaintedSelectionBound> end);
+                       absl::optional<PaintedSelectionBound> end,
+                       String debug_info);
   void RecordAnySelectionWasPainted() {
     paint_chunker_.RecordAnySelectionWasPainted();
   }
diff --git a/third_party/blink/renderer/platform/graphics/placeholder_image.cc b/third_party/blink/renderer/platform/graphics/placeholder_image.cc
index 3afef32..be25b3b 100644
--- a/third_party/blink/renderer/platform/graphics/placeholder_image.cc
+++ b/third_party/blink/renderer/platform/graphics/placeholder_image.cc
@@ -86,14 +86,17 @@
 
 FontDescription CreatePlaceholderFontDescription(float scale_factor) {
   FontDescription description;
-  description.FirstFamily().SetFamily("Roboto", FontFamily::Type::kFamilyName);
+  description.FirstFamily().SetFamily(font_family_names::kRoboto,
+                                      FontFamily::Type::kFamilyName);
 
   scoped_refptr<SharedFontFamily> helvetica_neue = SharedFontFamily::Create();
-  helvetica_neue->SetFamily("Helvetica Neue", FontFamily::Type::kFamilyName);
+  helvetica_neue->SetFamily(font_family_names::kHelveticaNeue,
+                            FontFamily::Type::kFamilyName);
   scoped_refptr<SharedFontFamily> helvetica = SharedFontFamily::Create();
-  helvetica->SetFamily("Helvetica", FontFamily::Type::kFamilyName);
+  helvetica->SetFamily(font_family_names::kHelvetica,
+                       FontFamily::Type::kFamilyName);
   scoped_refptr<SharedFontFamily> arial = SharedFontFamily::Create();
-  arial->SetFamily("Arial", FontFamily::Type::kFamilyName);
+  arial->SetFamily(font_family_names::kArial, FontFamily::Type::kFamilyName);
 
   helvetica->AppendFamily(std::move(arial));
   helvetica_neue->AppendFamily(std::move(helvetica));
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc b/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc
index 1b540ec3..cea929c 100644
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc
@@ -102,8 +102,8 @@
       // format that is backing `image->GetMailboxHolder()`, or, alternatively,
       // expose an accelerated SkImage.
       if (accelerated_frame_pool_->CopyRGBATextureToVideoFrame(
-              viz::SharedImageFormat::SinglePlane(
-                  viz::SkColorTypeToResourceFormat(kRGBA_8888_SkColorType)),
+              viz::SkColorTypeToSinglePlaneSharedImageFormat(
+                  kRGBA_8888_SkColorType),
               gfx::Size(image->width(), image->height()),
               gfx::ColorSpace::CreateSRGB(),
               image->IsOriginTopLeft() ? kTopLeft_GrSurfaceOrigin
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_utils.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_utils.cc
index c19c9168..b70ff9c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_utils.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_utils.cc
@@ -42,15 +42,16 @@
 
   // We place GET and POST first because they are more commonly used than
   // others.
-  const char* const kMethods[] = {
-      "GET", "POST", "DELETE", "HEAD", "OPTIONS", "PUT",
+  const AtomicString* kMethods[] = {
+      &http_names::kGET,  &http_names::kPOST,    &http_names::kDELETE,
+      &http_names::kHEAD, &http_names::kOPTIONS, &http_names::kPUT,
   };
 
   for (auto* const known : kMethods) {
-    if (EqualIgnoringASCIICase(method, known)) {
+    if (EqualIgnoringASCIICase(method, *known)) {
       // Don't bother allocating a new string if it's already all
       // uppercase.
-      return method == known ? method : known;
+      return method == *known ? method : *known;
     }
   }
   return method;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 973a077..63a7ff3 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -925,7 +925,7 @@
 }
 
 void Resource::ClearRangeRequestHeader() {
-  resource_request_.ClearHttpHeaderField("range");
+  resource_request_.ClearHttpHeaderField(http_names::kLowerRange);
 }
 
 void Resource::RevalidationSucceeded(
@@ -1165,6 +1165,8 @@
       return "SpeculationRule";
     case ResourceType::kMock:
       return "Mock";
+    case ResourceType::kDictionary:
+      return "Dictionary";
   }
   NOTREACHED();
   return InitiatorTypeNameToString(fetch_initiator_name);
@@ -1189,6 +1191,7 @@
     case ResourceType::kManifest:
     case ResourceType::kMock:
     case ResourceType::kSpeculationRules:
+    case ResourceType::kDictionary:
       return false;
   }
   NOTREACHED();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index 711f1cb..af8f171 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -94,7 +94,8 @@
   kManifest = 12,
   kSpeculationRules = 13,
   kMock = 14,  // Only for testing
-  kMaxValue = kMock
+  kDictionary = 15,
+  kMaxValue = kDictionary
 };
 
 // A resource that is held in the cache. Classes who want to use this object
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 1baccbd..2961b33 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -145,6 +145,7 @@
     RESOURCE_TYPE_NAME(Manifest)          // 12
     RESOURCE_TYPE_NAME(SpeculationRules)  // 13
     RESOURCE_TYPE_NAME(Mock)              // 14
+    RESOURCE_TYPE_NAME(Dictionary)        // 15
   }
 }
 
@@ -173,6 +174,7 @@
       return ResourceLoadPriority::kLow;
     case ResourceType::kLinkPrefetch:
     case ResourceType::kSpeculationRules:
+    case ResourceType::kDictionary:
       return ResourceLoadPriority::kVeryLow;
   }
 
@@ -396,6 +398,8 @@
       return mojom::blink::RequestContextType::SUBRESOURCE;
     case ResourceType::kSpeculationRules:
       return mojom::blink::RequestContextType::SUBRESOURCE;
+    case ResourceType::kDictionary:
+      return mojom::blink::RequestContextType::SUBRESOURCE;
   }
   NOTREACHED();
   return mojom::blink::RequestContextType::SUBRESOURCE;
@@ -427,6 +431,7 @@
     case ResourceType::kRaw:
     case ResourceType::kLinkPrefetch:
     case ResourceType::kMock:
+    case ResourceType::kDictionary:
       return network::mojom::RequestDestination::kEmpty;
   }
   NOTREACHED();
@@ -1089,7 +1094,8 @@
     // Add the "Sec-Purpose: prefetch;prerender" header to requests issued from
     // prerendered pages. Add "Purpose: prefetch" as well for compatibility
     // concerns (See https://github.com/WICG/nav-speculation/issues/133).
-    resource_request.SetHttpHeaderField("Sec-Purpose", "prefetch;prerender");
+    resource_request.SetHttpHeaderField(http_names::kSecPurpose,
+                                        AtomicString("prefetch;prerender"));
     resource_request.SetPurposeHeader("prefetch");
   }
 
@@ -1473,7 +1479,7 @@
     if (revalidating_request.GetCacheMode() ==
         mojom::blink::FetchCacheMode::kValidateCache) {
       revalidating_request.SetHttpHeaderField(http_names::kCacheControl,
-                                              "max-age=0");
+                                              AtomicString("max-age=0"));
     }
   }
   if (!last_modified.empty()) {
@@ -2240,7 +2246,7 @@
           network::mojom::FetchResponseType::kOpaque &&
       resource->GetResponse().HasRangeRequested() &&
       !resource->GetResourceRequest().HttpHeaderFields().Contains(
-          net::HttpRequestHeaders::kRange)) {
+          http_names::kRange)) {
     RemovePreload(resource);
   }
 
@@ -2723,7 +2729,7 @@
     if (!response.NetworkAccessed() &&
         (!response.WasFetchedViaServiceWorker() ||
          response.IsServiceWorkerPassThrough())) {
-      initiator_type = "early-hints";
+      initiator_type = AtomicString("early-hints");
     }
   }
 
@@ -2974,6 +2980,13 @@
         metrics.mock_fallback |= true;
       }
       break;
+    case ResourceType::kDictionary:  // 14
+      if (handled_by_serviceworker) {
+        metrics.dictionary_handled |= true;
+      } else {
+        metrics.dictionary_fallback |= true;
+      }
+      break;
   }
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index f9163f36..28e6a24 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -830,7 +830,7 @@
       passed_redirect_response.PrivateNetworkAccessPreflightResult());
 
   if (resource_->GetResourceRequest().HttpHeaderFields().Contains(
-          net::HttpRequestHeaders::kAuthorization) &&
+          http_names::kAuthorization) &&
       !SecurityOrigin::AreSameOrigin(resource_->LastResourceRequest().Url(),
                                      new_url)) {
     fetcher_->GetUseCounter().CountUse(
@@ -1153,8 +1153,7 @@
   // Range header: https://fetch.spec.whatwg.org/#main-fetch
   if (response.GetType() == network::mojom::FetchResponseType::kOpaque &&
       response.HttpStatusCode() == 206 && response.HasRangeRequested() &&
-      !initial_request.HttpHeaderFields().Contains(
-          net::HttpRequestHeaders::kRange)) {
+      !initial_request.HttpHeaderFields().Contains(http_names::kRange)) {
     HandleError(ResourceError::CancelledDueToAccessCheckError(
         response.CurrentRequestUrl(), ResourceRequestBlockedReason::kOther));
     return;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
index 79aaa06..5e1766c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
@@ -58,9 +58,6 @@
   return result;
 }
 
-static const char kCacheControlHeader[] = "cache-control";
-static const char kPragmaHeader[] = "pragma";
-
 }  // namespace
 
 ResourceResponse::ResourceResponse()
@@ -210,22 +207,18 @@
 }
 
 void ResourceResponse::UpdateHeaderParsedState(const AtomicString& name) {
-  static const char kAgeHeader[] = "age";
-  static const char kDateHeader[] = "date";
-  static const char kExpiresHeader[] = "expires";
-  static const char kLastModifiedHeader[] = "last-modified";
-
-  if (EqualIgnoringASCIICase(name, kAgeHeader))
+  if (EqualIgnoringASCIICase(name, http_names::kLowerAge)) {
     have_parsed_age_header_ = false;
-  else if (EqualIgnoringASCIICase(name, kCacheControlHeader) ||
-           EqualIgnoringASCIICase(name, kPragmaHeader))
+  } else if (EqualIgnoringASCIICase(name, http_names::kLowerCacheControl) ||
+             EqualIgnoringASCIICase(name, http_names::kLowerPragma)) {
     cache_control_header_ = CacheControlHeader();
-  else if (EqualIgnoringASCIICase(name, kDateHeader))
+  } else if (EqualIgnoringASCIICase(name, http_names::kLowerDate)) {
     have_parsed_date_header_ = false;
-  else if (EqualIgnoringASCIICase(name, kExpiresHeader))
+  } else if (EqualIgnoringASCIICase(name, http_names::kLowerExpires)) {
     have_parsed_expires_header_ = false;
-  else if (EqualIgnoringASCIICase(name, kLastModifiedHeader))
+  } else if (EqualIgnoringASCIICase(name, http_names::kLowerLastModified)) {
     have_parsed_last_modified_header_ = false;
+  }
 }
 
 void ResourceResponse::SetSSLInfo(const net::SSLInfo& ssl_info) {
@@ -289,8 +282,8 @@
 bool ResourceResponse::CacheControlContainsNoCache() const {
   if (!cache_control_header_.parsed) {
     cache_control_header_ = ParseCacheControlDirectives(
-        http_header_fields_.Get(kCacheControlHeader),
-        http_header_fields_.Get(kPragmaHeader));
+        http_header_fields_.Get(http_names::kLowerCacheControl),
+        http_header_fields_.Get(http_names::kLowerPragma));
   }
   return cache_control_header_.contains_no_cache;
 }
@@ -298,8 +291,8 @@
 bool ResourceResponse::CacheControlContainsNoStore() const {
   if (!cache_control_header_.parsed) {
     cache_control_header_ = ParseCacheControlDirectives(
-        http_header_fields_.Get(kCacheControlHeader),
-        http_header_fields_.Get(kPragmaHeader));
+        http_header_fields_.Get(http_names::kLowerCacheControl),
+        http_header_fields_.Get(http_names::kLowerPragma));
   }
   return cache_control_header_.contains_no_store;
 }
@@ -307,24 +300,22 @@
 bool ResourceResponse::CacheControlContainsMustRevalidate() const {
   if (!cache_control_header_.parsed) {
     cache_control_header_ = ParseCacheControlDirectives(
-        http_header_fields_.Get(kCacheControlHeader),
-        http_header_fields_.Get(kPragmaHeader));
+        http_header_fields_.Get(http_names::kLowerCacheControl),
+        http_header_fields_.Get(http_names::kLowerPragma));
   }
   return cache_control_header_.contains_must_revalidate;
 }
 
 bool ResourceResponse::HasCacheValidatorFields() const {
-  static const char kLastModifiedHeader[] = "last-modified";
-  static const char kETagHeader[] = "etag";
-  return !http_header_fields_.Get(kLastModifiedHeader).empty() ||
-         !http_header_fields_.Get(kETagHeader).empty();
+  return !http_header_fields_.Get(http_names::kLowerLastModified).empty() ||
+         !http_header_fields_.Get(http_names::kLowerETag).empty();
 }
 
 absl::optional<base::TimeDelta> ResourceResponse::CacheControlMaxAge() const {
   if (!cache_control_header_.parsed) {
     cache_control_header_ = ParseCacheControlDirectives(
-        http_header_fields_.Get(kCacheControlHeader),
-        http_header_fields_.Get(kPragmaHeader));
+        http_header_fields_.Get(http_names::kLowerCacheControl),
+        http_header_fields_.Get(http_names::kLowerPragma));
   }
   return cache_control_header_.max_age;
 }
@@ -332,8 +323,8 @@
 base::TimeDelta ResourceResponse::CacheControlStaleWhileRevalidate() const {
   if (!cache_control_header_.parsed) {
     cache_control_header_ = ParseCacheControlDirectives(
-        http_header_fields_.Get(kCacheControlHeader),
-        http_header_fields_.Get(kPragmaHeader));
+        http_header_fields_.Get(http_names::kLowerCacheControl),
+        http_header_fields_.Get(http_names::kLowerPragma));
   }
   if (!cache_control_header_.stale_while_revalidate ||
       cache_control_header_.stale_while_revalidate.value() <
@@ -361,8 +352,7 @@
 
 absl::optional<base::Time> ResourceResponse::Date() const {
   if (!have_parsed_date_header_) {
-    static const char kHeaderName[] = "date";
-    date_ = ParseDateValueInHeader(http_header_fields_, kHeaderName);
+    date_ = ParseDateValueInHeader(http_header_fields_, http_names::kLowerDate);
     have_parsed_date_header_ = true;
   }
   return date_;
@@ -370,8 +360,8 @@
 
 absl::optional<base::TimeDelta> ResourceResponse::Age() const {
   if (!have_parsed_age_header_) {
-    static const char kHeaderName[] = "age";
-    const AtomicString& header_value = http_header_fields_.Get(kHeaderName);
+    const AtomicString& header_value =
+        http_header_fields_.Get(http_names::kLowerAge);
     bool ok;
     double seconds = header_value.ToDouble(&ok);
     if (!ok) {
@@ -386,8 +376,8 @@
 
 absl::optional<base::Time> ResourceResponse::Expires() const {
   if (!have_parsed_expires_header_) {
-    static const char kHeaderName[] = "expires";
-    expires_ = ParseDateValueInHeader(http_header_fields_, kHeaderName);
+    expires_ =
+        ParseDateValueInHeader(http_header_fields_, http_names::kLowerExpires);
     have_parsed_expires_header_ = true;
   }
   return expires_;
@@ -395,8 +385,8 @@
 
 absl::optional<base::Time> ResourceResponse::LastModified() const {
   if (!have_parsed_last_modified_header_) {
-    static const char kHeaderName[] = "last-modified";
-    last_modified_ = ParseDateValueInHeader(http_header_fields_, kHeaderName);
+    last_modified_ = ParseDateValueInHeader(http_header_fields_,
+                                            http_names::kLowerLastModified);
     have_parsed_last_modified_header_ = true;
   }
   return last_modified_;
@@ -483,8 +473,8 @@
 
 network::mojom::CrossOriginEmbedderPolicyValue
 ResourceResponse::GetCrossOriginEmbedderPolicy() const {
-  static constexpr char kHeaderName[] = "cross-origin-embedder-policy";
-  const std::string value = HttpHeaderField(kHeaderName).Utf8();
+  const std::string value =
+      HttpHeaderField(http_names::kLowerCrossOriginEmbedderPolicy).Utf8();
   using Item = net::structured_headers::Item;
   const auto item = net::structured_headers::ParseItem(value);
   if (!item || item->item.Type() != Item::kTokenType) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc b/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
index f95f2d1..bd2da7df 100644
--- a/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
@@ -56,7 +56,7 @@
 
   // Step 1. ... "script", ... [spec text]
   ResourceLoaderOptions resource_loader_options(std::move(world_for_csp));
-  resource_loader_options.initiator_info.name = "script";
+  resource_loader_options.initiator_info.name = AtomicString("script");
   resource_loader_options.reject_coep_unsafe_none = reject_coep_unsafe_none_;
   FetchParameters params(std::move(resource_request), resource_loader_options);
   params.SetRequestContext(mojom::blink::RequestContextType::SCRIPT);
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc
index 9c5f9bb..6f7ffec 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc
@@ -695,6 +695,7 @@
     case network::mojom::RequestDestination::kWebBundle:
     case network::mojom::RequestDestination::kWorker:
     case network::mojom::RequestDestination::kXslt:
+    case network::mojom::RequestDestination::kDictionary:
       return net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"(
       semantics {
         sender: "Blink Resource Loader"
diff --git a/third_party/blink/renderer/platform/network/http_names.json5 b/third_party/blink/renderer/platform/network/http_names.json5
index 67c7bc0..bb2ba7c 100644
--- a/third_party/blink/renderer/platform/network/http_names.json5
+++ b/third_party/blink/renderer/platform/network/http_names.json5
@@ -8,6 +8,7 @@
     "GET",
     "HEAD",
     "POST",
+    "DELETE",
     "OPTIONS",
     "PUT",
     "Accept",
@@ -28,6 +29,7 @@
     "Attribution-Reporting-Register-OS-Trigger",
     "Attribution-Reporting-Register-Source",
     "Attribution-Reporting-Register-Trigger",
+    "Authorization",
     "Cache-Control",
     "Content-DPR",
     "Content-Disposition",
@@ -69,6 +71,7 @@
     "Resource-Freshness",
     "Require-Document-Policy",
     "Save-Data",
+    "Sec-Purpose",
     "Server-Timing",
     "Speculation-Rules",
     "SourceMap",
@@ -81,5 +84,23 @@
     "X-Frame-Options",
     "X-SourceMap",
     "X-XSS-Protection",
+
+    {name: "age", Symbol: "kLowerAge"},
+    {name: "cache-control", Symbol: "kLowerCacheControl"},
+    {name: "content-type", Symbol: "kLowerContentType"},
+    {name: "content-length", Symbol: "kLowerContentLength"},
+    {name: "content-disposition", Symbol: "kLowerContentDisposition"},
+    {name: "content-range", Symbol: "kLowerContentRange"},
+    {
+      name: "cross-origin-embedder-policy",
+      Symbol: "kLowerCrossOriginEmbedderPolicy",
+    },
+    {name: "date", Symbol: "kLowerDate"},
+    {name: "etag", Symbol: "kLowerETag"},
+    {name: "expires", Symbol: "kLowerExpires"},
+    {name: "last-modified", Symbol: "kLowerLastModified"},
+    {name: "pragma", Symbol: "kLowerPragma"},
+    {name: "range", Symbol: "kLowerRange"},
+    {name: "set-cookie", Symbol: "kLowerSetCookie"},
   ],
 }
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index 69ea69777..3c93a03 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -322,9 +322,11 @@
   // The list of response headers that we do not copy from the original
   // response when generating a ResourceResponse for a MIME payload.
   // Note: this is called only on the main thread.
-  DEFINE_STATIC_LOCAL(Vector<AtomicString>, headers,
-                      ({"content-type", "content-length", "content-disposition",
-                        "content-range", "range", "set-cookie"}));
+  DEFINE_STATIC_LOCAL(
+      Vector<AtomicString>, headers,
+      ({http_names::kLowerContentType, http_names::kLowerContentLength,
+        http_names::kLowerContentDisposition, http_names::kLowerContentRange,
+        http_names::kLowerRange, http_names::kLowerSetCookie}));
   return headers;
 }
 
diff --git a/third_party/blink/renderer/platform/network/network_utils.cc b/third_party/blink/renderer/platform/network/network_utils.cc
index ec2ae9bf..65137257 100644
--- a/third_party/blink/renderer/platform/network/network_utils.cc
+++ b/third_party/blink/renderer/platform/network/network_utils.cc
@@ -76,7 +76,7 @@
   auto buffer = SharedBuffer::Create(data_string.data(), data_string.size());
   ResourceResponse response;
   response.SetHttpStatusCode(200);
-  response.SetHttpStatusText("OK");
+  response.SetHttpStatusText(AtomicString("OK"));
   response.SetCurrentRequestUrl(url);
   response.SetMimeType(WebString::FromUTF8(utf8_mime_type));
   response.SetExpectedContentLength(buffer->size());
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
index c9a9106..c9b3889 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
@@ -633,15 +633,21 @@
     std::vector<base::test::FeatureRef> enabled_features = {
         features::kZeroCopyTabCapture,
     };
+    std::vector<base::test::FeatureRef> disabled_features;
+
     if (GetParam().init_on_first_frame) {
       enabled_features.push_back(
           features::kWebRtcInitializeEncoderOnFirstFrame);
+    } else {
+      disabled_features.push_back(
+          features::kWebRtcInitializeEncoderOnFirstFrame);
     }
     if (GetParam().async_encode) {
       enabled_features.push_back(features::kWebRtcEncoderAsyncEncode);
+    } else {
+      disabled_features.push_back(features::kWebRtcEncoderAsyncEncode);
     }
-    feature_list_.InitWithFeatures(enabled_features,
-                                   /*disabled_features=*/{});
+    feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
   ~RTCVideoEncoderEncodeTest() override = default;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index a806b509..053fd22 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -176,14 +176,20 @@
       default: "enabled_or_overridden",
     },
 
+    // browser_process_read_access indicates the runtime feature state should be
+    // readable in the browserprocess via RuntimeFeatureStateReadContext.
     browser_process_read_access: {
       default: false,
       value_type: "bool",
     },
+
+    // browser_process_read_write_access indicates the runtime feature state
+    // should be writable in the browserprocess via RuntimeFeatureStateContext.
     browser_process_read_write_access: {
       default: false,
       value_type: "bool",
     },
+
     override_from_pref: {
       valid_keys: [
         // Chrome Prefs name (string) from which we will conditionally override
@@ -343,6 +349,7 @@
       origin_trial_feature_name: "AttributionReportingCrossAppWeb",
       origin_trial_allows_third_party: true,
       base_feature: "none",
+      browser_process_read_access: true,
     },
     {
       // This only exists so we can use RuntimeEnabled in the IDL file
@@ -1365,6 +1372,7 @@
       origin_trial_feature_name: "DisableThirdPartyStoragePartitioning",
       origin_trial_type: "deprecation",
       origin_trial_allows_insecure: true,
+      origin_trial_allows_third_party: true,
       status: "experimental",
       base_feature: "none",
       browser_process_read_write_access: true,
diff --git a/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc b/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
index 70a387d..00672a1a 100644
--- a/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
+++ b/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
@@ -274,8 +274,8 @@
     const auto& it = locale_fallback.find(mapped_locale);
     if (it != locale_fallback.end()) {
       if (it->value->locale_for_exact_match && locale == mapped_locale)
-        return it->value->locale_for_exact_match;
-      return it->value->locale;
+        return AtomicString(it->value->locale_for_exact_match);
+      return AtomicString(it->value->locale);
     }
     const wtf_size_t last_hyphen = mapped_locale.ReverseFind('-');
     if (last_hyphen == kNotFound || !last_hyphen)
diff --git a/third_party/blink/renderer/platform/text/layout_locale.cc b/third_party/blink/renderer/platform/text/layout_locale.cc
index f2ae401a..1cefa93d 100644
--- a/third_party/blink/renderer/platform/text/layout_locale.cc
+++ b/third_party/blink/renderer/platform/text/layout_locale.cc
@@ -225,7 +225,7 @@
   if (UNLIKELY(!data.default_locale)) {
     AtomicString language = DefaultLanguage();
     data.default_locale =
-        LayoutLocale::Get(!language.empty() ? language : "en");
+        LayoutLocale::Get(!language.empty() ? language : AtomicString("en"));
   }
   return *data.default_locale;
 }
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.h b/third_party/blink/renderer/platform/text/text_break_iterator.h
index 8873f0a..091f10f6 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator.h
+++ b/third_party/blink/renderer/platform/text/text_break_iterator.h
@@ -216,6 +216,7 @@
   // Set the start offset. Text before this offset is disregarded. Properly
   // setting the start offset improves the performance significantly, because
   // ICU break iterator computes all the text from the beginning.
+  unsigned StartOffset() const { return start_offset_; }
   void SetStartOffset(unsigned offset) {
     CHECK_LE(offset, string_.length());
     start_offset_ = offset;
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.h b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
index 4e2166d..ad5262c 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string.h
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
@@ -40,6 +40,13 @@
 #include "base/apple/bridging.h"
 #endif
 
+// TODO(crbug.com/1444094): AtomicString constructors should be explicit.
+#if BLINK_PLATFORM_IMPLEMENTATION
+#define MAYBE_EXPLICIT explicit
+#else
+#define MAYBE_EXPLICIT
+#endif
+
 namespace WTF {
 
 // An AtomicString instance represents a string, and multiple AtomicString
@@ -54,7 +61,7 @@
   static void Init();
 
   AtomicString() = default;
-  AtomicString(const LChar* chars)
+  MAYBE_EXPLICIT AtomicString(const LChar* chars)
       : AtomicString(chars,
                      chars ? strlen(reinterpret_cast<const char*>(chars)) : 0) {
   }
@@ -65,14 +72,15 @@
   AtomicString(const LChar* chars, size_t length);
 #endif  // defined(ARCH_CPU_64_BITS)
 
-  AtomicString(const char* chars)
+  MAYBE_EXPLICIT AtomicString(const char* chars)
       : AtomicString(reinterpret_cast<const LChar*>(chars)) {}
   AtomicString(const LChar* chars, unsigned length);
   AtomicString(
       const UChar* chars,
       unsigned length,
       AtomicStringUCharEncoding encoding = AtomicStringUCharEncoding::kUnknown);
-  AtomicString(const UChar* chars);
+  MAYBE_EXPLICIT AtomicString(const UChar* chars);
+#undef MAYBE_EXPLICIT
 
   // Constructing an AtomicString from a String / StringImpl can be expensive if
   // the StringImpl is not already atomic.
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index a6044599..0fcb473f 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1294,6 +1294,7 @@
             'media::.+',
             'libyuv::.+',
             'viz::SkColorTypeToResourceFormat',
+            'viz::SkColorTypeToSinglePlaneSharedImageFormat',
         ]
     },
     {
diff --git a/third_party/blink/tools/run_blinkpy_tests.py b/third_party/blink/tools/run_blinkpy_tests.py
index 8e0b3b9..1aa817bc 100755
--- a/third_party/blink/tools/run_blinkpy_tests.py
+++ b/third_party/blink/tools/run_blinkpy_tests.py
@@ -61,7 +61,10 @@
             path_finder.get_blink_tools_dir(),
             path_finder.get_build_scripts_dir(),
         ],
-        path=[path_finder.get_blinkpy_thirdparty_dir()])
+        path=[
+            path_finder.get_blinkpy_thirdparty_dir(),
+            finder.path_from_chromium_base('third_party', 'pyjson5', 'src')
+        ])
 
 
 if __name__ == "__main__":
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b7e13ad..cb94e5a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -72,7 +72,6 @@
 
 # The following tests pass or fail depending on the underlying protocol (HTTP/1.1 vs HTTP/2).
 # The results of failures could be also different depending on the underlying protocol.
-crbug.com/1048761 external/wpt/websockets/constructor/002.html?wss [ Failure Pass ]
 crbug.com/1048761 external/wpt/websockets/interfaces/WebSocket/close/close-connecting.html?wss [ Failure Pass ]
 crbug.com/1048761 external/wpt/websockets/interfaces/WebSocket/close/close-nested.html?wss [ Failure Pass ]
 crbug.com/1048761 external/wpt/websockets/interfaces/WebSocket/readyState/003.html?wss [ Failure Pass ]
@@ -1845,8 +1844,7 @@
 
 # Popover test timeout/flakiness
 crbug.com/1416284 external/wpt/html/semantics/popovers/popover-attribute-basic.html [ Pass Timeout ]
-crbug.com/626703 external/wpt/html/semantics/popovers/popover-hide-crash.html [ Timeout ]
-crbug.com/1443372 external/wpt/html/semantics/popovers/popover-hover-hide.tentative.html [ Pass Failure ]
+crbug.com/1443372 external/wpt/html/semantics/popovers/popover-hover-hide.tentative.html [ Failure Pass ]
 
 # Only virtual/threaded version of these tests pass (or running them with --enable-threaded-compositing).
 crbug.com/936891 fast/scrolling/document-level-touchmove-event-listener-passive-by-default.html [ Failure ]
@@ -2922,6 +2920,7 @@
 crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac11 ] external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-post-message.https.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] external/wpt/html/semantics/links/hyperlink-auditing/headers.optional.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ]
 crbug.com/626703 [ Mac13 ] external/wpt/css/css-content/quotes-020.html [ Failure ]
diff --git a/third_party/blink/web_tests/editing/selection/range-between-block-and-inline.html b/third_party/blink/web_tests/editing/selection/range-between-block-and-inline.html
index fcc9cef9..f631d571 100644
--- a/third_party/blink/web_tests/editing/selection/range-between-block-and-inline.html
+++ b/third_party/blink/web_tests/editing/selection/range-between-block-and-inline.html
@@ -1,5 +1,12 @@
 <html>
 <head>
+<style>
+::selection,
+::selection:window-inactive {
+  background-color: rgb(176, 176, 176);
+  color: black;
+}
+</style>
 <script>
 function doTest()
 {
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index b0c9a09..9f3f191d 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -5510,13 +5510,6 @@
         {}
        ]
       ],
-      "popover-hide-crash.html": [
-       "db491e961e13fba979472748f84378ae6b0391bf",
-       [
-        null,
-        {}
-       ]
-      ],
       "popover-hint-crash.tentative.html": [
        "82f83538e93e364dc90b45aa41515a586ea2089b",
        [
@@ -134854,6 +134847,19 @@
          ]
         ]
        },
+       "masonry-columns-item-containing-block-is-grid-content-width.html": [
+        "e48b650253974a22e2dbf68eee6505ca918ddde7",
+        [
+         null,
+         [
+          [
+           "/css/reference/ref-filled-green-100px-square-only.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "order": {
         "masonry-order-001.html": [
          "d01f52ea0421199c37d04408b42d0f6929876301",
@@ -225924,6 +225930,19 @@
        {}
       ]
      ],
+     "exit-transition-with-anonymous-layout-object.html": [
+      "ea2d17b276100111263b1ea5278fbb4167042ee0",
+      [
+       null,
+       [
+        [
+         "/css/css-view-transitions/exit-transition-with-anonymous-layout-object-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "far-away-capture.html": [
       "bfe0b9fb9484f5984fbea9460d40818a40ab6ddd",
       [
@@ -272102,6 +272121,16 @@
    }
   },
   "support": {
+   ".cache": {
+    "gitignore2.json": [
+     "4fea38c7962c52d3aeae5024f9db13d74c9ac393",
+     []
+    ],
+    "mtime.json": [
+     "a3869f3dfc0398d482690cb292101531fa12c673",
+     []
+    ]
+   },
    ".gitignore": [
     "d93e645d547894b50149d3726de2654957b6e06f",
     []
@@ -282391,6 +282420,10 @@
        "ab06bba524093614ace91ce09daabf08a73cb135",
        []
       ],
+      "floats-placement-001.html.ini": [
+       "1d81cac24bca6aba08811062e8dd6fff0f19e881",
+       []
+      ],
       "floats-placement-005-ref.html": [
        "a286a4aeb75d6e73b96439fb19c62c6f38d8110a",
        []
@@ -283611,6 +283644,10 @@
        "7345888e9a1eadbb866c4f5f7d2669644ca8da62",
        []
       ],
+      "block-formatting-contexts-016.xht.ini": [
+       "bbedc86d3b26278acf37d3f8f0b633024a329378",
+       []
+      ],
       "block-in-inline-align-001-ref.html": [
        "da8d91657f950f68935d20b9fbfaf378aed8cf82",
        []
@@ -287961,26 +287998,50 @@
        "6d84745e7b18113980ac769b7f38c327f18f91ec",
        []
       ],
+      "animation-delay-end-computed.tentative.html.ini": [
+       "2e7e23118e63e5b42e79051b9c0d6809dc0d2f64",
+       []
+      ],
       "animation-delay-end-valid.tentative-expected.txt": [
        "71233d1aebe285e7a8989c8ffda59728099e3bb8",
        []
       ],
+      "animation-delay-end-valid.tentative.html.ini": [
+       "0809ede94234ff8c41fd2fc5f929d0fc6db22635",
+       []
+      ],
       "animation-delay-shorthand-computed-expected.txt": [
        "94b49acfe099599de5d1d60c9d22eae698e344fd",
        []
       ],
+      "animation-delay-shorthand-computed.html.ini": [
+       "52d53d8201e267acea33aced8fab72c3b5b1a63f",
+       []
+      ],
       "animation-delay-shorthand-expected.txt": [
        "4663aaaf0e2dd075bb6f7ddba292c4f351d9ced1",
        []
       ],
+      "animation-delay-shorthand.html.ini": [
+       "feb109afd9ae348648c491f4219dcf8e6fdd4ba4",
+       []
+      ],
       "animation-delay-start-computed.tentative-expected.txt": [
        "75dec90a103d4e638b8eaf8369f9d97c72d9c650",
        []
       ],
+      "animation-delay-start-computed.tentative.html.ini": [
+       "9ae307e70c2b72160ea65401204e3767d40a68f4",
+       []
+      ],
       "animation-delay-start-valid.tentative-expected.txt": [
        "3d4cc51069d8ddada0b28d2cd6f1459ccde7ad99",
        []
       ],
+      "animation-delay-start-valid.tentative.html.ini": [
+       "4ad3bb1e96bb5c0051fb454959cb484278042f4a",
+       []
+      ],
       "animation-name-computed-expected.txt": [
        "bbe7ac5483167f5926f25f928dd8e1df04956ac6",
        []
@@ -291931,10 +291992,6 @@
        "9e2a1e0b92143c20ee0bf7c2260fa6ebd7109509",
        []
       ],
-      "color-valid-system-color-expected.txt": [
-       "0ab1033c4e9a82659ec136f2084d572ab442298d",
-       []
-      ],
       "color-valid-system-color.html.ini": [
        "9746564795a98a36656d108bb6192c291276cd04",
        []
@@ -292524,6 +292581,10 @@
       "180db13123714fa7a0334d63bae71af3e21dec58",
       []
      ],
+     "contain-paint-017.html.ini": [
+      "8debe69c21a470cdf2649c26a67562cdbd8a8059",
+      []
+     ],
      "contain-paint-026.html.ini": [
       "7b3f18a255c0e0bc68fb86f45977c8f2440e8660",
       []
@@ -311078,7 +311139,7 @@
        []
       ],
       "clip-path-svg-invalidate.html.ini": [
-       "675938fece89cc04eb64599c04074d1aea5ea615",
+       "3b8b2259c6085f785bf1d9ebc95d8568830df26c",
        []
       ],
       "clip-path-svg-text-backdrop-filter-ref.html": [
@@ -323125,6 +323186,10 @@
        "73a0f031ccfa759178a2b86ed4d485f0f6586fe9",
        []
       ],
+      "text-transform-capitalize-010.html.ini": [
+       "52f0349faf6e1b203b0dbf208b1195a7ab0ceaf5",
+       []
+      ],
       "text-transform-capitalize-014.html.ini": [
        "4080d27f0bc429516e18336bf4fff03742a3a083",
        []
@@ -326383,7 +326448,7 @@
       []
      ],
      "preserve3d-and-flattening-z-order-006.html.ini": [
-      "bdb0fc50b32156b623f5874c50dacb5a87437bbb",
+      "62638fc6e2f2e7c20e4d353aa1b8e73ed6f80b28",
       []
      ],
      "preserve3d-and-flattening-z-order-008.html.ini": [
@@ -328162,10 +328227,18 @@
         "cd252b859a8950fe843a7f0fd53d6e4de057096d",
         []
        ],
+       "animation-delay-end.tentative.html.ini": [
+        "8da29565167e00564aef8017aad80a3592ea5360",
+        []
+       ],
        "animation-delay-start.tentative-expected.txt": [
         "2ec7b3a8a1271025b75e20352a77705d4afcd04f",
         []
        ],
+       "animation-delay-start.tentative.html.ini": [
+        "20ad1884778ae6c5f158a808b7fc389762e224ec",
+        []
+       ],
        "animation-delay.html.ini": [
         "c3362e8fb80557bd3c80521be95fc59538823b0b",
         []
@@ -328938,6 +329011,10 @@
       "2131756c61ad815531882044808c8ff719612d46",
       []
      ],
+     "appearance-menulist-001.html.ini": [
+      "51b90878d5dd7a91a8ff6bee85b204379343679b",
+      []
+     ],
      "appearance-progress-bar-002-ref.html": [
       "d243f0c75c75f57e6fd1ca629ccf0d3d924a0c13",
       []
@@ -329099,6 +329176,10 @@
        "fce7085a97394cc160e7dc62b707655044e1db5f",
        []
       ],
+      "kind-of-widget-fallback-color-input-border-inline-end-color-001.html.ini": [
+       "39a9482f4c65060d786acf8abc27efaf6f8ac77c",
+       []
+      ],
       "kind-of-widget-fallback-color-input-border-inline-end-style-001.html.ini": [
        "5bc56d3cf7154da70ff2a8de32d4ff3b697314c2",
        []
@@ -329107,6 +329188,10 @@
        "45c8c10b3d50fa0e7946ee1871f7d6e2d14f2b92",
        []
       ],
+      "kind-of-widget-fallback-color-input-border-inline-start-style-001.html.ini": [
+       "2885caae33f1641b730c95b46fc18585f8734cf2",
+       []
+      ],
       "kind-of-widget-fallback-color-input-border-left-width-001.html.ini": [
        "790ec0a2515cffe6f8324353c2a9273a6a1ebb11",
        []
@@ -329159,6 +329244,14 @@
        "e935a80df693f45b69f2ef1b013dd5d719fcc22d",
        []
       ],
+      "kind-of-widget-fallback-input-button-border-bottom-right-radius-001.html.ini": [
+       "eb0b7675ba01bed894bd6458bcfdef0842433a14",
+       []
+      ],
+      "kind-of-widget-fallback-input-button-border-end-end-radius-001.html.ini": [
+       "cde25330d709bf43e9ba41dfa22c5a9c6b3f8057",
+       []
+      ],
       "kind-of-widget-fallback-input-button-border-image-slice-001.html.ini": [
        "33ab63083b4362b433eacf5e7d422cd4ab6f9d2f",
        []
@@ -329171,6 +329264,10 @@
        "1643f87d971fb1bada2291af2aa95f54063bda3d",
        []
       ],
+      "kind-of-widget-fallback-input-button-border-inline-start-color-001.html.ini": [
+       "c90f91f91ce3d11bd78028efe9c3060483d574dc",
+       []
+      ],
       "kind-of-widget-fallback-input-button-border-inline-start-width-001.html.ini": [
        "7dcd817f746113233616f393724f4c05bbefd158",
        []
@@ -329224,7 +329321,7 @@
        []
       ],
       "kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini": [
-       "fc0838c06b72d4e544e40404313644fc594f5edc",
+       "53da70e4ca02963018613796dbb4beab5557da8f",
        []
       ],
       "kind-of-widget-fallback-input-reset-border-image-source-001.html.ini": [
@@ -329316,7 +329413,11 @@
        []
       ],
       "kind-of-widget-fallback-input-search-border-inline-end-width-001.html.ini": [
-       "e54f0fc546f2552e9977030330f2514dc283d7c9",
+       "3c5a779719f01e9a44a05f573b702c0a01e22147",
+       []
+      ],
+      "kind-of-widget-fallback-input-search-border-inline-start-color-001.html.ini": [
+       "2fc7ad2fbdf32b100c54aaec257bf18b97620e8a",
        []
       ],
       "kind-of-widget-fallback-input-search-border-inline-start-style-001.html.ini": [
@@ -329344,7 +329445,7 @@
        []
       ],
       "kind-of-widget-fallback-input-search-border-start-end-radius-001.html.ini": [
-       "0652ebf96f1ea0f2869e4027eb70580b29980065",
+       "122cb6287898930889578a1d3833c3fd1336381c",
        []
       ],
       "kind-of-widget-fallback-input-search-border-start-start-radius-001.html.ini": [
@@ -329383,6 +329484,10 @@
        "78a6effd39da5d27c686b214c0f9c0c29fac62b9",
        []
       ],
+      "kind-of-widget-fallback-input-search-text-background-size-001.html.ini": [
+       "d858bc58532bc701b1badd2690041b60e73143f8",
+       []
+      ],
       "kind-of-widget-fallback-input-search-text-border-block-end-color-001.html.ini": [
        "114fa292144ff7fbb138a832d2851cb1b748ca37",
        []
@@ -329572,7 +329677,7 @@
        []
       ],
       "kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini": [
-       "3198dfd78978a8e0723b68054d4e028056c18866",
+       "403c94368fb3e3cd268f662f39c19b1e705e716e",
        []
       ],
       "kind-of-widget-fallback-input-submit-border-inline-start-width-001.html.ini": [
@@ -329588,7 +329693,7 @@
        []
       ],
       "kind-of-widget-fallback-input-submit-border-left-width-001.html.ini": [
-       "7e86e3dde9c51af132c681e6c1b829bcefefbc34",
+       "1f7ab7ade35a0b03819a91c1031be3c6e17b6c4c",
        []
       ],
       "kind-of-widget-fallback-input-submit-border-right-color-001.html.ini": [
@@ -329972,7 +330077,7 @@
        []
       ],
       "kind-of-widget-fallback-textarea-border-inline-start-width-001.html.ini": [
-       "e8b5a37ee7faed92ea84fc866d8e9187e7841639",
+       "c33bd8ad87cd1fcc331ba7837cb0632fabef4103",
        []
       ],
       "kind-of-widget-fallback-textarea-border-left-color-001.html.ini": [
@@ -332328,6 +332433,10 @@
       "523c8616a6666ddfab4dcf3b02dced31523a92b5",
       []
      ],
+     "exit-transition-with-anonymous-layout-object-ref.html": [
+      "10e04ac58a44e9005d7297ca17c63666ed2c542a",
+      []
+     ],
      "far-away-capture-ref.html": [
       "9e10b9b44e302a32f71c0fa7efac78eca9f0456a",
       []
@@ -336501,7 +336610,7 @@
       []
      ],
      "backdrop-filter-basic.html.ini": [
-      "c091770e6b43e14d979cd0234fce1712303997ae",
+      "1047f60c7a66f7f1cea4d439fa4001bcfa406528",
       []
      ],
      "backdrop-filter-clip-rect-ref.html": [
@@ -336569,7 +336678,7 @@
       []
      ],
      "backdrop-filter-isolation-isolate.html.ini": [
-      "c8991e6d914481fa9eec370d80d8fa1b9b5c8cc1",
+      "f607a46a86ffede2fa7bf473ce6c23332345a479",
       []
      ],
      "backdrop-filter-isolation-ref.html": [
@@ -336621,7 +336730,7 @@
       []
      ],
      "backdrop-filter-svg-foreignObject.html.ini": [
-      "82031871ecb8c082be4808a30c5147e0ad199acc",
+      "6df726e6c60ca9f5644da63f8263b24fb10c1caa",
       []
      ],
      "backdrop-filter-update-ref.html": [
@@ -336657,7 +336766,7 @@
       []
      ],
      "backdrop-filters-grayscale-002.html.ini": [
-      "e958b5b798971b61b55e617eb0f9afe58b89b64d",
+      "3f30c1142708545ae86e3b30eb8787f4453f404f",
       []
      ],
      "backdrop-filters-grayscale-003.html.ini": [
@@ -336677,7 +336786,7 @@
       []
      ],
      "backdrop-filters-invert.html.ini": [
-      "7285229a320a2e6a997b33f845eb3b215217fd57",
+      "ea379defb561cfc7f6667f982b36111766639181",
       []
      ],
      "backdrop-filters-opacity-ref.html": [
@@ -336824,6 +336933,10 @@
       "c87c2fac63a54e56d77ce4866216507b18c1aebb",
       []
      ],
+     "css-filters-animation-saturate.html.ini": [
+      "ab0ed5d7a7ca394df1cacc464212aae1481c7851",
+      []
+     ],
      "css-filters-animation-sepia-ref.html": [
       "7b21bfadf1eff5fdcd9d7b45bd59f07de4dbe1ae",
       []
@@ -355754,6 +355867,22 @@
         "fb3b5b830d345d2aa858e41673e08f99977baf08",
         []
        ],
+       "2d.text.drawing.style.letterSpacing.measure.relative.html.ini": [
+        "9cb3a0a857bf2f20ad742761b47a914b5006355e",
+        []
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.relative.worker.js.ini": [
+        "eca264d68019cdeb1da890cd55637c1db6629d3c",
+        []
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.relative.html.ini": [
+        "7a3721c0c12f0a8a3f7857688c1403b5068eb458",
+        []
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.relative.worker.js.ini": [
+        "2142c1260983365f0a7bf1f3370b8164e24be26d",
+        []
+       ],
        "2d.text.measure.width.space-expected.txt": [
         "31bf7882298ab07a8c62aa47d0f90533c6dc8a75",
         []
@@ -355862,7 +355991,7 @@
       "yaml": {
        "element": {
         "drawing-text-to-the-canvas.yaml": [
-         "e0de95560cb122a2a2d6ea9ac47fcbf93ad941e0",
+         "3443ad35b3cdccffb0dcb383b946dcd81a0521d5",
          []
         ],
         "fill-and-stroke-styles.yaml": [
@@ -355904,7 +356033,7 @@
          []
         ],
         "text.yaml": [
-         "80c54ca6b664e63b6f54e3978c6665f1c9ba2a24",
+         "784a099aca09747325bbc800a0976031a4324d08",
          []
         ],
         "the-canvas-state.yaml": [
@@ -357060,14 +357189,26 @@
         "b3c24c3f82d2dbf07eefa9fa2e88fcf3817473d2",
         []
        ],
+       "access-reporting-closed.https.html.ini": [
+        "a6cab97d6268ab0bb189263aa3f38960939cefa5",
+        []
+       ],
        "access-reporting-openee-rp-ro.https-expected.txt": [
         "0d4d312cf505711ee11be920b0bb9d3b965f04c9",
         []
        ],
+       "access-reporting-openee-rp-ro.https.html.ini": [
+        "4b5f029c7a9eb203712da9472fce7deebcf6fed8",
+        []
+       ],
        "access-reporting-opener-rp-ro.https-expected.txt": [
         "da251b50de98778e4326efa63eedd702d47d0774",
         []
        ],
+       "access-reporting-opener-rp-ro.https.html.ini": [
+        "559ccdd873c68e03103f1a1b8c96425deaa87cb0",
+        []
+       ],
        "coop-rp-in-navigation-chain.https.html.headers": [
         "073ce7adfbd81cb7c0b2f91f96c8349b6677f26c",
         []
@@ -357236,6 +357377,10 @@
         "ea3108eb21ec47915e61e5d4b61c42d46a37754a",
         []
        ],
+       "reporting-from-rp-ro.https.html.ini": [
+        "c970a3b97eebd268427840cd7b3679d9815f48bf",
+        []
+       ],
        "reporting-from-rp-ro.https.html.sub.headers": [
         "424ad3e8de0297a2e66dd53914f0e5faa8651bff",
         []
@@ -357244,6 +357389,10 @@
         "840f72a3863b12bd0de8ac511cb5b050d4cce94e",
         []
        ],
+       "reporting-from-rp.https.html.ini": [
+        "1cc83dc3424e9781a28baa74b0013d7458f588f2",
+        []
+       ],
        "reporting-from-rp.https.html.sub.headers": [
         "6339ea34c7045eabe7457cf0c170edd35ea2ba76",
         []
@@ -357256,6 +357405,10 @@
         "16903320bb50789e0a64f9620540f1cc8c0902fd",
         []
        ],
+       "reporting-to-rp-ro.https.html.ini": [
+        "c2354d4a6ca86fce7b82a394968d0751c3fd7ba4",
+        []
+       ],
        "reporting-to-rp.https-expected.txt": [
         "6d598760c826b564a96fcff06b344d0b02b4c2ce",
         []
@@ -357263,6 +357416,10 @@
        "reporting-to-rp.https.html.headers": [
         "16903320bb50789e0a64f9620540f1cc8c0902fd",
         []
+       ],
+       "reporting-to-rp.https.html.ini": [
+        "dd141e92b38f30139266b765bb934fca021fd53e",
+        []
        ]
       }
      }
@@ -365186,6 +365343,14 @@
         "ce87abd9570be5001caff24ee7fdec7d1bec3a5a",
         []
        ],
+       "form-double-submit-requestsubmit-expected.txt": [
+        "bf1d8b7c162de549f0ba7323d3ab979c92346ce9",
+        []
+       ],
+       "form-double-submit-requestsubmit.html.ini": [
+        "6b936be9cf7449043730fe1e20655d8f8fd0281b",
+        []
+       ],
        "form-echo.py": [
         "72f1f51ce50e90fc615a898d282eb29b5304e5f3",
         []
@@ -366181,10 +366346,6 @@
        "2dc0d558b634279a09703798e9a531748215a563",
        []
       ],
-      "popover-hide-crash.html.ini": [
-       "0284e981a03fd7ca73d54039d7a33ec640c8423f",
-       []
-      ],
       "popover-inside-display-none-ref.html": [
        "3d58e4ca095c228f05a5f6a0e4cc99aac54fd407",
        []
@@ -375115,7 +375276,7 @@
       []
      ],
      "mediasource-worker-play-terminate-worker.html.ini": [
-      "ca7edf8f0510137064183f6a77497dd0d50b603d",
+      "c1da011580f1102f1102c68a3bd48703d5bcaf30",
       []
      ],
      "mediasource-worker-play-terminate-worker.js": [
@@ -382680,6 +382841,10 @@
       "5b9ea08d71d542889f1653491829e3421a452735",
       []
      ],
+     "animation-shorthand.html.ini": [
+      "c20285ad1f4bf99ae99e9851afb459e952426c42",
+      []
+     ],
      "animation-update-ref.html": [
       "7e375a1df7f063ba6cdbbdad92beb73915b84d6e",
       []
@@ -386283,7 +386448,7 @@
       []
      ],
      "unregister-immediately-during-extendable-events.https.html.ini": [
-      "099411deb66fa0fed34a5258192b037681df15b1",
+      "c346d607933e395a6f975f448e6d44f95ebd52f8",
       []
      ],
      "unregister-then-register-new-script.https-expected.txt": [
@@ -388238,7 +388403,15 @@
       "9271c769b25d73c571d553bccd9ac48c8b4b7f39",
       []
      ]
-    }
+    },
+    "storagemanager-persist-persisted-match.https.any.js.ini": [
+     "e58e43e830dcec80701596b3d20f6814d004799d",
+     []
+    ],
+    "storagemanager-persist-persisted-match.https.any.worker-expected.txt": [
+     "0b4cdf290df61474cb8507d671fc13b68a9cfed3",
+     []
+    ]
    },
    "storage-access-api": {
     "DIR_METADATA": [
@@ -395032,6 +395205,10 @@
       "571d4e1044db84f78f5bbf173b1c334e5f73d041",
       []
      ],
+     "020.html.ini": [
+      "a2275d79f0be6095ac032f5a50e1cf3f36a3849a",
+      []
+     ],
      "021.html.ini": [
       "7e1db6e1240d7873ab7c6812ddc273b0e8ffc022",
       []
@@ -396431,6 +396608,42 @@
      "6e141336536a22be05d71b3764743f3ff6c65dce",
      []
     ],
+    "Create-http-urls.any-expected.txt": [
+     "9412ba1b2a8047fff31a642449abf6be01b60ffe",
+     []
+    ],
+    "Create-http-urls.any.js.ini": [
+     "78bac82d71ea2db450531b306486dd7291c09154",
+     []
+    ],
+    "Create-http-urls.any.worker-expected.txt": [
+     "9412ba1b2a8047fff31a642449abf6be01b60ffe",
+     []
+    ],
+    "Create-invalid-urls.any-expected.txt": [
+     "851aded595c9cea34f9a5c0eb691be12b9fa17ef",
+     []
+    ],
+    "Create-invalid-urls.any.js.ini": [
+     "8b739adfdd95ed922af8a5b17d203a1f53db09e1",
+     []
+    ],
+    "Create-invalid-urls.any.worker-expected.txt": [
+     "851aded595c9cea34f9a5c0eb691be12b9fa17ef",
+     []
+    ],
+    "Create-non-absolute-url.any-expected.txt": [
+     "cd6dc873bab35a4a5c2e7b2de60690269b0cc66e",
+     []
+    ],
+    "Create-non-absolute-url.any.js.ini": [
+     "09cbb63af962685a5f7b7def4834505f7eb2e767",
+     []
+    ],
+    "Create-non-absolute-url.any.worker-expected.txt": [
+     "cd6dc873bab35a4a5c2e7b2de60690269b0cc66e",
+     []
+    ],
     "Create-on-worker-shutdown.any-expected.txt": [
      "c0c2dff7bedda980c35f32252ac2e3a73c11fe5a",
      []
@@ -396499,6 +396712,14 @@
      "114fa7d07a2ffcefe166bf8e30e81b9bfa2e7225",
      []
     ],
+    "Create-url-with-windows-1252-encoding-expected.txt": [
+     "e1df1c29f73b9d0d6b01e34b364e94a27d639d4b",
+     []
+    ],
+    "Create-url-with-windows-1252-encoding.html.ini": [
+     "918c19fbfcd3fad92809760e1bcc77a41ba35184",
+     []
+    ],
     "Create-valid-url-array-protocols.any.worker_wpt_flags=h2-expected.txt": [
      "f7aa3bd5bccb2e3af5ef7021922abc56b8e7fe31",
      []
@@ -396598,7 +396819,7 @@
      ]
     },
     "constants.sub.js": [
-     "65ea4f66f29d333145d548df41472d34e42f01d9",
+     "d8e340d304b26fb51be84ba76f68acbd0924ada7",
      []
     ],
     "constructor": {
@@ -396606,10 +396827,6 @@
       "283195c46953c3316edc4b755737a466938acec5",
       []
      ],
-     "002.html.ini": [
-      "b469a85e857cd15ac6bbd004fd5af31dbc06cbb1",
-      []
-     ],
      "002_wpt_flags=h2-expected.txt": [
       "283195c46953c3316edc4b755737a466938acec5",
       []
@@ -456413,21 +456630,28 @@
        ]
       ],
       "scroll-start-target-computed.html": [
-       "5dedf2483137e18bd5795d771aa2084949b3371a",
+       "bb31f2b24468786c57940fdf330cbd7a398bd2d1",
        [
         null,
         {}
        ]
       ],
       "scroll-start-target-invalid.html": [
-       "a08ef87237efbf383a4b6b8b9cef05c3e45e7305",
+       "03ca718629c38eafb7ace31540cfc4e5a3c74e24",
+       [
+        null,
+        {}
+       ]
+      ],
+      "scroll-start-target-shorthand.html": [
+       "601715784253cbb7ca1a32e5d589e8250550c10e",
        [
         null,
         {}
        ]
       ],
       "scroll-start-target-valid.html": [
-       "f972967acd5c63f2d1e852711792da2a276bbe35",
+       "aed964bdff4a77b6d7c849aca0df5d85f19fd242",
        [
         null,
         {}
@@ -461224,15 +461448,15 @@
         {}
        ]
       ],
-      "white-space-collapse-invalid copy.html": [
-       "6c18ecec21c5c83aa897c762c7bda8f5cabc37e1",
+      "white-space-collapse-invalid.html": [
+       "0d2856ba37f5d1b01d7944d93f3f0856624ab217",
        [
         null,
         {}
        ]
       ],
       "white-space-collapse-valid.html": [
-       "2191167527bb12336c17e87208b33fa2b34a498a",
+       "23c0cd39bb677fa4ad3d2cb5c78d0c69a97e50b7",
        [
         null,
         {}
@@ -511896,7 +512120,7 @@
       ]
      ],
      "element-request-fullscreen-options.tentative.html": [
-      "f3b99e84e69681e7753f379bf36f5e0b88c59d63",
+      "875431698f7a9212a40d444ddc10627defaf7b11",
       [
        null,
        {
@@ -521267,21 +521491,21 @@
         ]
        ],
        "2d.text.drawing.style.invalid.spacing.html": [
-        "61ca6d4a91533ea75bcc7505a0d8f3969be1ee07",
+        "9bf2440900c2f8193b36c45725fb94db084d6182",
         [
          null,
          {}
         ]
        ],
        "2d.text.drawing.style.letterSpacing.change.font.html": [
-        "5b42b89e3254c560810e35f1f571d85111503407",
+        "3b88ab6ee17c0b224f9a669335c567751c07699b",
         [
          null,
          {}
         ]
        ],
        "2d.text.drawing.style.letterSpacing.measure.html": [
-        "fadfaaf2015f4a8a3ec1f51e3def3b474833b409",
+        "ba8656ec1a3d5d84b0c3e2cc7ea7879eb308c605",
         [
          null,
          {}
@@ -521316,7 +521540,7 @@
         ]
        ],
        "2d.text.drawing.style.wordSpacing.measure.html": [
-        "4cd3c237cd8db811f6c937d6518db021bd7b27c2",
+        "4898c23ee78177b6438ccc042eb8edb58624eda1",
         [
          null,
          {}
@@ -537714,14 +537938,14 @@
         ]
        ],
        "2d.text.drawing.style.invalid.spacing.html": [
-        "a117be03656e6552b4859cfb6560138c40cbff89",
+        "5030055567a76411fb3c51cddc14eb4bb79a5d22",
         [
          null,
          {}
         ]
        ],
        "2d.text.drawing.style.invalid.spacing.worker.js": [
-        "7f6baf28b68d76b5e71020a19283b2a49e6058b7",
+        "e4b090cc76516851cabf6d1183326aaf5c1ab326",
         [
          "html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.html",
          {}
@@ -537741,17 +537965,31 @@
          {}
         ]
        ],
-       "2d.text.drawing.style.letterSpacing.measure.html": [
-        "b63c81b25579a022c61c1c566b9fcf55bf8eb1d9",
+       "2d.text.drawing.style.letterSpacing.measure.absolute.html": [
+        "5482c36b37080f962fb3b2289530b524caae2c28",
         [
          null,
          {}
         ]
        ],
-       "2d.text.drawing.style.letterSpacing.measure.worker.js": [
-        "b9189cba30cf6d757605d97c320d9d76edc45868",
+       "2d.text.drawing.style.letterSpacing.measure.absolute.worker.js": [
+        "22cab4cccd93e9b58ca9c81457167476338e2f5a",
         [
-         "html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.html",
+         "html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.worker.html",
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.relative.html": [
+        "fa5d2bce75459db2638669e64ea444f132f79c9c",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.relative.worker.js": [
+        "59d17ef82cf36f9d7f842b2506c84cefaa5f370c",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.html",
          {}
         ]
        ],
@@ -537853,17 +538091,31 @@
          {}
         ]
        ],
-       "2d.text.drawing.style.wordSpacing.measure.html": [
-        "9ef479bba2c061a5eec558a4db6d305919c28b08",
+       "2d.text.drawing.style.wordSpacing.measure.absolute.html": [
+        "07ca896f9752a2cf58928df7afa07c14b615bb47",
         [
          null,
          {}
         ]
        ],
-       "2d.text.drawing.style.wordSpacing.measure.worker.js": [
-        "3e850fcf3dfb2225b20f4b5cc838b8ff004688de",
+       "2d.text.drawing.style.wordSpacing.measure.absolute.worker.js": [
+        "ebfc05644fcbd3a395730ee4a89f54e5443adc29",
         [
-         "html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.html",
+         "html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.worker.html",
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.relative.html": [
+        "95f87cb03d05b79e1ebb48155723672ae04903e0",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.relative.worker.js": [
+        "2bded51edcbe3571274bb4e9b36d19908127b4a3",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.html",
          {}
         ]
        ],
@@ -542518,15 +542770,6 @@
          }
         ]
        ],
-       "reporting-bcg-reuse.https.html": [
-        "8428d0cf60ae1c5f4f002cee4ad5108c69875d53",
-        [
-         null,
-         {
-          "timeout": "long"
-         }
-        ]
-       ],
        "reporting-from-rp-ro.https.html": [
         "60322bffe7a1c7d8d536b35504e925b09ff0c6bd",
         [
@@ -552766,6 +553009,13 @@
          {}
         ]
        ],
+       "form-double-submit-requestsubmit.html": [
+        "b4028784edd933e64fd8d4c1c86cda694fc3b312",
+        [
+         null,
+         {}
+        ]
+       ],
        "form-double-submit-to-different-origin-frame.html": [
         "00a46bfd4326fc2d35d50bfc4a2f68890a5594bb",
         [
@@ -555713,6 +555963,13 @@
         }
        ]
       ],
+      "popover-anchor-transition.tentative.html": [
+       "ae2a3a8e4159c63fe9213a96969ec7dc24d90325",
+       [
+        null,
+        {}
+       ]
+      ],
       "popover-attribute-all-elements.html": [
        "5a536f026ee96744c744eb98244cb3e06017d277",
        [
@@ -555779,13 +556036,6 @@
         }
        ]
       ],
-      "popover-focus-child-dialog.html": [
-       "051eef14a7ccc762e66c868e4d80b2ea9da24e33",
-       [
-        null,
-        {}
-       ]
-      ],
       "popover-focus.html": [
        "98bb065de7b8b894c803d9e6f0d5145515e207bb",
        [
@@ -611558,6 +611808,31 @@
       }
      ]
     ],
+    "storagemanager-persist-persisted-match.https.any.js": [
+     "edbe67fae2c1e17bc7ce3aa3c3d1dc9db7982cac",
+     [
+      "storage/storagemanager-persist-persisted-match.https.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "StorageManager: result of persist() matches result of persisted()"
+        ]
+       ]
+      }
+     ],
+     [
+      "storage/storagemanager-persist-persisted-match.https.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "StorageManager: result of persist() matches result of persisted()"
+        ]
+       ]
+      }
+     ]
+    ],
     "storagemanager-persist.https.window.js": [
      "13e17a16e14198e21b0b5984ed46c93a50daed41",
      [
@@ -644323,262 +644598,37 @@
       }
      ]
     ],
+    "Create-http-urls.any.js": [
+     "17590fc43ef5ab55fdf43ed2224a13f96e24a646",
+     [
+      "websockets/Create-http-urls.any.html",
+      {}
+     ],
+     [
+      "websockets/Create-http-urls.any.worker.html",
+      {}
+     ]
+    ],
     "Create-invalid-urls.any.js": [
-     "89783a9ea7439ca1c9c7eb7ed74b5a05792e3842",
+     "73c9fadab9d8e249bcfc7e1f6a548becd1e27112",
      [
       "websockets/Create-invalid-urls.any.html",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-invalid-urls.any.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-invalid-urls.any.html?wss",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
+      {}
      ],
      [
       "websockets/Create-invalid-urls.any.worker.html",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-invalid-urls.any.worker.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-invalid-urls.any.worker.html?wss",
-      {
-       "script_metadata": [
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
+      {}
      ]
     ],
     "Create-non-absolute-url.any.js": [
-     "8d533fd2e04f14274c6639e68fc9a3ae9dd8fe90",
+     "5a7b1794d04188c96eed64ebe4440a0af92e4389",
      [
       "websockets/Create-non-absolute-url.any.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-non-absolute-url.any.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-non-absolute-url.any.html?wss",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
+      {}
      ],
      [
       "websockets/Create-non-absolute-url.any.worker.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-non-absolute-url.any.worker.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-non-absolute-url.any.worker.html?wss",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
+      {}
      ]
     ],
     "Create-nonAscii-protocol-string.any.js": [
@@ -645297,6 +645347,13 @@
       }
      ]
     ],
+    "Create-url-with-windows-1252-encoding.html": [
+     "6596b5e1a0b42a639cc0efee19fe88fbca6d373a",
+     [
+      null,
+      {}
+     ]
+    ],
     "Create-valid-url-array-protocols.any.js": [
      "00ab1ca9873248013dfaab04720befb8c0083f1f",
      [
@@ -646284,147 +646341,6 @@
       }
      ]
     ],
-    "Create-wrong-scheme.any.js": [
-     "00cfffece601c7f136d08ace80ea957e2db1ff10",
-     [
-      "websockets/Create-wrong-scheme.any.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-wrong-scheme.any.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-wrong-scheme.any.html?wss",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-wrong-scheme.any.worker.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-wrong-scheme.any.worker.html?wpt_flags=h2",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ],
-     [
-      "websockets/Create-wrong-scheme.any.worker.html?wss",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "constants.sub.js"
-        ],
-        [
-         "variant",
-         ""
-        ],
-        [
-         "variant",
-         "?wss"
-        ],
-        [
-         "variant",
-         "?wpt_flags=h2"
-        ]
-       ]
-      }
-     ]
-    ],
     "Send-0byte-data.any.js": [
      "b984b641084a3cddbf1b757aa794532ab708000c",
      [
@@ -650157,21 +650073,6 @@
        {}
       ]
      ],
-     "002.html": [
-      "8c80c23735f1cc32e0ed9e7ff30504514c837245",
-      [
-       null,
-       {}
-      ],
-      [
-       "websockets/constructor/002.html?wpt_flags=h2",
-       {}
-      ],
-      [
-       "websockets/constructor/002.html?wss",
-       {}
-      ]
-     ],
      "004.html": [
       "e599bf224ae0fe7667bfa08ff2d92be206648d0b",
       [
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats/floats-placement-001.html.ini b/third_party/blink/web_tests/external/wpt/css/CSS2/floats/floats-placement-001.html.ini
new file mode 100644
index 0000000..1d81cac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats/floats-placement-001.html.ini
@@ -0,0 +1,3 @@
+[floats-placement-001.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-formatting-contexts-016.xht.ini b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-formatting-contexts-016.xht.ini
new file mode 100644
index 0000000..bbedc86
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-formatting-contexts-016.xht.ini
@@ -0,0 +1,3 @@
+[block-formatting-contexts-016.xht]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-computed.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-computed.tentative.html.ini
new file mode 100644
index 0000000..2e7e2311
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-computed.tentative.html.ini
@@ -0,0 +1,12 @@
+[animation-delay-end-computed.tentative.html]
+  [Property animation-delay-end value '-500ms']
+    expected: FAIL
+
+  [Property animation-delay-end value '20s, 10s']
+    expected: FAIL
+
+  [Property animation-delay-end value 'calc(2 * 3s)']
+    expected: FAIL
+
+  [Property animation-delay-end value 'initial']
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-valid.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-valid.tentative.html.ini
new file mode 100644
index 0000000..0809ede
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-end-valid.tentative.html.ini
@@ -0,0 +1,12 @@
+[animation-delay-end-valid.tentative.html]
+  [e.style['animation-delay-end'\] = "-5ms" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-end'\] = "0s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-end'\] = "10s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-end'\] = "20s, 10s" should set the property value]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand-computed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand-computed.html.ini
new file mode 100644
index 0000000..52d53d8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand-computed.html.ini
@@ -0,0 +1,9 @@
+[animation-delay-shorthand-computed.html]
+  [Property animation-delay value '1s 2s']
+    expected: FAIL
+
+  [Property animation-delay value '1s 2s, 3s']
+    expected: FAIL
+
+  [Property animation-delay value '1s, 2s 3s']
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand.html.ini
new file mode 100644
index 0000000..feb109af
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-shorthand.html.ini
@@ -0,0 +1,45 @@
+[animation-delay-shorthand.html]
+  [e.style['animation-delay'\] = "1s 2s" should not set unrelated longhands]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s" should set animation-delay-end]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s" should set animation-delay-start]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s 4s" should not set unrelated longhands]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s 4s" should set animation-delay-end]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s 4s" should set animation-delay-start]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s, 4s 5s" should not set unrelated longhands]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s, 4s 5s" should set animation-delay-end]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s 2s, 3s, 4s 5s" should set animation-delay-start]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s" should not set unrelated longhands]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s" should set animation-delay-end]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s" should set animation-delay-start]
+    expected: FAIL
+
+  [e.style['animation-delay'\] = "1s, 2s 3s" should set the property value]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-computed.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-computed.tentative.html.ini
new file mode 100644
index 0000000..9ae307e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-computed.tentative.html.ini
@@ -0,0 +1,12 @@
+[animation-delay-start-computed.tentative.html]
+  [Property animation-delay-start value '-500ms']
+    expected: FAIL
+
+  [Property animation-delay-start value '20s, 10s']
+    expected: FAIL
+
+  [Property animation-delay-start value 'calc(2 * 3s)']
+    expected: FAIL
+
+  [Property animation-delay-start value 'initial']
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-valid.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-valid.tentative.html.ini
new file mode 100644
index 0000000..4ad3bb1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-delay-start-valid.tentative.html.ini
@@ -0,0 +1,12 @@
+[animation-delay-start-valid.tentative.html]
+  [e.style['animation-delay-start'\] = "-5ms" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-start'\] = "0s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-start'\] = "10s" should set the property value]
+    expected: FAIL
+
+  [e.style['animation-delay-start'\] = "20s, 10s" should set the property value]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-paint-017.html.ini b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-paint-017.html.ini
new file mode 100644
index 0000000..8debe69c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-paint-017.html.ini
@@ -0,0 +1,3 @@
+[contain-paint-017.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/display-contents-dynamic-style-queries.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/display-contents-dynamic-style-queries.html
new file mode 100644
index 0000000..782cf566
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/display-contents-dynamic-style-queries.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>CSS Container Queries Test: Invalidate style queries and display:contents</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+  #container.contents {
+    --foo: bar;
+    display: contents;
+  }
+  #target {
+    color: red;
+  }
+  @container style(--foo: bar) {
+    #target {
+      color: green;
+    }
+  }
+</style>
+<div id="container">
+  <div id="target">This should be green</div>
+</div>
+<script>
+  setup(() => assert_implements_container_queries());
+
+  test(() => {
+    assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)");
+  }, "Initially the color is red");
+
+  test(() => {
+    container.className = "contents";
+    assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+  }, "After display and --foo changes, style() query causes the color to be green");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-columns-item-containing-block-is-grid-content-width.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-columns-item-containing-block-is-grid-content-width.html
new file mode 100644
index 0000000..e48b650
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-columns-item-containing-block-is-grid-content-width.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-3/#containing-block">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Svg should use grid's content logical width for its containing block size and get sized to 100px x 100px">
+<style>
+grid {
+    display: grid;
+    grid-template-columns:masonry;
+    grid-template-rows: auto;
+}
+</style>
+</head>
+<body>
+<p>Test passes if there is a filled green square.</p>
+<grid>
+    <svg width="100" height="100" viewBox="0 0 1 1" style="width: 100%; max-width: 100px; background: green;"></svg>
+</grid>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-invalidate.html.ini b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-invalidate.html.ini
index 675938f..3b8b225 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-invalidate.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-invalidate.html.ini
@@ -1,5 +1,6 @@
 [clip-path-svg-invalidate.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid copy.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid.html
similarity index 60%
rename from third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid copy.html
rename to third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid.html
index 6c18ece..0d2856ba 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid copy.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-invalid.html
@@ -2,10 +2,10 @@
 <html>
 <head>
 <meta charset="utf-8">
-<title>CSS Text Module Test: parsing text-wrap with invalid values</title>
-<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
-<link rel="help" href="https://drafts.csswg.org/css-text-4/#text-wrap">
-<meta name="assert" content="text-wrap supports only the grammar 'wrap | nowrap | balance | stable | pretty'.">
+<title>CSS Text Module Test: parsing white-space-collapse with invalid values</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-4/#white-space-collapsing">
+<meta name="assert" content="white-space-collapse supports only the grammar 'collapse | discard | preserve | preserve-breaks | preserve-spaces | break-spaces'.">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/css/support/parsing-testcommon.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-valid.html
index 2191167..23c0cd39b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/white-space-collapse-valid.html
@@ -2,10 +2,10 @@
 <html>
 <head>
 <meta charset="utf-8">
-<title>CSS Text Module Test: parsing text-wrap with valid values</title>
-<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
-<link rel="help" href="https://drafts.csswg.org/css-text-4/#text-wrap">
-<meta name="assert" content="text-wrap supports the full grammar 'wrap | nowrap | balance | stable | pretty'.">
+<title>CSS Text Module Test: parsing white-space-collapse with valid values</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-4/#white-space-collapsing">
+<meta name="assert" content="white-space-collapse supports the full grammar 'collapse | discard | preserve | preserve-breaks | preserve-spaces | break-spaces'.">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/css/support/parsing-testcommon.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-010.html.ini b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-010.html.ini
new file mode 100644
index 0000000..52f0349
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-010.html.ini
@@ -0,0 +1,3 @@
+[text-transform-capitalize-010.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-006.html.ini b/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-006.html.ini
index bdb0fc50..62638fc6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-006.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-006.html.ini
@@ -1,4 +1,5 @@
 [preserve3d-and-flattening-z-order-006.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html.ini
new file mode 100644
index 0000000..8da2956
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html.ini
@@ -0,0 +1,27 @@
+[animation-delay-end.tentative.html]
+  [Can set 'animation-delay-end' to CSS-wide keywords: inherit]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to CSS-wide keywords: initial]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to CSS-wide keywords: revert]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to CSS-wide keywords: unset]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to a time: -3.14ms]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to a time: 0s]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to a time: 3.14s]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to a time: calc(0s + 0ms)]
+    expected: FAIL
+
+  [Can set 'animation-delay-end' to var() references:  var(--A)]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html.ini
new file mode 100644
index 0000000..20ad1884
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html.ini
@@ -0,0 +1,27 @@
+[animation-delay-start.tentative.html]
+  [Can set 'animation-delay-start' to CSS-wide keywords: inherit]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to CSS-wide keywords: initial]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to CSS-wide keywords: revert]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to CSS-wide keywords: unset]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to a time: -3.14ms]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to a time: 0s]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to a time: 3.14s]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to a time: calc(0s + 0ms)]
+    expected: FAIL
+
+  [Can set 'animation-delay-start' to var() references:  var(--A)]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-menulist-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-menulist-001.html.ini
new file mode 100644
index 0000000..51b9087
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-menulist-001.html.ini
@@ -0,0 +1,3 @@
+[appearance-menulist-001.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-end-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-end-color-001.html.ini
new file mode 100644
index 0000000..39a9482
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-end-color-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-color-input-border-inline-end-color-001.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-start-style-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-start-style-001.html.ini
new file mode 100644
index 0000000..2885caa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-inline-start-style-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-color-input-border-inline-start-style-001.html]
+  expected:
+    if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-bottom-right-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-bottom-right-radius-001.html.ini
new file mode 100644
index 0000000..eb0b767
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-bottom-right-radius-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-button-border-bottom-right-radius-001.html]
+  expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-end-end-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-end-end-radius-001.html.ini
new file mode 100644
index 0000000..cde2533
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-end-end-radius-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-button-border-end-end-radius-001.html]
+  expected:
+    if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-inline-start-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-inline-start-color-001.html.ini
new file mode 100644
index 0000000..c90f91f9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-inline-start-color-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-button-border-inline-start-color-001.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini
index fc0838c..53da70e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini
@@ -1,4 +1,5 @@
 [kind-of-widget-fallback-input-reset-border-image-repeat-001.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
     if (product == "content_shell") and (os == "linux"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-end-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-end-width-001.html.ini
index e54f0fc5..3c5a7797 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-end-width-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-end-width-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-input-search-border-inline-end-width-001.html]
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
+    if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-color-001.html.ini
new file mode 100644
index 0000000..2fc7ad2f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-color-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-search-border-inline-start-color-001.html]
+  expected:
+    if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-start-end-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-start-end-radius-001.html.ini
index 0652ebf9..122cb62 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-start-end-radius-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-start-end-radius-001.html.ini
@@ -2,3 +2,4 @@
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
+    if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-background-size-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-background-size-001.html.ini
new file mode 100644
index 0000000..d858bc5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-background-size-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-search-text-background-size-001.html]
+  expected:
+    if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini
index 3198dfd..403c943 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-input-submit-border-inline-start-style-001.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-left-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-left-width-001.html.ini
index 7e86e3d..1f7ab7a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-left-width-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-left-width-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-input-submit-border-left-width-001.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
     if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-inline-start-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-inline-start-width-001.html.ini
index e8b5a37..c33bd8a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-inline-start-width-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-inline-start-width-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-textarea-border-inline-start-width-001.html]
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
+    if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-basic.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-basic.html.ini
index c091770..1047f60 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-basic.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-basic.html.ini
@@ -1,4 +1,5 @@
 [backdrop-filter-basic.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html.ini
index c8991e6d..f607a46a 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html.ini
@@ -1,3 +1,4 @@
 [backdrop-filter-isolation-isolate.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-svg-foreignObject.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-svg-foreignObject.html.ini
index 82031871..6df726e 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-svg-foreignObject.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-svg-foreignObject.html.ini
@@ -1,4 +1,5 @@
 [backdrop-filter-svg-foreignObject.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini
index e958b5b7..3f30c11 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini
@@ -1,5 +1,7 @@
 [backdrop-filters-grayscale-002.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
index 7285229..ea379de 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
@@ -1,6 +1,7 @@
 [backdrop-filters-invert.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
-    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/css-filters-animation-saturate.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/css-filters-animation-saturate.html.ini
new file mode 100644
index 0000000..ab0ed5d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/css-filters-animation-saturate.html.ini
@@ -0,0 +1,3 @@
+[css-filters-animation-saturate.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fullscreen/api/element-request-fullscreen-options.tentative.html.ini b/third_party/blink/web_tests/external/wpt/fullscreen/api/element-request-fullscreen-options.tentative.html.ini
index 7fca800..1b21f6f 100644
--- a/third_party/blink/web_tests/external/wpt/fullscreen/api/element-request-fullscreen-options.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fullscreen/api/element-request-fullscreen-options.tentative.html.ini
@@ -1,5 +1,3 @@
 [element-request-fullscreen-options.tentative.html]
   [fullscreenOptions.screen getter is invoked on requestFullscreen]
-    expected:
-      if product == "chrome": PASS
-      FAIL
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html
index 61ca6d4..9bf2440 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html
@@ -32,6 +32,10 @@
 test_word_spacing('1min');
 test_word_spacing('1deg');
 test_word_spacing('1pp');
+test_word_spacing('initial');
+test_word_spacing('inherit');
+test_word_spacing('normal');
+test_word_spacing('none');
 
 
 });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.change.font.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.change.font.html
index 5b42b89..3b88ab6 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.change.font.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.change.font.html
@@ -29,7 +29,7 @@
 // 1em = 10px. Add 10px after each letter in "Hello World",
 // makes it 110px longer.
 var width_with_spacing = ctx.measureText('Hello World').width;
-_assertSame(width_with_spacing, width_normal + 110, "width_with_spacing", "width_normal + 110");
+assert_approx_equals(width_with_spacing, width_normal + 110, 0.1, "letterSpacing incorrect before font change");
 
 // Changing font to 20px. Without resetting the spacing, 1em letterSpacing
 // is now 20px, so it's suppose to be 220px longer without any letterSpacing set.
@@ -38,7 +38,7 @@
 // Now calculate the reference spacing for "Hello World" with no spacing.
 ctx.letterSpacing = '0em';
 width_normal = ctx.measureText('Hello World').width;
-_assertSame(width_with_spacing, width_normal + 220, "width_with_spacing", "width_normal + 220");
+assert_approx_equals(width_with_spacing, width_normal + 220, 0.1, "letterSpacing incorrect after font change");
 
 
 });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.measure.html
index fadfaaf..ba8656e 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.letterSpacing.measure.html
@@ -36,11 +36,11 @@
 // in 'hello world', so the length difference is always letterSpacing * 11.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 33, 0],
-              ['5px', 55, 0],
-              ['-2px', -22, 0],
-              ['1em', 110, 0],
-              ['1in', 1056, 0],
+test_cases = [['3px', 33, 0.1],
+              ['5px', 55, 0.1],
+              ['-2px', -22, 0.1],
+              ['1em', 110, 0.1],
+              ['1in', 1056, 0.1],
               ['-0.1cm', -41.65, 0.2],
               ['-0.6mm', -24,95, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.wordSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.wordSpacing.measure.html
index 4cd3c23..4898c23e 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.wordSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.wordSpacing.measure.html
@@ -36,11 +36,11 @@
 // in 'Hello World, again', so the length difference is always wordSpacing * 2.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 6, 0],
-              ['5px', 10, 0],
-              ['-2px', -4, 0],
-              ['1em', 20, 0],
-              ['1in', 192, 0],
+test_cases = [['3px', 6, 0.1],
+              ['5px', 10, 0.1],
+              ['-2px', -4, 0.1],
+              ['1em', 20, 0.1],
+              ['1in', 192, 0.1],
               ['-0.1cm', -7.57, 0.2],
               ['-0.6mm', -4.54, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html
index a117be0..5030055 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html
@@ -33,6 +33,10 @@
 test_word_spacing('1min');
 test_word_spacing('1deg');
 test_word_spacing('1pp');
+test_word_spacing('initial');
+test_word_spacing('inherit');
+test_word_spacing('normal');
+test_word_spacing('none');
 
 t.done();
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js
index 7f6baf28..e4b090cc 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js
@@ -29,6 +29,10 @@
 test_word_spacing('1min');
 test_word_spacing('1deg');
 test_word_spacing('1pp');
+test_word_spacing('initial');
+test_word_spacing('inherit');
+test_word_spacing('normal');
+test_word_spacing('none');
 
 t.done();
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.html
similarity index 82%
rename from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html
rename to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.html
index b63c81b..5482c36 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.text.drawing.style.letterSpacing.measure</title>
+<title>OffscreenCanvas test: 2d.text.drawing.style.letterSpacing.measure.absolute</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/html/canvas/resources/canvas-tests.js"></script>
 
-<h1>2d.text.drawing.style.letterSpacing.measure</h1>
-<p class="desc">Testing letter spacing and word spacing</p>
+<h1>2d.text.drawing.style.letterSpacing.measure.absolute</h1>
+<p class="desc">Testing letter spacing with absolute length</p>
 
 
 <script>
-var t = async_test("Testing letter spacing and word spacing");
+var t = async_test("Testing letter spacing with absolute length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -37,11 +37,10 @@
 // in 'hello world', so the length difference is always letterSpacing * 11.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 33, 0],
-              ['5px', 55, 0],
-              ['-2px', -22, 0],
-              ['1em', 110, 0],
-              ['1in', 1056, 0],
+test_cases = [['3px', 33, 0.1],
+              ['5px', 55, 0.1],
+              ['-2px', -22, 0.1],
+              ['1in', 1056, 0.1],
               ['-0.1cm', -41.65, 0.2],
               ['-0.6mm', -24,95, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.worker.js
similarity index 84%
rename from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js
rename to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.worker.js
index b9189cb..22cab4ccc 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.absolute.worker.js
@@ -1,12 +1,12 @@
 // DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.text.drawing.style.letterSpacing.measure
-// Description:Testing letter spacing and word spacing
+// OffscreenCanvas test in a worker:2d.text.drawing.style.letterSpacing.measure.absolute
+// Description:Testing letter spacing with absolute length
 // Note:
 
 importScripts("/resources/testharness.js");
 importScripts("/html/canvas/resources/canvas-tests.js");
 
-var t = async_test("Testing letter spacing and word spacing");
+var t = async_test("Testing letter spacing with absolute length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -33,11 +33,10 @@
 // in 'hello world', so the length difference is always letterSpacing * 11.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 33, 0],
-              ['5px', 55, 0],
-              ['-2px', -22, 0],
-              ['1em', 110, 0],
-              ['1in', 1056, 0],
+test_cases = [['3px', 33, 0.1],
+              ['5px', 55, 0.1],
+              ['-2px', -22, 0.1],
+              ['1in', 1056, 0.1],
               ['-0.1cm', -41.65, 0.2],
               ['-0.6mm', -24,95, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html
similarity index 75%
copy from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html
copy to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html
index b63c81b..fa5d2bc 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.text.drawing.style.letterSpacing.measure</title>
+<title>OffscreenCanvas test: 2d.text.drawing.style.letterSpacing.measure.relative</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/html/canvas/resources/canvas-tests.js"></script>
 
-<h1>2d.text.drawing.style.letterSpacing.measure</h1>
-<p class="desc">Testing letter spacing and word spacing</p>
+<h1>2d.text.drawing.style.letterSpacing.measure.relative</h1>
+<p class="desc">Testing letter spacing with font-relative length</p>
 
 
 <script>
-var t = async_test("Testing letter spacing and word spacing");
+var t = async_test("Testing letter spacing with font-relative length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -22,7 +22,9 @@
 
 _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
 _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+ctx.font = "10px monospace";
 var width_normal = ctx.measureText('Hello World').width;
+var ch_width = width_normal / 11;
 
 function test_letter_spacing(value, difference_spacing, epsilon) {
   ctx.letterSpacing = value;
@@ -35,15 +37,10 @@
 // The first value is the letter Spacing to be set, the second value the
 // change in length of string 'Hello World', note that there are 11 letters
 // in 'hello world', so the length difference is always letterSpacing * 11.
-// and the third value is the acceptable differencee for the length change,
-// note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 33, 0],
-              ['5px', 55, 0],
-              ['-2px', -22, 0],
-              ['1em', 110, 0],
-              ['1in', 1056, 0],
-              ['-0.1cm', -41.65, 0.2],
-              ['-0.6mm', -24,95, 0.2]]
+// and the third value is the acceptable differencee for the length change.
+test_cases = [['1em', 110, 0.1],
+              ['-0.1em', -11, 0.1],
+              ['1ch', 11 * ch_width, 0.1]]
 
 for (const test_case of test_cases) {
   test_letter_spacing(test_case[0], test_case[1], test_case[2]);
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html.ini b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html.ini
new file mode 100644
index 0000000..9cb3a0a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.drawing.style.letterSpacing.measure.relative.html]
+  [Testing letter spacing with font-relative length]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js
similarity index 76%
copy from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js
copy to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js
index b9189cb..59d17ef 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js
@@ -1,12 +1,12 @@
 // DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.text.drawing.style.letterSpacing.measure
-// Description:Testing letter spacing and word spacing
+// OffscreenCanvas test in a worker:2d.text.drawing.style.letterSpacing.measure.relative
+// Description:Testing letter spacing with font-relative length
 // Note:
 
 importScripts("/resources/testharness.js");
 importScripts("/html/canvas/resources/canvas-tests.js");
 
-var t = async_test("Testing letter spacing and word spacing");
+var t = async_test("Testing letter spacing with font-relative length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -18,7 +18,9 @@
 
 _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
 _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+ctx.font = "10px monospace";
 var width_normal = ctx.measureText('Hello World').width;
+var ch_width = width_normal / 11;
 
 function test_letter_spacing(value, difference_spacing, epsilon) {
   ctx.letterSpacing = value;
@@ -31,15 +33,10 @@
 // The first value is the letter Spacing to be set, the second value the
 // change in length of string 'Hello World', note that there are 11 letters
 // in 'hello world', so the length difference is always letterSpacing * 11.
-// and the third value is the acceptable differencee for the length change,
-// note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 33, 0],
-              ['5px', 55, 0],
-              ['-2px', -22, 0],
-              ['1em', 110, 0],
-              ['1in', 1056, 0],
-              ['-0.1cm', -41.65, 0.2],
-              ['-0.6mm', -24,95, 0.2]]
+// and the third value is the acceptable differencee for the length change.
+test_cases = [['1em', 110, 0.1],
+              ['-0.1em', -11, 0.1],
+              ['1ch', 11 * ch_width, 0.1]]
 
 for (const test_case of test_cases) {
   test_letter_spacing(test_case[0], test_case[1], test_case[2]);
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js.ini b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js.ini
new file mode 100644
index 0000000..eca264d6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.drawing.style.letterSpacing.measure.relative.worker.html]
+  [Testing letter spacing with font-relative length]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.html
similarity index 81%
rename from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html
rename to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.html
index 9ef479b..07ca896 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.text.drawing.style.wordSpacing.measure</title>
+<title>OffscreenCanvas test: 2d.text.drawing.style.wordSpacing.measure.absolute</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/html/canvas/resources/canvas-tests.js"></script>
 
-<h1>2d.text.drawing.style.wordSpacing.measure</h1>
-<p class="desc">Testing if word spacing is working properly</p>
+<h1>2d.text.drawing.style.wordSpacing.measure.absolute</h1>
+<p class="desc">Testing if word spacing is working properly with absolute length</p>
 
 
 <script>
-var t = async_test("Testing if word spacing is working properly");
+var t = async_test("Testing if word spacing is working properly with absolute length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -37,11 +37,10 @@
 // in 'Hello World, again', so the length difference is always wordSpacing * 2.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 6, 0],
-              ['5px', 10, 0],
-              ['-2px', -4, 0],
-              ['1em', 20, 0],
-              ['1in', 192, 0],
+test_cases = [['3px', 6, 0.1],
+              ['5px', 10, 0.1],
+              ['-2px', -4, 0.1],
+              ['1in', 192, 0.1],
               ['-0.1cm', -7.57, 0.2],
               ['-0.6mm', -4.54, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.worker.js
similarity index 83%
rename from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js
rename to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.worker.js
index 3e850fc..ebfc056 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.absolute.worker.js
@@ -1,12 +1,12 @@
 // DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.text.drawing.style.wordSpacing.measure
-// Description:Testing if word spacing is working properly
+// OffscreenCanvas test in a worker:2d.text.drawing.style.wordSpacing.measure.absolute
+// Description:Testing if word spacing is working properly with absolute length
 // Note:
 
 importScripts("/resources/testharness.js");
 importScripts("/html/canvas/resources/canvas-tests.js");
 
-var t = async_test("Testing if word spacing is working properly");
+var t = async_test("Testing if word spacing is working properly with absolute length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -33,11 +33,10 @@
 // in 'Hello World, again', so the length difference is always wordSpacing * 2.
 // and the third value is the acceptable differencee for the length change,
 // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 6, 0],
-              ['5px', 10, 0],
-              ['-2px', -4, 0],
-              ['1em', 20, 0],
-              ['1in', 192, 0],
+test_cases = [['3px', 6, 0.1],
+              ['5px', 10, 0.1],
+              ['-2px', -4, 0.1],
+              ['1in', 192, 0.1],
               ['-0.1cm', -7.57, 0.2],
               ['-0.6mm', -4.54, 0.2]]
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html
similarity index 75%
copy from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html
copy to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html
index 9ef479b..95f87cb 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
-<title>OffscreenCanvas test: 2d.text.drawing.style.wordSpacing.measure</title>
+<title>OffscreenCanvas test: 2d.text.drawing.style.wordSpacing.measure.relative</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/html/canvas/resources/canvas-tests.js"></script>
 
-<h1>2d.text.drawing.style.wordSpacing.measure</h1>
-<p class="desc">Testing if word spacing is working properly</p>
+<h1>2d.text.drawing.style.wordSpacing.measure.relative</h1>
+<p class="desc">Testing if word spacing is working properly with font-relative length</p>
 
 
 <script>
-var t = async_test("Testing if word spacing is working properly");
+var t = async_test("Testing if word spacing is working properly with font-relative length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -22,7 +22,9 @@
 
 _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
 _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+ctx.font = "10px monospace";
 var width_normal = ctx.measureText('Hello World, again').width;
+var ch_width = width_normal / 18;
 
 function test_word_spacing(value, difference_spacing, epsilon) {
   ctx.wordSpacing = value;
@@ -35,15 +37,10 @@
 // The first value is the word Spacing to be set, the second value the
 // change in length of string 'Hello World', note that there are 2 words
 // in 'Hello World, again', so the length difference is always wordSpacing * 2.
-// and the third value is the acceptable differencee for the length change,
-// note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 6, 0],
-              ['5px', 10, 0],
-              ['-2px', -4, 0],
-              ['1em', 20, 0],
-              ['1in', 192, 0],
-              ['-0.1cm', -7.57, 0.2],
-              ['-0.6mm', -4.54, 0.2]]
+// and the third value is the acceptable differencee for the length change.
+test_cases = [['1em', 20, 0.1],
+              ['-0.5em', -10, 0.1],
+              ['1ch', 2 * ch_width, 0.1]]
 
 for (const test_case of test_cases) {
   test_word_spacing(test_case[0], test_case[1], test_case[2]);
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html.ini b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html.ini
new file mode 100644
index 0000000..7a3721c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.drawing.style.wordSpacing.measure.relative.html]
+  [Testing if word spacing is working properly with font-relative length]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js
similarity index 76%
copy from third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js
copy to third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js
index 3e850fc..2bded51e 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.js
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js
@@ -1,12 +1,12 @@
 // DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
-// OffscreenCanvas test in a worker:2d.text.drawing.style.wordSpacing.measure
-// Description:Testing if word spacing is working properly
+// OffscreenCanvas test in a worker:2d.text.drawing.style.wordSpacing.measure.relative
+// Description:Testing if word spacing is working properly with font-relative length
 // Note:
 
 importScripts("/resources/testharness.js");
 importScripts("/html/canvas/resources/canvas-tests.js");
 
-var t = async_test("Testing if word spacing is working properly");
+var t = async_test("Testing if word spacing is working properly with font-relative length");
 var t_pass = t.done.bind(t);
 var t_fail = t.step_func(function(reason) {
     throw reason;
@@ -18,7 +18,9 @@
 
 _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
 _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+ctx.font = "10px monospace";
 var width_normal = ctx.measureText('Hello World, again').width;
+var ch_width = width_normal / 18;
 
 function test_word_spacing(value, difference_spacing, epsilon) {
   ctx.wordSpacing = value;
@@ -31,15 +33,10 @@
 // The first value is the word Spacing to be set, the second value the
 // change in length of string 'Hello World', note that there are 2 words
 // in 'Hello World, again', so the length difference is always wordSpacing * 2.
-// and the third value is the acceptable differencee for the length change,
-// note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-test_cases = [['3px', 6, 0],
-              ['5px', 10, 0],
-              ['-2px', -4, 0],
-              ['1em', 20, 0],
-              ['1in', 192, 0],
-              ['-0.1cm', -7.57, 0.2],
-              ['-0.6mm', -4.54, 0.2]]
+// and the third value is the acceptable differencee for the length change.
+test_cases = [['1em', 20, 0.1],
+              ['-0.5em', -10, 0.1],
+              ['1ch', 2 * ch_width, 0.1]]
 
 for (const test_case of test_cases) {
   test_word_spacing(test_case[0], test_case[1], test_case[2]);
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js.ini b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js.ini
new file mode 100644
index 0000000..2142c12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.drawing.style.wordSpacing.measure.relative.worker.html]
+  [Testing if word spacing is working properly with font-relative length]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
index e0de955..3443ad3 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
@@ -718,7 +718,7 @@
       @assert ctx.wordSpacing === '0px';
       @assert ctx.letterSpacing === '0px';
     }
-    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp'>);
+    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp' 'initial' 'inherit' 'normal' 'none'>);
 
 - name: 2d.text.drawing.style.letterSpacing.measure
   desc: Testing letter spacing and word spacing
@@ -740,11 +740,11 @@
     // in 'hello world', so the length difference is always letterSpacing * 11.
     // and the third value is the acceptable differencee for the length change,
     // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-    test_cases = [['3px', 33, 0],
-                  ['5px', 55, 0],
-                  ['-2px', -22, 0],
-                  ['1em', 110, 0],
-                  ['1in', 1056, 0],
+    test_cases = [['3px', 33, 0.1],
+                  ['5px', 55, 0.1],
+                  ['-2px', -22, 0.1],
+                  ['1em', 110, 0.1],
+                  ['1in', 1056, 0.1],
                   ['-0.1cm', -41.65, 0.2],
                   ['-0.6mm', -24,95, 0.2]]
 
@@ -772,11 +772,11 @@
     // in 'Hello World, again', so the length difference is always wordSpacing * 2.
     // and the third value is the acceptable differencee for the length change,
     // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-    test_cases = [['3px', 6, 0],
-                  ['5px', 10, 0],
-                  ['-2px', -4, 0],
-                  ['1em', 20, 0],
-                  ['1in', 192, 0],
+    test_cases = [['3px', 6, 0.1],
+                  ['5px', 10, 0.1],
+                  ['-2px', -4, 0.1],
+                  ['1em', 20, 0.1],
+                  ['1in', 192, 0.1],
                   ['-0.1cm', -7.57, 0.2],
                   ['-0.6mm', -4.54, 0.2]]
 
@@ -797,7 +797,7 @@
     // 1em = 10px. Add 10px after each letter in "Hello World",
     // makes it 110px longer.
     var width_with_spacing = ctx.measureText('Hello World').width;
-    @assert width_with_spacing === width_normal + 110;
+    assert_approx_equals(width_with_spacing, width_normal + 110, 0.1, "letterSpacing incorrect before font change");
 
     // Changing font to 20px. Without resetting the spacing, 1em letterSpacing
     // is now 20px, so it's suppose to be 220px longer without any letterSpacing set.
@@ -806,7 +806,8 @@
     // Now calculate the reference spacing for "Hello World" with no spacing.
     ctx.letterSpacing = '0em';
     width_normal = ctx.measureText('Hello World').width;
-    @assert width_with_spacing === width_normal + 220;
+    assert_approx_equals(width_with_spacing, width_normal + 220, 0.1, "letterSpacing incorrect after font change");
+
 
 - name: 2d.text.drawing.style.wordSpacing.change.font
   desc: Set word spacing and word spacing to font dependent value and verify it works after font change.
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
index 80c54ca..784a099 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
@@ -1183,12 +1183,12 @@
       @assert ctx.wordSpacing === '0px';
       @assert ctx.letterSpacing === '0px';
     }
-    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp'>);
+    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp' 'initial' 'inherit' 'normal' 'none'>);
 
     t.done();
 
-- name: 2d.text.drawing.style.letterSpacing.measure
-  desc: Testing letter spacing and word spacing
+- name: 2d.text.drawing.style.letterSpacing.measure.absolute
+  desc: Testing letter spacing with absolute length
   code: |
     @assert ctx.letterSpacing === '0px';
     @assert ctx.wordSpacing === '0px';
@@ -1207,11 +1207,10 @@
     // in 'hello world', so the length difference is always letterSpacing * 11.
     // and the third value is the acceptable differencee for the length change,
     // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-    test_cases = [['3px', 33, 0],
-                  ['5px', 55, 0],
-                  ['-2px', -22, 0],
-                  ['1em', 110, 0],
-                  ['1in', 1056, 0],
+    test_cases = [['3px', 33, 0.1],
+                  ['5px', 55, 0.1],
+                  ['-2px', -22, 0.1],
+                  ['1in', 1056, 0.1],
                   ['-0.1cm', -41.65, 0.2],
                   ['-0.6mm', -24,95, 0.2]]
 
@@ -1220,8 +1219,38 @@
     }
     t.done();
 
-- name: 2d.text.drawing.style.wordSpacing.measure
-  desc: Testing if word spacing is working properly
+- name: 2d.text.drawing.style.letterSpacing.measure.relative
+  desc: Testing letter spacing with font-relative length
+  code: |
+    @assert ctx.letterSpacing === '0px';
+    @assert ctx.wordSpacing === '0px';
+    ctx.font = "10px monospace";
+    var width_normal = ctx.measureText('Hello World').width;
+    var ch_width = width_normal / 11;
+
+    function test_letter_spacing(value, difference_spacing, epsilon) {
+      ctx.letterSpacing = value;
+      @assert ctx.letterSpacing === value;
+      @assert ctx.wordSpacing === '0px';
+      width_with_letter_spacing = ctx.measureText('Hello World').width;
+      assert_approx_equals(width_with_letter_spacing, width_normal + difference_spacing, epsilon, "letter spacing doesn't work.");
+    }
+
+    // The first value is the letter Spacing to be set, the second value the
+    // change in length of string 'Hello World', note that there are 11 letters
+    // in 'hello world', so the length difference is always letterSpacing * 11.
+    // and the third value is the acceptable differencee for the length change.
+    test_cases = [['1em', 110, 0.1],
+                  ['-0.1em', -11, 0.1],
+                  ['1ch', 11 * ch_width, 0.1]]
+
+    for (const test_case of test_cases) {
+      test_letter_spacing(test_case[0], test_case[1], test_case[2]);
+    }
+    t.done();
+
+- name: 2d.text.drawing.style.wordSpacing.measure.absolute
+  desc: Testing if word spacing is working properly with absolute length
   code: |
     @assert ctx.letterSpacing === '0px';
     @assert ctx.wordSpacing === '0px';
@@ -1240,11 +1269,10 @@
     // in 'Hello World, again', so the length difference is always wordSpacing * 2.
     // and the third value is the acceptable differencee for the length change,
     // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
-    test_cases = [['3px', 6, 0],
-                  ['5px', 10, 0],
-                  ['-2px', -4, 0],
-                  ['1em', 20, 0],
-                  ['1in', 192, 0],
+    test_cases = [['3px', 6, 0.1],
+                  ['5px', 10, 0.1],
+                  ['-2px', -4, 0.1],
+                  ['1in', 192, 0.1],
                   ['-0.1cm', -7.57, 0.2],
                   ['-0.6mm', -4.54, 0.2]]
 
@@ -1253,6 +1281,36 @@
     }
     t.done();
 
+- name: 2d.text.drawing.style.wordSpacing.measure.relative
+  desc: Testing if word spacing is working properly with font-relative length
+  code: |
+    @assert ctx.letterSpacing === '0px';
+    @assert ctx.wordSpacing === '0px';
+    ctx.font = "10px monospace";
+    var width_normal = ctx.measureText('Hello World, again').width;
+    var ch_width = width_normal / 18;
+
+    function test_word_spacing(value, difference_spacing, epsilon) {
+      ctx.wordSpacing = value;
+      @assert ctx.letterSpacing === '0px';
+      @assert ctx.wordSpacing === value;
+      width_with_word_spacing = ctx.measureText('Hello World, again').width;
+      assert_approx_equals(width_with_word_spacing, width_normal + difference_spacing, epsilon, "word spacing doesn't work.");
+    }
+
+    // The first value is the word Spacing to be set, the second value the
+    // change in length of string 'Hello World', note that there are 2 words
+    // in 'Hello World, again', so the length difference is always wordSpacing * 2.
+    // and the third value is the acceptable differencee for the length change.
+    test_cases = [['1em', 20, 0.1],
+                  ['-0.5em', -10, 0.1],
+                  ['1ch', 2 * ch_width, 0.1]]
+
+    for (const test_case of test_cases) {
+      test_word_spacing(test_case[0], test_case[1], test_case[2]);
+    }
+    t.done();
+
 - name: 2d.text.drawing.style.letterSpacing.change.font
   desc: Set letter spacing and word spacing to font dependent value and verify it works after font change.
   code: |
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-closed.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-closed.https.html.ini
new file mode 100644
index 0000000..a6cab97
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-closed.https.html.ini
@@ -0,0 +1,3 @@
+[access-reporting-closed.https.html]
+  expected:
+    if product == "chrome": [ERROR, OK]
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-openee-rp-ro.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-openee-rp-ro.https.html.ini
new file mode 100644
index 0000000..4b5f029
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-openee-rp-ro.https.html.ini
@@ -0,0 +1,5 @@
+[access-reporting-openee-rp-ro.https.html]
+  expected:
+    if product == "chrome": [OK, ERROR]
+  [access-reporting-openee-rp-ro]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-opener-rp-ro.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-opener-rp-ro.https.html.ini
new file mode 100644
index 0000000..559ccdd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/access-reporting-opener-rp-ro.https.html.ini
@@ -0,0 +1,5 @@
+[access-reporting-opener-rp-ro.https.html]
+  expected:
+    if product == "chrome": [OK, ERROR]
+  [access-reporting-opener-rp-ro]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp-ro.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp-ro.https.html.ini
new file mode 100644
index 0000000..c970a3b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp-ro.https.html.ini
@@ -0,0 +1,6 @@
+[reporting-from-rp-ro.https.html]
+  [coop reporting test Opening a restrict-properties to CROSS_ORIGIN with unsafe-none, , , ]
+    expected: FAIL
+
+  [coop reporting test Opening a restrict-properties to SAME_ORIGIN with unsafe-none, , , ]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp.https.html.ini
new file mode 100644
index 0000000..1cc83dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-from-rp.https.html.ini
@@ -0,0 +1,6 @@
+[reporting-from-rp.https.html]
+  [coop reporting test Opening a restrict-properties to CROSS_ORIGIN with unsafe-none, , , ]
+    expected: FAIL
+
+  [coop reporting test Opening a restrict-properties to SAME_ORIGIN with unsafe-none, , , ]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp-ro.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp-ro.https.html.ini
new file mode 100644
index 0000000..c2354d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp-ro.https.html.ini
@@ -0,0 +1,6 @@
+[reporting-to-rp-ro.https.html]
+  [coop reporting test reporting same origin with report-to to CROSS_ORIGIN with , , restrict-properties; report-to="coop-popup-report-only-endpoint", ]
+    expected: FAIL
+
+  [coop reporting test reporting same origin with report-to to SAME_ORIGIN with , , restrict-properties; report-to="coop-popup-report-only-endpoint", ]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp.https.html.ini
new file mode 100644
index 0000000..dd141e92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties/reporting-to-rp.https.html.ini
@@ -0,0 +1,6 @@
+[reporting-to-rp.https.html]
+  [coop reporting test reporting same origin with report-to to CROSS_ORIGIN with restrict-properties; report-to="coop-popup-report-endpoint", , , ]
+    expected: FAIL
+
+  [coop reporting test reporting same origin with report-to to SAME_ORIGIN with restrict-properties; report-to="coop-popup-report-endpoint", , , ]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit-expected.txt
new file mode 100644
index 0000000..bf1d8b7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: true, preventDefaultSubmitButton: false, passSubmitter: true
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: true, preventDefaultSubmitButton: false, passSubmitter: false
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: true, passSubmitter: true
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: true, passSubmitter: false
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: false, passSubmitter: true
+PASS test runTest with submitterType: input, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: false, passSubmitter: false
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: true, preventDefaultSubmitButton: false, passSubmitter: true
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: true, preventDefaultSubmitButton: false, passSubmitter: false
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: true, passSubmitter: true
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: true, passSubmitter: false
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: false, passSubmitter: true
+PASS test runTest with submitterType: button, preventDefaultRequestSubmit: false, preventDefaultSubmitButton: false, passSubmitter: false
+PASS test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: true, preventDefault: true, passSubmitter: true
+PASS test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: true, preventDefault: true, passSubmitter: false
+FAIL test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: true assert_equals: expected (object) null but got (string) "v3"
+PASS test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: false, preventDefault: false, passSubmitter: true
+PASS test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: false, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: true, preventDefault: true, passSubmitter: true
+PASS test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: true, preventDefault: true, passSubmitter: false
+FAIL test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: true assert_equals: expected (object) null but got (string) "v3"
+PASS test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: false, preventDefault: false, passSubmitter: true
+PASS test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: false, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: true, preventDefault: true, passSubmitter: true
+PASS test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: true, preventDefault: true, passSubmitter: false
+FAIL test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: true assert_equals: expected (object) null but got (string) "v3"
+PASS test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: false, preventDefault: false, passSubmitter: true
+PASS test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: false, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: true, preventDefault: true, passSubmitter: true
+PASS test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: true, preventDefault: true, passSubmitter: false
+FAIL test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: true assert_equals: expected (object) null but got (string) "v3"
+PASS test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: false
+PASS test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: false, preventDefault: false, passSubmitter: true
+PASS test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: false, preventDefault: false, passSubmitter: false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html
new file mode 100644
index 0000000..b402878
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="help"
+  href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/targetted-form.js"></script>
+
+<!-- The onclick requestSubmit() should get superseded by the default
+     action submit, which isn't preventDefaulted by onclick here.
+     This is per the Form Submission Algorithm [1], which
+     says that new planned navigations replace old planned navigations.
+     [1] https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#planned-navigation
+  -->
+
+<body>
+  <script>
+    function runTest({ submitterType, preventDefaultSubmitButton, preventDefaultRequestSubmit, passSubmitter, testName }) {
+      if (preventDefaultRequestSubmit && preventDefaultSubmitButton) {
+        // In this case, no submit action will take place.
+        return;
+      }
+
+      promise_test(async () => {
+        const form = populateForm(`<input name=n1 value=v1><${submitterType} type=submit name=n2 value=v2>${submitterType == 'button' ? '</button>' : ''}`);
+        const input = form.elements[0];
+        const submitter = form.elements[1];
+        submitter.addEventListener('click', e => {
+          form.addEventListener('submit', e => {
+            submitter.value = 'v3';
+            if (preventDefaultRequestSubmit) {
+              e.preventDefault();
+            }
+          }, { once: true });
+
+          form.requestSubmit(passSubmitter ? submitter : null);
+          input.value = 'v2';
+
+          form.addEventListener('submit', e => {
+            submitter.value = 'v4';
+            if (preventDefaultSubmitButton) {
+              e.preventDefault();
+            }
+          }, { once: true });
+        });
+
+        let formDataInEvent;
+        form.addEventListener('formdata', e => {
+          formDataInEvent = e.formData;
+        });
+
+        submitter.click();
+        assert_equals(formDataInEvent.get('n1'), preventDefaultSubmitButton ? 'v1' : 'v2');
+        if (preventDefaultSubmitButton && !passSubmitter) {
+          assert_false(formDataInEvent.has('n2'));
+        } else {
+          assert_equals(formDataInEvent.get('n2'),
+            preventDefaultSubmitButton && passSubmitter ? 'v3' : 'v4')
+        }
+
+        let iframe = form.previousSibling;
+        await loadPromise(iframe);
+        assert_equals(getParamValue(iframe, 'n1'), preventDefaultSubmitButton ? 'v1' : 'v2');
+        if (preventDefaultSubmitButton && !passSubmitter) {
+          assert_equals(getParamValue(iframe, 'n2'), null);
+        } else {
+          assert_equals(getParamValue(iframe, 'n2'),
+            preventDefaultSubmitButton && passSubmitter ? 'v3' : 'v4');
+        }
+      }, testName);
+    }
+
+    function runTest2({ submitterType, callRequestSubmit, callSubmit, preventDefault, passSubmitter, testName }) {
+      if (!callSubmit && preventDefault) {
+        // Without callSubmit, preventDefault will cause the form to not get
+        // submitted.
+        return;
+      }
+
+      promise_test(async () => {
+        const form = populateForm(`<input name=n1 value=v1><${submitterType} type=submit name=n2 value=v3>${submitterType == 'button' ? '</button>' : ''}`);
+        const input = form.elements[0];
+        const submitter = form.elements[1];
+
+        form.addEventListener('submit', e => {
+          if (callRequestSubmit) {
+            form.requestSubmit(passSubmitter ? submitter : null);
+            input.value = 'v2';
+          }
+          if (callSubmit) {
+            form.submit();
+          }
+          if (preventDefault) {
+            e.preventDefault();
+          }
+        });
+
+        form.requestSubmit(passSubmitter ? submitter : null);
+        let iframe = form.previousSibling;
+        await loadPromise(iframe);
+
+        assert_equals(getParamValue(iframe, 'n1'), callRequestSubmit ? 'v2' : 'v1');
+        if (callSubmit || !passSubmitter) {
+          assert_equals(getParamValue(iframe, 'n2'), null);
+        } else {
+          assert_equals(getParamValue(iframe, 'n2'), 'v3')
+        }
+      }, testName);
+    }
+
+    function callWithArgs(test, argsLeft, args) {
+      if (argsLeft.length == 0) {
+        args.testName = 'test ' + test.name + ' with ' + Object.entries(args).map(([key, value]) => `${key}: ${value}`).join(', ');
+        test(args);
+        return;
+      }
+
+      let [name, values] = argsLeft[0];
+      for (let value of values) {
+        callWithArgs(test, argsLeft.slice(1), { ...args, [name]: value })
+      }
+    }
+
+    let args = {
+      submitterType: ['input', 'button'],
+      preventDefaultRequestSubmit: [true, false],
+      preventDefaultSubmitButton: [true, false],
+      passSubmitter: [true, false],
+    };
+    callWithArgs(runTest, Object.entries(args), {});
+
+    args = {
+      submitterType: ['input', 'button'],
+      callRequestSubmit: [true, false],
+      callSubmit: [true, false],
+      preventDefault: [true, false],
+      passSubmitter: [true, false],
+    };
+    callWithArgs(runTest2, Object.entries(args), {});
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html.ini
new file mode 100644
index 0000000..6b936be9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/form-double-submit-requestsubmit.html.ini
@@ -0,0 +1,12 @@
+[form-double-submit-requestsubmit.html]
+  [test runTest2 with submitterType: button, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: true]
+    expected: FAIL
+
+  [test runTest2 with submitterType: button, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: true]
+    expected: FAIL
+
+  [test runTest2 with submitterType: input, callRequestSubmit: false, callSubmit: true, preventDefault: false, passSubmitter: true]
+    expected: FAIL
+
+  [test runTest2 with submitterType: input, callRequestSubmit: true, callSubmit: true, preventDefault: false, passSubmitter: true]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-anchor-transition.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-anchor-transition.tentative.html
new file mode 100644
index 0000000..ae2a3a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-anchor-transition.tentative.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests transitioning display property of anchored popover</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/popover.html">
+<link rel="help" href="https://github.com/whatwg/html/pull/9144">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+  margin: 0;
+}
+
+#target {
+  transition: display 2s;
+}
+</style>
+
+<div popover anchor id="target">
+  Popover
+</div>
+
+<script>
+test(() => {
+  target.showPopover();
+  const xBefore = target.offsetLeft;
+  const yBefore = target.offsetTop;
+
+  target.hidePopover();
+  assert_equals(target.offsetLeft, xBefore, 'Should not shift in x axis');
+  assert_equals(target.offsetTop, yBefore, 'Should not shift in y axis')
+}, 'Transitioning display property of an anchored popover should not cause a position shift');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html
deleted file mode 100644
index db491e9..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset='utf-8' />
-<title>Popover hide crash test</title>
-<link rel='author' href="mailto:cathiechen@iglaia.com">
-<link rel=help href="https://github.com/whatwg/html/issues/9197">
-
-<p>This test passes if it does not crash.</p>
-<div id='popover1' popover='auto'>
-    <div id='popover2' popover='auto'></div>
-    <div id='popover3' popover='auto'></div>
-</div>
-
-<script>
-var showedPopover2 = false;
-popover1.showPopover();
-popover3.showPopover();
-popover3.addEventListener('beforetoggle', (e) => {
-    if (e.newState != 'open' && !showedPopover2) {
-        showedPopover2 = true;
-        popover2.showPopover();
-    }
-});
-popover1.hidePopover();
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html.ini
deleted file mode 100644
index 0284e98..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[popover-hide-crash.html]
-  expected:
-    if product == "chrome": PASS
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html.ini b/third_party/blink/web_tests/external/wpt/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html.ini
index ca7edf8f..c1da011 100644
--- a/third_party/blink/web_tests/external/wpt/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html.ini
+++ b/third_party/blink/web_tests/external/wpt/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html.ini
@@ -1,32 +1,9 @@
 [mediasource-worker-play-terminate-worker.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): [OK, TIMEOUT]
   [Test worker MediaSource termination after at least 5 main thread setTimeouts, starting counting before setting srcObject]
     expected:
       if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 6 main thread setTimeouts, starting counting after setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 6 main thread setTimeouts, starting counting before setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 7 main thread setTimeouts, starting counting after setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 7 main thread setTimeouts, starting counting before setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 8 main thread setTimeouts, starting counting before setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
-
-  [Test worker MediaSource termination after at least 9 main thread setTimeouts, starting counting before setting srcObject]
-    expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-shorthand.html.ini b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-shorthand.html.ini
new file mode 100644
index 0000000..c20285a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-shorthand.html.ini
@@ -0,0 +1,6 @@
+[animation-shorthand.html]
+  [Animation shorthand can not represent non-initial animation-delay-end (computed)]
+    expected: FAIL
+
+  [Animation shorthand can not represent non-initial animation-delay-end (specified)]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
index 099411d..c346d60 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
@@ -1,8 +1,10 @@
 [unregister-immediately-during-extendable-events.https.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac11"): [OK, TIMEOUT]
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): OK
+    if (product == "content_shell") and (os == "mac") and (port == "mac12"): [OK, TIMEOUT]
     TIMEOUT
   [Clear-Site-Data must fail pending subresource fetch events.]
     expected:
       if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
+      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
       TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js
new file mode 100644
index 0000000..edbe67f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js
@@ -0,0 +1,9 @@
+// META: title=StorageManager: result of persist() matches result of persisted()
+
+promise_test(async t => {
+    var persistResult = await navigator.storage.persist();
+    assert_equals(typeof persistResult, 'boolean', persistResult + ' should be boolean');
+    var persistedResult = await navigator.storage.persisted();
+    assert_equals(typeof persistedResult, 'boolean', persistedResult + ' should be boolean');
+    assert_equals(persistResult, persistedResult);
+}, 'navigator.storage.persist() resolves to a value that matches navigator.storage.persisted()');
diff --git a/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js.ini b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js.ini
new file mode 100644
index 0000000..e58e43e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.js.ini
@@ -0,0 +1,3 @@
+[storagemanager-persist-persisted-match.https.any.worker.html]
+  [navigator.storage.persist() resolves to a value that matches navigator.storage.persisted()]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.worker-expected.txt
new file mode 100644
index 0000000..0b4cdf29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage/storagemanager-persist-persisted-match.https.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL navigator.storage.persist() resolves to a value that matches navigator.storage.persisted() promise_test: Unhandled rejection with value: object "TypeError: navigator.storage.persist is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/with-ports/020.html.ini b/third_party/blink/web_tests/external/wpt/webmessaging/with-ports/020.html.ini
new file mode 100644
index 0000000..a2275d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/with-ports/020.html.ini
@@ -0,0 +1,4 @@
+[020.html]
+  [cross-origin test]
+    expected:
+      if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any-expected.txt
new file mode 100644
index 0000000..9412ba1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL WebSocket: ensure both HTTP schemes are supported Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. 'http' is not allowed.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js
new file mode 100644
index 0000000..17590fc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js
@@ -0,0 +1,19 @@
+test(() => {
+  const url = new URL ("/", location);
+  url.protocol = "http";
+  const httpURL = url.href;
+  url.protocol = "https";
+  const httpsURL = url.href;
+  url.protocol = "ws";
+  const wsURL = url.href;
+  url.protocol = "wss";
+  const wssURL = url.href;
+
+  let ws = new WebSocket(httpURL);
+  assert_equals(ws.url, wsURL);
+  ws.close();
+
+  ws = new WebSocket(httpsURL);
+  assert_equals(ws.url, wssURL);
+  ws.close();
+}, "WebSocket: ensure both HTTP schemes are supported");
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js.ini b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js.ini
new file mode 100644
index 0000000..78bac82
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.js.ini
@@ -0,0 +1,8 @@
+[Create-http-urls.any.html]
+  [WebSocket: ensure both HTTP schemes are supported]
+    expected: FAIL
+
+
+[Create-http-urls.any.worker.html]
+  [WebSocket: ensure both HTTP schemes are supported]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.worker-expected.txt
new file mode 100644
index 0000000..9412ba1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-http-urls.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL WebSocket: ensure both HTTP schemes are supported Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. 'http' is not allowed.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any-expected.txt
new file mode 100644
index 0000000..851aded5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL new WebSocket("ws://foo bar.com/") should throw a "SyntaxError" DOMException assert_throws_dom: function "() => new WebSocket(input)" did not throw
+FAIL new WebSocket("wss://foo bar.com/") should throw a "SyntaxError" DOMException assert_throws_dom: function "() => new WebSocket(input)" did not throw
+PASS new WebSocket("ftp://web-platform.test:8001/") should throw a "SyntaxError" DOMException
+PASS new WebSocket("mailto:example@example.org") should throw a "SyntaxError" DOMException
+PASS new WebSocket("about:blank") should throw a "SyntaxError" DOMException
+PASS new WebSocket("http://web-platform.test:8001/#") should throw a "SyntaxError" DOMException
+PASS new WebSocket("http://web-platform.test:8001/#test") should throw a "SyntaxError" DOMException
+PASS new WebSocket("#test") should throw a "SyntaxError" DOMException
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js
index 89783a9..73c9fad 100644
--- a/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js
@@ -1,34 +1,14 @@
-// META: variant=
-// META: variant=?wss
-// META: variant=?wpt_flags=h2
-
-var wsocket;
-test(function() {
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = new WebSocket("/echo")
-  });
-}, "Url is /echo - should throw SYNTAX_ERR");
-
-test(function() {
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = new WebSocket("mailto:microsoft@microsoft.com")
-  });
-}, "Url is a mail address - should throw SYNTAX_ERR");
-
-test(function() {
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = new WebSocket("about:blank")
-  });
-}, "Url is about:blank - should throw SYNTAX_ERR");
-
-test(function() {
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = new WebSocket("?test")
-  });
-}, "Url is ?test - should throw SYNTAX_ERR");
-
-test(function() {
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = new WebSocket("#test")
-  });
-}, "Url is #test - should throw SYNTAX_ERR");
+[
+  "ws://foo bar.com/",
+  "wss://foo bar.com/",
+  "ftp://"+location.host+"/",
+  "mailto:example@example.org",
+  "about:blank",
+  location.origin + "/#",
+  location.origin + "/#test",
+  "#test"
+].forEach(input => {
+  test(() => {
+    assert_throws_dom("SyntaxError", () => new WebSocket(input));
+  }, `new WebSocket("${input}") should throw a "SyntaxError" DOMException`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js.ini b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js.ini
new file mode 100644
index 0000000..8b739adf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.js.ini
@@ -0,0 +1,14 @@
+[Create-invalid-urls.any.html]
+  [new WebSocket("ws://foo bar.com/") should throw a "SyntaxError" DOMException]
+    expected: FAIL
+
+  [new WebSocket("wss://foo bar.com/") should throw a "SyntaxError" DOMException]
+    expected: FAIL
+
+
+[Create-invalid-urls.any.worker.html]
+  [new WebSocket("ws://foo bar.com/") should throw a "SyntaxError" DOMException]
+    expected: FAIL
+
+  [new WebSocket("wss://foo bar.com/") should throw a "SyntaxError" DOMException]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.worker-expected.txt
new file mode 100644
index 0000000..851aded5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-invalid-urls.any.worker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL new WebSocket("ws://foo bar.com/") should throw a "SyntaxError" DOMException assert_throws_dom: function "() => new WebSocket(input)" did not throw
+FAIL new WebSocket("wss://foo bar.com/") should throw a "SyntaxError" DOMException assert_throws_dom: function "() => new WebSocket(input)" did not throw
+PASS new WebSocket("ftp://web-platform.test:8001/") should throw a "SyntaxError" DOMException
+PASS new WebSocket("mailto:example@example.org") should throw a "SyntaxError" DOMException
+PASS new WebSocket("about:blank") should throw a "SyntaxError" DOMException
+PASS new WebSocket("http://web-platform.test:8001/#") should throw a "SyntaxError" DOMException
+PASS new WebSocket("http://web-platform.test:8001/#test") should throw a "SyntaxError" DOMException
+PASS new WebSocket("#test") should throw a "SyntaxError" DOMException
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any-expected.txt
new file mode 100644
index 0000000..cd6dc87
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL Create WebSocket - Pass a non absolute URL: test Failed to construct 'WebSocket': The URL 'test' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: ? Failed to construct 'WebSocket': The URL '?' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: null Failed to construct 'WebSocket': The URL 'null' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: 123 Failed to construct 'WebSocket': The URL '123' is invalid.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js
index 8d533fd..5a7b179 100644
--- a/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js
@@ -1,11 +1,14 @@
-// META: script=constants.sub.js
-// META: variant=
-// META: variant=?wss
-// META: variant=?wpt_flags=h2
-
-test(function() {
-  var wsocket;
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = CreateWebSocketNonAbsolute()
-  });
-}, "Create WebSocket - Pass a non absolute URL - SYNTAX_ERR is thrown")
+[
+  "test",
+  "?",
+  null,
+  123,
+].forEach(input => {
+  test(() => {
+    const url = new URL(input, location);
+    url.protocol = "ws";
+    const ws = new WebSocket(input);
+    assert_equals(ws.url, url.href);
+    ws.close();
+  }, `Create WebSocket - Pass a non absolute URL: ${input}`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js.ini b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js.ini
new file mode 100644
index 0000000..09cbb63
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.js.ini
@@ -0,0 +1,26 @@
+[Create-non-absolute-url.any.html]
+  [Create WebSocket - Pass a non absolute URL: 123]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: ?]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: null]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: test]
+    expected: FAIL
+
+
+[Create-non-absolute-url.any.worker.html]
+  [Create WebSocket - Pass a non absolute URL: 123]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: ?]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: null]
+    expected: FAIL
+
+  [Create WebSocket - Pass a non absolute URL: test]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.worker-expected.txt
new file mode 100644
index 0000000..cd6dc87
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-non-absolute-url.any.worker-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL Create WebSocket - Pass a non absolute URL: test Failed to construct 'WebSocket': The URL 'test' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: ? Failed to construct 'WebSocket': The URL '?' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: null Failed to construct 'WebSocket': The URL 'null' is invalid.
+FAIL Create WebSocket - Pass a non absolute URL: 123 Failed to construct 'WebSocket': The URL '123' is invalid.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding-expected.txt b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding-expected.txt
new file mode 100644
index 0000000..e1df1c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL URL's percent-encoding is always in UTF-8 for WebSocket Failed to construct 'WebSocket': The URL '/?€' is invalid.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html
new file mode 100644
index 0000000..6596b5e1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset=windows-1252>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+test(() => {
+  const url = new URL("/", location);
+  url.protocol = "ws";
+  const input = "?\u20AC";
+  const expected = url.href + "?%E2%82%AC";
+
+  let ws = new WebSocket(url.href + input);
+  assert_equals(ws.url, expected);
+  ws.close();
+
+  ws = new WebSocket("/" + input);
+  assert_equals(ws.url, expected);
+  ws.close();
+}, "URL's percent-encoding is always in UTF-8 for WebSocket");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html.ini b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html.ini
new file mode 100644
index 0000000..918c19f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/Create-url-with-windows-1252-encoding.html.ini
@@ -0,0 +1,3 @@
+[Create-url-with-windows-1252-encoding.html]
+  [URL's percent-encoding is always in UTF-8 for WebSocket]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/Create-wrong-scheme.any.js b/third_party/blink/web_tests/external/wpt/websockets/Create-wrong-scheme.any.js
deleted file mode 100644
index 00cfffe..0000000
--- a/third_party/blink/web_tests/external/wpt/websockets/Create-wrong-scheme.any.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// META: script=constants.sub.js
-// META: variant=
-// META: variant=?wss
-// META: variant=?wpt_flags=h2
-
-test(function() {
-  var wsocket;
-  assert_throws_dom("SYNTAX_ERR", function() {
-    wsocket = CreateWebSocketNonWsScheme()
-  });
-}, "Create WebSocket - Pass a URL with a non ws/wss scheme - SYNTAX_ERR is thrown")
diff --git a/third_party/blink/web_tests/external/wpt/websockets/constants.sub.js b/third_party/blink/web_tests/external/wpt/websockets/constants.sub.js
index 65ea4f66..d8e340d 100644
--- a/third_party/blink/web_tests/external/wpt/websockets/constants.sub.js
+++ b/third_party/blink/web_tests/external/wpt/websockets/constants.sub.js
@@ -32,18 +32,6 @@
   }
 }
 
-function CreateWebSocketNonAbsolute() {
-  IsWebSocket();
-  const url = __SERVER__NAME;
-  return new WebSocket(url);
-}
-
-function CreateWebSocketNonWsScheme() {
-  IsWebSocket();
-  const url = "http://" + __SERVER__NAME + ":" + __PORT + "/" + __PATH;
-  return new WebSocket(url);
-}
-
 function CreateWebSocketNonAsciiProtocol(nonAsciiProtocol) {
   IsWebSocket();
   const url = SCHEME_DOMAIN_PORT + "/" + __PATH;
diff --git a/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html b/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html
deleted file mode 100644
index 8c80c237..0000000
--- a/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<title>WebSockets: new WebSocket(invalid url)</title>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=../constants.sub.js></script>
-<meta name="variant" content="">
-<meta name="variant" content="?wss">
-<meta name="variant" content="?wpt_flags=h2">
-<div id=log></div>
-<script>
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("/test")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("ws://foo bar.com/")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("wss://foo bar.com/")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("http://"+location.host+"/")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("mailto:example@example.org")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("about:blank")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket(SCHEME_DOMAIN_PORT+"/#")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket(SCHEME_DOMAIN_PORT+"/#test")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("?test")})});
-test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("#test")})});
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html.ini b/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html.ini
deleted file mode 100644
index b469a85e..0000000
--- a/third_party/blink/web_tests/external/wpt/websockets/constructor/002.html.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[002.html]
-  [WebSockets: new WebSocket(invalid url) 1]
-    expected: FAIL
-
-  [WebSockets: new WebSocket(invalid url) 2]
-    expected: FAIL
-
-
-[002.html?wpt_flags=h2]
-  [WebSockets: new WebSocket(invalid url) 1]
-    expected: FAIL
-
-  [WebSockets: new WebSocket(invalid url) 2]
-    expected: FAIL
-
-
-[002.html?wss]
-  [WebSockets: new WebSocket(invalid url) 1]
-    expected: FAIL
-
-  [WebSockets: new WebSocket(invalid url) 2]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/workers/shared-worker-parse-error-failure.html.ini b/third_party/blink/web_tests/external/wpt/workers/shared-worker-parse-error-failure.html.ini
deleted file mode 100644
index 54e3786..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/shared-worker-parse-error-failure.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[shared-worker-parse-error-failure.html]
-  expected: TIMEOUT
-  [Classic shared worker construction for script with syntax error should dispatch an event named error.]
-    expected: TIMEOUT
-
-  [Static import on classic shared worker should dispatch an event named error.]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/printing/css2.1/page-break-inside-000-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/printing/css2.1/page-break-inside-000-expected.txt
deleted file mode 100644
index 5e080f3c..0000000
--- a/third_party/blink/web_tests/flag-specific/highdpi/printing/css2.1/page-break-inside-000-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-There must be a page break below between "FIRST" and "LAST"
-FIRST dummy dummy dummy dummy dummy dummy dummy dummy dummy FIRST
-
-
-PASS: page number of "test1" is 0
-FAIL: expected page number of "test2" is 1. Was 0
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
index 50fad3f..9dc45b7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
@@ -14,9 +14,13 @@
   TestRunner.markStep('createIframesAndWaitForSourceMaps');
   await Promise.all([
     BindingsTestRunner.attachFrame('frame1', './resources/sourcemap-frame.html', '_test_create-iframe1.js'),
+    BindingsTestRunner.waitForSourceMap('sourcemap-script.js.map'),
+    BindingsTestRunner.waitForSourceMap('sourcemap-style.css.map'),
+  ]);
+  await Promise.all([
     BindingsTestRunner.attachFrame('frame2', './resources/sourcemap-frame.html', '_test_create-iframe2.js'),
     BindingsTestRunner.waitForSourceMap('sourcemap-script.js.map'),
-    BindingsTestRunner.waitForSourceMap('sourcemap-style.css.map')
+    BindingsTestRunner.waitForSourceMap('sourcemap-style.css.map'),
   ]);
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar-expected.txt
index a531922..d9e2016 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar-expected.txt
@@ -45,9 +45,9 @@
 Running: selectingErrorGroup
 Selecting item: 1 error
 MESSAGES:
-console-filter-sidebar.js:19 Error from test
-error1 @ console-filter-sidebar.js:19
-(anonymous) @ console-filter-sidebar.js:55
+console-filter-sidebar.js:22 Error from test
+error1 @ console-filter-sidebar.js:22
+(anonymous) @ console-filter-sidebar.js:58
 
 SIDEBAR:
 > 4 messages
@@ -71,7 +71,7 @@
 log-source.js:3 Log from log-source
 log-source.js:8 Warning from log-source
 warn2 @ log-source.js:8
-(anonymous) @ console-filter-sidebar.js:51
+(anonymous) @ console-filter-sidebar.js:54
 
 Running: clearConsole
 SIDEBAR:
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar.js b/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar.js
index d7327f6c..daf354d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console-sidebar/console-filter-sidebar.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console sidebar behaves properly.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.addScriptTag('resources/log-source.js');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/command-line-api.js b/third_party/blink/web_tests/http/tests/devtools/console/command-line-api.js
index ed5d23b7..fb27a63 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/command-line-api.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/command-line-api.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that command line api works.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
     <p id='foo'>
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-Object-overwritten.js b/third_party/blink/web_tests/http/tests/devtools/console/console-Object-overwritten.js
index 34861c3..d22de1c6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-Object-overwritten.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-Object-overwritten.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that Web Inspector's console is not broken if Object is overwritten in the inspected page. Test passes if the expression is evaluated in the console and no errors printed. Bug 101320.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-api-on-call-frame.js b/third_party/blink/web_tests/http/tests/devtools/console/console-api-on-call-frame.js
index 672c742c..f085a7b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-api-on-call-frame.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-api-on-call-frame.js
@@ -2,12 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Test that command line api does not mask values of scope variables while evaluating on a call frame.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-assert-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-assert-expected.txt
index 8184931..4d61861 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-assert-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-assert-expected.txt
@@ -1,13 +1,13 @@
 Tests that console.assert() will dump a message and stack trace with source URLs and line numbers.
 
-console-assert.js:14 Assertion failed: 1
-b @ console-assert.js:14
-a @ console-assert.js:20
+console-assert.js:17 Assertion failed: 1
+b @ console-assert.js:17
+a @ console-assert.js:23
 setTimeout (async)
-(anonymous) @ console-assert.js:37
-console-assert.js:15 Assertion failed: a b
-b @ console-assert.js:15
-a @ console-assert.js:20
+(anonymous) @ console-assert.js:40
+console-assert.js:18 Assertion failed: a b
+b @ console-assert.js:18
+a @ console-assert.js:23
 setTimeout (async)
-(anonymous) @ console-assert.js:37
+(anonymous) @ console-assert.js:40
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-assert.js b/third_party/blink/web_tests/http/tests/devtools/console/console-assert.js
index c2bc4ab..bb015fad 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-assert.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-assert.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console.assert() will dump a message and stack trace with source URLs and line numbers.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-bad-stacktrace.js b/third_party/blink/web_tests/http/tests/devtools/console/console-bad-stacktrace.js
index dafd56c..3e841b16 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-bad-stacktrace.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-bad-stacktrace.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console messages with invalid stacktraces will still be rendered, crbug.com/826210\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   var consoleView = Console.ConsoleView.instance();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-big-array.js b/third_party/blink/web_tests/http/tests/devtools/console/console-big-array.js
index a574831..92bdaf9da 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-big-array.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-big-array.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps large arrays properly.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-bind-fake.js b/third_party/blink/web_tests/http/tests/devtools/console/console-bind-fake.js
index ee3dfaa..ff04b50 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-bind-fake.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-bind-fake.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that overriding Function.prototype.bind does not break inspector.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto-expected.txt
index 0247c4ff..99480f5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto-expected.txt
@@ -1,6 +1,6 @@
 Tests that calling getter on prototype will call it on the object.
 
-console-call-getter-on-proto.js:27 B {value: 239}
+console-call-getter-on-proto.js:30 B {value: 239}
     value: 239
     foo: 239
     [[Prototype]]: A
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto.js b/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto.js
index 212bf7b6..7319122 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-call-getter-on-proto.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that calling getter on prototype will call it on the object.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-expected.txt
index 6aff65e..5570faf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-expected.txt
@@ -1,8 +1,8 @@
 Tests that console is cleared upon requestClearMessages call.
 
 === Before clear ===
-console-clear.js:12 one
-console-clear.js:13 two
-console-clear.js:14 three
+console-clear.js:14 one
+console-clear.js:15 two
+console-clear.js:16 three
 === After clear ===
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function-expected.txt
index da5f10bb..ea27253 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function-expected.txt
@@ -3,22 +3,22 @@
 
 Running: clearFromConsoleAPI
 === Before clear ===
-console-clear-function.js:14 one
-console-clear-function.js:15 two
-console-clear-function.js:16 three
+console-clear-function.js:17 one
+console-clear-function.js:18 two
+console-clear-function.js:19 three
 === After clear ===
-console-clear-function.js:21 Console was cleared
+console-clear-function.js:24 Console was cleared
 
 Running: shouldNotClearWithPreserveLog
 === Before clear ===
-console-clear-function.js:21 Console was cleared
-console-clear-function.js:14 one
-console-clear-function.js:15 two
-console-clear-function.js:16 three
+console-clear-function.js:24 Console was cleared
+console-clear-function.js:17 one
+console-clear-function.js:18 two
+console-clear-function.js:19 three
 === After clear ===
-console-clear-function.js:21 Console was cleared
-console-clear-function.js:14 one
-console-clear-function.js:15 two
-console-clear-function.js:16 three
-console-clear-function.js:21 console.clear() was prevented due to 'Preserve log'
+console-clear-function.js:24 Console was cleared
+console-clear-function.js:17 one
+console-clear-function.js:18 two
+console-clear-function.js:19 three
+console-clear-function.js:24 console.clear() was prevented due to 'Preserve log'
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function.js b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function.js
index 458dbb1..41317a39 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-clear-function.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console is cleared via console.clear() method\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function log()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-clear.js b/third_party/blink/web_tests/http/tests/devtools/console/console-clear.js
index 2eb6a24..8b6d1f9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-clear.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-clear.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+
 (async function() {
   TestRunner.addResult("Tests that console is cleared upon requestClearMessages call.\n");
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear-expected.txt
index 5636c991..fd35872e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear-expected.txt
@@ -1,9 +1,9 @@
 Tests that console is cleared upon clear() eval in console.
 
 === Before clear ===
-console-command-clear.js:14 one
-console-command-clear.js:15 two
-console-command-clear.js:16 three
+console-command-clear.js:17 one
+console-command-clear.js:18 two
+console-command-clear.js:19 three
 === After clear ===
 VM:1 Console was cleared
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear.js b/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear.js
index 10beb2bc..f01ea17 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-command-clear.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console is cleared upon clear() eval in console.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-command-copy.js b/third_party/blink/web_tests/http/tests/devtools/console/console-command-copy.js
index 887d71c6..1cf5ab9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-command-copy.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-command-copy.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console's copy command is copying into front-end buffer.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   var results = [];
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-control-characters.js b/third_party/blink/web_tests/http/tests/devtools/console/console-control-characters.js
index d734393..9eb9dd9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-control-characters.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-control-characters.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Verify that control characters are substituted with printable characters.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('var\u001d i = 0;', onEvaluated);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline-expected.txt
index 5693bd5..3be39d2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline-expected.txt
@@ -2,5 +2,5 @@
 
 
 Running: testSelectAll
-Selected text: console-copy-treeoutline.js:16 {foo: 1, bar: 'string'}
+Selected text: console-copy-treeoutline.js:19 {foo: 1, bar: 'string'}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline.js b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline.js
index 96a982a..57f361d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-treeoutline.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console copies tree outline messages properly.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-truncated-text.js b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-truncated-text.js
index a460f69d..43e21d8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-copy-truncated-text.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-copy-truncated-text.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console copies truncated text in messages properly.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   var longUrl = 'www.' + 'z123456789'.repeat(15) + '.com';
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-correct-suggestions.js b/third_party/blink/web_tests/http/tests/devtools/console/console-correct-suggestions.js
index f34c9ef..e745245f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-correct-suggestions.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-correct-suggestions.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console correctly finds suggestions in complicated cases.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters-expected.txt
index e214e20..bec02d6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters-expected.txt
@@ -1,9 +1,9 @@
 Tests that console logging dumps properly when there are multiple custom formatters on the page
 
-console-custom-formatters.js:120 Header formatted by 1 aBody formatted by 1 a
-console-custom-formatters.js:121 Header formatted by 2 bBody formatted by 2 b
-console-custom-formatters.js:122 Header formatted by 1 cBody formatted by 1 c
-console-custom-formatters.js:123 Formatter with config Header info: additional infobodyinfo: additional info
-console-custom-formatters.js:124 Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Object
+console-custom-formatters.js:123 Header formatted by 1 aBody formatted by 1 a
+console-custom-formatters.js:124 Header formatted by 2 bBody formatted by 2 b
+console-custom-formatters.js:125 Header formatted by 1 cBody formatted by 1 c
+console-custom-formatters.js:126 Formatter with config Header info: additional infobodyinfo: additional info
+console-custom-formatters.js:127 Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Object
 Custom Formatter Failed: Uncaught Too deep hierarchy of inlined custom previews
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters.js b/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters.js
index 43249d2d..cb10045 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-custom-formatters.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps properly when there are multiple custom formatters on the page\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated-expected.txt
index 95cd693..665cab4b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated-expected.txt
@@ -1,5 +1,5 @@
 Tests that console does not log deprecated warning messages while dir-dumping objects.
 
-console-dir-deprecated.js:17 Window
-console-dir-deprecated.js:18 undefined
+console-dir-deprecated.js:20 Window
+console-dir-deprecated.js:21 undefined
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated.js
index 6406a66..3de5ce8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-deprecated.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console does not log deprecated warning messages while dir-dumping objects.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6-expected.txt
index 00f1a78a..df75e0f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6-expected.txt
@@ -1,83 +1,83 @@
 Tests that console logging dumps proper messages.
 
-console-dir-es6.js:20 Object
+console-dir-es6.js:23 Object
     a: 1
     Symbol(): 2
     Symbol(Symbol.iterator): Symbol(foo)
     Symbol(a): 3
     Symbol(a): Symbol(Symbol.iterator)
     [[Prototype]]: Object
-console-dir-es6.js:23 Symbol()
-console-dir-es6.js:27 Map(1)
+console-dir-es6.js:26 Symbol()
+console-dir-es6.js:30 Map(1)
     [[Entries]]
         0: {Object => Object}
     size: 1
     [[Prototype]]: Map
-console-dir-es6.js:27 WeakMap
+console-dir-es6.js:30 WeakMap
     [[Entries]]
         0: {Object => Object}
     [[Prototype]]: WeakMap
-console-dir-es6.js:31 Set(1)
+console-dir-es6.js:34 Set(1)
     [[Entries]]
         0: Object
     size: 1
     [[Prototype]]: Set
-console-dir-es6.js:31 WeakSet
+console-dir-es6.js:34 WeakSet
     [[Entries]]
         0: Object
     [[Prototype]]: WeakSet
-console-dir-es6.js:39 Set(1)
+console-dir-es6.js:42 Set(1)
     [[Entries]]
         0: Set(1)
     size: 1
     [[Prototype]]: Set
-console-dir-es6.js:42 WeakMap
+console-dir-es6.js:45 WeakMap
     [[Entries]]
         No properties
     [[Prototype]]: WeakMap
-console-dir-es6.js:50 MapIterator
+console-dir-es6.js:53 MapIterator
     [[Entries]]
         0: Object
     [[Prototype]]: Map Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "keys"
-console-dir-es6.js:51 MapIterator
+console-dir-es6.js:54 MapIterator
     [[Entries]]
         0: Object
     [[Prototype]]: Map Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-dir-es6.js:52 MapIterator
+console-dir-es6.js:55 MapIterator
     [[Entries]]
         0: {Object => Object}
     [[Prototype]]: Map Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-dir-es6.js:50 SetIterator
+console-dir-es6.js:53 SetIterator
     [[Entries]]
         0: Object
     [[Prototype]]: Set Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-dir-es6.js:51 SetIterator
+console-dir-es6.js:54 SetIterator
     [[Entries]]
         0: Object
     [[Prototype]]: Set Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-dir-es6.js:52 SetIterator
+console-dir-es6.js:55 SetIterator
     [[Entries]]
         0: {Object => Object}
     [[Prototype]]: Set Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-dir-es6.js:90 Array(27)
+console-dir-es6.js:93 Array(27)
     0: class 
     1: class classWithWhitespace
     2: class FooClass
@@ -107,7 +107,7 @@
     26: ƒ (c = ")", {a: b})
     length: 27
     [[Prototype]]: Array(0)
-console-dir-es6.js:98 Array(4)
+console-dir-es6.js:101 Array(4)
     0: badArrow(x = a => {…}
     1: ƒ (a = ")
     2: ƒ (a = function()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6.js
index 1f3c673b..2adab26 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-es6.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps proper messages.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-global.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-global.js
index 728e8f5..05e4e37c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-global.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-global.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console dumps global object with properties.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives-expected.txt
index cd446ef..8b8e5f0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives-expected.txt
@@ -1,15 +1,15 @@
 Tests that console dir makes messages expandable only when necessary.
 
-Message text: console-dir-primitives.js:13 true
+Message text: console-dir-primitives.js:16 true
 Message is not expandable
 
-Message text: console-dir-primitives.js:14 Boolean
+Message text: console-dir-primitives.js:17 Boolean
 Message is expandable
 
-Message text: console-dir-primitives.js:16 foo
+Message text: console-dir-primitives.js:19 foo
 Message is not expandable
 
-Message text: console-dir-primitives.js:17 String
+Message text: console-dir-primitives.js:20 String
 Message is expandable
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives.js
index d00085c..7e1e326 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir-primitives.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console dir makes messages expandable only when necessary.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dir.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dir.js
index 4637108..9f748729 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dir.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dir.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging dumps proper messages.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml-expected.txt
index 71a226c..fc43014e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml-expected.txt
@@ -1,8 +1,8 @@
 Tests that console logging dumps proper messages.
 
-console-dirxml.js:17 #document
-console-dirxml.js:18 #document-fragment
-console-dirxml.js:19 <p></p>
-console-dirxml.js:20 [p]
-console-dirxml.js:21 (3) [document, document-fragment, span]
+console-dirxml.js:20 #document
+console-dirxml.js:21 #document-fragment
+console-dirxml.js:22 <p></p>
+console-dirxml.js:23 [p]
+console-dirxml.js:24 (3) [document, document-fragment, span]
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml.js b/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml.js
index fb011121..b140e68 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-dirxml.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps proper messages.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-expanded-tree.js b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-expanded-tree.js
index 043f98d..c865466 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-expanded-tree.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-expanded-tree.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that expanded tree element is editable in console.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value-expected.txt
index a7800b89..755d022 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value-expected.txt
@@ -5,7 +5,7 @@
 Node was hidden after dblclick: true
 Node was hidden after dblclick: true
 logToConsole()
-console-edit-property-value.js:15 {a: 1, b: 'foo', c: null, d: 2}
+console-edit-property-value.js:18 {a: 1, b: 'foo', c: null, d: 2}
     a: 3
     b: "foo"
     c: (3) [1, 2, 3]
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value.js b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value.js
index 30ad9579..fb3e549b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-edit-property-value.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that property values can be edited inline in the console via double click.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame-expected.txt
index ee96edc..7d37e38 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame-expected.txt
@@ -6,7 +6,7 @@
 console.error(42)
 VM:1 42
 eval @ VM:1
-testFunction @ console-error-on-call-frame.js:15
+testFunction @ console-error-on-call-frame.js:19
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame.js b/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame.js
index ead9128..6c3670d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-error-on-call-frame.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console.error does not throw exception when executed in console on call frame.\n`);
 
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-blocked.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-blocked.js
index c00d03a..955d6abd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-blocked.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-blocked.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluation in console still works even if script evals are prohibited by Content-Security-Policy. Bug 60800.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('1+2', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-exception-report.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-exception-report.js
index e1329d34..73e81ec 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-exception-report.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-exception-report.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluating an expression with an exception in the console provide correct exception information.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('\
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-fake.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-fake.js
index 465353c..0f587e15 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-fake.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-fake.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that overriding window.eval does not break inspector.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-global.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-global.js
index cc63e79..c8e0bac 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-global.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-global.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that simple evaluations may be performed in the console on global object.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped-expected.txt
index eaac06b..6c39d7b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped-expected.txt
@@ -2,7 +2,7 @@
 
 
 Running: testSnippet1
-console-eval-scoped.js:69 with: Object property value
+console-eval-scoped.js:72 with: Object property value
 VM:1 eval in with: Object property value
 
 Running: testSnippet2
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped.js
index bb54cfb..5d1bdbb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-scoped.js
@@ -2,13 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   'use strict';
   TestRunner.addResult(
     `Tests that evaluating 'console.log()' in the console will have access to its outer scope variables. Bug 60547.\n`
   );
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-syntax-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-syntax-error.js
index ded0faf9..4a14a21 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-syntax-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-syntax-error.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluating an expression with a syntax error in the console won't crash the browser. Bug 61194.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('foo().', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-throw.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-throw.js
index 014016f2..c6650527 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-throw.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-throw.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluating 'throw undefined|1|string|object|Error' in the console won't crash the browser and correctly reported. Bug 59611.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   async function dumpMessages(next, message) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-undefined-override.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-undefined-override.js
index 0bfd288..adcccc1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-undefined-override.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-undefined-override.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluating something in console won't crash the browser if undefined value is overriden. The test passes if it doesn't crash. Bug 64155.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('var x = {a:1}; x.self = x; undefined = x;', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-uses-repl-mode.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-uses-repl-mode.js
index e22c6e3..7319995 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval-uses-repl-mode.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval-uses-repl-mode.js
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console inputs are evaluated in REPL mode\n');
 
-  await TestRunner.loadTestModule('console_test_runner');
   await TestRunner.showPanel('console');
 
   TestRunner.addSniffer(TestRunner.RuntimeAgent, 'invoke_evaluate', function(args) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-eval.js b/third_party/blink/web_tests/http/tests/devtools/console/console-eval.js
index dfd2b46..06d56d5c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-eval.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-eval.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that simple evaluations may be performed in the console.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('1+2', step2);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node-expected.txt
index 9d55d45..aec12ee3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node-expected.txt
@@ -1,8 +1,8 @@
 Tests that removed Elements logged in the Console are properly formatted.
 
 Adding element
-console-expand-removed-node.js:19 <div>…</div>
+console-expand-removed-node.js:22 <div>…</div>
 Removing element
 Expanding element in Console
-console-expand-removed-node.js:19 <div></div>
+console-expand-removed-node.js:22 <div></div>
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node.js b/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node.js
index 2b3b6dff..8cfa3385 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-expand-removed-node.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that removed Elements logged in the Console are properly formatted.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   TestRunner.addResult(`Adding element`);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-export-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-export-expected.txt
index 538557ac..8828b3f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-export-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-export-expected.txt
@@ -2,28 +2,28 @@
 
 
 Dumping messages
-console-export.js:17 foo
-console-export.js:18 www.chromium.org
-console-export.js:19 baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar
-console-export.js:20 www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
-console-export.js:21 www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com foo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
-console-export.js:22 My important trace
-log @ console-export.js:22
-(anonymous) @ console-export.js:25
-console-export.js:23 My error
-log @ console-export.js:23
-(anonymous) @ console-export.js:25
+console-export.js:20 foo
+console-export.js:21 www.chromium.org
+console-export.js:22 baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar
+console-export.js:23 www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
+console-export.js:24 www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com foo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo…ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
+console-export.js:25 My important trace
+log @ console-export.js:25
+(anonymous) @ console-export.js:28
+console-export.js:26 My error
+log @ console-export.js:26
+(anonymous) @ console-export.js:28
 
 Dumping export strings
-console-export.js:17 foo
-console-export.js:18 www.chromium.org
-console-export.js:19 baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar
-console-export.js:20 www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
-console-export.js:21 www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com foo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
-console-export.js:22 My important trace
-log @ console-export.js:22
-(anonymous) @ console-export.js:25
-console-export.js:23 My error
-log @ console-export.js:23
-(anonymous) @ console-export.js:25
+console-export.js:20 foo
+console-export.js:21 www.chromium.org
+console-export.js:22 baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar
+console-export.js:23 www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
+console-export.js:24 www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com foo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar www.chromium.org www.loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongurl.com
+console-export.js:25 My important trace
+log @ console-export.js:25
+(anonymous) @ console-export.js:28
+console-export.js:26 My error
+log @ console-export.js:26
+(anonymous) @ console-export.js:28
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-export.js b/third_party/blink/web_tests/http/tests/devtools/console/console-export.js
index 542f256..261a751 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-export.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-export.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that exporting console messages produces proper output.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
index 38629249..b280d6ca 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
@@ -1,19 +1,19 @@
 Tests that console logging detects external arrays as arrays.
 
-console-external-array.js:14 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int8Array']
-console-external-array.js:15 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int16Array']
-console-external-array.js:16 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int32Array']
-console-external-array.js:17 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint8Array']
-console-external-array.js:18 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint16Array']
-console-external-array.js:19 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint32Array']
-console-external-array.js:20 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float32Array']
-console-external-array.js:21 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(80), byteLength: 80, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float64Array']
-console-external-array.js:23 Int8Array(10)
-console-external-array.js:24 Int16Array(10)
-console-external-array.js:25 Int32Array(10)
-console-external-array.js:26 Uint8Array(10)
-console-external-array.js:27 Uint16Array(10)
-console-external-array.js:28 Uint32Array(10)
-console-external-array.js:29 Float32Array(10)
-console-external-array.js:30 Float64Array(10)
+console-external-array.js:17 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int8Array']
+console-external-array.js:18 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int16Array']
+console-external-array.js:19 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int32Array']
+console-external-array.js:20 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint8Array']
+console-external-array.js:21 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint16Array']
+console-external-array.js:22 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint32Array']
+console-external-array.js:23 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float32Array']
+console-external-array.js:24 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(80), byteLength: 80, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float64Array']
+console-external-array.js:26 Int8Array(10)
+console-external-array.js:27 Int16Array(10)
+console-external-array.js:28 Int32Array(10)
+console-external-array.js:29 Uint8Array(10)
+console-external-array.js:30 Uint16Array(10)
+console-external-array.js:31 Uint32Array(10)
+console-external-array.js:32 Float32Array(10)
+console-external-array.js:33 Float64Array(10)
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array.js b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array.js
index 2ef63f0..e2ea840 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging detects external arrays as arrays.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test-expected.txt
index 0484339..c2c36bb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test-expected.txt
@@ -20,81 +20,81 @@
 Running: beforeFilter
 beforeFilter
 Level menu: Default levels
->console-filter-level-test.js:12 sample info
->console-filter-level-test.js:13 sample log
->console-filter-level-test.js:14 sample warning
-(anonymous) @ console-filter-level-test.js:14
->console-filter-level-test.js:16 sample error
-(anonymous) @ console-filter-level-test.js:16
->console-filter-level-test.js:18 abc info
->console-filter-level-test.js:19 def info
->console-filter-level-test.js:21 abc warn
-(anonymous) @ console-filter-level-test.js:21
->console-filter-level-test.js:22 def warn
-(anonymous) @ console-filter-level-test.js:22
+>console-filter-level-test.js:15 sample info
+>console-filter-level-test.js:16 sample log
+>console-filter-level-test.js:17 sample warning
+(anonymous) @ console-filter-level-test.js:17
+>console-filter-level-test.js:19 sample error
+(anonymous) @ console-filter-level-test.js:19
+>console-filter-level-test.js:21 abc info
+>console-filter-level-test.js:22 def info
+>console-filter-level-test.js:24 abc warn
+(anonymous) @ console-filter-level-test.js:24
+>console-filter-level-test.js:25 def warn
+(anonymous) @ console-filter-level-test.js:25
 >'Should be always visible'
 >'Should be always visible'
 
 Running: allLevels
 Level menu: All levels
->console-filter-level-test.js:12 sample info
->console-filter-level-test.js:13 sample log
->console-filter-level-test.js:14 sample warning
-(anonymous) @ console-filter-level-test.js:14
->console-filter-level-test.js:15 sample debug
->console-filter-level-test.js:16 sample error
-(anonymous) @ console-filter-level-test.js:16
->console-filter-level-test.js:18 abc info
->console-filter-level-test.js:19 def info
->console-filter-level-test.js:21 abc warn
-(anonymous) @ console-filter-level-test.js:21
->console-filter-level-test.js:22 def warn
-(anonymous) @ console-filter-level-test.js:22
+>console-filter-level-test.js:15 sample info
+>console-filter-level-test.js:16 sample log
+>console-filter-level-test.js:17 sample warning
+(anonymous) @ console-filter-level-test.js:17
+>console-filter-level-test.js:18 sample debug
+>console-filter-level-test.js:19 sample error
+(anonymous) @ console-filter-level-test.js:19
+>console-filter-level-test.js:21 abc info
+>console-filter-level-test.js:22 def info
+>console-filter-level-test.js:24 abc warn
+(anonymous) @ console-filter-level-test.js:24
+>console-filter-level-test.js:25 def warn
+(anonymous) @ console-filter-level-test.js:25
 >'Should be always visible'
 >'Should be always visible'
 
 Running: defaultLevels
 Level menu: Default levels
->console-filter-level-test.js:12 sample info
->console-filter-level-test.js:13 sample log
->console-filter-level-test.js:14 sample warning
-(anonymous) @ console-filter-level-test.js:14
->console-filter-level-test.js:16 sample error
-(anonymous) @ console-filter-level-test.js:16
->console-filter-level-test.js:18 abc info
->console-filter-level-test.js:19 def info
->console-filter-level-test.js:21 abc warn
-(anonymous) @ console-filter-level-test.js:21
->console-filter-level-test.js:22 def warn
-(anonymous) @ console-filter-level-test.js:22
+>console-filter-level-test.js:15 sample info
+>console-filter-level-test.js:16 sample log
+>console-filter-level-test.js:17 sample warning
+(anonymous) @ console-filter-level-test.js:17
+>console-filter-level-test.js:19 sample error
+(anonymous) @ console-filter-level-test.js:19
+>console-filter-level-test.js:21 abc info
+>console-filter-level-test.js:22 def info
+>console-filter-level-test.js:24 abc warn
+(anonymous) @ console-filter-level-test.js:24
+>console-filter-level-test.js:25 def warn
+(anonymous) @ console-filter-level-test.js:25
 >'Should be always visible'
 >'Should be always visible'
 
 Running: verbose
 Level menu: Verbose only
->console-filter-level-test.js:15 sample debug
+>console-filter-level-test.js:18 sample debug
 >'Should be always visible'
 >'Should be always visible'
 
 Running: info
 Level menu: Info only
->console-filter-level-test.js:12 sample info
->console-filter-level-test.js:13 sample log
->console-filter-level-test.js:18 abc info
->console-filter-level-test.js:19 def info
+>console-filter-level-test.js:15 sample info
+>console-filter-level-test.js:16 sample log
+>console-filter-level-test.js:21 abc info
+>console-filter-level-test.js:22 def info
 >'Should be always visible'
 >'Should be always visible'
 
 Running: warningsAndErrors
 Level menu: Custom levels
->console-filter-level-test.js:14 sample warning
-(anonymous) @ console-filter-level-test.js:14
->console-filter-level-test.js:16 sample error
-(anonymous) @ console-filter-level-test.js:16
->console-filter-level-test.js:21 abc warn
-(anonymous) @ console-filter-level-test.js:21
->console-filter-level-test.js:22 def warn
-(anonymous) @ console-filter-level-test.js:22
+>console-filter-level-test.js:17 sample warning
+(anonymous) @ console-filter-level-test.js:17
+>console-filter-level-test.js:19 sample error
+(anonymous) @ console-filter-level-test.js:19
+>console-filter-level-test.js:24 abc warn
+(anonymous) @ console-filter-level-test.js:24
+>console-filter-level-test.js:25 def warn
+(anonymous) @ console-filter-level-test.js:25
 >'Should be always visible'
 >'Should be always visible'
 
@@ -110,8 +110,8 @@
 
 Running: abcMessageRegexWarning
 Level menu: Warnings only
->console-filter-level-test.js:21 abc warn
-(anonymous) @ console-filter-level-test.js:21
+>console-filter-level-test.js:24 abc warn
+(anonymous) @ console-filter-level-test.js:24
 >'Should be always visible'
 >'Should be always visible'
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test.js b/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test.js
index 1450c97..e5a4a7d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-filter-level-test.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console can filter messages by source.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.addScriptTag('resources/log-source.js');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype-expected.txt
index 930a9cb..cd92b17 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype-expected.txt
@@ -2,35 +2,35 @@
 
 a0
 []
-console-format-array-prototype.js:14 []
+console-format-array-prototype.js:17 []
 a1
 [empty]
-console-format-array-prototype.js:14 [empty]
+console-format-array-prototype.js:17 [empty]
 a2
 (5) [empty × 5]
-console-format-array-prototype.js:14 (5) [empty × 5]
+console-format-array-prototype.js:17 (5) [empty × 5]
 a3
 (3) [empty, 2, 3]
-console-format-array-prototype.js:14 (3) [empty, 2, 3]
+console-format-array-prototype.js:17 (3) [empty, 2, 3]
 a4
 (15) [empty × 15]
-console-format-array-prototype.js:14 (15) [empty × 15]
+console-format-array-prototype.js:17 (15) [empty × 15]
 a5
 (15) [empty × 8, 8, empty × 6]
-console-format-array-prototype.js:14 (15) [empty × 8, 8, empty × 6]
+console-format-array-prototype.js:17 (15) [empty × 8, 8, empty × 6]
 a6
 (15) [0, empty × 9, 10, empty × 4]
-console-format-array-prototype.js:14 (15) [0, empty × 9, 10, empty × 4]
+console-format-array-prototype.js:17 (15) [0, empty × 9, 10, empty × 4]
 a7
 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …]
-console-format-array-prototype.js:14 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …]
+console-format-array-prototype.js:17 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …]
 a8
 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-console-format-array-prototype.js:14 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+console-format-array-prototype.js:17 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 a9
 (11) [empty, 1, 2, 3, 4, empty, 6, 7, 8, 9, empty, foo: 'bar']
-console-format-array-prototype.js:14 (11) [empty, 1, 2, 3, 4, empty, 6, 7, 8, 9, empty, foo: 'bar']
+console-format-array-prototype.js:17 (11) [empty, 1, 2, 3, 4, empty, 6, 7, 8, 9, empty, foo: 'bar']
 a10
 Array {}
-console-format-array-prototype.js:14 Array {}
+console-format-array-prototype.js:17 Array {}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype.js
index 33943a5..f462055 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-array-prototype.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps array values defined on Array.prototype[].\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-broken-unicode.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-broken-unicode.js
index c1f9792..34f9179 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-broken-unicode.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-broken-unicode.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging dumps proper messages with broken Unicode.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt
index 7348a01..c693896 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes-expected.txt
@@ -1,7 +1,7 @@
 Tests that console produces instant previews for arrays and objects.
 
-console-format-classes.js:30 Error: custom error with link www.chromium.org
-    at console-format-classes.js:20:9 
+console-format-classes.js:33 Error: custom error with link www.chromium.org
+    at console-format-classes.js:23:9 
   console-message
     source-code
       console-message-anchor
@@ -10,7 +10,7 @@
         object-value-error source-code
           devtools-link
           devtools-link
-console-format-classes.js:30 (6) [1, empty × 2, 2, (...), empty] 
+console-format-classes.js:33 (6) [1, empty × 2, 2, (...), empty] 
   console-message
     source-code
       console-message-anchor
@@ -31,7 +31,7 @@
               object-value-undefined
             object-state-note info-note
               children
-console-format-classes.js:30 {a: 1} 
+console-format-classes.js:33 {a: 1} 
   console-message
     source-code
       console-message-anchor
@@ -48,7 +48,7 @@
               object-value-number
             object-state-note info-note
               children
-console-format-classes.js:30 {str: '', nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} 
+console-format-classes.js:33 {str: '', nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} 
   console-message
     source-code
       console-message-anchor
@@ -73,7 +73,7 @@
               object-value-number
             object-state-note info-note
               children
-console-format-classes.js:30 {null: null, undef: undefined, re: /^[regexp]$/g, constructedRe: /foo\/bar/, bool: false} 
+console-format-classes.js:33 {null: null, undef: undefined, re: /^[regexp]$/g, constructedRe: /foo\/bar/, bool: false} 
   console-message
     source-code
       console-message-anchor
@@ -98,7 +98,7 @@
               object-value-boolean
             object-state-note info-note
               children
-console-format-classes.js:30 Proxy(Object) {a: 1} 
+console-format-classes.js:33 Proxy(Object) {a: 1} 
   console-message
     source-code
       console-message-anchor
@@ -116,7 +116,7 @@
               object-value-number
             object-state-note info-note
               children
-console-format-classes.js:30 HTMLAllCollection(4) [html, head, base, body] 
+console-format-classes.js:33 HTMLAllCollection(4) [html, head, base, body] 
   console-message
     source-code
       console-message-anchor
@@ -140,7 +140,7 @@
                 webkit-html-tag-name
             object-state-note info-note
               children
-console-format-classes.js:34 (7) [Error: custom error with link www.chromium.org
+console-format-classes.js:37 (7) [Error: custom error with link www.chromium.org
     at test://evaluations/0/console-format-classes.j…, Array(6), {…}, {…}, {…}, Proxy(Object), HTMLAllCollection(4)] 
   console-message
     source-code
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes.js
index dc07107..6ca2b58 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-classes.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console produces instant previews for arrays and objects.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       const objWithGetter = {a: 1, __proto__: 2};
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections-expected.txt
index 0cdfc074..2ade5ca 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections-expected.txt
@@ -1,39 +1,39 @@
 Tests that console nicely formats HTML Collections, NodeLists and DOMTokenLists.
 
-console-format-collections.js:33 HTMLCollection [select#sel, sel: select#sel]
-console-format-collections.js:37 HTMLCollection [base]
-console-format-collections.js:41 HTMLOptionsCollection(2) [option, option, selectedIndex: 0]
-console-format-collections.js:45 HTMLAllCollection(11) [html, head, base, body, div.c1.c2.c3, form#f, select#sel, option, option, input, input, f: form#f, sel: select#sel, x: HTMLCollection(2)]
-console-format-collections.js:49 HTMLFormControlsCollection(3) [select#sel, input, input, sel: select#sel, x: RadioNodeList(2)]
-console-format-collections.js:53 RadioNodeList(2) [input, input, value: '']
-console-format-collections.js:59 (2) [1, Array(2)]
-console-format-collections.js:62 NonArrayWithLength {keys: Array(0)}
-console-format-collections.js:69 Arguments(2) [1, '2', callee: ƒ, Symbol(Symbol.iterator): ƒ]
-console-format-collections.js:73 DOMTokenList(3) ['c1', 'c2', 'c3', value: 'c1 c2 c3']
-console-format-collections.js:76 ArrayLike {length: 5}
-console-format-collections.js:77 ArrayLike {length: 4294967295}
-console-format-collections.js:79 ArrayLike {length: -5}
-console-format-collections.js:80 ArrayLike {length: 5.6}
-console-format-collections.js:81 ArrayLike {length: NaN}
-console-format-collections.js:82 ArrayLike {length: Infinity}
-console-format-collections.js:83 ArrayLike {length: -0}
-console-format-collections.js:84 ArrayLike {length: 4294967296}
-console-format-collections.js:33 HTMLCollection [select#sel, sel: select#sel]
-console-format-collections.js:37 HTMLCollection [base]
-console-format-collections.js:41 HTMLOptionsCollection(2) [option, option, selectedIndex: 0]
-console-format-collections.js:45 HTMLAllCollection(11) [html, head, base, body, div.c1.c2.c3, form#f, select#sel, option, option, input, input, f: form#f, sel: select#sel, x: HTMLCollection(2)]
-console-format-collections.js:49 HTMLFormControlsCollection(3) [select#sel, input, input, sel: select#sel, x: RadioNodeList(2)]
-console-format-collections.js:53 RadioNodeList(2) [input, input, value: '']
-console-format-collections.js:59 (2) [1, Array(2)]
-console-format-collections.js:62 NonArrayWithLength {keys: Array(0)}
-console-format-collections.js:69 Arguments(2) [1, '2', callee: ƒ, Symbol(Symbol.iterator): ƒ]
-console-format-collections.js:73 DOMTokenList(3) ['c1', 'c2', 'c3', value: 'c1 c2 c3']
-console-format-collections.js:76 ArrayLike(5) [empty × 5]
-console-format-collections.js:77 ArrayLike(4294967295) [empty × 4294967295]
-console-format-collections.js:79 ArrayLike {length: -5}
-console-format-collections.js:80 ArrayLike {length: 5.6}
-console-format-collections.js:81 ArrayLike {length: NaN}
-console-format-collections.js:82 ArrayLike {length: Infinity}
-console-format-collections.js:83 ArrayLike {length: -0}
-console-format-collections.js:84 ArrayLike {length: 4294967296}
+console-format-collections.js:36 HTMLCollection [select#sel, sel: select#sel]
+console-format-collections.js:40 HTMLCollection [base]
+console-format-collections.js:44 HTMLOptionsCollection(2) [option, option, selectedIndex: 0]
+console-format-collections.js:48 HTMLAllCollection(11) [html, head, base, body, div.c1.c2.c3, form#f, select#sel, option, option, input, input, f: form#f, sel: select#sel, x: HTMLCollection(2)]
+console-format-collections.js:52 HTMLFormControlsCollection(3) [select#sel, input, input, sel: select#sel, x: RadioNodeList(2)]
+console-format-collections.js:56 RadioNodeList(2) [input, input, value: '']
+console-format-collections.js:62 (2) [1, Array(2)]
+console-format-collections.js:65 NonArrayWithLength {keys: Array(0)}
+console-format-collections.js:72 Arguments(2) [1, '2', callee: ƒ, Symbol(Symbol.iterator): ƒ]
+console-format-collections.js:76 DOMTokenList(3) ['c1', 'c2', 'c3', value: 'c1 c2 c3']
+console-format-collections.js:79 ArrayLike {length: 5}
+console-format-collections.js:80 ArrayLike {length: 4294967295}
+console-format-collections.js:82 ArrayLike {length: -5}
+console-format-collections.js:83 ArrayLike {length: 5.6}
+console-format-collections.js:84 ArrayLike {length: NaN}
+console-format-collections.js:85 ArrayLike {length: Infinity}
+console-format-collections.js:86 ArrayLike {length: -0}
+console-format-collections.js:87 ArrayLike {length: 4294967296}
+console-format-collections.js:36 HTMLCollection [select#sel, sel: select#sel]
+console-format-collections.js:40 HTMLCollection [base]
+console-format-collections.js:44 HTMLOptionsCollection(2) [option, option, selectedIndex: 0]
+console-format-collections.js:48 HTMLAllCollection(11) [html, head, base, body, div.c1.c2.c3, form#f, select#sel, option, option, input, input, f: form#f, sel: select#sel, x: HTMLCollection(2)]
+console-format-collections.js:52 HTMLFormControlsCollection(3) [select#sel, input, input, sel: select#sel, x: RadioNodeList(2)]
+console-format-collections.js:56 RadioNodeList(2) [input, input, value: '']
+console-format-collections.js:62 (2) [1, Array(2)]
+console-format-collections.js:65 NonArrayWithLength {keys: Array(0)}
+console-format-collections.js:72 Arguments(2) [1, '2', callee: ƒ, Symbol(Symbol.iterator): ƒ]
+console-format-collections.js:76 DOMTokenList(3) ['c1', 'c2', 'c3', value: 'c1 c2 c3']
+console-format-collections.js:79 ArrayLike(5) [empty × 5]
+console-format-collections.js:80 ArrayLike(4294967295) [empty × 4294967295]
+console-format-collections.js:82 ArrayLike {length: -5}
+console-format-collections.js:83 ArrayLike {length: 5.6}
+console-format-collections.js:84 ArrayLike {length: NaN}
+console-format-collections.js:85 ArrayLike {length: Infinity}
+console-format-collections.js:86 ArrayLike {length: -0}
+console-format-collections.js:87 ArrayLike {length: 4294967296}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections.js
index 7d652e4..f385ac2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-collections.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console nicely formats HTML Collections, NodeLists and DOMTokenLists.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2-expected.txt
index c55dc456..89f40e76 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2-expected.txt
@@ -1,39 +1,39 @@
 Tests that console properly displays information about ES6 features.
 
-console-format-es6-2.js:15 MapIterator {41, {…}}
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:18 MapIterator {41, {…}}
+console-format-es6-2.js:19 [MapIterator]
 globals[0]
 MapIterator {41, {…}}
-console-format-es6-2.js:15 MapIterator {42, {…}}
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:18 MapIterator {42, {…}}
+console-format-es6-2.js:19 [MapIterator]
 globals[1]
 MapIterator {42, {…}}
-console-format-es6-2.js:15 MapIterator {41 => 42, {…} => {…}}
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:18 MapIterator {41 => 42, {…} => {…}}
+console-format-es6-2.js:19 [MapIterator]
 globals[2]
 MapIterator {41 => 42, {…} => {…}}
-console-format-es6-2.js:15 SetIterator {41, {…}}
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:18 SetIterator {41, {…}}
+console-format-es6-2.js:19 [SetIterator]
 globals[3]
 SetIterator {41, {…}}
-console-format-es6-2.js:15 SetIterator {41, {…}}
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:18 SetIterator {41, {…}}
+console-format-es6-2.js:19 [SetIterator]
 globals[4]
 SetIterator {41, {…}}
-console-format-es6-2.js:15 SetIterator {41 => 41, {…} => {…}}
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:18 SetIterator {41 => 41, {…} => {…}}
+console-format-es6-2.js:19 [SetIterator]
 globals[5]
 SetIterator {41 => 41, {…} => {…}}
-console-format-es6-2.js:15 MapIterator {{…}}
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:18 MapIterator {{…}}
+console-format-es6-2.js:19 [MapIterator]
 globals[6]
 MapIterator {{…}}
-console-format-es6-2.js:15 SetIterator {{…}}
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:18 SetIterator {{…}}
+console-format-es6-2.js:19 [SetIterator]
 globals[7]
 SetIterator {{…}}
 Expanded all messages
-console-format-es6-2.js:15 MapIterator {41, {…}}
+console-format-es6-2.js:18 MapIterator {41, {…}}
     [[Entries]]
         0: 41
         1: Object
@@ -41,7 +41,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "keys"
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:19 [MapIterator]
     0: MapIterator {41, {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -54,7 +54,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "keys"
-console-format-es6-2.js:15 MapIterator {42, {…}}
+console-format-es6-2.js:18 MapIterator {42, {…}}
     [[Entries]]
         0: 42
         1: Object
@@ -62,7 +62,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:19 [MapIterator]
     0: MapIterator {42, {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -75,7 +75,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:15 MapIterator {41 => 42, {…} => {…}}
+console-format-es6-2.js:18 MapIterator {41 => 42, {…} => {…}}
     [[Entries]]
         0: {41 => 42}
         1: {Object => Object}
@@ -83,7 +83,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:19 [MapIterator]
     0: MapIterator {41 => 42, {…} => {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -96,7 +96,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-format-es6-2.js:15 SetIterator {41, {…}}
+console-format-es6-2.js:18 SetIterator {41, {…}}
     [[Entries]]
         0: 41
         1: Object
@@ -104,7 +104,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:19 [SetIterator]
     0: SetIterator {41, {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -117,7 +117,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:15 SetIterator {41, {…}}
+console-format-es6-2.js:18 SetIterator {41, {…}}
     [[Entries]]
         0: 41
         1: Object
@@ -125,7 +125,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:19 [SetIterator]
     0: SetIterator {41, {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -138,7 +138,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "values"
-console-format-es6-2.js:15 SetIterator {41 => 41, {…} => {…}}
+console-format-es6-2.js:18 SetIterator {41 => 41, {…} => {…}}
     [[Entries]]
         0: {41 => 41}
         1: {Object => Object}
@@ -146,7 +146,7 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:19 [SetIterator]
     0: SetIterator {41 => 41, {…} => {…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -159,14 +159,14 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 0
     [[IteratorKind]]: "entries"
-console-format-es6-2.js:15 MapIterator {{…}}
+console-format-es6-2.js:18 MapIterator {{…}}
     [[Entries]]
         0: Object
     [[Prototype]]: Map Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 1
     [[IteratorKind]]: "values"
-console-format-es6-2.js:16 [MapIterator]
+console-format-es6-2.js:19 [MapIterator]
     0: MapIterator {{…}}
     length: 1
     [[Prototype]]: Array(0)
@@ -178,14 +178,14 @@
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 1
     [[IteratorKind]]: "values"
-console-format-es6-2.js:15 SetIterator {{…}}
+console-format-es6-2.js:18 SetIterator {{…}}
     [[Entries]]
         0: Object
     [[Prototype]]: Set Iterator
     [[IteratorHasMore]]: true
     [[IteratorIndex]]: 1
     [[IteratorKind]]: "values"
-console-format-es6-2.js:16 [SetIterator]
+console-format-es6-2.js:19 [SetIterator]
     0: SetIterator {{…}}
     length: 1
     [[Prototype]]: Array(0)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2.js
index b5a2ba7..ed6b06a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-2.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console properly displays information about ES6 features.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt
index 859e20f..52bf760 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt
@@ -1,4 +1,4 @@
 Tests that console properly displays information about ES6 Symbols.
 
-console-format-es6-symbols-error.js:16 Symbol()
+console-format-es6-symbols-error.js:19 Symbol()
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error.js
index 3f9b198..71c080b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6-symbols-error.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console properly displays information about ES6 Symbols.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6.js
index 17ae2c70..cdb0e8c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-es6.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console properly displays information about ES6 features.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance-expected.txt
index b6e7162..d59644e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance-expected.txt
@@ -1,7 +1,7 @@
 Tests that console nicely formats performance getters.
 
-console-format-performance.js:14 PerformanceTiming {navigationStart: <number>, unloadEventStart: <number>, unloadEventEnd: <number>, redirectStart: <number>, redirectEnd: <number>, …}
-console-format-performance.js:15 MemoryInfo {totalJSHeapSize: <number>, usedJSHeapSize: <number>, jsHeapSizeLimit: <number>}
-console-format-performance.js:14 PerformanceTiming {navigationStart: <number>, unloadEventStart: <number>, unloadEventEnd: <number>, redirectStart: <number>, redirectEnd: <number>, …}
-console-format-performance.js:15 MemoryInfo {totalJSHeapSize: <number>, usedJSHeapSize: <number>, jsHeapSizeLimit: <number>}
+console-format-performance.js:17 PerformanceTiming {navigationStart: <number>, unloadEventStart: <number>, unloadEventEnd: <number>, redirectStart: <number>, redirectEnd: <number>, …}
+console-format-performance.js:18 MemoryInfo {totalJSHeapSize: <number>, usedJSHeapSize: <number>, jsHeapSizeLimit: <number>}
+console-format-performance.js:17 PerformanceTiming {navigationStart: <number>, unloadEventStart: <number>, unloadEventEnd: <number>, redirectStart: <number>, redirectEnd: <number>, …}
+console-format-performance.js:18 MemoryInfo {totalJSHeapSize: <number>, usedJSHeapSize: <number>, jsHeapSizeLimit: <number>}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance.js
index b2ada07..a7e7b8ba2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-performance.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console nicely formats performance getters.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed-expected.txt
index ad00350..f7016079 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed-expected.txt
@@ -1,13 +1,13 @@
 Tests that console logging dumps properly styled messages, and that the whole message gets the same style, regardless of multiple %c settings.
 
-console-format-style-allowed.js:13 Colors are awesome.
+console-format-style-allowed.js:16 Colors are awesome.
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-console-format-style-allowed.js:14 So are fonts!
+console-format-style-allowed.js:17 So are fonts!
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; font: 1em Helvetica;
-console-format-style-allowed.js:15 And borders and margins and paddings!
+console-format-style-allowed.js:18 And borders and margins and paddings!
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; border: 1px solid red; margin: 20px; padding: 10px;
-console-format-style-allowed.js:16 text-* is fine by us!
+console-format-style-allowed.js:19 text-* is fine by us!
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; text-decoration: none;
-console-format-style-allowed.js:18 Display, on the other hand, is bad news.
-console-format-style-allowed.js:19 And position too.
+console-format-style-allowed.js:21 Display, on the other hand, is bad news.
+console-format-style-allowed.js:22 And position too.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed.js
index a3148ab..a89e32b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-allowed.js
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
     `Tests that console logging dumps properly styled messages, and that the whole message gets the same style, regardless of multiple %c settings.\n`
   );
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     console.log('%cColors are awesome.', 'color: blue;');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-expected.txt
index c68ab67..34eb67f7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style-expected.txt
@@ -1,29 +1,29 @@
 Tests that console logging dumps properly styled messages.
 
-console-format-style.js:14 Blue!.
+console-format-style.js:17 Blue!.
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
-console-format-style.js:15 Blue! Red!
+console-format-style.js:18 Blue! Red!
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
 Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: red;
-console-format-style.js:16 Blue!Red!
+console-format-style.js:19 Blue!Red!
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
 Styled text #1: NO STYLES DEFINED
 Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: blue;
 Styled text #3: contain: paint; display: inline-block; max-width: 100%; color: red;
-console-format-style.js:17 www.google.com
+console-format-style.js:20 www.google.com
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue;
 Styled text #1: NO STYLES DEFINED
-console-format-style.js:18 www.google.com
-onload @ console-format-style.js:18
-(anonymous) @ console-format-style.js:22
+console-format-style.js:21 www.google.com
+onload @ console-format-style.js:21
+(anonymous) @ console-format-style.js:25
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue; background: blue;
 Styled text #1: NO STYLES DEFINED
-console-format-style.js:19 www.google.com
-onload @ console-format-style.js:19
-(anonymous) @ console-format-style.js:22
+console-format-style.js:22 www.google.com
+onload @ console-format-style.js:22
+(anonymous) @ console-format-style.js:25
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: blue; background: blue;
 Styled text #1: NO STYLES DEFINED
-console-format-style.js:20 12345678
+console-format-style.js:23 12345678
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-black);
 Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-red);
 Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-darkgray);
@@ -32,7 +32,7 @@
 Styled text #5: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-lightred); background-color: var(--console-color-red);
 Styled text #6: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-lightred); background-color: var(--console-color-darkgray);
 Styled text #7: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-lightred); background-color: var(--console-color-lightred);
-console-format-style.js:21 11.1a22.2b33.3
+console-format-style.js:24 11.1a22.2b33.3
 Styled text #0: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-black);
 Styled text #1: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-red);
 Styled text #2: contain: paint; display: inline-block; max-width: 100%; color: var(--console-color-darkgray);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style.js
index 7779f506..2e49425 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-style.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-style.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that console logging dumps properly styled messages.\n');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-table-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-format-table-expected.txt
index c697e9b..1f78d299 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-table-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-table-expected.txt
@@ -1,11 +1,11 @@
 Tests console.table.
 
-console-format-table.js:11 null
-console-format-table.js:13 Array of arrays
+console-format-table.js:14 null
+console-format-table.js:16 Array of arrays
 HEADER (index) | 0 | 1 | 2 | 
 ROW 1 | 2 | 3 | 
 ROW 4 | 5 | 6 | 
-console-format-table.js:16 Large array of arrays
+console-format-table.js:19 Large array of arrays
 HEADER (index) | 0 | 1 | 2 | 
 ROW 1 | 2 | 3 | 
 ROW 4 | 5 | 6 | 
@@ -15,56 +15,56 @@
 ROW 4 | 5 | 6 | 
 ROW 1 | 2 | 3 | 
 ROW 4 | 5 | 6 | 
-console-format-table.js:19 Array or array and object
+console-format-table.js:22 Array or array and object
 HEADER (index) | 0 | 1 | 2 | a | b | c | 
 ROW 1 | 2 | 3 | 
 ROW 1 | 2 | 3 | 
-console-format-table.js:22 Object table
+console-format-table.js:25 Object table
 HEADER (index) | a | b | 
 ROW 1 | 2 | 
 ROW 3 | 4 | 
-console-format-table.js:25 Null as columns
+console-format-table.js:28 Null as columns
 HEADER (index) | 0 | 1 | 2 | 
 ROW 1 | 2 | 3 | 
 ROW 4 | 5 | 6 | 
-console-format-table.js:28 Digit as columns
+console-format-table.js:31 Digit as columns
 HEADER (index) | 0 | 1 | 2 | 
 ROW 1 | 2 | 3 | 
 ROW 4 | 5 | 6 | 
-console-format-table.js:31 String as columns
+console-format-table.js:34 String as columns
 HEADER (index) | 0 | 
 ROW 1 | 
 ROW 4 | 
-console-format-table.js:34 Random string as columns
+console-format-table.js:37 Random string as columns
 HEADER (index) | Value | 
 ROW Array(3) | 
 ROW Array(3) | 
-console-format-table.js:37 Array of strings as columns
+console-format-table.js:40 Array of strings as columns
 HEADER (index) | a | b | 
 ROW 1 | 2 | 
 ROW 'foo' | 'bar' | 
-console-format-table.js:40 Good and bad column names
+console-format-table.js:43 Good and bad column names
 HEADER (index) | a | b | 
 ROW 1 | 2 | 
 ROW 'foo' | 
-console-format-table.js:43 Missing column name
+console-format-table.js:46 Missing column name
 HEADER (index) | Value | 
 ROW {…} | 
 ROW {…} | 
-console-format-table.js:46 Shallow array
+console-format-table.js:49 Shallow array
 HEADER (index) | Value | 
 ROW 1 | 
 ROW 'foo' | 
 ROW null | 
-console-format-table.js:49 Shallow array with 'Value' column
+console-format-table.js:52 Shallow array with 'Value' column
 HEADER (index) | Value | Value | 
 ROW 1 | 
 ROW 2 | 
-console-format-table.js:52 Deep and shallow array
+console-format-table.js:55 Deep and shallow array
 HEADER (index) | Value | 0 | 
 ROW 1 | 
 ROW 'foo' | 
 ROW 2 | 
-console-format-table.js:55 Non-standard call should use fallback
-console-format-table.js:56 foo (3) [1, 2, 3]
+console-format-table.js:58 Non-standard call should use fallback
+console-format-table.js:59 foo (3) [1, 2, 3]
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-format-table.js b/third_party/blink/web_tests/http/tests/devtools/console/console-format-table.js
index 26d62a2..010c32f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-format-table.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-format-table.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console.table.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       console.table();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-functions-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-functions-expected.txt
index 49c3d1f..2989729 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-functions-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-functions-expected.txt
@@ -1,106 +1,106 @@
 Tests that console logging different types of functions correctly.
 
-console-functions.js:27 ƒ simple() {}
-console-functions.js:28 ƒ simple()
+console-functions.js:30 ƒ simple() {}
+console-functions.js:31 ƒ simple()
     arguments: null
     caller: null
     length: 0
     name: "simple"
     prototype: {constructor: ƒ}
-    [[FunctionLocation]]: console-functions.js:13
+    [[FunctionLocation]]: console-functions.js:16
     [[Prototype]]: ƒ ()
     [[Scopes]]: Scopes[1]
-console-functions.js:27 async ƒ asyncSimple() {}
-console-functions.js:28 async ƒ asyncSimple()
+console-functions.js:30 async ƒ asyncSimple() {}
+console-functions.js:31 async ƒ asyncSimple()
     length: 0
     name: "asyncSimple"
     arguments: (...)
     caller: (...)
-    [[FunctionLocation]]: console-functions.js:14
+    [[FunctionLocation]]: console-functions.js:17
     [[Prototype]]: AsyncFunction
     [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ* genSimple() {}
-console-functions.js:28 ƒ* genSimple()
+console-functions.js:30 ƒ* genSimple() {}
+console-functions.js:31 ƒ* genSimple()
     length: 0
     name: "genSimple"
     prototype: Generator {}
     arguments: (...)
     caller: (...)
-    [[FunctionLocation]]: console-functions.js:15
+    [[FunctionLocation]]: console-functions.js:18
     [[IsGenerator]]: true
     [[Prototype]]: GeneratorFunction
     [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ (){}
-console-functions.js:28 ƒ anonymous()
+console-functions.js:30 ƒ (){}
+console-functions.js:31 ƒ anonymous()
     arguments: null
     caller: null
     length: 0
     name: ""
     prototype: {constructor: ƒ}
-    [[FunctionLocation]]: console-functions.js:16
-    [[Prototype]]: ƒ ()
-    [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ (x, y){}
-console-functions.js:28 ƒ anonymous(x, y)
-    arguments: null
-    caller: null
-    length: 2
-    name: ""
-    prototype: {constructor: ƒ}
-    [[FunctionLocation]]: console-functions.js:17
-    [[Prototype]]: ƒ ()
-    [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ namedArgs(x) {}
-console-functions.js:28 ƒ namedArgs(x)
-    arguments: null
-    caller: null
-    length: 1
-    name: "namedArgs"
-    prototype: {constructor: ƒ}
-    [[FunctionLocation]]: console-functions.js:18
-    [[Prototype]]: ƒ ()
-    [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ namedArgs2(x, y) {}
-console-functions.js:28 ƒ namedArgs2(x, y)
-    arguments: null
-    caller: null
-    length: 2
-    name: "namedArgs2"
-    prototype: {constructor: ƒ}
     [[FunctionLocation]]: console-functions.js:19
     [[Prototype]]: ƒ ()
     [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ ({}) {}
-console-functions.js:28 ƒ anonymous({})
+console-functions.js:30 ƒ (x, y){}
+console-functions.js:31 ƒ anonymous(x, y)
     arguments: null
     caller: null
-    length: 1
+    length: 2
     name: ""
     prototype: {constructor: ƒ}
     [[FunctionLocation]]: console-functions.js:20
     [[Prototype]]: ƒ ()
     [[Scopes]]: Scopes[1]
-console-functions.js:27 ƒ *    whitespace   (  x  )    {   }
-console-functions.js:28 ƒ *    whitespace(  x  )
+console-functions.js:30 ƒ namedArgs(x) {}
+console-functions.js:31 ƒ namedArgs(x)
+    arguments: null
+    caller: null
+    length: 1
+    name: "namedArgs"
+    prototype: {constructor: ƒ}
+    [[FunctionLocation]]: console-functions.js:21
+    [[Prototype]]: ƒ ()
+    [[Scopes]]: Scopes[1]
+console-functions.js:30 ƒ namedArgs2(x, y) {}
+console-functions.js:31 ƒ namedArgs2(x, y)
+    arguments: null
+    caller: null
+    length: 2
+    name: "namedArgs2"
+    prototype: {constructor: ƒ}
+    [[FunctionLocation]]: console-functions.js:22
+    [[Prototype]]: ƒ ()
+    [[Scopes]]: Scopes[1]
+console-functions.js:30 ƒ ({}) {}
+console-functions.js:31 ƒ anonymous({})
+    arguments: null
+    caller: null
+    length: 1
+    name: ""
+    prototype: {constructor: ƒ}
+    [[FunctionLocation]]: console-functions.js:23
+    [[Prototype]]: ƒ ()
+    [[Scopes]]: Scopes[1]
+console-functions.js:30 ƒ *    whitespace   (  x  )    {   }
+console-functions.js:31 ƒ *    whitespace(  x  )
     length: 1
     name: "whitespace"
     prototype: Generator {}
     arguments: (...)
     caller: (...)
-    [[FunctionLocation]]: console-functions.js:21
+    [[FunctionLocation]]: console-functions.js:24
     [[IsGenerator]]: true
     [[Prototype]]: GeneratorFunction
     [[Scopes]]: Scopes[1]
-console-functions.js:27 async ƒ whitespace2   (  x  ,  y  ,  z  )    {   }
-console-functions.js:28 async ƒ whitespace2(  x  ,  y  ,  z  )
+console-functions.js:30 async ƒ whitespace2   (  x  ,  y  ,  z  )    {   }
+console-functions.js:31 async ƒ whitespace2(  x  ,  y  ,  z  )
     length: 3
     name: "whitespace2"
     arguments: (...)
     caller: (...)
-    [[FunctionLocation]]: console-functions.js:22
+    [[FunctionLocation]]: console-functions.js:25
     [[Prototype]]: AsyncFunction
     [[Scopes]]: Scopes[1]
-console-functions.js:31 {func0: ƒ, func1: ƒ, func2: ƒ, func3: ƒ, func4: ƒ, …}
+console-functions.js:34 {func0: ƒ, func1: ƒ, func2: ƒ, func3: ƒ, func4: ƒ, …}
     func0: ƒ simple()
     func1: async ƒ asyncSimple()
     func2: ƒ* genSimple()
@@ -112,7 +112,7 @@
     func8: ƒ *    whitespace(  x  )
     func9: async ƒ whitespace2(  x  ,  y  ,  z  )
     [[Prototype]]: Object
-console-functions.js:32 Object
+console-functions.js:35 Object
     func0: ƒ simple()
     func1: async ƒ asyncSimple()
     func2: ƒ* genSimple()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-functions.js b/third_party/blink/web_tests/http/tests/devtools/console/console-functions.js
index 5845d0f0..4bda8ed7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-functions.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-functions.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging different types of functions correctly.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-group-click-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-group-click-expected.txt
index 324d1c1..36bd234 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-group-click-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-group-click-expected.txt
@@ -2,13 +2,13 @@
 
 
 Before
-console-group-click.js:12 group with object {x: 1}
+console-group-click.js:15 group with object {x: 1}
 
 Click on the group
-console-group-click.js:12 group with object {x: 1}
-console-group-click.js:13 Message inside group
+console-group-click.js:15 group with object {x: 1}
+console-group-click.js:16 Message inside group
 
 Click on the object
-console-group-click.js:12 group with object {x: 1}x: 1[[Prototype]]: Object
-console-group-click.js:13 Message inside group
+console-group-click.js:15 group with object {x: 1}x: 1[[Prototype]]: Object
+console-group-click.js:16 Message inside group
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-group-click.js b/third_party/blink/web_tests/http/tests/devtools/console/console-group-click.js
index 08a12ad..5e67f5be 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-group-click.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-group-click.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that clicks on console.group target the appropriate element.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-group-similar.js b/third_party/blink/web_tests/http/tests/devtools/console/console-group-similar.js
index 621b3ee..46f071c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-group-similar.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-group-similar.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console correctly groups similar messages.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   // Show all messages, including verbose.
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-history-contains-requested-text.js b/third_party/blink/web_tests/http/tests/devtools/console/console-history-contains-requested-text.js
index cce8ad7..1620ee4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-history-contains-requested-text.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-history-contains-requested-text.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that expression which is evaluated as Object Literal, is correctly stored in console history. (crbug.com/584881)\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('{a:1, b:2}', step2);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-last-result.js b/third_party/blink/web_tests/http/tests/devtools/console/console-last-result.js
index 583b1ec..2f5f6552 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-last-result.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-last-result.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console exposes last evaluation result as $_.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet.js b/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet.js
index bf12fc83..5cc52cb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-link-to-snippet.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that link to snippet works.\n`);
 
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   TestRunner.addSniffer(
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
index b71b29d..942f846 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
@@ -1,7 +1,7 @@
 Test that console.log() would linkify its location in respect with ignore-listing.
 
-foo.js:13 
-boo.js:20 
-console-linkify-message-location.js:25 
-foo.js:13 
+foo.js:16 
+boo.js:23 
+console-linkify-message-location.js:28 
+foo.js:16 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
index 0cf4e95..d1927b9b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that console.log() would linkify its location in respect with ignore-listing.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function foo()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links-expected.txt
index 3558765..1a5856f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links-expected.txt
@@ -1,6 +1,6 @@
 Test that logging an error in console would linkify relative URLs
 
-console-linkify-relative-links.js:10 Error with relative links
+console-linkify-relative-links.js:13 Error with relative links
     at (foo1.js:10:50)
     at (foo2.js:10:50)
     at (:8000/foo3.js:10:50)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links.js b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links.js
index 0b5cfd94f..8dfc8a9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-relative-links.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that logging an error in console would linkify relative URLs\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
 console.log(\`Error with relative links
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-links-on-messages-before-inspection.js b/third_party/blink/web_tests/http/tests/devtools/console/console-links-on-messages-before-inspection.js
index 4d15dcee..ee1130a9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-links-on-messages-before-inspection.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-links-on-messages-before-inspection.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests a handling of a click on the link in a message, which had been shown before its originating script was added.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open-expected.txt
index 06f2d5853..4596adc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open-expected.txt
@@ -1,9 +1,9 @@
 Tests that Web Inspector won't crash if some console have been logged by the time it's opening.
 
-console-log-before-inspector-open.js:13 log
-console-log-before-inspector-open.js:14 info
-console-log-before-inspector-open.js:15 warn
-(anonymous) @ console-log-before-inspector-open.js:15
-console-log-before-inspector-open.js:16 error
-(anonymous) @ console-log-before-inspector-open.js:16
+console-log-before-inspector-open.js:16 log
+console-log-before-inspector-open.js:17 info
+console-log-before-inspector-open.js:18 warn
+(anonymous) @ console-log-before-inspector-open.js:18
+console-log-before-inspector-open.js:19 error
+(anonymous) @ console-log-before-inspector-open.js:19
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open.js
index ab96d63..d441740 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-before-inspector-open.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that Web Inspector won't crash if some console have been logged by the time it's opening.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements-expected.txt
index e5892e6..f4baf46 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements-expected.txt
@@ -1,4 +1,4 @@
 Tests that logging custom elements uses proper formatting.
 
-console-log-custom-elements.js:19 foo-bar
+console-log-custom-elements.js:22 foo-bar
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements.js
index 556a578..eb1680c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-custom-elements.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that logging custom elements uses proper formatting.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
     <foo-bar></foo-bar>
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto-expected.txt
index f9b6e26..393c672 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto-expected.txt
@@ -1,4 +1,4 @@
 Test that console.dir(document.__proto__) won't result in an exception when the message is formatted in the inspector.Bug 27169.
 
-console-log-document-proto.js:14 HTMLDocument
+console-log-document-proto.js:17 HTMLDocument
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto.js
index 773f6bb..f4a1b61 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-document-proto.js
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
     `Test that console.dir(document.__proto__) won't result in an exception when the message is formatted in the inspector.Bug 27169.\n`
   );
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt
index c0c1fe6..2ce9f4a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error-expected.txt
@@ -1,13 +1,13 @@
 Tests that syntax errors in eval are logged into console, contains correct link and doesn't cause browser crash.
 
 VM:1 Uncaught SyntaxError: Unexpected token '}'
-    at foo (<anonymous>:13:11)
-foo @ VM:13
-setTimeout (async)
-(anonymous) @ console-log-eval-syntax-error.js:21
-boo.js:2 Uncaught SyntaxError: Unexpected token '}' (at boo.js:2:1)
-    at boo (<anonymous>:17:11)
-boo @ VM:17
+    at foo (<anonymous>:16:11)
+foo @ VM:16
 setTimeout (async)
 (anonymous) @ console-log-eval-syntax-error.js:24
+boo.js:2 Uncaught SyntaxError: Unexpected token '}' (at boo.js:2:1)
+    at boo (<anonymous>:20:11)
+boo @ VM:20
+setTimeout (async)
+(anonymous) @ console-log-eval-syntax-error.js:27
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error.js
index 580cb47..a986c20 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-eval-syntax-error.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that syntax errors in eval are logged into console, contains correct link and doesn't cause browser crash.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function foo()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-in-xhtml.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-in-xhtml.js
index b75f352..666ddcf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-in-xhtml.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-in-xhtml.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that console message from inline script in xhtml document contains correct script position information.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.navigatePromise('resources/console-log-in-xhtml.xhtml');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js
index 39c55559..ee39ee3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that console.log() would linkify the links. Bug 231074.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.loadLegacyModule('components');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt
index 9569b54..6264e21 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors-expected.txt
@@ -3,62 +3,62 @@
 foob.js:5 Error: Some test
     at namedFunction (foob.js:5:17)
     at foob.js:8:1
-console-log-linkify-…ack-in-errors.js:15 Error: line
+console-log-linkify-…ack-in-errors.js:18 Error: line
 break
-    at forStack (console-log-linkify-…-in-errors.js:15:23)
-    at console-log-linkify-…k-in-errors.js:18:7
-console-log-linkify-…ack-in-errors.js:34 Error: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
-    at domError (console-log-linkify-…-in-errors.js:32:29)
-    at console-log-linkify-…k-in-errors.js:38:7
-console-log-linkify-…ack-in-errors.js:45 Error: some error
-    at logError (console-log-linkify-…-in-errors.js:43:21)
-    at console-log-linkify-…k-in-errors.js:49:7
-console-log-linkify-…ack-in-errors.js:51 Error message without stacks http://www.chromium.org/
-console-log-linkify-…ack-in-errors.js:53 Error valid stack #2
+    at forStack (console-log-linkify-…-in-errors.js:18:23)
+    at console-log-linkify-…k-in-errors.js:21:7
+console-log-linkify-…ack-in-errors.js:37 Error: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+    at domError (console-log-linkify-…-in-errors.js:35:29)
+    at console-log-linkify-…k-in-errors.js:41:7
+console-log-linkify-…ack-in-errors.js:48 Error: some error
+    at logError (console-log-linkify-…-in-errors.js:46:21)
+    at console-log-linkify-…k-in-errors.js:52:7
+console-log-linkify-…ack-in-errors.js:54 Error message without stacks http://www.chromium.org/
+console-log-linkify-…ack-in-errors.js:56 Error valid stack #2
     at www.chromium.org/boo.js:40:70
     at foo(www.chromium.org/foo.js:10:50)
-console-log-linkify-…ack-in-errors.js:54 Error valid stack #3
+console-log-linkify-…ack-in-errors.js:57 Error valid stack #3
     at www.chromium.org/foo.js:40
-console-log-linkify-…ack-in-errors.js:55 Error: MyError
+console-log-linkify-…ack-in-errors.js:58 Error: MyError
     at throwError (www.chromium.org/foo.js:40)
     at eval (eval at <anonymous> (www.chromium.org/foo.js:42:1), <anonymous>:1:1)
     at www.chromium.org/foo.js:239
-console-log-linkify-…ack-in-errors.js:24 ReferenceError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
-    at console-log-linkify-…k-in-errors.js:57:7
-console-log-linkify-…ack-in-errors.js:24 EvalError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
-    at console-log-linkify-…k-in-errors.js:58:7
-console-log-linkify-…ack-in-errors.js:24 SyntaxError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
-    at console-log-linkify-…k-in-errors.js:59:7
-console-log-linkify-…ack-in-errors.js:24 RangeError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
+console-log-linkify-…ack-in-errors.js:27 ReferenceError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
     at console-log-linkify-…k-in-errors.js:60:7
-console-log-linkify-…ack-in-errors.js:24 TypeError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
+console-log-linkify-…ack-in-errors.js:27 EvalError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
     at console-log-linkify-…k-in-errors.js:61:7
-console-log-linkify-…ack-in-errors.js:24 URIError: valid stack
-    at stack2 (console-log-linkify-…-in-errors.js:24:27)
-    at stack1 (console-log-linkify-…-in-errors.js:26:11)
+console-log-linkify-…ack-in-errors.js:27 SyntaxError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
     at console-log-linkify-…k-in-errors.js:62:7
-console-log-linkify-…ack-in-errors.js:64 Error broken stack
+console-log-linkify-…ack-in-errors.js:27 RangeError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
+    at console-log-linkify-…k-in-errors.js:63:7
+console-log-linkify-…ack-in-errors.js:27 TypeError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
+    at console-log-linkify-…k-in-errors.js:64:7
+console-log-linkify-…ack-in-errors.js:27 URIError: valid stack
+    at stack2 (console-log-linkify-…-in-errors.js:27:27)
+    at stack1 (console-log-linkify-…-in-errors.js:29:11)
+    at console-log-linkify-…k-in-errors.js:65:7
+console-log-linkify-…ack-in-errors.js:67 Error broken stack
     at function_name(foob.js foob.js:30:1)
  at foob.js:40:70
-console-log-linkify-…ack-in-errors.js:65 Error broken stack #2
+console-log-linkify-…ack-in-errors.js:68 Error broken stack #2
     at function_name(foob.js:20:30
-console-log-linkify-…ack-in-errors.js:66 Error broken stack #3
+console-log-linkify-…ack-in-errors.js:69 Error broken stack #3
     at function_name(foob:20.js:30   bla
-console-log-linkify-…ack-in-errors.js:67 Error broken stack #4
+console-log-linkify-…ack-in-errors.js:70 Error broken stack #4
     at function_name)foob.js:20:30(
-console-log-linkify-…ack-in-errors.js:68 Error broken stack #5
+console-log-linkify-…ack-in-errors.js:71 Error broken stack #5
     at function_name foob.js:20:30)
-console-log-linkify-…ack-in-errors.js:69 Error broken stack #6
+console-log-linkify-…ack-in-errors.js:72 Error broken stack #6
     at foob.js foob.js:40:70
 stack-with-sourceMap.coffee:2 Error
     at window.letsFailWithStack (stack-with-sourceMap.coffee:2:18)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors.js
index 03e2358..342d265 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-stack-in-errors.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Test that console.log(new Error().stack) would linkify links in stacks for sourceUrls and sourceMaps Bug 424001.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.addScriptTag('resources/stack-with-sourceUrl.js');
   await TestRunner.addScriptTag('resources/stack-with-sourceMap.js');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter-expected.txt
index b4879ae..11c222c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter-expected.txt
@@ -1,9 +1,9 @@
 Tests that console logging dumps object values defined by getters and allows to expand it.
 
-console-log-object-with-getter.js:30 {}
-console-log-object-with-getter.js:31 (2) [(...), empty]
-console-log-object-with-getter.js:32 {}
-console-log-object-with-getter.js:30 {}foo: Objectget foo: ƒ ()set bar: ƒ (x)[[Prototype]]: Object
-console-log-object-with-getter.js:31 (2) [(...), empty]0: 1length: 2get 0: ƒ ()set 1: ƒ (x)[[Prototype]]: Array(0)
-console-log-object-with-getter.js:32 {}error: [Exception: custom stack]function: [Exception: ƒ ()]number: [Exception: 123]string: [Exception: "myString"]get error: ƒ error()get function: ƒ ()get number: ƒ number()get string: ƒ string()[[Prototype]]: Object
+console-log-object-with-getter.js:33 {}
+console-log-object-with-getter.js:34 (2) [(...), empty]
+console-log-object-with-getter.js:35 {}
+console-log-object-with-getter.js:33 {}foo: Objectget foo: ƒ ()set bar: ƒ (x)[[Prototype]]: Object
+console-log-object-with-getter.js:34 (2) [(...), empty]0: 1length: 2get 0: ƒ ()set 1: ƒ (x)[[Prototype]]: Array(0)
+console-log-object-with-getter.js:35 {}error: [Exception: custom stack]function: [Exception: ƒ ()]number: [Exception: 123]string: [Exception: "myString"]get error: ƒ error()get function: ƒ ()get number: ƒ number()get string: ƒ string()[[Prototype]]: Object
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter.js
index 55b7f17..bfbe656 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-object-with-getter.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging dumps object values defined by getters and allows to expand it.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     var obj = {}
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method-expected.txt
index ab62cf4..ab3c29af 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method-expected.txt
@@ -1,6 +1,6 @@
 Tests that Web Inspector won't crash if some console have been logged by the time it's opening.
 
-console-log-short-hand-method.js:24 {foo: ƒ, boo: ƒ, gen: ƒ}
+console-log-short-hand-method.js:27 {foo: ƒ, boo: ƒ, gen: ƒ}
     baz: (...)
     boo: ƒ (c,d)
     foo: ƒ foo(a,b)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method.js
index d3ccc46..f960ef1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-short-hand-method.js
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that Web Inspector won't crash if some console have been logged by the time it's opening.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
index 745d43b..f8ca493 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
@@ -1,35 +1,35 @@
 Tests various extreme usages of console.log()
 
-console-log-side-effects.js:24 string
-console-log-side-effects.js:25 42
-console-log-side-effects.js:26 false
-console-log-side-effects.js:27 undefined
-console-log-side-effects.js:28 null
-console-log-side-effects.js:29 NaN
-console-log-side-effects.js:30 -Infinity
-console-log-side-effects.js:31 -0
-console-log-side-effects.js:32 Number {42}
-console-log-side-effects.js:33 Number {-4.242e-11}
-console-log-side-effects.js:34 Boolean {true}
-console-log-side-effects.js:35 String {'foo'}
-console-log-side-effects.js:36 {}
-console-log-side-effects.js:37 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
-console-log-side-effects.js:43 
-console-log-side-effects.js:47 {foo: 1, bar: 2}
-console-log-side-effects.js:48 (3) [1, 2, 3]
-console-log-side-effects.js:50 Uint32Array(3) [1, 2, 3, buffer: ArrayBuffer(12), byteLength: 12, byteOffset: 0, length: 3, Symbol(Symbol.toStringTag): 'Uint32Array']
-console-log-side-effects.js:53 (4) [1, 2, 3, {…}]
-console-log-side-effects.js:56 {toString: ƒ}
-console-log-side-effects.js:59 (5) [1, 2, 3, {…}, {…}]
-console-log-side-effects.js:70 (3) [Array(1), Array(1), Array(3)]
-console-log-side-effects.js:79 {toString: ƒ}
-console-log-side-effects.js:82 (6) [1, 2, 3, {…}, {…}, {…}]
-console-log-side-effects.js:88 (100001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000]
-console-log-side-effects.js:88 (1000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000]
-console-log-side-effects.js:88 (10000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000]
-console-log-side-effects.js:88 (100000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000]
-console-log-side-effects.js:88 (1000000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000, empty × 899999999, 1000000000]
-console-log-side-effects.js:91 (4294967295) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000, empty × 899999999, 1000000000, empty × 3294967293, Array(3)]
-console-log-side-effects.js:98 (10001) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …]
-console-log-side-effects.js:104 [Array(1)]
+console-log-side-effects.js:27 string
+console-log-side-effects.js:28 42
+console-log-side-effects.js:29 false
+console-log-side-effects.js:30 undefined
+console-log-side-effects.js:31 null
+console-log-side-effects.js:32 NaN
+console-log-side-effects.js:33 -Infinity
+console-log-side-effects.js:34 -0
+console-log-side-effects.js:35 Number {42}
+console-log-side-effects.js:36 Number {-4.242e-11}
+console-log-side-effects.js:37 Boolean {true}
+console-log-side-effects.js:38 String {'foo'}
+console-log-side-effects.js:39 {}
+console-log-side-effects.js:40 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
+console-log-side-effects.js:46 
+console-log-side-effects.js:50 {foo: 1, bar: 2}
+console-log-side-effects.js:51 (3) [1, 2, 3]
+console-log-side-effects.js:53 Uint32Array(3) [1, 2, 3, buffer: ArrayBuffer(12), byteLength: 12, byteOffset: 0, length: 3, Symbol(Symbol.toStringTag): 'Uint32Array']
+console-log-side-effects.js:56 (4) [1, 2, 3, {…}]
+console-log-side-effects.js:59 {toString: ƒ}
+console-log-side-effects.js:62 (5) [1, 2, 3, {…}, {…}]
+console-log-side-effects.js:73 (3) [Array(1), Array(1), Array(3)]
+console-log-side-effects.js:82 {toString: ƒ}
+console-log-side-effects.js:85 (6) [1, 2, 3, {…}, {…}, {…}]
+console-log-side-effects.js:91 (100001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000]
+console-log-side-effects.js:91 (1000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000]
+console-log-side-effects.js:91 (10000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000]
+console-log-side-effects.js:91 (100000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000]
+console-log-side-effects.js:91 (1000000001) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000, empty × 899999999, 1000000000]
+console-log-side-effects.js:94 (4294967295) [1, 2, 3, {…}, {…}, {…}, empty × 99994, 100000, empty × 899999, 1000000, empty × 8999999, 10000000, empty × 89999999, 100000000, empty × 899999999, 1000000000, empty × 3294967293, Array(3)]
+console-log-side-effects.js:101 (10001) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …]
+console-log-side-effects.js:107 [Array(1)]
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects.js
index fbbd200..30913b9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests various extreme usages of console.log()\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
       <p id="node">
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error.js
index bf0355f..3705eb8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-syntax-error.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that syntax errors are logged into console and doesn't cause browser crash.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.addScriptTag('resources/syntax-error.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-toString-object.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-toString-object.js
index 2ff8afe9..f976c56 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-toString-object.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-toString-object.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that passing an object which throws on string conversion into console.log won't crash inspected Page. The test passes if it doesn't crash. Bug 57557\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.navigatePromise('resources/console-log-toString-object.html');
   await TestRunner.reloadPagePromise();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console-expected.txt
index bc9c65e..62bd363 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console-expected.txt
@@ -1,9 +1,9 @@
 Test that console.log can be called without console receiver.
 
-console-log-without-console.js:12 1
-console-log-without-console.js:14 2
-console-log-without-console.js:16 3
-(anonymous) @ console-log-without-console.js:16
-console-log-without-console.js:18 4
-(anonymous) @ console-log-without-console.js:18
+console-log-without-console.js:15 1
+console-log-without-console.js:17 2
+console-log-without-console.js:19 3
+(anonymous) @ console-log-without-console.js:19
+console-log-without-console.js:21 4
+(anonymous) @ console-log-without-console.js:21
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console.js
index a8d2575..565bfdc9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-without-console.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that console.log can be called without console receiver.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     var log = console.log;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
index a72352f..0063236 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
@@ -1,5 +1,5 @@
 Tests console.log() anchor location when the skip-stack-frames feature is enabled.
 
-console-log-wrapped-in-framework.js:13 direct console.log()
-console-log-wrapped-in-framework.js:14 framework log
+console-log-wrapped-in-framework.js:16 direct console.log()
+console-log-wrapped-in-framework.js:17 framework log
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
index b8424bf8..2cabc2b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console.log() anchor location when the skip-stack-frames feature is enabled.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.addScriptTag('resources/framework.js');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-memory-equals-console-memory.js b/third_party/blink/web_tests/http/tests/devtools/console/console-memory-equals-console-memory.js
index ead206bd..817c770 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-memory-equals-console-memory.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-memory-equals-console-memory.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console.memory returns fresh instance/samples.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('console.memory === console.memory', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack-expected.txt
index 6b4e2f8..3ef4345 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack-expected.txt
@@ -2,5 +2,5 @@
 
 VM:1 Uncaught SyntaxError: Unexpected end of input
 setTimeout (async)
-(anonymous) @ console-message-cont…s-async-stack.js:14
+(anonymous) @ console-message-cont…s-async-stack.js:17
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack.js b/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack.js
index 56d72525..19ab690 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-contains-async-stack.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests exception message with empty stack in console contains async stack trace.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.DebuggerAgent.setAsyncCallStackDepth(200);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-format-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-message-format-expected.txt
index d8b7f94..81f5533 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-format-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-format-expected.txt
@@ -1,14 +1,14 @@
 Tests that console logging uses proper message formatting.
 
-console-message-format.js:11 Message format number 1, 2 and 3.5
-console-message-format.js:12 Message format for string
-console-message-format.js:13 Object {foo: 'bar'}
-console-message-format.js:14 Array (2) ['foo', 'bar']
-console-message-format.js:15 Object as object: Object
-console-message-format.js:16 Array as object: Array(2)
-console-message-format.js:17 Floating as integers: 42 42
-console-message-format.js:18 Floating as is: 42.5
-console-message-format.js:19 Non-numbers as numbers: NaN NaN NaN
-console-message-format.js:20 String as is: string
-console-message-format.js:21 Object as string: [object HTMLDocument]
+console-message-format.js:14 Message format number 1, 2 and 3.5
+console-message-format.js:15 Message format for string
+console-message-format.js:16 Object {foo: 'bar'}
+console-message-format.js:17 Array (2) ['foo', 'bar']
+console-message-format.js:18 Object as object: Object
+console-message-format.js:19 Array as object: Array(2)
+console-message-format.js:20 Floating as integers: 42 42
+console-message-format.js:21 Floating as is: 42.5
+console-message-format.js:22 Non-numbers as numbers: NaN NaN NaN
+console-message-format.js:23 String as is: string
+console-message-format.js:24 Object as string: [object HTMLDocument]
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-format.js b/third_party/blink/web_tests/http/tests/devtools/console/console-message-format.js
index ded15269..05c69d5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-format.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-format.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging uses proper message formatting.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     console.log('Message format number %i, %d and %f', 1, 2, 3.5);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt
index 176e8a1..dc4b27c56b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url-expected.txt
@@ -1,9 +1,9 @@
 Tests that log message and syntax errors from inline scripts with sourceURL are logged into console, contains correct link and doesn't cause browser crash.
 
-foo.js:13 foo
+foo.js:16 foo
 boo.js:1 Uncaught SyntaxError: Unexpected token '}' (at boo.js:1:1)
-    at addInlineWithSyntaxError (foo.js:21:30)
-addInlineWithSyntaxError @ foo.js:21
+    at addInlineWithSyntaxError (foo.js:24:30)
+addInlineWithSyntaxError @ foo.js:24
 setTimeout (async)
-(anonymous) @ console-message-from…line-with-url.js:29
+(anonymous) @ console-message-from…line-with-url.js:32
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url.js b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url.js
index 5a6f261..e0cbd3cc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-inline-with-url.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that log message and syntax errors from inline scripts with sourceURL are logged into console, contains correct link and doesn't cause browser crash.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function foo()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-script-inside-svg.js b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-script-inside-svg.js
index 2dc857d..b6fa7053 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-script-inside-svg.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-message-from-script-inside-svg.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
     `Tests that message from script inside svg has correct source location.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.navigatePromise('resources/svg.html');
   await ConsoleTestRunner.dumpConsoleMessages();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-native-function.js b/third_party/blink/web_tests/http/tests/devtools/console/console-native-function.js
index 11c6a61..8b9ff11 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-native-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-native-function.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console dumps native function without exception.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('Math.random', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group-expected.txt
index 9d8c152..2b1913e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group-expected.txt
@@ -1,11 +1,11 @@
 Tests that console.group/groupEnd messages won't be coalesced. Bug 56114. Bug 63521.
 
-console-nested-group.js:12 outer group console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-nested-group.js:13 inner group console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-nested-group.js:14 Message inside inner group console-message-wrapper console-from-api console-info-level > console-message
-console-nested-group.js:17 Message that must not be in any group console-message-wrapper console-from-api console-info-level > console-message
-console-nested-group.js:22 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-nested-group.js:22 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-nested-group.js:22 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-nested-group.js:24 Message inside third group console-message-wrapper console-from-api console-info-level > console-message
+console-nested-group.js:15 outer group console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-nested-group.js:16 inner group console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-nested-group.js:17 Message inside inner group console-message-wrapper console-from-api console-info-level > console-message
+console-nested-group.js:20 Message that must not be in any group console-message-wrapper console-from-api console-info-level > console-message
+console-nested-group.js:25 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-nested-group.js:25 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-nested-group.js:25 One of several groups which shouldn't be coalesced. console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-nested-group.js:27 Message inside third group console-message-wrapper console-from-api console-info-level > console-message
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group.js b/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group.js
index b3fcb39..ff10b8d1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-nested-group.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console.group/groupEnd messages won't be coalesced. Bug 56114. Bug 63521.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name-expected.txt
index cbb4b78..6183c79 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name-expected.txt
@@ -1,6 +1,6 @@
 Tests that the name of the function invoked as object constructor will be displayed as its type in the front-end. Bug 50063.
 
-console-object-constructor-name.js:17 Parent {}
-console-object-constructor-name.js:18 Child {}
-console-object-constructor-name.js:19 inner {}
+console-object-constructor-name.js:20 Parent {}
+console-object-constructor-name.js:21 Child {}
+console-object-constructor-name.js:22 inner {}
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name.js b/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name.js
index 1b99861..75e2ea4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-object-constructor-name.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that the name of the function invoked as object constructor will be displayed as its type in the front-end. Bug 50063.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview-expected.txt
index 06fb11b4..2b44aeb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview-expected.txt
@@ -1,68 +1,68 @@
 Tests that console produces instant previews for arrays and objects.
 
-console-object-preview.js:10 Mutating object in a loop
-console-object-preview.js:14 {a: 0, b: 0, c: 0}
-console-object-preview.js:14 {a: 0, b: 0, c: 1}
-console-object-preview.js:14 {a: 0, b: 0, c: 2}
-console-object-preview.js:17 Mutating array in a loop
-console-object-preview.js:21 (3) [0, 0, 0]
-console-object-preview.js:21 (3) [0, 0, 1]
-console-object-preview.js:21 (3) [0, 0, 2]
-console-object-preview.js:24 Object with many properties
-console-object-preview.js:29 {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …}
-console-object-preview.js:31 Array with many properties
-console-object-preview.js:36 (2) [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …]
-console-object-preview.js:38 Array with gaps and overflow
-console-object-preview.js:43 (5733) [32: 0, 89: 1, 146: 2, 203: 3, 260: 4, 317: 5, 374: 6, 431: 7, 488: 8, 545: 9, 602: 10, 659: 11, 716: 12, 773: 13, 830: 14, 887: 15, 944: 16, 1001: 17, 1058: 18, 1115: 19, 1172: 20, 1229: 21, 1286: 22, 1343: 23, 1400: 24, 1457: 25, 1514: 26, 1571: 27, 1628: 28, 1685: 29, 1742: 30, 1799: 31, 1856: 32, 1913: 33, 1970: 34, 2027: 35, 2084: 36, 2141: 37, 2198: 38, 2255: 39, 2312: 40, 2369: 41, 2426: 42, 2483: 43, 2540: 44, 2597: 45, 2654: 46, 2711: 47, 2768: 48, 2825: 49, 2882: 50, 2939: 51, 2996: 52, 3053: 53, 3110: 54, 3167: 55, 3224: 56, 3281: 57, 3338: 58, 3395: 59, 3452: 60, 3509: 61, 3566: 62, 3623: 63, 3680: 64, 3737: 65, 3794: 66, 3851: 67, 3908: 68, 3965: 69, 4022: 70, 4079: 71, 4136: 72, 4193: 73, 4250: 74, 4307: 75, 4364: 76, 4421: 77, 4478: 78, 4535: 79, 4592: 80, 4649: 81, 4706: 82, 4763: 83, 4820: 84, 4877: 85, 4934: 86, 4991: 87, 5048: 88, 5105: 89, 5162: 90, 5219: 91, 5276: 92, 5333: 93, 5390: 94, 5447: 95, 5504: 96, 5561: 97, 5618: 98, 5675: 99, …]
-console-object-preview.js:45 Array with gaps without overflow
-console-object-preview.js:50 (5619) [empty × 32, 0, empty × 56, 1, empty × 56, 2, empty × 56, 3, empty × 56, 4, empty × 56, 5, empty × 56, 6, empty × 56, 7, empty × 56, 8, empty × 56, 9, empty × 56, 10, empty × 56, 11, empty × 56, 12, empty × 56, 13, empty × 56, 14, empty × 56, 15, empty × 56, 16, empty × 56, 17, empty × 56, 18, empty × 56, 19, empty × 56, 20, empty × 56, 21, empty × 56, 22, empty × 56, 23, empty × 56, 24, empty × 56, 25, empty × 56, 26, empty × 56, 27, empty × 56, 28, empty × 56, 29, empty × 56, 30, empty × 56, 31, empty × 56, 32, empty × 56, 33, empty × 56, 34, empty × 56, 35, empty × 56, 36, empty × 56, 37, empty × 56, 38, empty × 56, 39, empty × 56, 40, empty × 56, 41, empty × 56, 42, empty × 56, 43, empty × 56, 44, empty × 56, 45, empty × 56, 46, empty × 56, 47, empty × 56, 48, empty × 56, 49, empty × 56, 50, empty × 56, 51, empty × 56, 52, empty × 56, 53, empty × 56, 54, empty × 56, 55, empty × 56, 56, empty × 56, 57, empty × 56, 58, empty × 56, 59, empty × 56, 60, empty × 56, 61, empty
-console-object-preview.js:52 Object with proto
-console-object-preview.js:55 {d: 1}
-console-object-preview.js:57 Sparse array
-console-object-preview.js:60 (150) [empty × 50, 50, empty × 99]
-console-object-preview.js:62 Dense array with indexes and propeties
-console-object-preview.js:68 (150) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …]
-console-object-preview.js:70 Object with properties containing whitespaces
-console-object-preview.js:77 {" a b ": " a b ", c d: "c d", "": "", "  ": "  ", "a↵↵b↵c": "a↵↵b↵c"}
-console-object-preview.js:79 Object with a document.all property
-console-object-preview.js:80 {all: HTMLAllCollection(4)}
-console-object-preview.js:82 Object with special numbers
-console-object-preview.js:84 {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0}
-console-object-preview.js:86 Object with exactly 5 properties: expected to be lossless
-console-object-preview.js:87 {a: 1, b: 2, c: 3, d: 4, e: 5}
-console-object-preview.js:89 {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false}
-console-object-preview.js:96 IHavePrivateProperties {regularProperty: 3, #privateProperty1: 1, #privateProperty2: 2}
+console-object-preview.js:13 Mutating object in a loop
+console-object-preview.js:17 {a: 0, b: 0, c: 0}
+console-object-preview.js:17 {a: 0, b: 0, c: 1}
+console-object-preview.js:17 {a: 0, b: 0, c: 2}
+console-object-preview.js:20 Mutating array in a loop
+console-object-preview.js:24 (3) [0, 0, 0]
+console-object-preview.js:24 (3) [0, 0, 1]
+console-object-preview.js:24 (3) [0, 0, 2]
+console-object-preview.js:27 Object with many properties
+console-object-preview.js:32 {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …}
+console-object-preview.js:34 Array with many properties
+console-object-preview.js:39 (2) [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …]
+console-object-preview.js:41 Array with gaps and overflow
+console-object-preview.js:46 (5733) [32: 0, 89: 1, 146: 2, 203: 3, 260: 4, 317: 5, 374: 6, 431: 7, 488: 8, 545: 9, 602: 10, 659: 11, 716: 12, 773: 13, 830: 14, 887: 15, 944: 16, 1001: 17, 1058: 18, 1115: 19, 1172: 20, 1229: 21, 1286: 22, 1343: 23, 1400: 24, 1457: 25, 1514: 26, 1571: 27, 1628: 28, 1685: 29, 1742: 30, 1799: 31, 1856: 32, 1913: 33, 1970: 34, 2027: 35, 2084: 36, 2141: 37, 2198: 38, 2255: 39, 2312: 40, 2369: 41, 2426: 42, 2483: 43, 2540: 44, 2597: 45, 2654: 46, 2711: 47, 2768: 48, 2825: 49, 2882: 50, 2939: 51, 2996: 52, 3053: 53, 3110: 54, 3167: 55, 3224: 56, 3281: 57, 3338: 58, 3395: 59, 3452: 60, 3509: 61, 3566: 62, 3623: 63, 3680: 64, 3737: 65, 3794: 66, 3851: 67, 3908: 68, 3965: 69, 4022: 70, 4079: 71, 4136: 72, 4193: 73, 4250: 74, 4307: 75, 4364: 76, 4421: 77, 4478: 78, 4535: 79, 4592: 80, 4649: 81, 4706: 82, 4763: 83, 4820: 84, 4877: 85, 4934: 86, 4991: 87, 5048: 88, 5105: 89, 5162: 90, 5219: 91, 5276: 92, 5333: 93, 5390: 94, 5447: 95, 5504: 96, 5561: 97, 5618: 98, 5675: 99, …]
+console-object-preview.js:48 Array with gaps without overflow
+console-object-preview.js:53 (5619) [empty × 32, 0, empty × 56, 1, empty × 56, 2, empty × 56, 3, empty × 56, 4, empty × 56, 5, empty × 56, 6, empty × 56, 7, empty × 56, 8, empty × 56, 9, empty × 56, 10, empty × 56, 11, empty × 56, 12, empty × 56, 13, empty × 56, 14, empty × 56, 15, empty × 56, 16, empty × 56, 17, empty × 56, 18, empty × 56, 19, empty × 56, 20, empty × 56, 21, empty × 56, 22, empty × 56, 23, empty × 56, 24, empty × 56, 25, empty × 56, 26, empty × 56, 27, empty × 56, 28, empty × 56, 29, empty × 56, 30, empty × 56, 31, empty × 56, 32, empty × 56, 33, empty × 56, 34, empty × 56, 35, empty × 56, 36, empty × 56, 37, empty × 56, 38, empty × 56, 39, empty × 56, 40, empty × 56, 41, empty × 56, 42, empty × 56, 43, empty × 56, 44, empty × 56, 45, empty × 56, 46, empty × 56, 47, empty × 56, 48, empty × 56, 49, empty × 56, 50, empty × 56, 51, empty × 56, 52, empty × 56, 53, empty × 56, 54, empty × 56, 55, empty × 56, 56, empty × 56, 57, empty × 56, 58, empty × 56, 59, empty × 56, 60, empty × 56, 61, empty
+console-object-preview.js:55 Object with proto
+console-object-preview.js:58 {d: 1}
+console-object-preview.js:60 Sparse array
+console-object-preview.js:63 (150) [empty × 50, 50, empty × 99]
+console-object-preview.js:65 Dense array with indexes and propeties
+console-object-preview.js:71 (150) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …]
+console-object-preview.js:73 Object with properties containing whitespaces
+console-object-preview.js:80 {" a b ": ' a b ', c d: 'c d', "": '', "  ": '  ', "a↵↵b↵c": 'a\n\nb\nc'}
+console-object-preview.js:82 Object with a document.all property
+console-object-preview.js:83 {all: HTMLAllCollection(4)}
+console-object-preview.js:85 Object with special numbers
+console-object-preview.js:87 {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0}
+console-object-preview.js:89 Object with exactly 5 properties: expected to be lossless
+console-object-preview.js:90 {a: 1, b: 2, c: 3, d: 4, e: 5}
+console-object-preview.js:92 {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false}
+console-object-preview.js:99 IHavePrivateProperties {regularProperty: 3, #privateProperty1: 1, #privateProperty2: 2}
 Expanded all messages
-console-object-preview.js:10 Mutating object in a loop
-console-object-preview.js:14 {a: 0, b: 0, c: 0}a: 0b: 0c: 2__proto__: Object
-console-object-preview.js:14 {a: 0, b: 0, c: 1}a: 0b: 0c: 2__proto__: Object
-console-object-preview.js:14 {a: 0, b: 0, c: 2}a: 0b: 0c: 2__proto__: Object
-console-object-preview.js:17 Mutating array in a loop
-console-object-preview.js:21 (3) [0, 0, 0]0: 01: 02: 2length: 3__proto__: Array(0)
-console-object-preview.js:21 (3) [0, 0, 1]0: 01: 02: 2length: 3__proto__: Array(0)
-console-object-preview.js:21 (3) [0, 0, 2]0: 01: 02: 2length: 3__proto__: Array(0)
-console-object-preview.js:24 Object with many properties
-console-object-preview.js:29 {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …}property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9__proto__: Object
-console-object-preview.js:31 Array with many properties
-console-object-preview.js:36 (2) [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …]0: 01: 1property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9length: 2__proto__: Array(0)
-console-object-preview.js:38 Array with gaps and overflow
-console-object-preview.js:43 (5733) [32: 0, 89: 1, 146: 2, 203: 3, 260: 4, 317: 5, 374: 6, 431: 7, 488: 8, 545: 9, 602: 10, 659: 11, 716: 12, 773: 13, 830: 14, 887: 15, 944: 16, 1001: 17, 1058: 18, 1115: 19, 1172: 20, 1229: 21, 1286: 22, 1343: 23, 1400: 24, 1457: 25, 1514: 26, 1571: 27, 1628: 28, 1685: 29, 1742: 30, 1799: 31, 1856: 32, 1913: 33, 1970: 34, 2027: 35, 2084: 36, 2141: 37, 2198: 38, 2255: 39, 2312: 40, 2369: 41, 2426: 42, 2483: 43, 2540: 44, 2597: 45, 2654: 46, 2711: 47, 2768: 48, 2825: 49, 2882: 50, 2939: 51, 2996: 52, 3053: 53, 3110: 54, 3167: 55, 3224: 56, 3281: 57, 3338: 58, 3395: 59, 3452: 60, 3509: 61, 3566: 62, 3623: 63, 3680: 64, 3737: 65, 3794: 66, 3851: 67, 3908: 68, 3965: 69, 4022: 70, 4079: 71, 4136: 72, 4193: 73, 4250: 74, 4307: 75, 4364: 76, 4421: 77, 4478: 78, 4535: 79, 4592: 80, 4649: 81, 4706: 82, 4763: 83, 4820: 84, 4877: 85, 4934: 86, 4991: 87, 5048: 88, 5105: 89, 5162: 90, 5219: 91, 5276: 92, 5333: 93, 5390: 94, 5447: 95, 5504: 96, 5561: 97, 5618: 98, 5675: 99, …][32 … 5675]573
-console-object-preview.js:45 Array with gaps without overflow
-console-object-preview.js:50 (5619) [empty × 32, 0, empty × 56, 1, empty × 56, 2, empty × 56, 3, empty × 56, 4, empty × 56, 5, empty × 56, 6, empty × 56, 7, empty × 56, 8, empty × 56, 9, empty × 56, 10, empty × 56, 11, empty × 56, 12, empty × 56, 13, empty × 56, 14, empty × 56, 15, empty × 56, 16, empty × 56, 17, empty × 56, 18, empty × 56, 19, empty × 56, 20, empty × 56, 21, empty × 56, 22, empty × 56, 23, empty × 56, 24, empty × 56, 25, empty × 56, 26, empty × 56, 27, empty × 56, 28, empty × 56, 29, empty × 56, 30, empty × 56, 31, empty × 56, 32, empty × 56, 33, empty × 56, 34, empty × 56, 35, empty × 56, 36, empty × 56, 37, empty × 56, 38, empty × 56, 39, empty × 56, 40, empty × 56, 41, empty × 56, 42, empty × 56, 43, empty × 56, 44, empty × 56, 45, empty × 56, 46, empty × 56, 47, empty × 56, 48, empty × 56, 49, empty × 56, 50, empty × 56, 51, empty × 56, 52, empty × 56, 53, empty × 56, 54, empty × 56, 55, empty × 56, 56, empty × 56, 57, empty × 56, 58, empty × 56, 59, empty × 56, 60, empty × 56, 61, empty
-console-object-preview.js:52 Object with proto
-console-object-preview.js:55 {d: 1}d: 1__proto__: Object
-console-object-preview.js:57 Sparse array
-console-object-preview.js:60 (150) [empty × 50, 50, empty × 99]50: 50length: 150__proto__: Array(0)
-console-object-preview.js:62 Dense array with indexes and propeties
-console-object-preview.js:68 (150) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …][0 … 99][100 … 149]property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9property_10: 10property_11: 11property_12: 12property_13: 13property_14: 14property_15: 15property_16: 16property_17: 17property_18: 18property_19: 19property_20: 20property_21: 21property_22: 22property_23: 23property_24: 24property_25: 25property_26: 26property_27: 27property_28: 28property_29: 29property_30: 30property_31: 31property_32: 32property_33: 33property_34: 34property_35: 35property_36: 36property_37: 37property_38: 38property_39:
-console-object-preview.js:70 Object with properties containing whitespaces
-console-object-preview.js:77 {" a b ": " a b ", c d: "c d", "": "", "  ": "  ", "a↵↵b↵c": "a↵↵b↵c"}"": """  ": "  "" a b ": " a b ""a↵↵b↵c": "a↵↵b↵c"c d: "c d"__proto__: Object
-console-object-preview.js:79 Object with a document.all property
-console-object-preview.js:80 {all: HTMLAllCollection(4)}all: HTMLAllCollection(4) [html, head, base, body]__proto__: Object
-console-object-preview.js:82 Object with special numbers
-console-object-preview.js:84 {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0}nan: NaNnegInf: -InfinitynegZero: -0posInf: Infinity__proto__: Object
-console-object-preview.js:86 Object with exactly 5 properties: expected to be lossless
-console-object-preview.js:87 {a: 1, b: 2, c: 3, d: 4, e: 5}a: 1b: 2c: 3d: 4e: 5__proto__: Object
-console-object-preview.js:89 {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false}bool: falsenull: nullregexp: /^[regexp]$/gundef: undefined__proto__: Object
-console-object-preview.js:96 IHavePrivateProperties {regularProperty: 3, #privateProperty1: 1, #privateProperty2: 2}regularProperty: 3#privateProperty1: 1#privateProperty2: 2__proto__: Object
+console-object-preview.js:13 Mutating object in a loop
+console-object-preview.js:17 {a: 0, b: 0, c: 0}a: 0b: 0c: 2[[Prototype]]: Object
+console-object-preview.js:17 {a: 0, b: 0, c: 1}a: 0b: 0c: 2[[Prototype]]: Object
+console-object-preview.js:17 {a: 0, b: 0, c: 2}a: 0b: 0c: 2[[Prototype]]: Object
+console-object-preview.js:20 Mutating array in a loop
+console-object-preview.js:24 (3) [0, 0, 0]0: 01: 02: 2length: 3[[Prototype]]: Array(0)
+console-object-preview.js:24 (3) [0, 0, 1]0: 01: 02: 2length: 3[[Prototype]]: Array(0)
+console-object-preview.js:24 (3) [0, 0, 2]0: 01: 02: 2length: 3[[Prototype]]: Array(0)
+console-object-preview.js:27 Object with many properties
+console-object-preview.js:32 {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …}property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9[[Prototype]]: Object
+console-object-preview.js:34 Array with many properties
+console-object-preview.js:39 (2) [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4, …]0: 01: 1property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9length: 2[[Prototype]]: Array(0)
+console-object-preview.js:41 Array with gaps and overflow
+console-object-preview.js:46 (5733) [32: 0, 89: 1, 146: 2, 203: 3, 260: 4, 317: 5, 374: 6, 431: 7, 488: 8, 545: 9, 602: 10, 659: 11, 716: 12, 773: 13, 830: 14, 887: 15, 944: 16, 1001: 17, 1058: 18, 1115: 19, 1172: 20, 1229: 21, 1286: 22, 1343: 23, 1400: 24, 1457: 25, 1514: 26, 1571: 27, 1628: 28, 1685: 29, 1742: 30, 1799: 31, 1856: 32, 1913: 33, 1970: 34, 2027: 35, 2084: 36, 2141: 37, 2198: 38, 2255: 39, 2312: 40, 2369: 41, 2426: 42, 2483: 43, 2540: 44, 2597: 45, 2654: 46, 2711: 47, 2768: 48, 2825: 49, 2882: 50, 2939: 51, 2996: 52, 3053: 53, 3110: 54, 3167: 55, 3224: 56, 3281: 57, 3338: 58, 3395: 59, 3452: 60, 3509: 61, 3566: 62, 3623: 63, 3680: 64, 3737: 65, 3794: 66, 3851: 67, 3908: 68, 3965: 69, 4022: 70, 4079: 71, 4136: 72, 4193: 73, 4250: 74, 4307: 75, 4364: 76, 4421: 77, 4478: 78, 4535: 79, 4592: 80, 4649: 81, 4706: 82, 4763: 83, 4820: 84, 4877: 85, 4934: 86, 4991: 87, 5048: 88, 5105: 89, 5162: 90, 5219: 91, 5276: 92, 5333: 93, 5390: 94, 5447: 95, 5504: 96, 5561: 97, 5618: 98, 5675: 99, …][32 … 5675]573
+console-object-preview.js:48 Array with gaps without overflow
+console-object-preview.js:53 (5619) [empty × 32, 0, empty × 56, 1, empty × 56, 2, empty × 56, 3, empty × 56, 4, empty × 56, 5, empty × 56, 6, empty × 56, 7, empty × 56, 8, empty × 56, 9, empty × 56, 10, empty × 56, 11, empty × 56, 12, empty × 56, 13, empty × 56, 14, empty × 56, 15, empty × 56, 16, empty × 56, 17, empty × 56, 18, empty × 56, 19, empty × 56, 20, empty × 56, 21, empty × 56, 22, empty × 56, 23, empty × 56, 24, empty × 56, 25, empty × 56, 26, empty × 56, 27, empty × 56, 28, empty × 56, 29, empty × 56, 30, empty × 56, 31, empty × 56, 32, empty × 56, 33, empty × 56, 34, empty × 56, 35, empty × 56, 36, empty × 56, 37, empty × 56, 38, empty × 56, 39, empty × 56, 40, empty × 56, 41, empty × 56, 42, empty × 56, 43, empty × 56, 44, empty × 56, 45, empty × 56, 46, empty × 56, 47, empty × 56, 48, empty × 56, 49, empty × 56, 50, empty × 56, 51, empty × 56, 52, empty × 56, 53, empty × 56, 54, empty × 56, 55, empty × 56, 56, empty × 56, 57, empty × 56, 58, empty × 56, 59, empty × 56, 60, empty × 56, 61, empty
+console-object-preview.js:55 Object with proto
+console-object-preview.js:58 {d: 1}d: 1[[Prototype]]: Object
+console-object-preview.js:60 Sparse array
+console-object-preview.js:63 (150) [empty × 50, 50, empty × 99]50: 50length: 150[[Prototype]]: Array(0)
+console-object-preview.js:65 Dense array with indexes and propeties
+console-object-preview.js:71 (150) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, …][0 … 99][100 … 149]property_0: 0property_1: 1property_2: 2property_3: 3property_4: 4property_5: 5property_6: 6property_7: 7property_8: 8property_9: 9property_10: 10property_11: 11property_12: 12property_13: 13property_14: 14property_15: 15property_16: 16property_17: 17property_18: 18property_19: 19property_20: 20property_21: 21property_22: 22property_23: 23property_24: 24property_25: 25property_26: 26property_27: 27property_28: 28property_29: 29property_30: 30property_31: 31property_32: 32property_33: 33property_34: 34property_35: 35property_36: 36property_37: 37property_38: 38property_39:
+console-object-preview.js:73 Object with properties containing whitespaces
+console-object-preview.js:80 {" a b ": ' a b ', c d: 'c d', "": '', "  ": '  ', "a↵↵b↵c": 'a\n\nb\nc'}"": """  ": "  "" a b ": " a b ""a↵↵b↵c": "a\n\nb\nc"c d: "c d"[[Prototype]]: Object
+console-object-preview.js:82 Object with a document.all property
+console-object-preview.js:83 {all: HTMLAllCollection(4)}all: HTMLAllCollection(4) [html, head, base, body][[Prototype]]: Object
+console-object-preview.js:85 Object with special numbers
+console-object-preview.js:87 {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0}nan: NaNnegInf: -InfinitynegZero: -0posInf: Infinity[[Prototype]]: Object
+console-object-preview.js:89 Object with exactly 5 properties: expected to be lossless
+console-object-preview.js:90 {a: 1, b: 2, c: 3, d: 4, e: 5}a: 1b: 2c: 3d: 4e: 5[[Prototype]]: Object
+console-object-preview.js:92 {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false}bool: falsenull: nullregexp: /^[regexp]$/gundef: undefined[[Prototype]]: Object
+console-object-preview.js:99 IHavePrivateProperties {regularProperty: 3, #privateProperty1: 1, #privateProperty2: 2}regularProperty: 3#privateProperty1: 1#privateProperty2: 2[[Prototype]]: Object
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview.js b/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview.js
index 692b00b4..22b3e1d8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-object-preview.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console produces instant previews for arrays and objects.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
           console.log("Mutating object in a loop");
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-on-animation-worklet.js b/third_party/blink/web_tests/http/tests/devtools/console/console-on-animation-worklet.js
index c3c1c25..93af8396 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-on-animation-worklet.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-on-animation-worklet.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console output from AnimationWorklet.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function importWorklet()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-on-paint-worklet.js b/third_party/blink/web_tests/http/tests/devtools/console/console-on-paint-worklet.js
index 5869a357..9467ce4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-on-paint-worklet.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-on-paint-worklet.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console output from PaintWorklet.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function importWorklet() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-originating-command.js b/third_party/blink/web_tests/http/tests/devtools/console/console-originating-command.js
index 0f6e7d3..19c7df8e7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-originating-command.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-originating-command.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console result has originating command associated with it.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   ConsoleTestRunner.evaluateInConsole('1 + 1', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
index cc40a63..42fbb4c0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that the console can preserve log messages across cross-process navigations.`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.navigatePromise('http://devtools.oopif.test:8000/devtools/console/resources/log-message.html')
   Common.settingForTest('preserveConsoleLog').set(true);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
index a500f0b..99ca948 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that the console can preserve log messages across navigations. Bug 53359\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   const consoleModel = SDK.targetManager.primaryPageTarget().model(SDK.ConsoleModel);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-scroll.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-scroll.js
index ac9f4a3..90bbc82 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-scroll.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-scroll.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console preserves scroll position when switching away.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   // Do not use ConsoleTestRunner.fixConsoleViewportDimensions because fixing the height will affect
   // tests that may cause scrolling while the console moves into/out of the drawer.
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-proxy-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-proxy-expected.txt
index b532eb7..2247317 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-proxy-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-proxy-expected.txt
@@ -1,10 +1,10 @@
 Tests that console logging dumps proxy properly.
 
-console-proxy.js:25 Proxy(Object) {boo: 42, foo: 43}
-console-proxy.js:27 Proxy(Object) {boo: 42, foo: 43}
+console-proxy.js:28 Proxy(Object) {boo: 42, foo: 43}
+console-proxy.js:30 Proxy(Object) {boo: 42, foo: 43}
 window.accessedGet = false
 info-note display: inline-block
-console-proxy.js:25 Proxy(Object) {boo: 42, foo: 43}[[Handler]]: Object[[Target]]: Object[[IsRevoked]]: false
-console-proxy.js:27 Proxy(Object) {boo: 42, foo: 43}[[Handler]]: Object[[Target]]: Proxy(Object)[[IsRevoked]]: false
+console-proxy.js:28 Proxy(Object) {boo: 42, foo: 43}[[Handler]]: Object[[Target]]: Object[[IsRevoked]]: false
+console-proxy.js:30 Proxy(Object) {boo: 42, foo: 43}[[Handler]]: Object[[Target]]: Proxy(Object)[[IsRevoked]]: false
 window.accessedGet = false
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-proxy.js b/third_party/blink/web_tests/http/tests/devtools/console/console-proxy.js
index 8c06720b..a71c613 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-proxy.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-proxy.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging dumps proxy properly.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     window.accessedGet = false;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count-expected.txt
index b64e8aa5..fea6b1f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count-expected.txt
@@ -7,29 +7,29 @@
 await delayedPromise
 undefined
 undefined
-2console-repeat-count.js:15 Message
-2console-repeat-count.js:18 Error: Message with error
-    at dumpMessages (console-repeat-count.js:18:21)
-    at console-repeat-count.js:49:1
-console-repeat-count.js:21 {a: 1}
-dumpMessages @ console-repeat-count.js:21
-(anonymous) @ console-repeat-count.js:49
-console-repeat-count.js:21 {a: 1}
-dumpMessages @ console-repeat-count.js:21
-(anonymous) @ console-repeat-count.js:49
-2console-repeat-count.js:31 Uncaught Primitive value
-(anonymous) @ console-repeat-count.js:31
+2console-repeat-count.js:18 Message
+2console-repeat-count.js:21 Error: Message with error
+    at dumpMessages (console-repeat-count.js:21:21)
+    at console-repeat-count.js:52:1
+console-repeat-count.js:24 {a: 1}
+dumpMessages @ console-repeat-count.js:24
+(anonymous) @ console-repeat-count.js:52
+console-repeat-count.js:24 {a: 1}
+dumpMessages @ console-repeat-count.js:24
+(anonymous) @ console-repeat-count.js:52
+2console-repeat-count.js:34 Uncaught Primitive value
+(anonymous) @ console-repeat-count.js:34
 setTimeout (async)
-throwPrimitiveValues @ console-repeat-count.js:31
-(anonymous) @ console-repeat-count.js:50
-console-repeat-count.js:26 Uncaught {a: 1}
-(anonymous) @ console-repeat-count.js:26
+throwPrimitiveValues @ console-repeat-count.js:34
+(anonymous) @ console-repeat-count.js:53
+console-repeat-count.js:29 Uncaught {a: 1}
+(anonymous) @ console-repeat-count.js:29
 setTimeout (async)
-throwObjects @ console-repeat-count.js:26
-(anonymous) @ console-repeat-count.js:51
-console-repeat-count.js:26 Uncaught {a: 1}
-(anonymous) @ console-repeat-count.js:26
+throwObjects @ console-repeat-count.js:29
+(anonymous) @ console-repeat-count.js:54
+console-repeat-count.js:29 Uncaught {a: 1}
+(anonymous) @ console-repeat-count.js:29
 setTimeout (async)
-throwObjects @ console-repeat-count.js:26
-(anonymous) @ console-repeat-count.js:51
+throwObjects @ console-repeat-count.js:29
+(anonymous) @ console-repeat-count.js:54
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count.js b/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count.js
index dfcfaa58a..5a50d740 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-repeat-count.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that repeat count is properly updated.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-in-worker.js b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-in-worker.js
index c57d1d6..6fe8f49 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-in-worker.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-in-worker.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console revokes lazily handled promise rejections.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       var worker;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error.js
index ee3f929..a404e4c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console revokes lazily handled promise rejections.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       var p = [];
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-save-to-temp-var.js b/third_party/blink/web_tests/http/tests/devtools/console/console-save-to-temp-var.js
index 01e6a58..75432b3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-save-to-temp-var.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-save-to-temp-var.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests saving objects to temporary variables.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-script-with-same-url.js b/third_party/blink/web_tests/http/tests/devtools/console/console-script-with-same-url.js
index a463841..010cf6b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-script-with-same-url.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-script-with-same-url.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       'Checks that we show correct location for script evaluated twice.\n');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPageAnonymously('console.log(1);//# sourceURL=a.js');
   await TestRunner.evaluateInPageAnonymously('console.log(2);//# sourceURL=a.js');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-search-reveals-messages.js b/third_party/blink/web_tests/http/tests/devtools/console/console-search-reveals-messages.js
index a1a1f26..b88e5e5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-search-reveals-messages.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-search-reveals-messages.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console viewport reveals messages on searching.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     for (var i = 0; i < 200; ++i)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-search.js b/third_party/blink/web_tests/http/tests/devtools/console/console-search.js
index 57a1d63..10cd37f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-search.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-search.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console search.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     console.log("FIRST MATCH, SECOND MATCH");
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow-expected.txt
index c435b9d..adc3b6e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow-expected.txt
@@ -1,26 +1,26 @@
 Tests that when stack overflow exception happens when inspector is open the stack trace is correctly shown in console.
 
-console-stack-overflow.js:15 Uncaught RangeError: Maximum call stack size exceeded
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-    at overflow (console-stack-overflow.js:15:27)
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
-overflow @ console-stack-overflow.js:15
+console-stack-overflow.js:18 Uncaught RangeError: Maximum call stack size exceeded
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+    at overflow (console-stack-overflow.js:18:27)
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
+overflow @ console-stack-overflow.js:18
 o
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow.js b/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow.js
index fe8d320b..b88f9d68 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-stack-overflow.js
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
     `Tests that when stack overflow exception happens when inspector is open the stack trace is correctly shown in console.\n`
   );
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     // Both the call and the function entry may trigger stack overflow.
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-string-format.js b/third_party/blink/web_tests/http/tests/devtools/console/console-string-format.js
index 2d7f1d4..3738143 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-string-format.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-string-format.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that formatting processes '%' properly in case of missing formatters.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   var params = [
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-substituted.js b/third_party/blink/web_tests/http/tests/devtools/console/console-substituted.js
index 1e6647c1..3576d36 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-substituted.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-substituted.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that evaluate in console works even if window.console is substituted or deleted. Bug 53072\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-table.js b/third_party/blink/web_tests/http/tests/devtools/console/console-table.js
index 3d454919..bd727f4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-table.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-table.js
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
     `Tests that console.table is properly rendered on tables with more than 20 columns(maxColumnsToRender).\n`
   );
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     a = {};
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-tainted-globals.js b/third_party/blink/web_tests/http/tests/devtools/console/console-tainted-globals.js
index df01f2c2..30efbf0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-tainted-globals.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-tainted-globals.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that overriding global methods (like Array.prototype.push, Math.max) will not break the inspector.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       var originalError = window.Error;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-tests-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-tests-expected.txt
index ab91c608..9a5d5cd0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-tests-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-tests-expected.txt
@@ -1,22 +1,22 @@
 Tests that console logging dumps proper messages.
 
-console-tests.js:11 log console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:12 debug console-message-wrapper console-from-api console-verbose-level > console-message
-console-tests.js:13 info console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:14 warn
-(anonymous) @ console-tests.js:14 console-message-wrapper console-from-api console-warning-level > console-message
-console-tests.js:15 error
-(anonymous) @ console-tests.js:15 console-message-wrapper console-from-api console-error-level > console-message
-5console-tests.js:17 repeated console-message-wrapper console-from-api console-info-level > console-message repeated-message
-console-tests.js:19 count: 1 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:19 count: 2 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:20 group console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-tests.js:22 1 2 3 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:23 groupCollapsed console-message-wrapper console-group-title console-from-api console-info-level > console-message
-console-tests.js:35 default: 1 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:36 default: 2 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:37 default: 3 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:38 title: 1 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:39 title: 2 console-message-wrapper console-from-api console-info-level > console-message
-console-tests.js:40 title: 3 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:14 log console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:15 debug console-message-wrapper console-from-api console-verbose-level > console-message
+console-tests.js:16 info console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:17 warn
+(anonymous) @ console-tests.js:17 console-message-wrapper console-from-api console-warning-level > console-message
+console-tests.js:18 error
+(anonymous) @ console-tests.js:18 console-message-wrapper console-from-api console-error-level > console-message
+5console-tests.js:20 repeated console-message-wrapper console-from-api console-info-level > console-message repeated-message
+console-tests.js:22 count: 1 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:22 count: 2 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:23 group console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-tests.js:25 1 2 3 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:26 groupCollapsed console-message-wrapper console-group-title console-from-api console-info-level > console-message
+console-tests.js:38 default: 1 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:39 default: 2 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:40 default: 3 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:41 title: 1 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:42 title: 2 console-message-wrapper console-from-api console-info-level > console-message
+console-tests.js:43 title: 3 console-message-wrapper console-from-api console-info-level > console-message
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-tests.js b/third_party/blink/web_tests/http/tests/devtools/console/console-tests.js
index 332c56d..00fa291e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-tests.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-tests.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console logging dumps proper messages.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     console.log('log');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-time-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-time-expected.txt
index 410eec6..e0b1e1e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-time-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-time-expected.txt
@@ -1,7 +1,7 @@
 console.time / console.timeEnd tests.
 
-console-time.js:14 default: <time>
-console-time.js:16 42: <time>
-console-time.js:18 239: <time>
-console-time.js:20 [object Object]: <time>
+console-time.js:17 default: <time>
+console-time.js:19 42: <time>
+console-time.js:21 239: <time>
+console-time.js:23 [object Object]: <time>
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-time.js b/third_party/blink/web_tests/http/tests/devtools/console/console-time.js
index 56040985..bcff8693 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-time.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-time.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`console.time / console.timeEnd tests.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
index 276a64e..7f4e754 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the console timestamp setting.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   // It is essential that we calculate timezone for this particular moment of time
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-top-level-await.js b/third_party/blink/web_tests/http/tests/devtools/console/console-top-level-await.js
index c2afb9d2..5e95caa 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-top-level-await.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-top-level-await.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult('Tests that evaluation with top-level await may be performed in console.');
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments-expected.txt
index 53b4c199..c6aa347f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments-expected.txt
@@ -1,7 +1,7 @@
 Tests that console.trace dumps arguments alongside the stack trace.
 
-console-trace-arguments.js:13 1 2 3
-a @ console-trace-arguments.js:13
+console-trace-arguments.js:16 1 2 3
+a @ console-trace-arguments.js:16
 setTimeout (async)
-(anonymous) @ console-trace-arguments.js:21
+(anonymous) @ console-trace-arguments.js:24
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments.js b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments.js
index 7179ca17..b37601d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-arguments.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console.trace dumps arguments alongside the stack trace.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function a()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-expected.txt
index 6caf37b15..3be4cbe 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-expected.txt
@@ -1,8 +1,8 @@
 Tests that console.trace dumps stack trace with source URLs and line numbers.
 
-console-trace.js:13 console.trace
-b @ console-trace.js:13
-a @ console-trace.js:18
+console-trace.js:16 console.trace
+b @ console-trace.js:16
+a @ console-trace.js:21
 setTimeout (async)
-(anonymous) @ console-trace.js:26
+(anonymous) @ console-trace.js:29
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval-expected.txt
index de894e1..c5de412a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval-expected.txt
@@ -5,8 +5,8 @@
 a @ evalURL.js:10
 evalSource @ evalURL.js:13
 eval @ evalURL.js:14
-(anonymous) @ console-trace-in-eval.js:29
+(anonymous) @ console-trace-in-eval.js:32
 setTimeout (async)
-doEvalSource @ console-trace-in-eval.js:28
-(anonymous) @ console-trace-in-eval.js:39
+doEvalSource @ console-trace-in-eval.js:31
+(anonymous) @ console-trace-in-eval.js:42
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval.js b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval.js
index a3a4369..10280cef 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace-in-eval.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that when console.trace is called in eval'ed script ending with //# sourceURL=url it will dump a stack trace that will have the url as the script source. Bug 47252.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function evalSource()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trace.js b/third_party/blink/web_tests/http/tests/devtools/console/console-trace.js
index 83abf4b..3582065 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trace.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trace.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console.trace dumps stack trace with source URLs and line numbers.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     function b()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls-expected.txt
index f0d9e05852..5ece6da 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls-expected.txt
@@ -1,5 +1,5 @@
 Tests that a URL logged to the console is trimmed down to 150 characters.
 
-console-trim-long-urls.js:14 The URL is: http://example.com/2---------3---------4---------5---------6---------7-----…---3---------4---------5---------6---------7---------8---------9---------0
-console-trim-long-urls.js:15 http://example.com/2---------3---------4---------5---------6---------7-----…---3---------4---------5---------6---------7---------8---------9---------0
+console-trim-long-urls.js:17 The URL is: http://example.com/2---------3---------4---------5---------6---------7-----…---3---------4---------5---------6---------7---------8---------9---------0
+console-trim-long-urls.js:18 http://example.com/2---------3---------4---------5---------6---------7-----…---3---------4---------5---------6---------7---------8---------9---------0
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls.js b/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls.js
index 188c103..696e917 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-trim-long-urls.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that a URL logged to the console is trimmed down to 150 characters.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     //        0---------1---------2---------3---------4---------5---------6---------7---------8---------9---------0---------1---------2---------3---------4---------5---------6---------7---------8---------9---------0
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval-expected.txt
index ea45d38..81b8f2ea 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval-expected.txt
@@ -11,8 +11,8 @@
 evalSource @ evalURL.js:13
 eval @ evalURL.js:14
 setTimeout (async)
-doEvalWithSourceURL @ VM:30
-(anonymous) @ console-uncaught-exception-in-eval.js:40
+doEvalWithSourceURL @ VM:33
+(anonymous) @ console-uncaught-exception-in-eval.js:43
 VM:5 Uncaught Error: Exception in eval:anonymous
     at b (eval at <anonymous> (unknown source), <anonymous>:5:21)
     at a (eval at <anonymous> (unknown source), <anonymous>:10:15)
@@ -24,6 +24,6 @@
 evalSource @ VM:13
 eval @ VM:14
 setTimeout (async)
-doAnonymousEvalWith @ VM:36
-(anonymous) @ console-uncaught-exception-in-eval.js:43
+doAnonymousEvalWith @ VM:39
+(anonymous) @ console-uncaught-exception-in-eval.js:46
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval.js b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval.js
index e95f925..93f2c944 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-in-eval.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that when uncaught exception in eval'ed script ending with //# sourceURL=url is logged into console, its stack trace will have the url as the script source. Bug 47252.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception.js b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception.js
index 49d4f3cb..7afb3e1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that uncaught exceptions are logged into console.Bug 47250.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-promise-in-worker.js b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-promise-in-worker.js
index 9d011cf..6533aae 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-promise-in-worker.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-promise-in-worker.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that uncaught promise rejections happenned in workers are logged into console.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       var worker;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-control.js b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-control.js
index b89791bf..a4a546f6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-control.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-control.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Verifies viewport correctly shows and hides messages while logging and scrolling.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function addMessages(count)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-indices.js b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-indices.js
index 7ea0052..ec9b44e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-indices.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-indices.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
     TestRunner.addResult(`Verifies viewport's visible and active message ranges.\n`);
-    await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+    await TestRunner.loadLegacyModule('console');
     await TestRunner.showPanel('console');
     await TestRunner.evaluateInPagePromise(`
         function addNormalMessages(count)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection-expected.txt
index d4493c7..b6c4ae8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection-expected.txt
@@ -13,8 +13,8 @@
 
 Running: testSelectionMultiLineText
 Selected text:<<<EOL
-ole-viewport-selection.js:13 Message #74
-console-viewport-selection.js:13 Message #75
+ole-viewport-selection.js:16 Message #74
+console-viewport-selection.js:16 Message #75
 console
 EOL
 
@@ -58,10 +58,10 @@
 Selected all 150 messages.
 
 Running: testSelectWithNonTextNodeContainer
-Selected text: console-viewport-selection.js:13 Message #1
+Selected text: console-viewport-selection.js:16 Message #1
 
-Selected text: console-viewport-selection.js:13 Message #1
+Selected text: console-viewport-selection.js:16 Message #1
 
-Selected text: console-viewport-selection.js:13 Message #1
+Selected text: console-viewport-selection.js:16 Message #1
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection.js b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection.js
index 76df03e5..37d6982 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console viewport handles selection properly.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function populateConsoleWithMessages(count)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js
index abb9bc9..5028f18 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Verifies viewport stick-to-bottom behavior when Console is opened.\n`);
 
@@ -12,7 +15,7 @@
 
       //# sourceURL=console-viewport-stick-to-bottom-onload.js
     `);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-worker-nested-imports-syntax-error.js b/third_party/blink/web_tests/http/tests/devtools/console/console-worker-nested-imports-syntax-error.js
index 88e0ed01..5766c350 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-worker-nested-imports-syntax-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-worker-nested-imports-syntax-error.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that nested import scripts in worker show correct stack on syntax error.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function startWorker()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document-expected.txt
index 5a0dd62..670c9cc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document-expected.txt
@@ -1,5 +1,5 @@
 Tests that XML document contents are logged using the correct case in the console.
 
-console-xml-document.js:11 #document<MixedCase> Test </MixedCase>
-console-xml-document.js:13 <Book></Book>
+console-xml-document.js:14 #document<MixedCase> Test </MixedCase>
+console-xml-document.js:16 <Book></Book>
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document.js b/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document.js
index f335ede8..d9d0d97 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-xml-document.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that XML document contents are logged using the correct case in the console.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     console.dirxml((new DOMParser()).parseFromString("<MixedCase> Test </MixedCase>", "text/xml"));
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-xpath-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-xpath-expected.txt
index 7f52e40..43d99d0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-xpath-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-xpath-expected.txt
@@ -16,5 +16,5 @@
 VM:1 Uncaught DOMException: Failed to execute '$x' on 'CommandLineAPI': The string './a@href' is not a valid XPath expression.
     at <anonymous>:1:1
 (anonymous) @ VM:1
-console-xpath.js:25 complete
+console-xpath.js:28 complete
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-xpath.js b/third_party/blink/web_tests/http/tests/devtools/console/console-xpath.js
index abece30d..89f22e6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-xpath.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-xpath.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests $x for iterator and non-iterator types.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
       <a href="http://chromium.org"></a>
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/exception-objects-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/exception-objects-expected.txt
index bc5a368..1e2114d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/exception-objects-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/exception-objects-expected.txt
@@ -2,60 +2,60 @@
 
 setTimeout(throwError, 0); undefined
 undefined
-foo.js:12 Uncaught Error: error_text
-    at throwError (foo.js:12:17)
-throwError @ foo.js:12
+foo.js:15 Uncaught Error: error_text
+    at throwError (foo.js:15:17)
+throwError @ foo.js:15
 setTimeout (async)
 (anonymous) @ VM:1
 throwError();
-foo.js:12 Uncaught Error: error_text
-    at throwError (foo.js:12:17)
+foo.js:15 Uncaught Error: error_text
+    at throwError (foo.js:15:17)
     at <anonymous>:1:1
-throwError @ foo.js:12
+throwError @ foo.js:15
 (anonymous) @ VM:1
 setTimeout(throwObject, 0); undefined
 undefined
-foo.js:17 Uncaught {a: 42}
-throwObject @ foo.js:17
+foo.js:20 Uncaught {a: 42}
+throwObject @ foo.js:20
 setTimeout (async)
 (anonymous) @ VM:1
 throwObject();
-foo.js:17 Uncaught {a: 42}
-throwObject @ foo.js:17
+foo.js:20 Uncaught {a: 42}
+throwObject @ foo.js:20
 (anonymous) @ VM:1
 setTimeout(throwNumber, 0); undefined
 undefined
-foo.js:22 Uncaught 42
-throwNumber @ foo.js:22
+foo.js:25 Uncaught 42
+throwNumber @ foo.js:25
 setTimeout (async)
 (anonymous) @ VM:1
 throwNumber();
-foo.js:22 Uncaught 42
-throwNumber @ foo.js:22
+foo.js:25 Uncaught 42
+throwNumber @ foo.js:25
 (anonymous) @ VM:1
 setTimeout(rejectWithError, 0); undefined
 undefined
-foo.js:27 Uncaught (in promise) Error: promise_error
-    at rejectWithError (foo.js:27:26)
-rejectWithError @ foo.js:27
+foo.js:30 Uncaught (in promise) Error: promise_error
+    at rejectWithError (foo.js:30:26)
+rejectWithError @ foo.js:30
 setTimeout (async)
 (anonymous) @ VM:1
 rejectWithError();
 undefined
-foo.js:27 Uncaught (in promise) Error: promise_error
-    at rejectWithError (foo.js:27:26)
+foo.js:30 Uncaught (in promise) Error: promise_error
+    at rejectWithError (foo.js:30:26)
     at <anonymous>:1:1
-rejectWithError @ foo.js:27
+rejectWithError @ foo.js:30
 (anonymous) @ VM:1
 setTimeout(rejectWithObject, 0); undefined
 undefined
-foo.js:32 Uncaught (in promise) {b: 42}
-rejectWithObject @ foo.js:32
+foo.js:35 Uncaught (in promise) {b: 42}
+rejectWithObject @ foo.js:35
 setTimeout (async)
 (anonymous) @ VM:1
 rejectWithObject();
 undefined
-foo.js:32 Uncaught (in promise) {b: 42}
-rejectWithObject @ foo.js:32
+foo.js:35 Uncaught (in promise) {b: 42}
+rejectWithObject @ foo.js:35
 (anonymous) @ VM:1
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/exception-objects.js b/third_party/blink/web_tests/http/tests/devtools/console/exception-objects.js
index b8331bd1..5643c0ff6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/exception-objects.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/exception-objects.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that expressions have thrown objects.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function throwError()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack-expected.txt
index a9ab142..c16cb5c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack-expected.txt
@@ -1,9 +1,9 @@
 Tests exception message contains stack with correct function name.
 
-function-name-in-con…message-stack.js:13 Uncaught Error
-foo.function.name @ function-name-in-con…message-stack.js:13
-bar @ function-name-in-con…message-stack.js:21
-baz.function.name @ function-name-in-con…message-stack.js:28
+function-name-in-con…message-stack.js:16 Uncaught Error
+foo.function.name @ function-name-in-con…message-stack.js:16
+bar @ function-name-in-con…message-stack.js:24
+baz.function.name @ function-name-in-con…message-stack.js:31
 setTimeout (async)
-(anonymous) @ function-name-in-con…message-stack.js:35
+(anonymous) @ function-name-in-con…message-stack.js:38
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack.js b/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack.js
index baced66..90100fa 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/function-name-in-console-message-stack.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests exception message contains stack with correct function name.\n`);
 
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
     var foo = function ()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/inspect-html-all-collection.js b/third_party/blink/web_tests/http/tests/devtools/console/inspect-html-all-collection.js
index fa45317..9e99ba274 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/inspect-html-all-collection.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/inspect-html-all-collection.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that HTMLAllCollection properties can be inspected.\n`);
   await TestRunner.showPanel('console');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/nested-worker-eval-contains-stack.js b/third_party/blink/web_tests/http/tests/devtools/console/nested-worker-eval-contains-stack.js
index 61318cc4..7c1a9c0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/nested-worker-eval-contains-stack.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/nested-worker-eval-contains-stack.js
@@ -1,6 +1,9 @@
+
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
 (async function() {
   TestRunner.addResult(`Tests exception message from eval on nested worker context in console contains stack trace.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function startWorker()
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/only-one-deprecation-warning.js b/third_party/blink/web_tests/http/tests/devtools/console/only-one-deprecation-warning.js
index 139d2b4..3bda194 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/only-one-deprecation-warning.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/only-one-deprecation-warning.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`This test passes if only one deprecation warning is presented in the console.\n`);
   await TestRunner.showPanel('console');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.evaluateInPagePromise(`
     var x = window.webkitStorageInfo;
     var y = window.webkitStorageInfo;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/paintworklet-console-selector.js b/third_party/blink/web_tests/http/tests/devtools/console/paintworklet-console-selector.js
index bc363531..2e7a6d01 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/paintworklet-console-selector.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/paintworklet-console-selector.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests console execution context selector for paintworklet.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
     <script id="code" type="text/worklet">
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js b/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
index f3b7ad1..6fedb3c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {ElementsTestRunner} from 'elements_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that $0 works with shadow dom.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('elements'); await TestRunner.loadTestModule('elements_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('elements');
   await TestRunner.showPanel('console');
   await TestRunner.loadHTML(`
       <div><div><div id="host"></div></div></div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-clicking-messages.js b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-clicking-messages.js
index 6bf4d63..f204864 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-clicking-messages.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-clicking-messages.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console messages are navigable with the keyboard.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   ConsoleTestRunner.fixConsoleViewportDimensions(600, 200);
   await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links-expected.txt
index 9680f7f..3770897 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links-expected.txt
@@ -9,7 +9,7 @@
 Shift+Tab:
 Viewport virtual selection: 2
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:26
+active text: console-key-links.js:29
 
 ArrowUp:
 Viewport virtual selection: 2
@@ -19,12 +19,12 @@
 ArrowUp:
 Viewport virtual selection: 2
 activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-links.js:26 www.chromium.org/2
+active text: console-key-links.js:29 www.chromium.org/2
 
 ArrowUp:
 Viewport virtual selection: 1
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:26
+active text: console-key-links.js:29
 
 ArrowUp:
 Viewport virtual selection: 1
@@ -39,7 +39,7 @@
 ArrowUp:
 Viewport virtual selection: 1
 activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-links.js:26 Text around www.chromium.org/1a multiple links, www.chromium.org/1b
+active text: console-key-links.js:29 Text around www.chromium.org/1a multiple links, www.chromium.org/1b
 
 ArrowDown:
 Viewport virtual selection: 1
@@ -54,12 +54,12 @@
 ArrowDown:
 Viewport virtual selection: 1
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:26
+active text: console-key-links.js:29
 
 ArrowDown:
 Viewport virtual selection: 2
 activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected
-active text: console-key-links.js:26 www.chromium.org/2
+active text: console-key-links.js:29 www.chromium.org/2
 
 ArrowDown:
 Viewport virtual selection: 2
@@ -69,7 +69,7 @@
 ArrowDown:
 Viewport virtual selection: 2
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:26
+active text: console-key-links.js:29
 
 Running: testNavigatingLinksInStackTrace
 Evaluating: fn1()
@@ -96,17 +96,17 @@
 Viewport virtual selection: 0
 Is trace expanded: NO
 activeElement: DIV.console-message-wrapper.console-from-api.console-error-level.console-selected
-active text: foo.js:18 Custom error with link www.chromium.org/linkInErrMsg
-fn1 @ foo.js:18
-(anonymous) @ console-key-links.js:71
+active text: foo.js:21 Custom error with link www.chromium.org/linkInErrMsg
+fn1 @ foo.js:21
+(anonymous) @ console-key-links.js:74
 
 ArrowRight:
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: DIV.console-message-wrapper.console-from-api.console-error-level.console-selected
-active text: foo.js:18 Custom error with link www.chromium.org/linkInErrMsg
-fn1 @ foo.js:18
-(anonymous) @ console-key-links.js:71
+active text: foo.js:21 Custom error with link www.chromium.org/linkInErrMsg
+fn1 @ foo.js:21
+(anonymous) @ console-key-links.js:74
 
 ArrowDown:
 Viewport virtual selection: 0
@@ -118,39 +118,39 @@
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: SPAN.devtools-link
-active text: foo.js:18
+active text: foo.js:21
 
 ArrowDown:
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: SPAN.devtools-link
-active text: foo.js:18
+active text: foo.js:21
 
 ArrowDown:
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:71
+active text: console-key-links.js:74
 
 ArrowDown:
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: SPAN.devtools-link
-active text: console-key-links.js:71
+active text: console-key-links.js:74
 
 ArrowLeft:
 Viewport virtual selection: 0
 Is trace expanded: YES
 activeElement: DIV.console-message-wrapper.console-from-api.console-error-level.console-selected
-active text: foo.js:18 Custom error with link www.chromium.org/linkInErrMsg
-fn1 @ foo.js:18
-(anonymous) @ console-key-links.js:71
+active text: foo.js:21 Custom error with link www.chromium.org/linkInErrMsg
+fn1 @ foo.js:21
+(anonymous) @ console-key-links.js:74
 
 ArrowLeft:
 Viewport virtual selection: 0
 Is trace expanded: NO
 activeElement: DIV.console-message-wrapper.console-from-api.console-error-level.console-selected
-active text: foo.js:18 Custom error with link www.chromium.org/linkInErrMsg
-fn1 @ foo.js:18
-(anonymous) @ console-key-links.js:71
+active text: foo.js:21 Custom error with link www.chromium.org/linkInErrMsg
+fn1 @ foo.js:21
+(anonymous) @ console-key-links.js:74
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links.js b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links.js
index e3626839..31291bd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-links.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that console links are keyboard navigable.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   ConsoleTestRunner.fixConsoleViewportDimensions(600, 200);
   await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-expand-object.js b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-expand-object.js
index 85162fc..28a34c1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-expand-object.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-expand-object.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Verifies viewport stick-to-bottom behavior when prompt has space below editable area.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
   ConsoleTestRunner.fixConsoleViewportDimensions(600, 200);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/worker-eval-contains-stack.js b/third_party/blink/web_tests/http/tests/devtools/console/worker-eval-contains-stack.js
index 04e16861b..04598c8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/worker-eval-contains-stack.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/worker-eval-contains-stack.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests exception message from eval on worker context in console contains stack trace.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.evaluateInPagePromise(`
       function startWorker()
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-events.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-events.js
index 96a67f1..1783537a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-events.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-events.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the if events are getting emitted when coverage changes.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
 
 
   TestRunner.addResult('Should have coverage information even when not covered yet');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export-expected.txt b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export-expected.txt
index 5f62bc5..ba9a915 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export-expected.txt
@@ -46,6 +46,6 @@
 
 File: test://evaluations/0/coverage-export.js
 
-Usage: [0, 79]
+Usage: [0, 82]
 performActions()//# sourceURL=test://evaluations/0/coverage-export.js
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
index 90c653d..c2b6125 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-export.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage export functionality and format.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
 
   await CoverageTestRunner.startCoverage(true);
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated-per-function.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated-per-function.js
index 55076e2..50908ac 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated-per-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated-per-function.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after finishing recording in the Coverage view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.loadHTML(`
       <p class="class">
       </p>
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
index b730fae3..5579e041 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-repeated.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after finishing recording in the Coverage view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.loadHTML(`
       <p class="class">
       </p>
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended-per-function.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended-per-function.js
index 21cc8c8..232e593 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended-per-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended-per-function.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after suspending the coverage model.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.loadHTML(`
       <p class="class">
       </p>
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended.js
index 7a505ee..b3794a6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-suspended.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after suspending the coverage model.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.loadHTML(`
       <p class="class">
       </p>
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js
index 719eeb8..4d21584 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Test if coverage view also shows completly uncovered css files\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.navigatePromise(
       TestRunner.url('resources/css-coverage-import.html'));
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter-per-function.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter-per-function.js
index 474215f..1c52f5d42 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter-per-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter-per-function.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the filter is properly applied to coverage list view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
 
   await CoverageTestRunner.startCoverage(false);
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
index efe50d8e9..0b76c522 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-filter.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the filter is properly applied to coverage list view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
 
   await CoverageTestRunner.startCoverage(true);
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-per-function.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-per-function.js
index 4f35896..57a5dff 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-per-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-per-function.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after finishing recording in the Coverage view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
 
   await TestRunner.evaluateInPagePromise('performActions()');
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
index e777c35..faf64fa 100644
--- a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {CoverageTestRunner} from 'coverage_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests the coverage list view after finishing recording in the Coverage view.\n`);
-  await TestRunner.loadLegacyModule('panels/coverage'); await TestRunner.loadTestModule('coverage_test_runner');
+  await TestRunner.loadLegacyModule('panels/coverage');
   await TestRunner.navigatePromise(TestRunner.url('resources/basic-coverage.html'));
 
   await TestRunner.evaluateInPagePromise('performActions()');
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace-expected.txt b/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace-expected.txt
index efb370e..702e1660 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace-expected.txt
@@ -1,10 +1,10 @@
 This test injects an inline script from JavaScript. The resulting console error should contain a stack trace.
 
-Message[0]: csp-inline-warning-contains-stacktrace.js:18 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-CihokcEcBW4atb/CW/XWsvWwbTjqwQlE9nj9ii5ww5M='), or a nonce ('nonce-...') is required to enable inline execution.
+Message[0]: csp-inline-warning-contains-stacktrace.js:21 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-CihokcEcBW4atb/CW/XWsvWwbTjqwQlE9nj9ii5ww5M='), or a nonce ('nonce-...') is required to enable inline execution.
 
 Stack Trace:
 
   url: test://evaluations/0/csp-inline-warning-contains-stacktrace.js
   function: thisTest
-  line: 18
+  line: 21
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace.js b/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace.js
index 57b07c8a..00d5991 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace.js
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-inline-warning-contains-stacktrace.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `This test injects an inline script from JavaScript. The resulting console error should contain a stack trace.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
 
   await TestRunner.loadHTML(`
     <!DOCTYPE html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace-expected.txt b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace-expected.txt
index a18a0bff..b50fe28 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace-expected.txt
@@ -1,10 +1,10 @@
 This test should trigger a CSP violation by attempting to evaluate a string with setInterval.
 
-Message[0]: csp-setInterval-warning-contains-stacktrace.js:16 Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".
+Message[0]: csp-setInterval-warning-contains-stacktrace.js:19 Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".
 
 Stack Trace:
 
   url: test://evaluations/0/csp-setInterval-warning-contains-stacktrace.js
   function: thisTest
-  line: 16
+  line: 19
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace.js b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace.js
index bebb80b..65170654 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace.js
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setInterval-warning-contains-stacktrace.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
     TestRunner.addResult(
       `This test should trigger a CSP violation by attempting to evaluate a string with setInterval.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
 
   await TestRunner.loadHTML(`
     <!DOCTYPE html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace-expected.txt b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace-expected.txt
index bfbfa71..15d20dd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace-expected.txt
@@ -1,10 +1,10 @@
 This test should trigger a CSP violation by attempting to evaluate a string with setTimeout.
 
-Message[0]: csp-setTimeout-warning-contains-stacktrace.js:16 Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".
+Message[0]: csp-setTimeout-warning-contains-stacktrace.js:19 Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".
 
 Stack Trace:
 
   url: test://evaluations/0/csp-setTimeout-warning-contains-stacktrace.js
   function: thisTest
-  line: 16
+  line: 19
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace.js b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace.js
index be58871..878df7e1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace.js
+++ b/third_party/blink/web_tests/http/tests/devtools/csp/csp-setTimeout-warning-contains-stacktrace.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
     TestRunner.addResult(
       `This test should trigger a CSP violation by attempting to evaluate a string with setTimeout.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
 
   await TestRunner.loadHTML(`
     <!DOCTYPE html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints-expected.txt b/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints-expected.txt
index f4346b08..34c5b80 100644
--- a/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints-expected.txt
@@ -4,7 +4,7 @@
 Running: testFetchBreakpoint
 Script execution paused.
 Call stack:
-    0) sendRequest (fetch-breakpoints.js:11)
+    0) sendRequest (fetch-breakpoints.js:14)
     1)  (:1)
 Script execution resumed.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints.js b/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints.js
index ae9fb10..60a46cba 100644
--- a/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints.js
+++ b/third_party/blink/web_tests/http/tests/devtools/debugger/fetch-breakpoints.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests fetch() breakpoints.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.evaluateInPagePromise(`
       function sendRequest(url)
       {
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
index dfedf77f..dfdfcde 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {DeviceModeTestRunner} from 'device_mode_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test that device mode's responsive mode behaves correctly when adjusting inputs.\n`);
-  await TestRunner.loadTestModule('device_mode_test_runner');
 
   var phone0 = DeviceModeTestRunner.buildFakePhone();
   var phone1 = DeviceModeTestRunner.buildFakePhone();
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
index f23c5f11..69764317e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {DeviceModeTestRunner} from 'device_mode_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test preservation of orientation and scale when that switching devices in device mode.\n`);
-  await TestRunner.loadTestModule('device_mode_test_runner');
 
   var phoneA = DeviceModeTestRunner.buildFakePhone();
   var phoneB = DeviceModeTestRunner.buildFakePhone();
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
index ce39c389..9324fb1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {DeviceModeTestRunner} from 'device_mode_test_runner';
+
 (async function() {
   TestRunner.addResult(`Test toolbar state when switching modes.\n`);
-  await TestRunner.loadTestModule('device_mode_test_runner');
 
   var phoneA = DeviceModeTestRunner.buildFakePhone();
   var view = new Emulation.DeviceModeView();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-cancellation-status-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-cancellation-status-expected.txt
index 356216c..0963d923 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-cancellation-status-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-cancellation-status-expected.txt
@@ -2,7 +2,7 @@
 {
     method : Preload.prerenderAttemptCompleted
     params : {
-        finalStatus : TriggerDestroyed
+        finalStatus : TriggerPageNavigated
         initiatingFrameId : <string>
         key : {
             action : Prerender
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value-expected.txt
index be3c986..a6363a3 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-htmldom-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-htmldom-expected.txt
index be3c986..a6363a3 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-htmldom-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-htmldom-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttribute-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttribute-expected.txt
index be3c986..a6363a3 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttribute-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttribute-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS-expected.txt
index be3c986..a6363a3 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNode-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNode-expected.txt
index be3c986..a6363a3 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNode-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNode-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-getAttribute-value-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-getAttribute-value-expected.txt
index 2024f4a..d26f1a0 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-getAttribute-value-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-getAttribute-value-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This test passes as long as the word 'FAIL' and an accompanying message do not appear in the subframe.
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-htmldom-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-htmldom-expected.txt
index 2024f4a..d26f1a0 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-htmldom-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-htmldom-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This test passes as long as the word 'FAIL' and an accompanying message do not appear in the subframe.
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute-expected.txt
index 2024f4a..d26f1a0 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This test passes as long as the word 'FAIL' and an accompanying message do not appear in the subframe.
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS-expected.txt
index 2024f4a..d26f1a0 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This test passes as long as the word 'FAIL' and an accompanying message do not appear in the subframe.
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode-expected.txt b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode-expected.txt
index 2024f4a..d26f1a0 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode-expected.txt
@@ -1,6 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This test passes as long as the word 'FAIL' and an accompanying message do not appear in the subframe.
 
 --------
diff --git a/third_party/blink/web_tests/http/tests/security/javascriptURL/resources/javascriptURL-execution-context.js b/third_party/blink/web_tests/http/tests/security/javascriptURL/resources/javascriptURL-execution-context.js
index 1da566c..e594f51b 100644
--- a/third_party/blink/web_tests/http/tests/security/javascriptURL/resources/javascriptURL-execution-context.js
+++ b/third_party/blink/web_tests/http/tests/security/javascriptURL/resources/javascriptURL-execution-context.js
@@ -1,5 +1,6 @@
 if (window.testRunner) {
     testRunner.dumpAsText();
+    testRunner.setDumpConsoleMessages(false);
     testRunner.dumpChildFrames();
     testRunner.waitUntilDone();
 }
diff --git a/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias-expected.txt b/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias-expected.txt
index c0b38006..a49ada0 100644
--- a/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias-expected.txt
@@ -1,11 +1,3 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
 This script tests if iframe.src can be set to a JavaScript URL via alternate DOM interfaces (such as Node.textContent or NamedNode.setNamedItem). The test is successful if no alerts appear and the page finishes loading.
 
 
diff --git a/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias.html b/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias.html
index f7e7ed21..aa86173 100644
--- a/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias.html
+++ b/third_party/blink/web_tests/http/tests/security/xss-DENIED-iframe-src-alias.html
@@ -5,6 +5,7 @@
 {
     if (window.testRunner) {
         testRunner.dumpAsText();
+        testRunner.setDumpConsoleMessages(false);
         testRunner.waitUntilDone();
     }
 
diff --git a/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces-expected.txt b/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces-expected.txt
index 9d50cf5..411236a 100644
--- a/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces-expected.txt
@@ -1,2 +1 @@
-CONSOLE ERROR: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 There should be no alert displayed.
diff --git a/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces.html b/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces.html
index 945b2de1..6eae835 100644
--- a/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces.html
+++ b/third_party/blink/web_tests/http/tests/security/xss-DENIED-javascript-with-spaces.html
@@ -4,6 +4,7 @@
 <script>
 if (window.testRunner) {
     testRunner.dumpAsText();
+    testRunner.setDumpConsoleMessages(false);
     testRunner.waitUntilDone();
 }
 
diff --git a/third_party/blink/web_tests/platform/linux/editing/selection/range-between-block-and-inline-expected.png b/third_party/blink/web_tests/platform/linux/editing/selection/range-between-block-and-inline-expected.png
index 1984938..f8f84d4 100644
--- a/third_party/blink/web_tests/platform/linux/editing/selection/range-between-block-and-inline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/editing/selection/range-between-block-and-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/editing/selection/range-between-block-and-inline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/editing/selection/range-between-block-and-inline-expected.png
index e501399..3e419f0 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/editing/selection/range-between-block-and-inline-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/editing/selection/range-between-block-and-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/selection/range-between-block-and-inline-expected.png b/third_party/blink/web_tests/platform/mac/editing/selection/range-between-block-and-inline-expected.png
index aae25ad..3e419f0 100644
--- a/third_party/blink/web_tests/platform/mac/editing/selection/range-between-block-and-inline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/editing/selection/range-between-block-and-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt
new file mode 100644
index 0000000..72a948d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing letter spacing with font-relative length assert_approx_equals: letter spacing doesn't work. expected 132.021484375 +/- 0.1 but got 66.0107421875
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt
new file mode 100644
index 0000000..72a948d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing letter spacing with font-relative length assert_approx_equals: letter spacing doesn't work. expected 132.021484375 +/- 0.1 but got 66.0107421875
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt
new file mode 100644
index 0000000..e1ea3c42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing if word spacing is working properly with font-relative length assert_approx_equals: word spacing doesn't work. expected 120.01953125 +/- 0.1 but got 108.017578125
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt
new file mode 100644
index 0000000..e1ea3c42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing if word spacing is working properly with font-relative length assert_approx_equals: word spacing doesn't work. expected 120.01953125 +/- 0.1 but got 108.017578125
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/editing/selection/range-between-block-and-inline-expected.png b/third_party/blink/web_tests/platform/win/editing/selection/range-between-block-and-inline-expected.png
index b15380b1..2674f30 100644
--- a/third_party/blink/web_tests/platform/win/editing/selection/range-between-block-and-inline-expected.png
+++ b/third_party/blink/web_tests/platform/win/editing/selection/range-between-block-and-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt
new file mode 100644
index 0000000..219ba61
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing letter spacing with font-relative length assert_approx_equals: letter spacing doesn't work. expected 132 +/- 0.1 but got 66
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt
new file mode 100644
index 0000000..219ba61
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.relative.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing letter spacing with font-relative length assert_approx_equals: letter spacing doesn't work. expected 132 +/- 0.1 but got 66
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt
new file mode 100644
index 0000000..0c4b417
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing if word spacing is working properly with font-relative length assert_approx_equals: word spacing doesn't work. expected 120 +/- 0.1 but got 108
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt
new file mode 100644
index 0000000..0c4b417
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.relative.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Testing if word spacing is working properly with font-relative length assert_approx_equals: word spacing doesn't work. expected 120 +/- 0.1 but got 108
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-local.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-local.sub.https.html
new file mode 100644
index 0000000..8416daf
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-local.sub.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Local Storage: DisableThirdPartyStoragPartitioning deprecation trial third-party for wrong origin</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js"></script>
+<body>
+<script type="module">
+import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js";
+// Here's the set-up for this test:
+// Step 1 (top-frame) Create an ID in storage.
+// Step 2 (top-frame) Set up listener for "UserID" message.
+// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame.
+// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame.
+// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup.
+// Step 6 (sub-sub-frame) Send "UserID" message to top-frame.
+// Step 7 (top-frame) Compare IDs recieved and cleanup.
+
+async_test(t => {
+  // Step 1
+  const userID = getOrCreateID(/*useSessionStorage=*/false);
+
+  // Step 2
+  window.addEventListener("message", t.step_func(e => {
+    // Step 7
+    if (e.data.message === "UserID") {
+      t.step(() => {
+        assert_true(e.data.userID !== userID, "IDs pulled from same-origin partitioned frames should be different.")
+      });
+      clearID(/*useSessionStorage=*/false);
+      t.done();
+    };
+  }));
+
+  // Step 3
+  let iframe = document.createElement("iframe");
+  iframe.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html";
+  document.body.appendChild(iframe);
+}, "Test for Local Storage with DisableThirdPartySessionStoragePartitioning disabled in cross-origin iframe");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-session.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-session.sub.https.html
new file mode 100644
index 0000000..98b101a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-disabled-session.sub.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Session Storage: DisableThirdPartyStoragePartitioning deprecation trial third-party for wrong origin</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js"></script>
+<body>
+<script type="module">
+import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js";
+// Here's the set-up for this test:
+// Step 1 (top-frame) Create an ID in storage.
+// Step 2 (top-frame) Set up listener for "UserID" message.
+// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame.
+// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame.
+// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup.
+// Step 6 (sub-sub-frame) Send "UserID" message to top-frame.
+// Step 7 (top-frame) Compare IDs recieved and cleanup.
+
+async_test(t => {
+  // Step 1
+  const userID = getOrCreateID(/*useSessionStorage=*/true);
+
+  // Step 2
+  window.addEventListener("message", t.step_func(e => {
+    // Step 7
+    if (e.data.message === "UserID") {
+      t.step(() => {
+        assert_true(e.data.userID !== userID, "IDs pulled from same-origin partitioned frames should be different.")
+      });
+      clearID(/*useSessionStorage=*/true);
+      t.done();
+    };
+  }));
+
+  // Step 3
+  let iframe = document.createElement("iframe");
+  iframe.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html?session";
+  document.body.appendChild(iframe);
+}, "Test for Session Storage with DisableThirdPartySessionStoragePartitioning disabled in cross-origin iframe");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-local.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-local.sub.https.html
new file mode 100644
index 0000000..d97024b
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-local.sub.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Local Storage: DisableThirdPartyStoragPartitioning deprecation trial third-party</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js"></script>
+<body>
+<script type="module">
+import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js";
+// Here's the set-up for this test:
+// Step 1 (top-frame) Create an ID in storage.
+// Step 2 (top-frame) Set up listener for "UserID" message.
+// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame.
+// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame.
+// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup.
+// Step 6 (sub-sub-frame) Send "UserID" message to top-frame.
+// Step 7 (top-frame) Compare IDs recieved and cleanup.
+
+async_test(t => {
+  // Step 1
+  const userID = getOrCreateID(/*useSessionStorage=*/false);
+
+  // Step 2
+  window.addEventListener("message", t.step_func(e => {
+    // Step 7
+    if (e.data.message === "UserID") {
+      t.step(() => {
+        assert_true(e.data.userID === userID, "IDs pulled from same-origin un-partitioned frames shouldn't be different.")
+      });
+      clearID(/*useSessionStorage=*/false);
+      t.done();
+    };
+  }));
+
+  // Step 3
+  let iframe = document.createElement("iframe");
+  iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html";
+  document.body.appendChild(iframe);
+}, "Test for Local Storage with DisableThirdPartySessionStoragePartitioning enabled in cross-origin iframe");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-session.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-session.sub.https.html
new file mode 100644
index 0000000..c500f27
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webstorage/general-storage-deprecation-trial-third-party-enabled-session.sub.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Session Storage: DisableThirdPartyStoragePartitioning deprecation trial third-party</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js"></script>
+<body>
+<script type="module">
+import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js";
+// Here's the set-up for this test:
+// Step 1 (top-frame) Create an ID in storage.
+// Step 2 (top-frame) Set up listener for "UserID" message.
+// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame.
+// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame.
+// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup.
+// Step 6 (sub-sub-frame) Send "UserID" message to top-frame.
+// Step 7 (top-frame) Compare IDs recieved and cleanup.
+
+async_test(t => {
+  // Step 1
+  const userID = getOrCreateID(/*useSessionStorage=*/true);
+
+  // Step 2
+  window.addEventListener("message", t.step_func(e => {
+    // Step 7
+    if (e.data.message === "UserID") {
+      t.step(() => {
+        assert_true(e.data.userID === userID, "IDs pulled from same-origin un-partitioned frames shouldn't be different.")
+      });
+      clearID(/*useSessionStorage=*/true);
+      t.done();
+    };
+  }));
+
+  // Step 3
+  let iframe = document.createElement("iframe");
+  iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html?session";
+  document.body.appendChild(iframe);
+}, "Test for Session Storage with DisableThirdPartySessionStoragePartitioning enabled in cross-origin iframe");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js
new file mode 100644
index 0000000..5495354b
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-third-party-injection.js
@@ -0,0 +1,6 @@
+const otMeta = document.createElement('meta');
+otMeta.httpEquiv = 'origin-trial';
+// The token below was generated via the following command:
+// tools/origin_trials/generate_token.py https://not-web-platform.test:8444 DisableThirdPartyStoragePartitioning --expire-timestamp=2000000000 --is-third-party
+otMeta.content = 'A5e8lolpivDBfLwsRrIt4gO7FEOMwRvhqcyjs4GXE2KHSQr1xsWEQwYdmf/ZvFngnLDAtmkvLZ+/LrB1C2xfdwEAAACPeyJvcmlnaW4iOiAiaHR0cHM6Ly9ub3Qtd2ViLXBsYXRmb3JtLnRlc3Q6ODQ0NCIsICJmZWF0dXJlIjogIkRpc2FibGVUaGlyZFBhcnR5U3RvcmFnZVBhcnRpdGlvbmluZyIsICJleHBpcnkiOiAyMDAwMDAwMDAwLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZX0=';
+document.head.append(otMeta);
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index f11818c..5120b04 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-0-134-g3af4772d6
-Revision: 3af4772d68f261ae34677db4a0434ababe5676bd
+Version: VER-2-13-0-136-ge1a4e081a
+Revision: e1a4e081aa57b3e044c7f30c3118cb6015e397d6
 CPEPrefix: cpe:/a:freetype:freetype:2.12.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium
index 4e39533..caa12c8b 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: 529503149
-Date: 2023/05/04 UTC
+Version: 530973247
+Date: 2023/05/10 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 550d0ab..08ac069 100644
--- a/third_party/metrics_proto/system_profile.proto
+++ b/third_party/metrics_proto/system_profile.proto
@@ -1217,6 +1217,7 @@
     enum CustomizationFacet {
       UNDEFINED = 0;
       CLOUD_GAMING_DEVICE = 1;
+      FEATURE_AWARE_DEVICE = 2;
     }
     repeated CustomizationFacet customization_facet = 3 [packed = true];
   }
diff --git a/third_party/wayland-protocols/unstable/keyboard/keyboard-configuration-unstable-v1.xml b/third_party/wayland-protocols/unstable/keyboard/keyboard-configuration-unstable-v1.xml
index 6318719..751de46 100644
--- a/third_party/wayland-protocols/unstable/keyboard/keyboard-configuration-unstable-v1.xml
+++ b/third_party/wayland-protocols/unstable/keyboard/keyboard-configuration-unstable-v1.xml
@@ -24,7 +24,7 @@
     DEALINGS IN THE SOFTWARE.
   </copyright>
 
-  <interface name="zcr_keyboard_configuration_v1" version="3">
+  <interface name="zcr_keyboard_configuration_v1" version="4">
     <description summary="extends wl_keyboard with events for device configuration change">
       Allows a wl_keyboard to notify device configuration change events of
       the keyboard to the client.
@@ -57,7 +57,7 @@
     </request>
   </interface>
 
-  <interface name="zcr_keyboard_device_configuration_v1" version="3">
+  <interface name="zcr_keyboard_device_configuration_v1" version="4">
     <description summary="extension of wl_keyboard protocol">
       The zcr_keyboard_device_configuration_v1 interface extends the wl_keyboard
       interface with events to describe device configuration of a keyboard.
@@ -101,6 +101,24 @@
       </description>
       <arg name="key_bits" type="array" summary="Uint64 key bits" />
     </event>
+
+    <!-- Version 4 additions -->
+    <event name="layout_install" since="4">
+      <description summary="installed keyboard layout">
+        Notify that the user installed a new keyboard layout. This doesn't
+        mean the user is switching to this layout. Actual switch will be
+        notified through `layout_change` event.
+
+        This event provides a file descriptor to the client which can be
+        memory-mapped to provide a keyboard mapping description. Difference
+        between this and wl_keyboards's `keymap` event is this event will be sent both
+        on client startup and also on newly-added layout (not on layout switch).
+      </description>
+      <arg name="name" type="string" summary="XKB layout name e.g. us(dvorak)"/>
+      <arg name="format" type="uint" enum="wl_keyboard.keymap_format" summary="keymap format"/>
+      <arg name="fd" type="fd" summary="keymap file descriptor"/>
+      <arg name="size" type="uint" summary="keymap size, in bytes"/>
+    </event>
   </interface>
 
 </protocol>
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index fdf8209..68b35fa 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -48,6 +48,7 @@
 src/common/tools/image_utils.ts
 src/common/tools/presubmit.ts
 src/common/tools/run_wpt_ref_tests.ts
+src/common/tools/validate.ts
 src/common/tools/version.ts
 src/common/util/collect_garbage.ts
 src/common/util/preprocessor.ts
@@ -343,7 +344,11 @@
 src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_division.spec.ts
-src/webgpu/shader/execution/expression/binary/f32_matrix_arithmetic.spec.ts
+src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts
+src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts
+src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts
+src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts
+src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 31f8660..6d4f3fb1 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -37654,8 +37654,6 @@
   <suffix name="NewTabPageHomeButton"
       label="For NewTabPageHomeButton feature."/>
   <suffix name="NewTabTip" label="For NewTabTip feature."/>
-  <suffix name="OverflowMenuTip"
-      label="For the overflow menu help tip on iOS."/>
   <suffix name="PageInfo" label="In product help for opening PageInfo."/>
   <suffix name="PageInfoStoreInfo" label="For PageInfoStoreInfo feature."/>
   <suffix name="PageZoom" label="For Page Zoom feature."/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1aa0e1e..df75b0f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26629,6 +26629,7 @@
   <int value="71" label="outermostTargetSelector"/>
   <int value="72" label="jsProfilerTemporarilyEnable"/>
   <int value="73" label="highlightErrorsElementsPanel"/>
+  <int value="74" label="setAllBreakpointsEagerly"/>
 </enum>
 
 <enum name="DevToolsGridOverlayOpenedFrom">
@@ -27121,9 +27122,9 @@
   <int value="1" label="Elements"/>
   <int value="2" label="Resources"/>
   <int value="3" label="Network"/>
-  <int value="4" label="Scripts"/>
-  <int value="5" label="Timeline"/>
-  <int value="6" label="Heap profiler"/>
+  <int value="4" label="Sources"/>
+  <int value="5" label="Performance"/>
+  <int value="6" label="Memory"/>
   <int value="7" label="Legacy Audits"/>
   <int value="8" label="Console"/>
   <int value="9" label="Layers"/>
@@ -27135,7 +27136,7 @@
   <int value="15" label="Drawer - Search"/>
   <int value="16" label="Security"/>
   <int value="17" label="JavaScript Profiler"/>
-  <int value="18" label="Audits"/>
+  <int value="18" label="Lighthouse"/>
   <int value="19" label="Drawer - Coverage"/>
   <int value="20" label="Drawer - Protocol monitor"/>
   <int value="21" label="Drawer - Remote devices"/>
@@ -36364,6 +36365,14 @@
   <int value="6" label="History"/>
 </enum>
 
+<enum name="ExtensionNavigationScheme">
+  <int value="0" label="HttpOrHttps"/>
+  <int value="1" label="Chrome"/>
+  <int value="2" label="FileWithPermission"/>
+  <int value="3" label="FileWithoutPermission"/>
+  <int value="4" label="Other"/>
+</enum>
+
 <enum name="ExtensionNotificationType">
   <int value="0" label="NOTIFICATION_TYPE_SIMPLE"/>
   <int value="1" label="NOTIFICATION_TYPE_BASE_FORMAT"/>
@@ -60540,6 +60549,7 @@
   <int value="-1068084507" label="ShareSheetCustomActionsPolish:enabled"/>
   <int value="-1067635248" label="SpeculativeResourcePrefetching:disabled"/>
   <int value="-1065887406" label="PictureInPictureV2:disabled"/>
+  <int value="-1065697407" label="PriceInsights:enabled"/>
   <int value="-1065227777" label="CrOSAutoSelect:disabled"/>
   <int value="-1064733740" label="ui-show-composited-layer-borders"/>
   <int value="-1064302126"
@@ -60878,6 +60888,8 @@
   <int value="-886912558" label="ChromeHomePromo:enabled"/>
   <int value="-886898803" label="CooperativeScheduling:enabled"/>
   <int value="-886509859" label="DefaultChromeAppUninstallSync:enabled"/>
+  <int value="-886296821"
+      label="NtpHistoryClustersModuleUseModelRanking:disabled"/>
   <int value="-885601782" label="enable-contextual-search"/>
   <int value="-885209667" label="FilesZipMount:disabled"/>
   <int value="-884864731" label="WebPaymentsSingleAppUiSkip:enabled"/>
@@ -62582,6 +62594,8 @@
   <int value="23121136" label="MobileIdentityConsistencyVar:enabled"/>
   <int value="23556595" label="MarkHttpAs:enabled"/>
   <int value="24332306" label="ButtonARCNetworkDiagnostics:disabled"/>
+  <int value="26632553"
+      label="NtpHistoryClustersModuleUseModelRanking:enabled"/>
   <int value="26875005" label="disable-explicit-dma-fences"/>
   <int value="26945819" label="EnhancedDeskAnimations:disabled"/>
   <int value="27442980" label="ArcGameModeFeature:enabled"/>
@@ -62959,6 +62973,7 @@
   <int value="228107154"
       label="OmniboxUpdatedConnectionSecurityIndicators:enabled"/>
   <int value="228845546" label="ShimlessRMAOsUpdate:enabled"/>
+  <int value="229312162" label="PriceInsights:disabled"/>
   <int value="229476202" label="CryptAuthV2Enrollment:enabled"/>
   <int value="229877058" label="ShelfScrollable:disabled"/>
   <int value="231949727" label="ClipboardHistoryReorder:enabled"/>
@@ -78752,6 +78767,7 @@
   <int value="22" label="Virtual Card Manual Fallback"/>
   <int value="23" label="Zoom"/>
   <int value="24" label="Save IBAN"/>
+  <int value="25" label="Mandatory Reauth"/>
 </enum>
 
 <enum name="PageActionPageEvent">
@@ -79806,6 +79822,10 @@
   <int value="10" label="Note edited"/>
   <int value="11" label="Note deleted"/>
   <int value="12" label="Credential row with note clicked"/>
+  <int value="13" label="Part of a note selected"/>
+  <int value="14" label="Full note selected"/>
+  <int value="15" label="Part of a note copied"/>
+  <int value="16" label="Full note copied"/>
 </enum>
 
 <enum name="PasswordManager.AssistantStoppedBubble.CloseReason">
@@ -85395,6 +85415,9 @@
       label="kMainFrameSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation"/>
   <int value="67" label="kMemoryPressureOnTrigger"/>
   <int value="68" label="kMemoryPressureAfterTriggered"/>
+  <int value="69" label="SpeculationRuleRemoved"/>
+  <int value="70" label="TriggerPageNavigated"/>
+  <int value="71" label="OtherPrerenderedPageActivated"/>
 </enum>
 
 <enum name="PrerenderHoverEvent">
@@ -90618,6 +90641,7 @@
   <int value="20" label="WORKER"/>
   <int value="21" label="XSLT"/>
   <int value="22" label="FENCED_FRAME"/>
+  <int value="23" label="DICTIONARY"/>
 </enum>
 
 <enum name="RequestedImageMimeType">
@@ -90916,6 +90940,7 @@
   <int value="12" label="Manifest"/>
   <int value="13" label="SpeculationRules"/>
   <int value="14" label="Mock"/>
+  <int value="15" label="Dictionary"/>
 </enum>
 
 <enum name="RestoreAction">
@@ -100285,7 +100310,7 @@
   <int value="100123" label="LanguageRemapSearchKeyTo"/>
   <int value="100124" label="MultiProfileNeverShowIntro"/>
   <int value="100125" label="MultiProfileWarningShowDismissed"/>
-  <int value="100126" label="OfficeSetupComplete"/>
+  <int value="100126" label="(obsolete) OfficeSetupComplete"/>
   <int value="100127" label="ResolveTimezoneByGeolocationMethod"/>
   <int value="100128" label="ResolveTimezoneByGeolocationMigratedToMethod"/>
   <int value="100129" label="ShelfDefaultPinLayoutRolls"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 9b0e4b9..2b613f3 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1460,6 +1460,24 @@
 </histogram>
 
 <histogram
+    name="Ash.CalendarView.SmoothScrollToTodaysDateCell.{CalendarChildView}.AnimationSmoothness"
+    units="%" expires_after="2024-05-04">
+  <owner>newcomer@google.com</owner>
+  <owner>samcackett@google.com</owner>
+  <owner>cros-status-area-eng@google.com</owner>
+  <summary>
+    Animation smoothness recorded on the {CalendarChildView} when the Calendar
+    scroll view is auto-scrolled (note this is actually done via layer
+    transforms to give the appearance of smooth scrolling) to reveal todays date
+    cell, when covered by the up next view.
+  </summary>
+  <token key="CalendarChildView">
+    <variant name="LabelView" summary="label view"/>
+    <variant name="MonthView" summary="month view"/>
+  </token>
+</histogram>
+
+<histogram
     name="Ash.CalendarView.{Animation}.{CalendarChildView}.AnimationSmoothness"
     units="%" expires_after="2023-09-18">
   <owner>newcomer@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index df5704082..fcfcb0e 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -46,6 +46,7 @@
 <variants name="ResourceType">
   <variant name="Audio" summary="Audio"/>
   <variant name="CSSStyleSheet" summary="CSS Style Sheet"/>
+  <variant name="Dictionary" summary="Dictionary"/>
   <variant name="Font" summary="Font"/>
   <variant name="Image" summary="Image"/>
   <variant name="LinkPrefetch" summary="Link Prefetch"/>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 8eb9acf..1715e6f6 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -3528,7 +3528,7 @@
   </token>
 </histogram>
 
-<histogram name="Extensions.Navigation.Scheme" enum="NavigationScheme"
+<histogram name="Extensions.Navigation.Scheme" enum="ExtensionNavigationScheme"
     expires_after="2024-01-01">
   <owner>jkokatsu@google.com</owner>
   <owner>extensions-core@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index da4f081..7fc60228 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -215,8 +215,6 @@
   <variant name="IPH_NewTab" summary="new tab"/>
   <variant name="IPH_NewTabPageHomeButton" summary="new tab page button"/>
   <variant name="IPH_NewTabTip" summary="new tab tip"/>
-  <variant name="IPH_OverflowMenuTip"
-      summary="the Overflow Menu help tip on iOS"/>
   <variant name="IPH_PageInfo" summary="opening PageInfo"/>
   <variant name="IPH_PageInfoStoreInfo" summary="PageInfoStoreInfo feature"/>
   <variant name="IPH_PageZoom"
diff --git a/tools/metrics/histograms/metadata/na_cl/histograms.xml b/tools/metrics/histograms/metadata/na_cl/histograms.xml
index 85f6883..04db85a 100644
--- a/tools/metrics/histograms/metadata/na_cl/histograms.xml
+++ b/tools/metrics/histograms/metadata/na_cl/histograms.xml
@@ -426,18 +426,6 @@
   </summary>
 </histogram>
 
-<histogram name="NaCl.ResourceCreationImpl.CreateVideoDecoderDev_Invoked"
-    enum="Boolean" expires_after="2023-09-01">
-  <owner>blundell@chromium.org</owner>
-  <owner>dschuff@chromium.org</owner>
-  <summary>
-    True is emitted when ResourceCreationImpl::CreateVideoDecoderDev() is
-    invoked. Targeted metric to get clarity on whether there are any attempted
-    creations of this API against production Chrome as we work toward
-    eliminating support for the API.
-  </summary>
-</histogram>
-
 <histogram name="NaCl.ValidationCache.Query" enum="NaClValidationCacheEnum"
     expires_after="2023-07-31">
   <owner>dschuff@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 53b87968..02865dd 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -915,7 +915,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrameScheme2" enum="NavigationScheme"
-    expires_after="2023-09-05">
+    expires_after="2024-01-15">
   <owner>estark@chromium.org</owner>
   <owner>elawrence@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
@@ -942,7 +942,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrameSchemeDifferentPageOTR2"
-    enum="NavigationScheme" expires_after="2023-05-07">
+    enum="NavigationScheme" expires_after="2024-01-15">
   <owner>estark@chromium.org</owner>
   <owner>elawrence@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
@@ -955,7 +955,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrameSchemeOTR2" enum="NavigationScheme"
-    expires_after="2023-05-07">
+    expires_after="2024-01-15">
   <owner>elawrence@chromium.org</owner>
   <owner>estark@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index dadb384..c871701 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -175,6 +175,7 @@
     <variant name="IntentPicker"/>
     <variant name="LocalCardMigration"/>
     <variant name="ManagePasswords"/>
+    <variant name="MandatoryReauth"/>
     <variant name="PaymentsOfferNotification"/>
     <variant name="PriceTracking"/>
     <variant name="PWAInstall"/>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 249971c..a6e1debc 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -1559,7 +1559,7 @@
 </histogram>
 
 <histogram name="Signin.TransactionalReauthUserAction"
-    enum="SigninReauthUserAction" expires_after="2023-04-30">
+    enum="SigninReauthUserAction" expires_after="2023-10-22">
 <!-- Name completed by histogram_suffixes
 name="TransactionalReauthEntryPoint" -->
 
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index 7b48867..5697e1a3 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -56,6 +56,19 @@
   </summary>
 </histogram>
 
+<histogram name="V8.CFIPageSizeMismatch" units="BooleanOccurred"
+    expires_after="2024-06-01">
+  <owner>sroettger@google.com</owner>
+  <owner>v8-security@google.com</owner>
+  <summary>
+    Whether there's a mismatch between the maximum page size we assume at
+    compile time and the page size we assume at runtime.
+
+    This metric is recorded once at renderer startup when the
+    ThreadIsolatedAllocator is initialized.
+  </summary>
+</histogram>
+
 <histogram name="V8.CodeCacheRejectReason" enum="V8CodeCacheRejectReason"
     expires_after="M77">
   <owner>yangguo@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index b777e47..3ead1d1 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -21558,6 +21558,18 @@
       CSSStyleSheet in the page. (boolean value. true: 1 or false: 0)
     </summary>
   </metric>
+  <metric name="DictionaryFallback">
+    <summary>
+      True if there are network fallback sub-resources of Dictionary in the
+      page. (boolean value. true: 1 or false: 0)
+    </summary>
+  </metric>
+  <metric name="DictionaryHandled">
+    <summary>
+      True if there are service workers handling sub-resource loads of
+      Dictionary in the page. (boolean value. true: 1 or false: 0)
+    </summary>
+  </metric>
   <metric name="FontFallback">
     <summary>
       True if there are network fallback sub-resources of CSSStyleSheet in the
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 154614e..2b2b8bc3 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "perfetto-luci-artifacts/v34.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "f085c34f2d2f081b55de458f0e07beb94c78762e",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/8636689446ccacc31a106573931c8bad825e9dc1/trace_processor_shell.exe"
+            "hash": "79436072ceab4698c704d1c35523a7a90b92170d",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/8962065c2d161b04046d8bb1af2f68b2cb155487/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "336a42cb9ec3c417e13a97816271fec10cdf67e5",
             "full_remote_path": "perfetto-luci-artifacts/v34.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "a30c7e0da4ee9a75bc53542310a26cfed58c0725",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/edd765afa06f3b0c0d117e9e1e7ab12b441ed765/trace_processor_shell"
+            "hash": "ce67e881f8fc52d4df2eced8ae970cc6eb053732",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/8962065c2d161b04046d8bb1af2f68b2cb155487/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "c32364e05e22cdf82ee0866aedd11c0e2050809c",
             "full_remote_path": "perfetto-luci-artifacts/v34.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "d79dc368361818d7f1c42ddeb9964ebce65e5ab2",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/a6abd9944464ff392ea57c6e3e82784e603987ec/trace_processor_shell"
+            "hash": "3bfb7d97430e99a15327eea63b5601b3cb2ac0c0",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/8962065c2d161b04046d8bb1af2f68b2cb155487/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/base/clipboard/BUILD.gn b/ui/base/clipboard/BUILD.gn
index 71532bc..7be3061 100644
--- a/ui/base/clipboard/BUILD.gn
+++ b/ui/base/clipboard/BUILD.gn
@@ -98,6 +98,8 @@
     "clipboard_observer.cc",
     "clipboard_observer.h",
     "clipboard_sequence_number_token.h",
+    "clipboard_util.cc",
+    "clipboard_util.h",
     "custom_data_helper.cc",
     "custom_data_helper.h",
     "scoped_clipboard_writer.cc",
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index 75ca03f..89ad4d5 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -29,6 +29,7 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/ui_base_jni_headers/Clipboard_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -722,6 +723,11 @@
 // Encoding SkBitmap to PNG data. Then, |g_map| can commit the PNG data to
 // Android system clipboard without encode/decode.
 void ClipboardAndroid::WriteBitmap(const SkBitmap& sk_bitmap) {
+  // Encode the bitmap to a PNG from the UI thread. Ideally this CPU-intensive
+  // encoding operation would be performed on a background thread, but
+  // ui::base::Clipboard writes are (unfortunately) synchronous.
+  // We could consider making writes async, then moving this image encoding to a
+  // background sequence.
   scoped_refptr<base::RefCountedMemory> image_memory =
       gfx::Image::CreateFrom1xBitmap(sk_bitmap).As1xPNGBytes();
   std::string packed(image_memory->front_as<char>(), image_memory->size());
diff --git a/ui/base/clipboard/clipboard_data.cc b/ui/base/clipboard/clipboard_data.cc
index 03eb550..6d796a99 100644
--- a/ui/base/clipboard/clipboard_data.cc
+++ b/ui/base/clipboard/clipboard_data.cc
@@ -8,26 +8,13 @@
 #include <ostream>
 #include <vector>
 
-#include "base/threading/thread_restrictions.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/clipboard/clipboard_sequence_number_token.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
-#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/skia_util.h"
 
 namespace ui {
 
-// static
-std::vector<uint8_t> ClipboardData::EncodeBitmapData(const SkBitmap& bitmap) {
-  // Encoding a PNG can be a long CPU operation.
-  base::AssertLongCPUWorkAllowed();
-
-  std::vector<uint8_t> data;
-  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, /*discard_transparency=*/false,
-                                    &data);
-  return data;
-}
-
 ClipboardData::ClipboardData() = default;
 
 ClipboardData::ClipboardData(const ClipboardData& other) {
@@ -94,7 +81,7 @@
   //   a.SetBitmapData(image);
   //
   //   ClipboardData b;
-  //   b.SetPngData(EncodeBitmapData(image));
+  //   b.SetPngData(clipboard_util::EncodeBitmapToPng(image));
   //
   // Avoid this scenario if possible.
   if (maybe_bitmap_.has_value() != that.maybe_bitmap_.has_value())
diff --git a/ui/base/clipboard/clipboard_data.h b/ui/base/clipboard/clipboard_data.h
index f35fab2..98e32ca 100644
--- a/ui/base/clipboard/clipboard_data.h
+++ b/ui/base/clipboard/clipboard_data.h
@@ -40,10 +40,6 @@
 // It mostly just provides APIs to cleanly access and manipulate this data.
 class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardData {
  public:
-  // Encode a bitmap to a PNG. Callers encoding a PNG on a background thread
-  // should use this method.
-  static std::vector<uint8_t> EncodeBitmapData(const SkBitmap& bitmap);
-
   ClipboardData();
   ClipboardData(const ClipboardData&);
   ClipboardData(ClipboardData&&);
@@ -135,7 +131,7 @@
   void SetBitmapData(const SkBitmap& bitmap);
   // Use this method to obtain the bitmap to be encoded to a PNG. It is only
   // recommended to call this method after checking that `maybe_png()` returns
-  // no value. If this returns a value, use `EncodeBitmapData()` to encode the
+  // no value. If this returns a value, use `EncodeBitmapToPng()` to encode the
   // bitmap to a PNG on a background thread.
   absl::optional<SkBitmap> GetBitmapIfPngNotEncoded() const;
 
diff --git a/ui/base/clipboard/clipboard_data_unittest.cc b/ui/base/clipboard/clipboard_data_unittest.cc
index d0b3bdee..75a4c1c 100644
--- a/ui/base/clipboard/clipboard_data_unittest.cc
+++ b/ui/base/clipboard/clipboard_data_unittest.cc
@@ -9,9 +9,9 @@
 #include "base/strings/string_piece_forward.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/image/image_unittest_util.h"
-#include "ui/gfx/skia_util.h"
 #include "url/gurl.h"
 
 namespace ui {
@@ -61,8 +61,8 @@
   EXPECT_EQ(data2.maybe_png(), absl::nullopt);
 
   // Encode the PNG of one of the clipboards.
-  auto png1 =
-      ClipboardData::EncodeBitmapData(data1.GetBitmapIfPngNotEncoded().value());
+  auto png1 = clipboard_util::EncodeBitmapToPng(
+      data1.GetBitmapIfPngNotEncoded().value());
   data1.SetPngDataAfterEncoding(png1);
 
   // Comparing the clipboards when only one has an encoded PNG checks the cached
diff --git a/ui/base/clipboard/clipboard_mac.h b/ui/base/clipboard/clipboard_mac.h
index e12ad605..df594ed2 100644
--- a/ui/base/clipboard/clipboard_mac.h
+++ b/ui/base/clipboard/clipboard_mac.h
@@ -27,12 +27,8 @@
   ClipboardMac& operator=(const ClipboardMac&) = delete;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, ReadImageRetina);
-  FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, ReadImageNonRetina);
-  FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, EmptyImage);
-  FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, PDFImage);
-  FRIEND_TEST_ALL_PREFIXES(ClipboardMacTest, WriteBitmapAddsPNGToClipboard);
   friend class Clipboard;
+  friend class ClipboardMacTest;
 
   ClipboardMac();
   ~ClipboardMac() override;
@@ -109,8 +105,9 @@
                  base::span<const uint8_t> data) override;
 
   void WriteBitmapInternal(const SkBitmap& bitmap, NSPasteboard* pasteboard);
-  std::vector<uint8_t> ReadPngInternal(ClipboardBuffer buffer,
-                                       NSPasteboard* pasteboard) const;
+  void ReadPngInternal(ClipboardBuffer buffer,
+                       NSPasteboard* pasteboard,
+                       ReadPngCallback callback) const;
 
   // Mapping of OS-provided sequence number to a unique token.
   mutable struct {
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index a543ddd2..d5d0ddce 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -23,6 +23,9 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "net/base/filename_util.h"
 #include "skia/ext/skia_utils_base.h"
 #include "skia/ext/skia_utils_mac.h"
@@ -71,18 +74,32 @@
 
 // Read raw PNG bytes from the clipboard.
 std::vector<uint8_t> GetPngFromPasteboard(NSPasteboard* pasteboard) {
-  if (!pasteboard)
-    return std::vector<uint8_t>();
+  if (!pasteboard) {
+    return {};
+  }
 
   NSData* data = [pasteboard dataForType:NSPasteboardTypePNG];
-  if (!data)
-    return std::vector<uint8_t>();
+  if (!data) {
+    return {};
+  }
 
   const uint8_t* bytes = static_cast<const uint8_t*>(data.bytes);
   std::vector<uint8_t> png(bytes, bytes + data.length);
   return png;
 }
 
+std::vector<uint8_t> EncodeGfxImageToPng(gfx::Image image) {
+  base::AssertLongCPUWorkAllowed();
+
+  if (image.IsEmpty()) {
+    return {};
+  }
+
+  scoped_refptr<base::RefCountedMemory> mem = image.As1xPNGBytes();
+  std::vector<uint8_t> image_data(mem->data(), mem->data() + mem->size());
+  return image_data;
+}
+
 }  // namespace
 
 // Clipboard factory method.
@@ -315,7 +332,7 @@
                            const DataTransferEndpoint* data_dst,
                            ReadPngCallback callback) const {
   RecordRead(ClipboardFormatMetric::kPng);
-  std::move(callback).Run(ReadPngInternal(buffer, GetPasteboard()));
+  ReadPngInternal(buffer, GetPasteboard(), std::move(callback));
 }
 
 // |data_dst| is not used. It's only passed to be consistent with other
@@ -467,29 +484,36 @@
   [GetPasteboard() setData:nil forType:format];
 }
 
-std::vector<uint8_t> ClipboardMac::ReadPngInternal(
-    ClipboardBuffer buffer,
-    NSPasteboard* pasteboard) const {
+void ClipboardMac::ReadPngInternal(ClipboardBuffer buffer,
+                                   NSPasteboard* pasteboard,
+                                   ReadPngCallback callback) const {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
 
   std::vector<uint8_t> png = GetPngFromPasteboard(pasteboard);
-  if (!png.empty())
-    return png;
+  if (!png.empty()) {
+    std::move(callback).Run(std::move(png));
+    return;
+  }
 
   // If we can’t read a PNG, try reading for an NSImage, and if successful,
   // transcode it to PNG.
   base::scoped_nsobject<NSImage> image = GetNSImage(pasteboard);
-  if (!image)
-    return std::vector<uint8_t>();
+  if (!image) {
+    std::move(callback).Run({});
+    return;
+  }
 
   auto gfx_image = gfx::Image(image);
-  if (gfx_image.IsEmpty())
-    return std::vector<uint8_t>();
+  if (gfx_image.IsEmpty()) {
+    std::move(callback).Run({});
+    return;
+  }
 
-  scoped_refptr<base::RefCountedMemory> mem = gfx_image.As1xPNGBytes();
-  std::vector<uint8_t> image_data(mem->data(), mem->data() + mem->size());
-  return image_data;
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+      base::BindOnce(&EncodeGfxImageToPng, std::move(gfx_image)),
+      std::move(callback));
 }
 
 void ClipboardMac::WriteBitmapInternal(const SkBitmap& bitmap,
diff --git a/ui/base/clipboard/clipboard_mac_unittest.mm b/ui/base/clipboard/clipboard_mac_unittest.mm
index f1f0d74..9b6a7e04 100644
--- a/ui/base/clipboard/clipboard_mac_unittest.mm
+++ b/ui/base/clipboard/clipboard_mac_unittest.mm
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #import "ui/base/clipboard/clipboard_mac.h"
+#include "base/test/test_future.h"
 
 #import <AppKit/AppKit.h>
 
@@ -15,6 +16,8 @@
 #include "base/memory/free_deleter.h"
 #include "base/memory/ref_counted.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
 #include "testing/platform_test.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
@@ -48,7 +51,8 @@
 class ClipboardMacTest : public PlatformTest,
                          public testing::WithParamInterface<bool> {
  public:
-  ClipboardMacTest() = default;
+  ClipboardMacTest()
+      : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
 
   void SetUp() override {
     scoped_feature_list_.InitWithFeatureState(
@@ -86,8 +90,24 @@
 
   bool ShouldWriteImageWithPng() const { return GetParam(); }
 
+  std::vector<uint8_t> ReadPngSync(ClipboardMac* clipboard_mac,
+                                   NSPasteboard* pasteboard) {
+    base::test::TestFuture<std::vector<uint8_t>> future;
+    clipboard_mac->ReadPngInternal(
+        ClipboardBuffer::kCopyPaste, pasteboard,
+        future.GetCallback<const std::vector<uint8_t>&>());
+    return future.Get();
+  }
+
+  void WriteBitmap(ClipboardMac* clipboard_mac,
+                   const SkBitmap& bitmap,
+                   NSPasteboard* pasteboard) {
+    clipboard_mac->WriteBitmapInternal(bitmap, pasteboard);
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
+  base::test::TaskEnvironment task_environment_;
 };
 
 TEST_P(ClipboardMacTest, ReadImageRetina) {
@@ -100,8 +120,7 @@
   Clipboard* clipboard = Clipboard::GetForCurrentThread();
   ClipboardMac* clipboard_mac = static_cast<ClipboardMac*>(clipboard);
 
-  std::vector<uint8_t> png_data = clipboard_mac->ReadPngInternal(
-      ClipboardBuffer::kCopyPaste, pasteboard->get());
+  std::vector<uint8_t> png_data = ReadPngSync(clipboard_mac, pasteboard->get());
   SkBitmap bitmap;
   gfx::PNGCodec::Decode(png_data.data(), png_data.size(), &bitmap);
   EXPECT_EQ(2 * width, bitmap.width());
@@ -118,8 +137,7 @@
   Clipboard* clipboard = Clipboard::GetForCurrentThread();
   ClipboardMac* clipboard_mac = static_cast<ClipboardMac*>(clipboard);
 
-  std::vector<uint8_t> png_data = clipboard_mac->ReadPngInternal(
-      ClipboardBuffer::kCopyPaste, pasteboard->get());
+  std::vector<uint8_t> png_data = ReadPngSync(clipboard_mac, pasteboard->get());
   SkBitmap bitmap;
   gfx::PNGCodec::Decode(png_data.data(), png_data.size(), &bitmap);
   EXPECT_EQ(width, bitmap.width());
@@ -134,8 +152,7 @@
   Clipboard* clipboard = Clipboard::GetForCurrentThread();
   ClipboardMac* clipboard_mac = static_cast<ClipboardMac*>(clipboard);
 
-  std::vector<uint8_t> png_data = clipboard_mac->ReadPngInternal(
-      ClipboardBuffer::kCopyPaste, pasteboard->get());
+  std::vector<uint8_t> png_data = ReadPngSync(clipboard_mac, pasteboard->get());
   SkBitmap bitmap;
   gfx::PNGCodec::Decode(png_data.data(), png_data.size(), &bitmap);
   EXPECT_EQ(0, bitmap.width());
@@ -159,8 +176,7 @@
   Clipboard* clipboard = Clipboard::GetForCurrentThread();
   ClipboardMac* clipboard_mac = static_cast<ClipboardMac*>(clipboard);
 
-  std::vector<uint8_t> png_data = clipboard_mac->ReadPngInternal(
-      ClipboardBuffer::kCopyPaste, pasteboard->get());
+  std::vector<uint8_t> png_data = ReadPngSync(clipboard_mac, pasteboard->get());
   SkBitmap bitmap;
   gfx::PNGCodec::Decode(png_data.data(), png_data.size(), &bitmap);
   EXPECT_EQ(width, bitmap.width());
@@ -178,7 +194,7 @@
   SkBitmap bitmap;
   bitmap.allocN32Pixels(width, height);
   bitmap.eraseColor(SK_ColorRED);
-  clipboard_mac->WriteBitmapInternal(bitmap, pasteboard->get());
+  WriteBitmap(clipboard_mac, bitmap, pasteboard->get());
 
   NSData* data = [pasteboard->get() dataForType:NSPasteboardTypePNG];
 
diff --git a/ui/base/clipboard/clipboard_non_backed.cc b/ui/base/clipboard/clipboard_non_backed.cc
index d0679ed..8055349 100644
--- a/ui/base/clipboard/clipboard_non_backed.cc
+++ b/ui/base/clipboard/clipboard_non_backed.cc
@@ -33,6 +33,7 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/clipboard_sequence_number_token.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/clipboard/custom_data_helper.h"
 #include "ui/base/clipboard/file_info.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
@@ -223,7 +224,7 @@
 
     png_encoding_runner_->PostTaskAndReplyWithResult(
         FROM_HERE,
-        base::BindOnce(&ClipboardData::EncodeBitmapData,
+        base::BindOnce(&clipboard_util::EncodeBitmapToPng,
                        std::move(maybe_bitmap.value())),
         base::BindOnce(&ClipboardInternal::DidEncodePng,
                        weak_factory_.GetMutableWeakPtr(), sequence_number()));
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
index 8e2008f6..fa95c4a 100644
--- a/ui/base/clipboard/clipboard_ozone.cc
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -24,6 +24,7 @@
 #include "base/timer/timer.h"
 #include "base/types/variant_util.h"
 #include "build/build_config.h"
+#include "clipboard_util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -31,6 +32,7 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/clipboard/custom_data_helper.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint_serializer.h"
@@ -556,7 +558,9 @@
 void ClipboardOzone::ReadPng(ClipboardBuffer buffer,
                              const DataTransferEndpoint* data_dst,
                              ReadPngCallback callback) const {
-  auto clipboard_data = ReadPngInternal(buffer);
+  auto clipboard_data =
+      async_clipboard_ozone_->ReadClipboardDataSetSourceAndWait(buffer,
+                                                                kMimeTypePNG);
 
   if (!IsReadAllowed(GetSource(buffer), data_dst, clipboard_data)) {
     std::move(callback).Run(std::vector<uint8_t>());
@@ -730,9 +734,17 @@
 }
 
 void ClipboardOzone::WriteBitmap(const SkBitmap& bitmap) {
-  std::vector<unsigned char> output;
-  if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output))
-    async_clipboard_ozone_->InsertData(std::move(output), {kMimeTypePNG});
+  // Encode the bitmap to a PNG from the UI thread. Unfortunately we can't hop
+  // to a background thread to perform the encoding because clipboard writes are
+  // (unfortunately) currently synchronous. We could consider making writes
+  // async, then encode the image on a background sequence. We could also
+  // consider storing the image as a bitmap and only encoding to a PNG on paste
+  // (e.g. see https://crrev.com/c/3260985).
+  std::vector<uint8_t> png_bytes =
+      clipboard_util::EncodeBitmapToPngAcceptJank(bitmap);
+  if (!png_bytes.empty()) {
+    async_clipboard_ozone_->InsertData(std::move(png_bytes), {kMimeTypePNG});
+  }
 }
 
 void ClipboardOzone::WriteData(const ClipboardFormatType& format,
@@ -764,12 +776,4 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
-base::span<uint8_t> ClipboardOzone::ReadPngInternal(
-    const ClipboardBuffer buffer) const {
-  DCHECK(CalledOnValidThread());
-
-  return async_clipboard_ozone_->ReadClipboardDataSetSourceAndWait(
-      buffer, kMimeTypePNG);
-}
-
 }  // namespace ui
diff --git a/ui/base/clipboard/clipboard_ozone.h b/ui/base/clipboard/clipboard_ozone.h
index e57ecead6..524eca72 100644
--- a/ui/base/clipboard/clipboard_ozone.h
+++ b/ui/base/clipboard/clipboard_ozone.h
@@ -111,8 +111,6 @@
                  std::unique_ptr<DataTransferEndpoint> data_src);
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
-  base::span<uint8_t> ReadPngInternal(const ClipboardBuffer buffer) const;
-
   class AsyncClipboardOzone;
 
   std::unique_ptr<AsyncClipboardOzone> async_clipboard_ozone_;
diff --git a/ui/base/clipboard/clipboard_util.cc b/ui/base/clipboard/clipboard_util.cc
new file mode 100644
index 0000000..33b031fe
--- /dev/null
+++ b/ui/base/clipboard/clipboard_util.cc
@@ -0,0 +1,37 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/clipboard_util.h"
+
+#include "base/threading/thread_restrictions.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace ui::clipboard_util {
+
+namespace {
+
+std::vector<uint8_t> EncodeBitmapToPngImpl(const SkBitmap& bitmap) {
+  // Prefer faster image encoding, even if it results in a PNG with a worse
+  // compression ratio.
+  std::vector<uint8_t> data;
+  gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, /*discard_transparency=*/false,
+                                        &data);
+  return data;
+}
+
+}  // namespace
+
+std::vector<uint8_t> EncodeBitmapToPng(const SkBitmap& bitmap) {
+  // Encoding a PNG can be a long CPU operation.
+  base::AssertLongCPUWorkAllowed();
+
+  return EncodeBitmapToPngImpl(bitmap);
+}
+
+std::vector<uint8_t> EncodeBitmapToPngAcceptJank(const SkBitmap& bitmap) {
+  return EncodeBitmapToPngImpl(bitmap);
+}
+
+}  // namespace ui::clipboard_util
diff --git a/ui/base/clipboard/clipboard_util.h b/ui/base/clipboard/clipboard_util.h
new file mode 100644
index 0000000..f60fdfd
--- /dev/null
+++ b/ui/base/clipboard/clipboard_util.h
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace ui::clipboard_util {
+
+// Encodes a bitmap to a PNG. This is an expensive method that must be
+// called on a sequence that allows long-running CPU operations.
+[[nodiscard]] COMPONENT_EXPORT(UI_BASE_CLIPBOARD)
+    std::vector<uint8_t> EncodeBitmapToPng(const SkBitmap& bitmap);
+
+// Prefer EncodeBitmapToPng() if possible. Use this method only when encoding
+// must be done synchronously from a sequence which does not allow long-running
+// CPU operations, such as while writing to the clipboard from the UI thread,
+// which may cause jank.
+[[nodiscard]] COMPONENT_EXPORT(UI_BASE_CLIPBOARD)
+    std::vector<uint8_t> EncodeBitmapToPngAcceptJank(const SkBitmap& bitmap);
+
+}  // namespace ui::clipboard_util
+
+#endif  // UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_H_
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index 5586af8..419781ea 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -26,16 +26,20 @@
 #include "base/strings/utf_offset_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/win/message_window.h"
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/scoped_hdc.h"
 #include "base/win/scoped_hglobal.h"
+#include "clipboard_util.h"
 #include "net/base/filename_util.h"
 #include "skia/ext/skia_utils_base.h"
 #include "skia/ext/skia_utils_win.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
+#include "ui/base/clipboard/clipboard_util.h"
 #include "ui/base/clipboard/clipboard_util_win.h"
 #include "ui/base/clipboard/custom_data_helper.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
@@ -485,12 +489,16 @@
   std::vector<uint8_t> data = ReadPngInternal(buffer);
   // On Windows, PNG and bitmap are separate formats. Read PNG if possible,
   // otherwise fall back to reading as a bitmap.
-  if (data.empty()) {
-    SkBitmap bitmap = ReadBitmapInternal(buffer);
-    gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, /*discard_transparency=*/false,
-                                      &data);
+  if (!data.empty()) {
+    std::move(callback).Run(data);
+    return;
   }
-  std::move(callback).Run(data);
+
+  SkBitmap bitmap = ReadBitmapInternal(buffer);
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+      base::BindOnce(&clipboard_util::EncodeBitmapToPng, bitmap),
+      std::move(callback));
 }
 
 // |data_dst| is not used. It's only passed to be consistent with other
@@ -728,10 +736,15 @@
   // order is also important as some programs will use the first compatible
   // format that is available on the clipboard, and we want Word to choose the
   // PNG format.
-
-  std::vector<unsigned char> png_encoded_bitmap;
-  if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, /*discard_transparency=*/false,
-                                        &png_encoded_bitmap)) {
+  //
+  // Encode the bitmap to a PNG from the UI thread. Ideally this CPU-intensive
+  // encoding operation would be performed on a background thread, but
+  // ui::base::Clipboard writes are (unfortunately) synchronous.
+  // We could consider making writes async, then moving this image encoding to a
+  // background sequence.
+  std::vector<uint8_t> png_encoded_bitmap =
+      clipboard_util::EncodeBitmapToPngAcceptJank(bitmap);
+  if (!png_encoded_bitmap.empty()) {
     HGLOBAL png_hglobal = skia::CreateHGlobalForByteArray(png_encoded_bitmap);
     if (png_hglobal)
       WriteToClipboard(ClipboardFormatType::PngType(), png_hglobal);
diff --git a/ui/base/ime/win/input_method_win_base.cc b/ui/base/ime/win/input_method_win_base.cc
index 39211bb..e0aeb0d5 100644
--- a/ui/base/ime/win/input_method_win_base.cc
+++ b/ui/base/ime/win/input_method_win_base.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include <cwctype>
 
 #include <memory>
 #include <vector>
@@ -15,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
 #include "base/win/windows_version.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h"
@@ -230,9 +230,9 @@
   }
 
   // If only 1 WM_CHAR per the key event, set it as the character of it.
-  if (char_msgs.size() == 1 &&
-      !std::iswcntrl(static_cast<wint_t>(char_msgs[0].wParam)))
+  if (char_msgs.size() == 1 && !base::IsAsciiControl(char_msgs[0].wParam)) {
     event->set_character(static_cast<char16_t>(char_msgs[0].wParam));
+  }
 
   return ProcessUnhandledKeyEvent(event, &char_msgs);
 }
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 55d33f4..3f6d166 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -1769,7 +1769,7 @@
     You are currently offline. Sync will resume when the connection is back on.
   </message>
   <message name="IDS_FILE_BROWSER_BULK_PINNING_TITLE" translateable="false" desc="The title of the dialog offering the Google Drive bulk pinning feature">
-    Keep your files available when you’re offline
+    Easily access your Google Drive files when you’re offline
   </message>
   <message name="IDS_FILE_BROWSER_BULK_PINNING_EXPLANATION" translateable="false" desc="The main text of the dialog offering the Google Drive bulk pinning feature">
     Your files in My Drive will sync to your Chromebook automatically so you can access them without an internet connection.
@@ -1798,6 +1798,9 @@
   <message name="IDS_FILE_BROWSER_BULK_PINNING_CONTINUE" translateable="false" desc="Text in the Continue button of the dialog offering the Google Drive bulk pinning feature">
     Continue
   </message>
+  <message name="IDS_FILE_BROWSER_BULK_PINNING_GET_STARTED" translateable="false" desc="Text in the Get started button of the banner offering the Google Drive bulk pinning feature">
+    Get started
+  </message>
   <message name="IDS_FILE_BROWSER_GOOGLE_DRIVE_BULK_PINNING_NOT_ENOUGH_SPACE_LABEL" translateable="false" desc="The text used when the bulk pinning of Google Drive items has failed due to insufficient space.">
     You don't have enough local storage to keep all your files available offline.
   </message>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_af.xtb b/ui/chromeos/translations/ui_chromeos_strings_af.xtb
index f03ab43..b4a1730 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_af.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_af.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">Geen onlangse video's nie</translation>
 <translation id="3634507049637220048">Netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" />, deur jou administrateur bestuur, besonderhede</translation>
 <translation id="3645233063072417428"><ph name="NUMBER_OF_ITEMS" /> items is geskuif.</translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> lêers is gekies</translation>
 <translation id="3685122418104378273">Google Drive-sinkronisering is by verstek afgeskakel wanneer dit mobiele data gebruik.</translation>
 <translation id="3689865792480713551">Kanselleer <ph name="ACTIVITY_DESCRIPTION" />.</translation>
 <translation id="3690128548376345212">Netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />; nie geaktiveer nie; <ph name="CONNECTION_STATUS" />; seinsterkte <ph name="SIGNAL_STRENGTH" />%; besonderhede</translation>
@@ -576,6 +577,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" />-prent</translation>
 <translation id="5534520101572674276">Bereken tans grootte</translation>
 <translation id="554153475311314364">Griekse transliterasie</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> vouers is gekies</translation>
 <translation id="5580591966435005537">virtuele masjien</translation>
 <translation id="5583640892426849032">Backspace</translation>
 <translation id="5583664733673201137">Leestekenbreedte is vol</translation>
@@ -598,6 +600,7 @@
 <translation id="5724172041621205163">Thai met Pattachote-sleutelbord</translation>
 <translation id="57383366388012121">Verlede maand</translation>
 <translation id="5756666464756035725">Hongaarse QWERTY</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> items is gekies</translation>
 <translation id="5763377084591234761">Duits (Switserland)</translation>
 <translation id="5769519078756170258">Gasheer of domein om uit te sluit</translation>
 <translation id="5775750595919327203">Oerdoe</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_am.xtb b/ui/chromeos/translations/ui_chromeos_strings_am.xtb
index 584c933f..2bf367b3 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_am.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_am.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">ምንም የቅርብ ጊዜ ቪድዮዎች የሉም</translation>
 <translation id="3634507049637220048">አውታረመረብ <ph name="NETWORK_INDEX" /> ከ<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />፣ <ph name="CONNECTION_STATUS" />፣ በእርስዎ አስተዳዳሪ የሚተዳደር፣ ዝርዝሮች</translation>
 <translation id="3645233063072417428"><ph name="NUMBER_OF_ITEMS" /> ንጥሎች ተወስደዋል።</translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> ፋይሎች ተመርጠዋል</translation>
 <translation id="3685122418104378273">የሞባይል ውሂብ ጥቅም ላይ በሚውልበት ጊዜ Google Drive ማመሳሰል በነባሪ ይሰናከላል።</translation>
 <translation id="3689865792480713551"><ph name="ACTIVITY_DESCRIPTION" />ን ሰርዝ።</translation>
 <translation id="3690128548376345212">አውታረ መረብ <ph name="NETWORK_INDEX" /> ከ<ph name="NETWORK_COUNT" />፣ <ph name="NETWORK_NAME" />፣ ያልነቃ፣ <ph name="CONNECTION_STATUS" />፣ የሲግናል ጥንካሬ <ph name="SIGNAL_STRENGTH" />%፣ ዝርዝሮች</translation>
@@ -577,6 +578,7 @@
 <translation id="5533102081734025921">የ<ph name="IMAGE_TYPE" /> ምስል</translation>
 <translation id="5534520101572674276">መጠንን በማስላት ላይ</translation>
 <translation id="554153475311314364">በግሪክ ቋንቋ ፊደል መጻፍ</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> አቃፊዎች ተመርጠዋል</translation>
 <translation id="5580591966435005537">ምናባዊ ማሽን</translation>
 <translation id="5583640892426849032">Backspace</translation>
 <translation id="5583664733673201137">የሥርዓተ ነጥብ ስፋት ሙሉ ነው</translation>
@@ -599,6 +601,7 @@
 <translation id="5724172041621205163">ታይላንድኛ በፓቶቾት ቁልፍ ሰሌዳ</translation>
 <translation id="57383366388012121">ባለፈው ወር</translation>
 <translation id="5756666464756035725">የሃንጋሪኛ QWERTY</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> ንጥሎች ተመርጠዋል</translation>
 <translation id="5763377084591234761">ጀርመንኛ (ስዊዘርላንድ)</translation>
 <translation id="5769519078756170258">የሚገለል አስተናጋጅ ወይም ጎራ</translation>
 <translation id="5775750595919327203">ኡርዱ</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_da.xtb b/ui/chromeos/translations/ui_chromeos_strings_da.xtb
index 2996bca..507c133 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_da.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_da.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">Du har ikke åbnet nogen videoer for nylig</translation>
 <translation id="3634507049637220048">Netværk <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" />, administreret af din administrator, oplysninger</translation>
 <translation id="3645233063072417428"><ph name="NUMBER_OF_ITEMS" /> elementer blev flyttet.</translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> filer er valgt</translation>
 <translation id="3685122418104378273">Synkronisering af Google Drev er som standard deaktiveret, når du bruger mobildata.</translation>
 <translation id="3689865792480713551">Annuller <ph name="ACTIVITY_DESCRIPTION" />.</translation>
 <translation id="3690128548376345212">Netværk <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, ikke aktiveret, <ph name="CONNECTION_STATUS" />, signalstyrke på <ph name="SIGNAL_STRENGTH" /> %, oplysninger</translation>
@@ -577,6 +578,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" />-billede</translation>
 <translation id="5534520101572674276">Beregner størrelse</translation>
 <translation id="554153475311314364">Græsk translitteration</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> mapper er valgt</translation>
 <translation id="5580591966435005537">virtuel maskine</translation>
 <translation id="5583640892426849032">Backspace</translation>
 <translation id="5583664733673201137">Tegnsætningsbredden er Fuld</translation>
@@ -599,6 +601,7 @@
 <translation id="5724172041621205163">Thai med Pattachote-tastatur</translation>
 <translation id="57383366388012121">Sidste måned</translation>
 <translation id="5756666464756035725">Ungarsk QWERTY-tastatur</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> elementer er valgt</translation>
 <translation id="5763377084591234761">Tysk (Schweiz)</translation>
 <translation id="5769519078756170258">Host eller domæne, der skal ekskluderes</translation>
 <translation id="5775750595919327203">Urdu</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_lo.xtb b/ui/chromeos/translations/ui_chromeos_strings_lo.xtb
index 0973c2e..9d680a66 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_lo.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_lo.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">ບໍ່ມີວິດີໂອຫຼ້າສຸດ</translation>
 <translation id="3634507049637220048">ເຄືອຂ່າຍທີ <ph name="NETWORK_INDEX" /> ຈາກທັງໝົດ <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" />, ຈັດການໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ, ລາຍລະອຽດ</translation>
 <translation id="3645233063072417428">ຍ້າຍ <ph name="NUMBER_OF_ITEMS" /> ລາຍການແລ້ວ.</translation>
+<translation id="3658269352872031728">ເລືອກ <ph name="SELECTED_FILE_COUNT" /> ໄຟລ໌ແລ້ວ</translation>
 <translation id="3685122418104378273">ການ​ຊິງ​ຄ໌ Google Drive ປິດ​ໃຊ້​ງານ​ໂດຍ​ມາດ​ຕະ​ຖານ​ແລ້ວ, ເມື່ອ​ກຳ​ລັງ​ໃຊ້​ຂໍ້​ມູນ​ມື​ຖື.</translation>
 <translation id="3689865792480713551">ຍົກເລີກ <ph name="ACTIVITY_DESCRIPTION" />.</translation>
 <translation id="3690128548376345212">ເຄືອຂ່າຍທີ <ph name="NETWORK_INDEX" /> ຈາກທັງໝົດ <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, ບໍ່ໄດ້ເປີດໃຊ້, <ph name="CONNECTION_STATUS" />, ຄວາມແຮງສັນຍານ <ph name="SIGNAL_STRENGTH" />%, ລາຍລະອຽດ</translation>
@@ -576,6 +577,7 @@
 <translation id="5533102081734025921">ຮູບ <ph name="IMAGE_TYPE" /></translation>
 <translation id="5534520101572674276">ກໍາລັງຄິດໄລ່ຂະໜາດ</translation>
 <translation id="554153475311314364">ການແປທັບສັບພາສາກຣີກ</translation>
+<translation id="5554171655917412781">ເລືອກ <ph name="SELECTED_FOLDERS_COUNT" /> ໂຟນເດີແລ້ວ</translation>
 <translation id="5580591966435005537">ເຄື່ອງສະເໝືອນ</translation>
 <translation id="5583640892426849032">ລຶບຄືນຫຼັງ</translation>
 <translation id="5583664733673201137">ຄວາມກວ້າງເຄື່ອງໝາຍວັກຕອນເຕັມແລ້ວ</translation>
@@ -598,6 +600,7 @@
 <translation id="5724172041621205163">ພາສາໄທທີ່ໃຊ້ແປ້ນພິມປັດຕາໂຊດ</translation>
 <translation id="57383366388012121">ເດືອນທີ່ຜ່ານມາ</translation>
 <translation id="5756666464756035725">QWERTY ພາ​ສາ​ຮົງ​ກາ​ລີ</translation>
+<translation id="5760252553414789727">ເລືອກ <ph name="SELECTED_FILES_COUNT" /> ລາຍການແລ້ວ</translation>
 <translation id="5763377084591234761">ພາສາເຢຍລະມັນ (ສະວິດເຊີແລນ)</translation>
 <translation id="5769519078756170258">ໂຮສ ຫຼື ໂດເມນທີ່ຈະຍົກເວັ້ນ</translation>
 <translation id="5775750595919327203">ພາສາອູຣະດູ</translation>
@@ -916,6 +919,7 @@
 <translation id="8264024885325823677">ການຕັ້ງຄ່ານີ້ຈັດການໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ.</translation>
 <translation id="8269755669432358899">ຫຍໍ້ແຜງຄຳຕິຊົມໄຟລ໌ລົງ</translation>
 <translation id="8280151743281770066">ການອອກສຽງພາສາອາກເມນີ</translation>
+<translation id="8285791779547722821">ໄດ້ຖືກເຂົ້າລະຫັດ <ph name="ORIGINAL_MIME_TYPE" /></translation>
 <translation id="8294431847097064396">ແຫຼ່ງທີ່ມາ</translation>
 <translation id="8297012244086013755">ຮາງກຸລ 3 ຊຸດ (​ບໍ່​ໃຊ້ປຸ່ມ  shift)</translation>
 <translation id="8299269255470343364">ພາສາຍີ່ປຸ່ນ</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_ne.xtb b/ui/chromeos/translations/ui_chromeos_strings_ne.xtb
index 06e61ee..3466281 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_ne.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_ne.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">हालसालै कुनै पनि भिडियो हेरिएको छैन</translation>
 <translation id="3634507049637220048"><ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" /> मध्ये नेटवर्क <ph name="NETWORK_INDEX" />, तपाईंका प्रशासकले व्यवस्थित गर्नुभएको छ, विवरणहरू</translation>
 <translation id="3645233063072417428"><ph name="NUMBER_OF_ITEMS" /> वटा वस्तु सारिए।</translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> वटा फाइलहरू चयन गरिएका छन्</translation>
 <translation id="3685122418104378273">Google ड्राइभ सिंक डिफल्ट रूपमा अक्षम गरिएको हुन्छ, मोबाइल डेटाको खपत गर्ने क्रममा।</translation>
 <translation id="3689865792480713551"><ph name="ACTIVITY_DESCRIPTION" /> रद्द गर्नुहोस्।</translation>
 <translation id="3690128548376345212"><ph name="NETWORK_COUNT" /> मध्ये <ph name="NETWORK_INDEX" /> नेटवर्क, <ph name="NETWORK_NAME" />, अन नगरिएको, <ph name="CONNECTION_STATUS" />सिग्नलको क्षमता <ph name="SIGNAL_STRENGTH" />%, विवरणहरू</translation>
@@ -576,6 +577,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" /> छवि</translation>
 <translation id="5534520101572674276">परिमाण हिसाब गर्दै</translation>
 <translation id="554153475311314364">ग्रिक लिपि रूपान्तरण</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> वटा फोल्डर चयन गरिएका छन्</translation>
 <translation id="5580591966435005537">भर्चुअल मेसिन</translation>
 <translation id="5583640892426849032">ब्याकस्पेस</translation>
 <translation id="5583664733673201137">विरामको चौडाइ पूर्ण छ</translation>
@@ -598,6 +600,7 @@
 <translation id="5724172041621205163">थाई पत्ताचोते किबोर्ड</translation>
 <translation id="57383366388012121">गत महिना</translation>
 <translation id="5756666464756035725">हंगेरी QWERTY</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> वटा सामग्री चयन गरिएका छन्</translation>
 <translation id="5763377084591234761">जर्मन (स्विजरल्यान्ड)</translation>
 <translation id="5769519078756170258">वर्जित गर्नु पर्ने होस्ट वा डोमेन</translation>
 <translation id="5775750595919327203">उर्दू</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_te.xtb b/ui/chromeos/translations/ui_chromeos_strings_te.xtb
index ed49986..cae45a2 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_te.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_te.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">ఇటీవలి వీడియోలు ఏవీ లేవు</translation>
 <translation id="3634507049637220048"><ph name="NETWORK_COUNT" />లో <ph name="NETWORK_INDEX" /> నెట్‌వర్క్, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" />, మీ అడ్మినిస్ట్రేటర్ ద్వారా నిర్వహించబడుతోంది, వివరాలు</translation>
 <translation id="3645233063072417428"><ph name="NUMBER_OF_ITEMS" /> ఐటెమ్‌లు తరలించబడ్డాయి.</translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> ఫైల్స్ ఎంచుకోబడ్డాయి</translation>
 <translation id="3685122418104378273">మొబైల్ డేటాను ఉపయోగిస్తున్నప్పుడు Google Drive సింక్ డిఫాల్ట్‌గా నిలిపివేయబడుతుంది.</translation>
 <translation id="3689865792480713551"><ph name="ACTIVITY_DESCRIPTION" />ను రద్దు చేయండి.</translation>
 <translation id="3690128548376345212"><ph name="NETWORK_COUNT" />లోని నెట్‌వర్క్ <ph name="NETWORK_INDEX" />, <ph name="NETWORK_NAME" />, యాక్టివేట్ చేయబడలేదు, <ph name="CONNECTION_STATUS" />, సిగ్నల్ సామర్థ్యం <ph name="SIGNAL_STRENGTH" />%, వివరాలు</translation>
@@ -577,6 +578,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" /> చిత్రం</translation>
 <translation id="5534520101572674276">పరిమాణాన్ని లెక్కిస్తోంది</translation>
 <translation id="554153475311314364">గ్రీక్ ట్రాన్స్‌లిటరేషన్</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> ఫోల్డర్‌లు ఎంచుకోబడ్డాయి</translation>
 <translation id="5580591966435005537">వర్చువల్ మెషిన్</translation>
 <translation id="5583640892426849032">Backspace</translation>
 <translation id="5583664733673201137">విరామచిహ్నం వెడల్పు నిండింది</translation>
@@ -599,6 +601,7 @@
 <translation id="5724172041621205163">పట్టచోటె కీబోర్డ్‌తో థాయ్</translation>
 <translation id="57383366388012121">గత నెల</translation>
 <translation id="5756666464756035725">హంగేరియన్ QWERTY</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> ఐటెమ్‌లు ఎంచుకోబడ్డాయి</translation>
 <translation id="5763377084591234761">జర్మన్ (స్విట్జర్లాండ్)</translation>
 <translation id="5769519078756170258">మినహాయించాల్సిన హోస్ట్ లేదా డొమైన్</translation>
 <translation id="5775750595919327203">ఉర్దూ</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_uz.xtb b/ui/chromeos/translations/ui_chromeos_strings_uz.xtb
index a3109baf..b3e6981 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_uz.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_uz.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">Oxirgi videolar yoʻq</translation>
 <translation id="3634507049637220048">Tarmoq: <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" />, Nomi: <ph name="NETWORK_NAME" />, Ulanish:<ph name="CONNECTION_STATUS" />, Administrator boshqaruvida, Batafsil</translation>
 <translation id="3645233063072417428">Boshqa joyga olindi: <ph name="NUMBER_OF_ITEMS" /></translation>
+<translation id="3658269352872031728"><ph name="SELECTED_FILE_COUNT" /> ta fayl tanlandi.</translation>
 <translation id="3685122418104378273">Google Disk‘ni mobil internet orqali sinxronlash birlamchi holatda o‘chirib qo‘yilgan.</translation>
 <translation id="3689865792480713551">Bekor qilish <ph name="ACTIVITY_DESCRIPTION" />.</translation>
 <translation id="3690128548376345212">Tarmoq: <ph name="NETWORK_INDEX" /> / <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, faolsizlantirilgan, <ph name="CONNECTION_STATUS" />, signal kuchi <ph name="SIGNAL_STRENGTH" />%, tafsilotlar</translation>
@@ -576,6 +577,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" /> rasm</translation>
 <translation id="5534520101572674276">Hajm hisoblanmoqda...</translation>
 <translation id="554153475311314364">Grek tili transliteratsiyasi</translation>
+<translation id="5554171655917412781"><ph name="SELECTED_FOLDERS_COUNT" /> ta jild tanlandi</translation>
 <translation id="5580591966435005537">virtual mashina</translation>
 <translation id="5583640892426849032">Backspace</translation>
 <translation id="5583664733673201137">Toʻliq enli imlo tekshiruvi</translation>
@@ -598,6 +600,7 @@
 <translation id="5724172041621205163">Tay (Pattachote klaviaturasi)</translation>
 <translation id="57383366388012121">Avvalgi oy</translation>
 <translation id="5756666464756035725">Venger QWERTY klaviaturasi</translation>
+<translation id="5760252553414789727"><ph name="SELECTED_FILES_COUNT" /> ta element tanlandi</translation>
 <translation id="5763377084591234761">Nemis (Shveytsariya)</translation>
 <translation id="5769519078756170258">Istisno host yoki domen</translation>
 <translation id="5775750595919327203">Urdu</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_zu.xtb b/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
index 566167a..b5dacc2 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
@@ -320,6 +320,7 @@
 <translation id="3619593063686672873">Awekho amavidiyo akamuva</translation>
 <translation id="3634507049637220048">Inethiwekhi <ph name="NETWORK_INDEX" /> ye-<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="CONNECTION_STATUS" />, Iphethwe umlawuli wakho, imininingwane</translation>
 <translation id="3645233063072417428">izinto ezihanjisiwe ezingu-<ph name="NUMBER_OF_ITEMS" />.</translation>
+<translation id="3658269352872031728">Kukhethwe amafayela angu-<ph name="SELECTED_FILE_COUNT" /></translation>
 <translation id="3685122418104378273">Ukuvumelanisa kwe-Google Drayivu kukhutshaziwe ngokuzenzakalela, uma kusetshenziswa idatha yeselula.</translation>
 <translation id="3689865792480713551">Khansela i-<ph name="ACTIVITY_DESCRIPTION" />.</translation>
 <translation id="3690128548376345212">Inethiwekhi engu-<ph name="NETWORK_INDEX" /> kwezingu-<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, Akusetshenzisiwe <ph name="CONNECTION_STATUS" />, Amandla Wesignali <ph name="SIGNAL_STRENGTH" />%, Imininingwane</translation>
@@ -576,6 +577,7 @@
 <translation id="5533102081734025921"><ph name="IMAGE_TYPE" /> isithombe</translation>
 <translation id="5534520101572674276">Ibala usayizi</translation>
 <translation id="554153475311314364">Ukuguqulwa kwamaletha kwesi-Greek</translation>
+<translation id="5554171655917412781">Kukhethwe amafolda angu-<ph name="SELECTED_FOLDERS_COUNT" /></translation>
 <translation id="5580591966435005537">umshini we-virtual</translation>
 <translation id="5583640892426849032">I-Backspace</translation>
 <translation id="5583664733673201137">Ububanzi bezimpawu zokubhala Bugcwele</translation>
@@ -598,6 +600,7 @@
 <translation id="5724172041621205163">Thai esinekhibhodi ye-Pattachote</translation>
 <translation id="57383366388012121">Inyanga edlule</translation>
 <translation id="5756666464756035725">I-Hungarian QWERTY</translation>
+<translation id="5760252553414789727">Kukhethwe izinto ezingu-<ph name="SELECTED_FILES_COUNT" /></translation>
 <translation id="5763377084591234761">German (Switzerland)</translation>
 <translation id="5769519078756170258">Umsingathi noma isizinda esizokhishwa</translation>
 <translation id="5775750595919327203">Isi-Urdu</translation>
diff --git a/ui/color/material_ui_color_mixer.cc b/ui/color/material_ui_color_mixer.cc
index ab08a8b..0c903291 100644
--- a/ui/color/material_ui_color_mixer.cc
+++ b/ui/color/material_ui_color_mixer.cc
@@ -65,11 +65,11 @@
   mixer[kColorMenuIcon] = {kColorSysOnSurfaceSubtle};
   mixer[kColorMenuItemForegroundSecondary] = {kColorSysOnSurfaceSubtle};
   mixer[kColorMenuItemForeground] = {kColorSysOnSurface};
-  mixer[kColorMenuSeparator] = {kColorSysDivider};
   mixer[kColorRadioButtonForegroundChecked] = {kColorSysPrimary};
   mixer[kColorRadioButtonForegroundDisabled] = {
       kColorSysStateDisabledContainer};
   mixer[kColorRadioButtonForegroundUnchecked] = {kColorSysOutline};
+  mixer[kColorSeparator] = {kColorSysDivider};
   mixer[kColorSliderThumb] = {kColorSysPrimary};
   mixer[kColorSliderThumbMinimal] = {kColorSysSecondary};
   mixer[kColorSliderTrack] = {kColorSysOnPrimary};
diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc
index 7b250f1ac..0284eaa 100644
--- a/ui/color/ui_color_mixer.cc
+++ b/ui/color/ui_color_mixer.cc
@@ -141,7 +141,7 @@
   mixer[kColorMenuItemForegroundHighlighted] = {kColorMenuItemForeground};
   mixer[kColorMenuItemForegroundSecondary] = {kColorSecondaryForeground};
   mixer[kColorMenuItemForegroundSelected] = {kColorMenuItemForeground};
-  mixer[kColorMenuSeparator] = {kColorMidground};
+  mixer[kColorMenuSeparator] = {kColorSeparator};
   mixer[kColorNotificationActionsBackground] = {
       kColorNotificationBackgroundActive};
   mixer[kColorNotificationBackgroundActive] = {kColorSubtleEmphasisBackground};
diff --git a/ui/file_manager/base/gn/file_types.json5 b/ui/file_manager/base/gn/file_types.json5
index ca390a71..769808f 100644
--- a/ui/file_manager/base/gn/file_types.json5
+++ b/ui/file_manager/base/gn/file_types.json5
@@ -540,6 +540,14 @@
     "mime": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
   },
   {
+    "type": "document",
+    "icon": "excel",
+    "translationKey": "EXCEL_FILE_TYPE",
+    "subtype": "Excel",
+    "extensions": [".xlsm"],
+    "mime": "application/vnd.ms-excel.sheet.macroEnabled.12"
+  },
+  {
     "type": "archive",
     "icon": "tini",
     "translationKey": "TINI_FILE_TYPE",
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js
index 0c462d2..5b4197e 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_handler.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -100,9 +100,8 @@
             if (event.itemCount === 1) {
               // Single item: the user can continue the action directly from
               // the notification.
-              chrome.fileManagerPrivate.resumeIOTask(
-                  event.taskId,
-                  chrome.fileManagerPrivate.ResumeParams('', false));
+              // TODO(b/281973963): Pass resume reason.
+              chrome.fileManagerPrivate.resumeIOTask(event.taskId, {});
             } else {
               // Multiple items: the user can continue the action from the
               // review dialog.
diff --git a/ui/file_manager/file_manager/background/js/progress_center.js b/ui/file_manager/file_manager/background/js/progress_center.js
index c894ff2..31dc11b6 100644
--- a/ui/file_manager/file_manager/background/js/progress_center.js
+++ b/ui/file_manager/file_manager/background/js/progress_center.js
@@ -4,7 +4,7 @@
 
 import {AsyncQueue} from '../../common/js/async_util.js';
 import {notifications} from '../../common/js/notifications.js';
-import {ProgressCenterItem, ProgressItemState} from '../../common/js/progress_center_common.js';
+import {ProgressCenterItem, ProgressItemState, ProgressItemType} from '../../common/js/progress_center_common.js';
 import {getFilesAppIconURL} from '../../common/js/url_constants.js';
 import {str} from '../../common/js/util.js';
 import {ProgressCenter} from '../../externs/background/progress_center.js';
@@ -202,6 +202,155 @@
       this.panels_[i].dismissErrorItem(id);
     }
   }
+
+  /**
+   * Testing method to construct a new notification panel item.
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   * @return {!ProgressCenterItem}
+   */
+  constructTestItem_(props) {
+    const item = new ProgressCenterItem();
+    const defaults = {
+      id: Math.ceil(Math.random() * 10000).toString(),
+      itemCount: Math.ceil(Math.random() * 5),
+      sourceMessage: 'fake_file.test',
+      destinationMessage: 'Downloads',
+      type: ProgressItemType.COPY,
+      progressMax: 100,
+    };
+    // Apply defaults and overrides.
+    Object.assign(item, defaults, props);
+
+    return item;
+  }
+
+  /**
+   * Testing method to add the notification panel item to the notification
+   * panel.
+   * @private
+   * @param {ProgressCenterItem} item the panel item to be added.
+   *
+   * @suppress {checkTypes} add new property to the struct.
+   */
+  addItemToPanel_(item) {
+    // Make notification panel item show immediately.
+    this.panels_[0].PENDING_TIME_MS_ = 0;
+    // Make notification panel item keep showing for 5 minutes.
+    this.panels_[0].TIMEOUT_TO_REMOVE_MS_ = 5 * 60 * 1000;
+    // Add the item to the panel.
+    this.items_.push(item);
+    this.updateItem(item);
+  }
+
+  /**
+   * Testing method to add a new "progressing" state notification panel item.
+   *
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   */
+  addProcessingTestItem_(props) {
+    const item = this.constructTestItem_({
+      state: ProgressItemState.PROGRESSING,
+      progressValue: Math.ceil(Math.random() * 90),
+      remainingTime: 150,
+      ...props,
+    });
+    this.addItemToPanel_(item);
+    return item;
+  }
+
+  /**
+   * Testing method to add a new "completed" state notification panel item.
+   *
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   *
+   * @suppress {missingProperties} access private properties.
+   */
+  addCompletedTestItem_(props) {
+    const item = this.constructTestItem_({
+      state: ProgressItemState.COMPLETED,
+      progressValue: 100,
+      ...props,
+    });
+    // Completed item needs to be in the panel before it completes.
+    const oldItem = item.clone();
+    oldItem.state = ProgressItemState.PROGRESSING;
+    this.panels_[0].items_[item.id] = oldItem;
+    this.addItemToPanel_(item);
+    return item;
+  }
+
+  /**
+   * Testing method to add a new "error" state notification panel item.
+   *
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   *
+   * @suppress {missingProperties} access private properties.
+   */
+  addErrorTestItem_(props) {
+    const item = this.constructTestItem_({
+      state: ProgressItemState.ERROR,
+      message: 'Something went wrong. This is a very long error message.',
+      ...props,
+    });
+    item.extraButton.set(ProgressItemState.ERROR, {
+      text: 'Learn more',
+      callback: () => {},
+    });
+    this.addItemToPanel_(item);
+    return item;
+  }
+
+  /**
+   * Testing method to add a new "scanning" state notification panel item.
+   *
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   *
+   * @suppress {missingProperties} access private properties.
+   */
+  addScanningTestItem_(props) {
+    const item = this.constructTestItem_({
+      state: ProgressItemState.SCANNING,
+      progressValue: Math.ceil(Math.random() * 90),
+      remainingTime: 100,
+      ...props,
+    });
+    // Scanning item needs to be in the panel before it starts to scan.
+    const oldItem = item.clone();
+    this.panels_[0].items_[item.id] = oldItem;
+    this.addItemToPanel_(item);
+    return item;
+  }
+
+  /**
+   * Testing method to add a new "paused" state notification panel item.
+   *
+   * @private
+   * @param {Object|undefined} props partial properties from
+   *     the {ProgressCenterItem}.
+   *
+   * @suppress {missingProperties} access private properties.
+   */
+  addPausedTestItem_(props) {
+    const item = this.constructTestItem_({
+      state: ProgressItemState.PAUSED,
+      ...props,
+    });
+    // Paused item needs to be in the panel before it pauses.
+    const oldItem = item.clone();
+    this.panels_[0].items_[item.id] = oldItem;
+    this.addItemToPanel_(item);
+    return item;
+  }
 }
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 387de21..6b61f495 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1251,12 +1251,20 @@
   font: var(--cros-body-2-font);
   margin-top: 16px;
   text-align: center;
+  /* Ensure links in label are on top when not hidden so a click is not
+  absorbed by an empty file-list. */
+  z-index: 999;
 }
 
 #empty-folder > .label > span#empty-folder-title {
   font-weight: bold;
 }
 
+#empty-folder > .label > span#empty-folder-desc > a {
+  color: var(--cros-text-color-prominent);
+  font: var(--cros-body-1-font);
+}
+
 #detail-table {
   display: flex;
   flex: auto;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
index f5cfa7ed..d22d2c3 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
@@ -1024,12 +1024,20 @@
   margin-top: 16px;
   text-align: center;
   width: 320px;
+  /* Ensure links in label are on top when not hidden so a click is not
+  absorbed by an empty file-list. */
+  z-index: 999;
 }
 
 #empty-folder #empty-folder-title {
   font: var(--cros-button-2-font);
 }
 
+#empty-folder > .label > span#empty-folder-desc > a {
+  color: var(--cros-text-color-prominent);
+  font: var(--cros-body-1-font);
+}
+
 #detail-table {
   display: flex;
   flex: auto;
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_button.html b/ui/file_manager/file_manager/foreground/elements/xf_button.html
index 6b5d95a..535879c 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_button.html
+++ b/ui/file_manager/file_manager/foreground/elements/xf_button.html
@@ -2,10 +2,10 @@
 <style>
   cr-icon-button,
   cr-button {
-    margin-inline-start: 0;
+    margin-inline: 0;
   }
 
-  cr-button {
+  :host-context([theme='legacy']) cr-button {
     --active-bg: var(--cros-button-background-color-secondary-hover);
     /* The shadow can only be customized via rgb values, to turn the shadow
        off make the shadow appear as the background color. */
@@ -19,13 +19,41 @@
     --text-color: var(--cros-button-label-color-secondary);
   }
 
-  cr-icon-button {
+  :host-context([theme='refresh23']) cr-button {
+    --active-bg: none;
+    --hover-bg-color: var(--cros-sys-hover_on_subtle);
+    --ink-color: var(--cros-sys-ripple_neutral_on_subtle);
+    --paper-ripple-opacity: 100%;
+    --text-color: var(--cros-sys-primary);
+    border: none;
+    border-radius: 18px;
+    box-shadow: none;
+    font: var(--cros-button-2-font);
+    height: 36px;
+    padding-inline: 16px;
+  }
+
+  :host-context([theme='refresh23']):host-context(.focus-outline-visible)
+      cr-button:focus {
+    outline: 2px solid var(--cros-sys-focus_ring);
+    outline-offset: 2px;
+  }
+
+  :host-context([theme='legacy']) cr-icon-button {
     --cr-active-bg-color: var(--cros-icon-button-pressed-color);
     --cr-focus-outline-color: var(--cros-focus-ring-color);
     --cr-hover-background-color: var(--cros-ripple-color);
     --cr-icon-button-fill-color: var(--cros-icon-color-primary);
   }
 
+  :host-context([theme='refresh23']) cr-icon-button {
+    --cr-active-bg-color: var(--cros-sys-pressed_on_subtle);
+    --cr-focus-outline-color: var(--cros-sys-focus_ring);
+    --cr-hover-background-color: var(--cros-sys-hover_on_subtle);
+    --cr-icon-button-fill-color: var(--cros-sys-on_surface);
+    border-radius: 12px;
+  }
+
   @keyframes setcollapse {
     from {
       transform: rotate(0deg);
@@ -78,11 +106,11 @@
   }
 
   :host([data-category='dismiss']) #dismiss {
-    display: unset;
+    display: inline-block;
   }
 
   :host([data-category='extra-button']) #extra-button {
-    display: unset;
+    display: inline-block;
   }
 </style>
 <cr-button id='dismiss'>$i18n{DRIVE_WELCOME_DISMISS}</cr-button>
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.html b/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.html
index 9f9529a..41f7231 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.html
+++ b/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.html
@@ -16,19 +16,38 @@
     width: 28px;
   }
 
-  .bottom {
+  :host-context([theme='legacy']) .bottom {
     fill: none;
     stroke: var(--cros-highlight-color);
   }
-  .top {
+  :host-context([theme='refresh23']) .bottom {
+    fill: none;
+    stroke: var(--cros-sys-primary_container);
+  }
+  :host-context([theme='legacy']) .top {
     fill: none;
     stroke: var(--cros-icon-color-prominent);
     stroke-linecap: round;
   }
-  text {
+  :host-context([theme='refresh23']) .top {
+    fill: none;
+    stroke: var(--cros-sys-primary);
+    stroke-linecap: round;
+  }
+  :host-context([theme='legacy']) text {
     fill: var(--cros-text-color-prominent);
     font: bold 14px Roboto;
   }
+  :host-context([theme='refresh23']) text {
+    fill: var(--cros-sys-primary);
+    font: var(--cros-button-1-font);
+  }
+  :host-context([theme='legacy']) .errormark {
+    fill: rgb(217, 48, 37);
+  }
+  :host-context([theme='refresh23']) .errormark {
+    fill: var(--cros-sys-error);
+  }
 </style>
 <div class='progress'>
   <svg xmlns='http://www.w3.org/2000/svg'
@@ -41,7 +60,6 @@
     <text class='label' x='18' y='18' text-anchor='middle'
       alignment-baseline='central'></text>
     <circle class='errormark' visibility='hidden'
-      cx='25.5' cy='10.5' r='4'
-      fill='#D93025' stroke='none'></circle>
+      cx='25.5' cy='10.5' r='4' stroke='none'></circle>
   </svg>
 </div>
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.html b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.html
index ee1b2f1..730e290d 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.html
+++ b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.html
@@ -5,18 +5,29 @@
   }
   #container {
     align-items: stretch;
-    background-color: var(--cros-bg-color-elevation-2);
-    border-radius: 4px;
     box-shadow: var(--cros-elevation-2-shadow);
     display: flex;
     flex-direction: column;
     max-width: min-content;
     z-index: 100;
   }
+  :host-context([theme='legacy']) #container {
+    background-color: var(--cros-bg-color-elevation-2);
+    border-radius: 4px;
+  }
+  :host-context([theme='refresh23']) #container {
+    background-color: var(--cros-sys-base_elevated);
+    border-radius: 8px;
+  }
   #separator {
-    background-color: var(--cros-separator-color);
     height: 1px;
   }
+  :host-context([theme='legacy']) #separator {
+    background-color: var(--cros-separator-color);
+  }
+  :host-context([theme='refresh23']) #separator {
+    background-color: var(--cros-sys-separator);
+  }
   /* Limit to 3 visible progress panels before scroll. */
   #panels {
     max-height: calc(192px + 28px);
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.html b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.html
index be63e40..c4b3f7c 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.html
+++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.html
@@ -1,29 +1,44 @@
 <style>
   .xf-panel-item {
       align-items: center;
-      background-color: var(--cros-bg-color-elevation-2);
-      border-radius: 4px;
       display: flex;
       flex-direction: row;
       height: 68px;
       width: 504px;
   }
 
-  .xf-button {
-      height: 36px;
-      width: 36px;
+  :host-context([theme='legacy']) .xf-panel-item {
+    background-color: var(--cros-bg-color-elevation-2);
+    border-radius: 4px;
+  }
+
+  :host-context([theme='refresh23']) .xf-panel-item {
+    background-color: var(--cros-sys-base_elevated);
+    border-radius: 8px;
+  }
+
+  :host-context([theme='refresh23']) xf-button {
+    height: 36px;
   }
 
   .xf-panel-text {
-      color: var(--cros-text-color-primary);
       flex: 1;
-      font: 13px Roboto;
-      line-height: 20px;
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
   }
 
+  :host-context([theme='legacy']) .xf-panel-text {
+    color: var(--cros-text-color-primary);
+    font: 13px Roboto;
+    line-height: 20px;
+  }
+
+  :host-context([theme='refresh23']) .xf-panel-text {
+    color: var(--cros-sys-on_surface);
+    font: var(--cros-body-2-font);
+  }
+
   .xf-panel-label-text {
       outline: none;
   }
@@ -41,14 +56,25 @@
   }
 
   .xf-panel-label-text {
-      color: var(--cros-text-color-primary);
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
   }
 
-  .xf-panel-secondary-text {
-      color: var(--cros-text-color-secondary);
+  :host-context([theme='legacy']) .xf-panel-label-text {
+    color: var(--cros-text-color-primary);
+  }
+
+  :host-context([theme='refresh23']) .xf-panel-label-text {
+    color: var(--cros-sys-on_surface);
+  }
+
+  :host-context([theme='legacy']) .xf-panel-secondary-text {
+    color: var(--cros-text-color-secondary);
+  }
+
+  :host-context([theme='refresh23']) .xf-panel-secondary-text {
+    color: var(--cros-sys-on_surface_variant);
   }
 
   :host(:not([detailed-panel])) .xf-padder-4 {
@@ -84,18 +110,44 @@
       margin-inline-start: 24px;
   }
 
-  :host([detailed-panel][panel-type='2']) .xf-panel-secondary-text {
-      color: var(--cros-text-color-positive);
+  :host-context([theme='legacy']):host([detailed-panel][panel-type='2'])
+      .xf-panel-secondary-text {
+    color: var(--cros-text-color-positive);
   }
 
-  :host([detailed-panel][panel-type='2'][fade-secondary-text]) .xf-panel-secondary-text {
-      color: var(--cros-text-color-secondary);
+  :host-context([theme='refresh23']):host([detailed-panel][panel-type='2'])
+      .xf-panel-secondary-text {
+    color: var(--cros-sys-positive);
   }
 
-  :host([detailed-panel]:not([detailed-summary])) xf-button {
+  :host-context([theme='legacy']):host([detailed-panel][panel-type='2'][fade-secondary-text])
+      .xf-panel-secondary-text {
+    color: var(--cros-text-color-secondary);
+  }
+
+  :host-context([theme='refresh23']):host([detailed-panel][panel-type='2'][fade-secondary-text])
+      .xf-panel-secondary-text {
+    color: var(--cros-sys-on_surface_variant);
+  }
+
+
+  :host-context([theme='legacy']):host([detailed-panel]:not([detailed-summary])) xf-button {
       margin-inline-end: 12px;
   }
 
+  :host-context([theme='refresh23']):host([detailed-panel]:not([detailed-summary])) xf-button {
+    margin-inline-end: 8px;
+  }
+
+  :host-context([theme='refresh23']):host([detailed-panel]:not([detailed-summary])) xf-button:last-of-type {
+    margin-inline-end: 12px;
+  }
+
+  :host-context([theme='refresh23']):host([detailed-panel]:not([detailed-summary])) xf-button[data-category='cancel'] {
+    /* This is to make sure the cancel icon button is aligned with the collapse button. */
+    margin-inline-end: 16px;
+  }
+
   :host([detailed-panel]:not([detailed-summary])) #indicator {
       display: none;
   }
@@ -113,29 +165,53 @@
       width: 100%;
   }
 
+  :host-context([theme='refresh23']):host([detailed-summary]) .xf-panel-text {
+      font: var(--cros-button-2-font);
+  }
+
   :host([detailed-summary]) #indicator {
       margin-inline-start: 22px;
       padding: 0;
   }
 
-  :host([detailed-summary]) #indicator[icon='files36:success'] {
-      --iron-icon-fill-color: var(--cros-icon-color-positive);
+  :host-context([theme='legacy']):host([detailed-summary])
+      #indicator[icon='files36:success'] {
+    --iron-icon-fill-color: var(--cros-icon-color-positive);
   }
 
-  :host([detailed-summary]) #indicator[icon='files36:failure'] {
-      --iron-icon-stroke-color: var(--cros-icon-color-alert);
+
+  :host-context([theme='refresh23']):host([detailed-summary])
+      #indicator[icon='files36:success'] {
+    --iron-icon-fill-color: var(--cros-sys-positive);
   }
 
-  :host([detailed-summary][data-category='collapsed']) #indicator {
+
+  :host-context([theme='legacy']):host([detailed-summary])
+      #indicator[icon='files36:failure'] {
+    --iron-icon-stroke-color: var(--cros-icon-color-alert);
+  }
+
+  :host-context([theme='refresh23']):host([detailed-summary])
+      #indicator[icon='files36:failure'] {
+    --iron-icon-stroke-color: var(--cros-sys-error);
+  }
+
+  :host-context([theme='legacy']):host([detailed-summary][data-category='collapsed']) #indicator {
       margin-inline-end: 20px;
       min-width: 28px;
   }
 
-  :host([detailed-summary][data-category='expanded']) #indicator {
+  :host-context([theme='legacy']):host([detailed-summary][data-category='expanded']) #indicator {
       margin-inline-end: 18px;
       min-width: 32px;
   }
 
+  :host-context([theme='refresh23']) #indicator {
+    height: 32px;
+    margin-inline-end: 18px;
+    width: 32px;
+  }
+
   :host([detailed-summary]) #primary-action {
       align-items: center;
       display: flex;
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 4112c44..0d2fc8ad 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -9,6 +9,7 @@
 import {mountGuest} from '../../common/js/api.js';
 import {AsyncQueue, ConcurrentQueue} from '../../common/js/async_util.js';
 import {createDOMError} from '../../common/js/dom_utils.js';
+import {isEntryInsideDrive} from '../../common/js/entry_utils.js';
 import {FileType} from '../../common/js/file_type.js';
 import {EntryList} from '../../common/js/files_app_entry_types.js';
 import {metrics} from '../../common/js/metrics.js';
@@ -258,6 +259,20 @@
     this.rootType_ = locationInfo ? locationInfo.rootType : null;
     this.query_ = query.toLowerCase();
     this.options_ = options || getDefaultSearchOptions();
+    this.driveSearchTypeMap_ = new Map([
+      [
+        VolumeManagerCommon.RootType.DRIVE_OFFLINE,
+        chrome.fileManagerPrivate.SearchType.OFFLINE,
+      ],
+      [
+        VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME,
+        chrome.fileManagerPrivate.SearchType.SHARED_WITH_ME,
+      ],
+      [
+        VolumeManagerCommon.RootType.DRIVE_RECENT,
+        chrome.fileManagerPrivate.SearchType.EXCLUDE_DIRECTORIES,
+      ],
+    ]);
   }
 
   /**
@@ -437,13 +452,15 @@
    * @private
    */
   createDriveSearch_(modifiedTimestamp, category, maxResults) {
+    const searchType = this.driveSearchTypeMap_.get(this.rootType_) ||
+        chrome.fileManagerPrivate.SearchType.ALL;
     return new Promise((resolve, reject) => {
       metrics.startInterval('Search.Drive.Latency');
       chrome.fileManagerPrivate.searchDriveMetadata(
           {
             query: this.query_,
             category: category,
-            types: chrome.fileManagerPrivate.SearchType.ALL,
+            types: searchType,
             maxResults: maxResults,
             timestamp: modifiedTimestamp,
           },
@@ -472,7 +489,7 @@
    * @private
    */
   createDirectorySearch_(modifiedTimestamp, category, maxResults) {
-    if (this.rootType_ === VolumeManagerCommon.RootType.DRIVE) {
+    if (isEntryInsideDrive({rootType: this.rootType_})) {
       return [this.createDriveSearch_(modifiedTimestamp, category, maxResults)];
     }
     if (this.options_.location == SearchLocation.THIS_FOLDER) {
diff --git a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
index b6a7e3e..d43afe7 100644
--- a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
@@ -161,6 +161,58 @@
   }
 
   /**
+   * TODO(b/254586358): i18n these strings.
+   * Shows the ODFS reauthentication required message. Include the "Sign in"
+   * and "Settings" links and set the handlers.
+   * @private
+   */
+  showODFSReauthenticationMessage_() {
+    const titleSpan = document.createElement('span');
+    titleSpan.id = 'empty-folder-title';
+    titleSpan.innerText = 'You\'ve been logged out';
+
+    const signInLink = document.createElement('a');
+    signInLink.setAttribute('class', 'sign-in');
+    signInLink.innerText = 'Sign in';
+    signInLink.addEventListener('click', this.onODFSSignIn_.bind(this));
+
+    const inBetweenText = document.createElement('span');
+    inBetweenText.innerText = ' to your OneDrive account to open Office files' +
+        ' stored on your Chromebook or go to ';
+
+    const settingsLink = document.createElement('a');
+    settingsLink.setAttribute('class', 'settings');
+    settingsLink.innerText = 'Settings';
+    settingsLink.addEventListener('click', this.onSettings_.bind(this));
+
+    const descSpan = document.createElement('span');
+    descSpan.id = 'empty-folder-desc';
+    descSpan.appendChild(signInLink);
+    descSpan.appendChild(inBetweenText);
+    descSpan.appendChild(settingsLink);
+
+    this.label_.appendChild(titleSpan);
+    this.label_.appendChild(document.createElement('br'));
+    this.label_.appendChild(descSpan);
+  }
+
+  /**
+   * Called when "Sign in" link for ODFS reauthentication is clicked.
+   * @private
+   */
+  onODFSSignIn_() {
+    // TODO(cassycc): handle sign in.
+  }
+
+  /**
+   * Called when "Settings" link for ODFS reauthentication is clicked.
+   * @private
+   */
+  onSettings_() {
+    // TODO(cassycc): handle settings navigation.
+  }
+
+  /**
    * Updates visibility of empty folder UI. `odfsAndReauthenticationRequired` is
    * true when the volume is ODFS and reauthentication is required.
    * @param {boolean} odfsAndReauthenticationRequired
@@ -205,11 +257,7 @@
     }
 
     if (svgRef == ODFS_REAUTHENTICATION_REQUIRED) {
-      // TODO(b/254586358): i18n these strings.
-      this.showMessage_(
-          'You\'ve been logged out',
-          'Sign in to your OneDrive account to open Office files' +
-              '\nstored on your Chromebook or go to Settings');
+      this.showODFSReauthenticationMessage_();
       return;
     }
 
diff --git a/ui/file_manager/file_manager/foreground/js/empty_folder_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/empty_folder_controller_unittest.js
index 2febeee..3136095 100644
--- a/ui/file_manager/file_manager/foreground/js/empty_folder_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/empty_folder_controller_unittest.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
+import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
 
 import {createChild} from '../../common/js/dom_utils.js';
 import {FakeEntryImpl} from '../../common/js/files_app_entry_types.js';
@@ -204,9 +204,10 @@
   emptyFolderController.onScanFailed_(event);
 
   assertFalse(element.hidden);
-  const text = emptyFolderController.label_.innerText;
-  // TODO(b/254586358): use the i18n version of this string.
-  assertTrue(text.includes('You\'ve been logged out'));
+  const signInLink = emptyFolderController.label_.querySelector('.sign-in');
+  assertNotEquals(signInLink, null);
+  const settingsLink = emptyFolderController.label_.querySelector('.settings');
+  assertNotEquals(settingsLink, null);
 }
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.ts b/ui/file_manager/file_manager/foreground/js/file_tasks.ts
index 280ecc9e..817b9fe 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.ts
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.ts
@@ -846,7 +846,7 @@
 
 /** Office file extensions. */
 const OFFICE_EXTENSIONS =
-    new Set(['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx']);
+    new Set(['.doc', '.docx', '.xls', 'xlsm', '.xlsx', '.ppt', '.pptx']);
 
 export interface AnnotatedTask extends chrome.fileManagerPrivate.FileTask {
   iconType: string;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.html
index 52c98df..fc78cf7 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.html
@@ -11,12 +11,8 @@
   }
 </style>
 <educational-banner>
-  <span slot="title">
-    Make everything in your Google Drive available when you’re offline
-  </span>
-  <span slot="subtitle">
-    This will automatically download all files in your My Drive, allowing you to
-    access and edit your files without an internet connection.
-  </span>
-  <cr-button slot="extra-button" class="action-button"> Learn more </cr-button>
+  <span slot="title">$i18n{BULK_PINNING_TITLE}</span>
+  <cr-button slot="extra-button" class="action-button">
+    $i18n{BULK_PINNING_GET_STARTED}
+  </cr-button>
 </educational-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.js b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.js
index b54b9a6..6e0a016 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_bulk_pinning_banner.js
@@ -36,6 +36,7 @@
   /**
    * Returns the HTML template for the Drive Bulk Pinning educational banner.
    * @returns {!Node}
+   * @override
    */
   getTemplate() {
     return htmlTemplate.content.cloneNode(true);
@@ -45,6 +46,7 @@
    * Only show the banner when the user has navigated to the Drive volume type
    * and the feature flag is enabled.
    * @returns {!Array<!Banner.AllowedVolume>}
+   * @override
    */
   allowedVolumes() {
     return [{
@@ -53,6 +55,11 @@
     }];
   }
 
+  /**
+   * Show this banner for an unlimited number of sessions.
+   * @returns {number}
+   * @override
+   */
   showLimit() {
     return 0;
   }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.html
index 1c57210..e4baae2 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.html
@@ -15,6 +15,7 @@
   #educational-text-group {
     align-items: flex-start;
     display: flex;
+    flex: 1 0 0;
     flex-direction: column;
     flex-wrap: nowrap;
   }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
index 3c1b904..6b8a2913 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
@@ -44,10 +44,20 @@
     this.dismissErrorItemCallback = null;
 
     /**
-     * Timeout for hiding file operations in progress.
-     * @type {number}
+     * Defer showing in progress operation to avoid displaying quick
+     * operations, e.g. the notification panel only shows if the task is
+     * processing longer than this time.
+     * @private {number}
      */
     this.PENDING_TIME_MS_ = 2000;
+
+    /**
+     * Timeout for removing the notification panel, e.g. the notification
+     * panel will be removed after this time.
+     * @private {number}
+     */
+    this.TIMEOUT_TO_REMOVE_MS_ = 4000;
+
     if (window.IN_TEST) {
       this.PENDING_TIME_MS_ = 0;
     }
@@ -480,7 +490,7 @@
             setTimeout(() => {
               this.feedbackHost_.removePanelItem(donePanelItem);
               delete this.items_[donePanelItem.id];
-            }, 4000);
+            }, this.TIMEOUT_TO_REMOVE_MS_);
           }
           // Drop through to remove the progress panel.
         case ProgressItemState.CANCELED:
diff --git a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts
index a4379b2fcc..a2b010ac 100644
--- a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts
+++ b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts
@@ -176,7 +176,7 @@
       <cr-dialog @close="${this.onClose}">
         <div slot="title">
           <xf-icon type="drive_bulk_pinning" size="medium"></xf-icon>
-          <div class="title">
+          <div class="title" style="flex: 1 0 0">
             ${str('BULK_PINNING_TITLE')}
           </div>
         </div>
diff --git a/ui/file_manager/file_manager/widgets/xf_path_display.ts b/ui/file_manager/file_manager/widgets/xf_path_display.ts
index 206223c..dc483d5 100644
--- a/ui/file_manager/file_manager/widgets/xf_path_display.ts
+++ b/ui/file_manager/file_manager/widgets/xf_path_display.ts
@@ -108,13 +108,14 @@
         display: none !important;
       }
       :host {
+        align-items: center;
+        border-top: 1px solid var(--cros-sys-separator);
         display: flex;
         flex-direction: row;
-        align-items: center;
-        padding: 8px;
-        border-top: 1px solid var(--cros-sys-separator);
         font: var(--cros-button-1-font);
         outline: none;
+        padding: 8px;
+        padding-inline-start: 20px;
         user-select: none;
       }
       div.folder {
@@ -127,6 +128,9 @@
         padding: 4px 4px;
         border-radius: 8px;
       }
+      div.folder:first-of-type {
+        padding-inline-start: 0;
+      }
       div.mid-folder {
         color: var(--cros-sys-on_surface_variant);
       }
diff --git a/ui/file_manager/file_manager/widgets/xf_select.ts b/ui/file_manager/file_manager/widgets/xf_select.ts
index 85dc4dff..b26b839 100644
--- a/ui/file_manager/file_manager/widgets/xf_select.ts
+++ b/ui/file_manager/file_manager/widgets/xf_select.ts
@@ -404,6 +404,9 @@
       padding-inline: 12px;
       white-space: nowrap;
     }
+    :host(:first-of-type) #dropdown-toggle {
+      margin-inline-start: 0;
+    }
     :host-context(.focus-outline-visible) #dropdown-toggle:focus {
       outline: 2px solid var(--cros-sys-focus_ring);
       outline-offset: 2px;
diff --git a/ui/file_manager/integration_tests/file_manager/search.js b/ui/file_manager/integration_tests/file_manager/search.js
index 1fc9b07..7fa0e2d 100644
--- a/ui/file_manager/integration_tests/file_manager/search.js
+++ b/ui/file_manager/integration_tests/file_manager/search.js
@@ -934,3 +934,36 @@
       appId, TestEntryInfo.getExpectedRows([ENTRIES.hello, helloTrashinfo]),
       {ignoreLastModifiedTime: true, ignoreFileSize: true});
 };
+
+/**
+ * Checcks that finding files directly in Shared with me, or in folders nested
+ * in Shared with me, works.
+ */
+testcase.searchSharedWithMe = async () => {
+  // Create a shared file for nested directory. It must have SHARED_WITH_ME
+  // attribute on it, as NESTED_SHARED_WITH_ME does not have shared metadata
+  // set on it.
+  const nestedTestSharedFile = ENTRIES.sharedWithMeDirectoryFile.cloneWith({
+    sharedOption: SharedOption.SHARED_WITH_ME,
+    targetPath: 'Shared Directory/nested.txt',
+    nameText: 'nested.txt',
+  });
+  // Open Files app on Drive containing "Shared with me" file entries.
+  const appId = await setupAndWaitUntilReady(RootPath.DRIVE, [], [
+    ENTRIES.testSharedFile,
+    ENTRIES.sharedWithMeDirectory,
+    nestedTestSharedFile,
+  ]);
+
+  await navigateWithDirectoryTree(appId, '/Shared with me');
+
+  // Find the specific file, test.txt
+  await remoteCall.typeSearchText(appId, 'test.txt');
+  await remoteCall.waitForFiles(
+      appId, TestEntryInfo.getExpectedRows([ENTRIES.testSharedFile]));
+
+  // Search for the file nested in the shared directory.
+  await remoteCall.typeSearchText(appId, 'nested.txt');
+  await remoteCall.waitForFiles(
+      appId, TestEntryInfo.getExpectedRows([nestedTestSharedFile]));
+};
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 967393d..4b25785 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -265,15 +265,24 @@
 Object.freeze(EntryType);
 
 /**
+ * Enumeration that determines the shared status of entries.
  * @enum {string}
  * @const
  */
-
 export const SharedOption = {
+  // Not shared.
   NONE: 'none',
+
+  // Shared but not visible in the 'Shared with me' view.
   SHARED: 'shared',
+
+  // Shared and appears in the 'Shared With Me' view.
   SHARED_WITH_ME: 'sharedWithMe',
-  NESTED_SHARED_WITH_ME: 'nestedSharedWithMe',
+
+  // Not directly shared, but belongs to a folder that is shared with me.
+  // Entries marked as indirectly shared do not have the 'shared' metadata
+  // field, and thus cannot be located via search for shared items.
+  INDIRECTLY_SHARED_WITH_ME: 'indirectlySharedWithMe',
 };
 Object.freeze(SharedOption);
 
@@ -1563,7 +1572,7 @@
     sourceFileName: 'text.txt',
     targetPath: 'Shared Directory/file.txt',
     mimeType: 'text/plain',
-    sharedOption: SharedOption.NESTED_SHARED_WITH_ME,
+    sharedOption: SharedOption.INDIRECTLY_SHARED_WITH_ME,
     lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
     nameText: 'file.txt',
     sizeText: '51 bytes',
diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
index 5791b8f..34035dd 100644
--- a/ui/gfx/color_transform.cc
+++ b/ui/gfx/color_transform.cc
@@ -35,6 +35,30 @@
 
 namespace {
 
+// The maximum brightness of the reference display for HLG computations.
+static constexpr float kHLGRefMaxLumNits = 1000.f;
+
+// The maximum reference brightness of a PQ signal.
+static constexpr float kPQRefMaxLumNits = 10000.f;
+
+// The luminance vector in rec2020 linear space.
+static constexpr float kLr = 0.2627;
+static constexpr float kLg = 0.6780;
+static constexpr float kLb = 0.0593;
+
+// Return true if HLG and PQ tonemapping is unified (HLG is transcoded to a
+// 1,000 nit PQ signal and then rendered like PQ).
+bool IsHlgPqUnifiedTonemapEnabled() {
+  return base::FeatureList::IsEnabled(kHlgPqUnifiedTonemap);
+}
+
+// Return true if input HLG and PQ signals are SDR relative. This applies
+// only to Windows, where they can be absolute (they are otherwise always
+// SDR relative).
+bool IsHlgPqSdrRelative() {
+  return base::FeatureList::IsEnabled(kHlgPqSdrRelative);
+}
+
 struct SkShaderUniforms {
   float offset = 0.f;
   float multiplier = 0.f;
@@ -154,44 +178,16 @@
   return 0;
 }
 
-// Returns true if tone mapping will be a non-identity operation. Computes the
-// constants used by the tone mapping algorithm described in
-// https://colab.research.google.com/drive/1hI10nq6L6ru_UFvz7-f7xQaQp0qarz_K
-bool ComputePQToneMapConstants(
-    const gfx::ColorTransform::RuntimeOptions& options,
-    float& a,
-    float& b) {
-  const auto hdr_metadata = gfx::HDRMetadata::PopulateUnspecifiedWithDefaults(
-      options.src_hdr_metadata);
-  const float src_max_lum_nits =
-      hdr_metadata.max_content_light_level > 0
-          ? hdr_metadata.max_content_light_level
-          : hdr_metadata.color_volume_metadata.luminance_max;
-  const float src_max_lum_relative =
-      src_max_lum_nits / options.sdr_max_luminance_nits;
-
-  if (src_max_lum_relative > options.dst_max_luminance_relative) {
-    a = options.dst_max_luminance_relative /
-        (src_max_lum_relative * src_max_lum_relative);
-    b = 1.f / options.dst_max_luminance_relative;
-    return true;
-  }
-  a = 0;
-  b = 0;
-  return false;
-}
-
-void ComputeHLGToneMapConstants(
-    const gfx::ColorTransform::RuntimeOptions& options,
-    float& gamma_minus_one) {
-  const float dst_max_luminance_nits =
-      options.sdr_max_luminance_nits * options.dst_max_luminance_relative;
-  gamma_minus_one =
-      1.2f + 0.42f * logf(dst_max_luminance_nits / 1000.f) / logf(10.f) - 1.f;
-}
-
 }  // namespace
 
+BASE_FEATURE(kHlgPqUnifiedTonemap,
+             "HlgPqUnifiedTonemap",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kHlgPqSdrRelative,
+             "HlgPqSdrRelative",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 class ColorTransformMatrix;
 class ColorTransformSkTransferFn;
 class ColorTransformFromLinear;
@@ -884,11 +880,6 @@
  public:
   ColorTransformHLG_OOTF() = default;
 
-  // The luminance vector in linear space.
-  static constexpr float kLr = 0.2627;
-  static constexpr float kLg = 0.6780;
-  static constexpr float kLb = 0.0593;
-
   // ColorTransformStep implementation:
   void Transform(ColorTransform::TriStim* color,
                  size_t num,
@@ -923,18 +914,57 @@
         options.dst_max_luminance_relative;
     ComputeHLGToneMapConstants(options, uniforms->hlg_ootf_gamma_minus_one);
   }
+
+ private:
+  static void ComputeHLGToneMapConstants(
+      const gfx::ColorTransform::RuntimeOptions& options,
+      float& gamma_minus_one) {
+    const float dst_max_luminance_nits =
+        options.sdr_max_luminance_nits * options.dst_max_luminance_relative;
+    gamma_minus_one =
+        1.2f +
+        0.42f * logf(dst_max_luminance_nits / kHLGRefMaxLumNits) / logf(10.f) -
+        1.f;
+  }
+};
+
+// Apply the HLG OOTF for a 1,000 nit reference display.
+class ColorTransformHLG_RefOOTF : public ColorTransformStep {
+ public:
+  ColorTransformHLG_RefOOTF() = default;
+
+  static constexpr float kGammaMinusOne = 0.2f;
+
+  // ColorTransformStep implementation:
+  void Transform(ColorTransform::TriStim* color,
+                 size_t num,
+                 const ColorTransform::RuntimeOptions& options) const override {
+    for (size_t i = 0; i < num; i++) {
+      float L = kLr * color[i].x() + kLg * color[i].y() + kLb * color[i].z();
+      if (L > 0.f) {
+        color[i].Scale(powf(L, kGammaMinusOne));
+      }
+    }
+  }
+  void AppendSkShaderSource(std::stringstream* src) const override {
+    *src << "{\n"
+         << "  half4 luma_vec = half4(" << kLr << ", " << kLg << ", " << kLb
+         << ", 0.0);\n"
+         << "  half L = dot(color, luma_vec);\n"
+         << "  if (L > 0.0) {\n"
+         << "    color.rgb *= pow(L, " << kGammaMinusOne << ");\n"
+         << "  }\n"
+         << "}\n";
+  }
 };
 
 // Scale the color such that the luminance `input_max_value` maps to
 // `output_max_value`.
 class ColorTransformToneMapInRec2020Linear : public ColorTransformStep {
  public:
-  ColorTransformToneMapInRec2020Linear() = default;
-
-  // The luminance vector in linear space.
-  static constexpr float kLr = 0.2627;
-  static constexpr float kLg = 0.6780;
-  static constexpr float kLb = 0.0593;
+  explicit ColorTransformToneMapInRec2020Linear(const gfx::ColorSpace& src)
+      : use_ref_max_luminance_(src.GetTransferID() ==
+                               ColorSpace::TransferID::HLG) {}
 
   // ColorTransformStep implementation:
   void Transform(ColorTransform::TriStim* color,
@@ -942,7 +972,7 @@
                  const ColorTransform::RuntimeOptions& options) const override {
     float a = 0.f;
     float b = 0.f;
-    ComputePQToneMapConstants(options, a, b);
+    ComputeToneMapConstants(options, a, b);
 
     for (size_t i = 0; i < num; i++) {
       float L = kLr * color[i].x() + kLg * color[i].y() + kLb * color[i].z();
@@ -963,31 +993,76 @@
   }
   void SetShaderUniforms(const ColorTransform::RuntimeOptions& options,
                          SkShaderUniforms* uniforms) const override {
-    ComputePQToneMapConstants(options, uniforms->pq_tonemap_a,
-                              uniforms->pq_tonemap_b);
+    ComputeToneMapConstants(options, uniforms->pq_tonemap_a,
+                            uniforms->pq_tonemap_b);
   }
+
+ private:
+  float ComputeSrcMaxLumRelative(
+      const ColorTransform::RuntimeOptions& options) const {
+    float src_max_lum_nits = kHLGRefMaxLumNits;
+    if (!use_ref_max_luminance_) {
+      const auto hdr_metadata =
+          gfx::HDRMetadata::PopulateUnspecifiedWithDefaults(
+              options.src_hdr_metadata);
+      src_max_lum_nits = hdr_metadata.max_content_light_level > 0
+                             ? hdr_metadata.max_content_light_level
+                             : hdr_metadata.color_volume_metadata.luminance_max;
+    }
+    if (IsHlgPqSdrRelative()) {
+      return src_max_lum_nits / ColorSpace::kDefaultSDRWhiteLevel;
+    }
+    return src_max_lum_nits / options.sdr_max_luminance_nits;
+  }
+  // Computes the constants used by the tone mapping algorithm described in
+  // https://colab.research.google.com/drive/1hI10nq6L6ru_UFvz7-f7xQaQp0qarz_K
+  void ComputeToneMapConstants(
+      const gfx::ColorTransform::RuntimeOptions& options,
+      float& a,
+      float& b) const {
+    const float src_max_lum_relative = ComputeSrcMaxLumRelative(options);
+    if (src_max_lum_relative > options.dst_max_luminance_relative) {
+      a = options.dst_max_luminance_relative /
+          (src_max_lum_relative * src_max_lum_relative);
+      b = 1.f / options.dst_max_luminance_relative;
+    } else {
+      a = 0;
+      b = 0;
+    }
+  }
+
+  const bool use_ref_max_luminance_;
 };
 
 // Converts from nits-relative (where 1.0 is `unity_nits` nits) to SDR-relative
-// (where 1.0 is SDR white). Use `RuntimeOptions::sdr_max_luminance_nits` for
-// the number of nits of SDR white.
+// (where 1.0 is SDR white). If `use_default_sdr_white` is true then use 203
+// nits for SDR white, otherwise use `RuntimeOptions::sdr_max_luminance_nits`
+// for SDR white.
 class ColorTransformNitsToSdrRelative : public ColorTransformStep {
  public:
-  explicit ColorTransformNitsToSdrRelative(float unity_nits)
-      : unity_nits_(unity_nits) {}
+  ColorTransformNitsToSdrRelative(float unity_nits, bool use_default_sdr_white)
+      : unity_nits_(unity_nits),
+        use_default_sdr_white_(use_default_sdr_white) {}
 
   // ColorTransformStep implementation:
   void Transform(ColorTransform::TriStim* color,
                  size_t num,
                  const ColorTransform::RuntimeOptions& options) const override {
-    const float factor = unity_nits_ / options.sdr_max_luminance_nits;
+    const float sdr_white_nits = use_default_sdr_white_
+                                     ? ColorSpace::kDefaultSDRWhiteLevel
+                                     : options.sdr_max_luminance_nits;
+    const float factor = unity_nits_ / sdr_white_nits;
     for (size_t i = 0; i < num; i++) {
       color[i].Scale(factor);
     }
   }
   void AppendSkShaderSource(std::stringstream* src) const override {
-    *src << "  color.rgb *= (" << unity_nits_
-         << " / sdr_max_luminance_nits);\n";
+    *src << "  color.rgb *= " << unity_nits_ << " / ";
+    if (use_default_sdr_white_) {
+      *src << ColorSpace::kDefaultSDRWhiteLevel << ";";
+    } else {
+      *src << "sdr_max_luminance_nits;\n";
+    }
   }
   void SetShaderUniforms(const ColorTransform::RuntimeOptions& options,
                          SkShaderUniforms* uniforms) const override {
@@ -996,6 +1071,7 @@
 
  private:
   const float unity_nits_;
+  const bool use_default_sdr_white_;
 };
 
 // Converts from SDR-relative (where 1.0 is SDR white) to nits-relative (where
@@ -1063,18 +1139,13 @@
   switch (src.GetTransferID()) {
     case ColorSpace::TransferID::HLG:
       steps_.push_back(std::make_unique<ColorTransformHLG_InvOETF>());
-      if (!options.tone_map_pq_and_hlg_to_dst) {
-        steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(
-            12.f * ColorSpace::kDefaultSDRWhiteLevel));
-      }
       break;
     case ColorSpace::TransferID::PQ:
       steps_.push_back(std::make_unique<ColorTransformPQToLinear>());
-      steps_.push_back(
-          std::make_unique<ColorTransformNitsToSdrRelative>(10000.f));
       break;
     case ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
-      steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(80.f));
+      steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(
+          80.f, /*use_default_sdr_white=*/false));
       break;
     case ColorSpace::TransferID::PIECEWISE_HDR: {
       skcms_TransferFunction fn;
@@ -1105,28 +1176,70 @@
       std::make_unique<ColorTransformMatrix>(src.GetPrimaryMatrix()));
 
   // Perform tone mapping in a linear space
-  if (options.tone_map_pq_and_hlg_to_dst) {
-    switch (src.GetTransferID()) {
-      case ColorSpace::TransferID::HLG: {
-        // Apply the HLG OOTF for the specified maximum luminance.
-        steps_.push_back(std::make_unique<ColorTransformHLG_OOTF>());
-        break;
-      }
-      case ColorSpace::TransferID::PQ: {
-        const ColorSpace rec2020_linear(
-            ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR,
-            ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
+  const ColorSpace rec2020_linear(
+      ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR,
+      ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
+  switch (src.GetTransferID()) {
+    case ColorSpace::TransferID::HLG: {
+      if (IsHlgPqUnifiedTonemapEnabled()) {
+        // Convert from XYZ to Rec2020 primaries.
         steps_.push_back(std::make_unique<ColorTransformMatrix>(
             Invert(rec2020_linear.GetPrimaryMatrix())));
-        steps_.push_back(
-            std::make_unique<ColorTransformToneMapInRec2020Linear>());
+
+        // Apply the reference HLG OOTF.
+        steps_.push_back(std::make_unique<ColorTransformHLG_RefOOTF>());
+
+        // Convert from linear nits-relative space (where 1.0 is 1,000 nits) to
+        // SDR-relative space (where 1.0 is SDR white).
+        steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(
+            kHLGRefMaxLumNits, IsHlgPqSdrRelative()));
+
+        // If tone mapping is requested, tone map down to the available
+        // headroom.
+        if (options.tone_map_pq_and_hlg_to_dst) {
+          steps_.push_back(
+              std::make_unique<ColorTransformToneMapInRec2020Linear>(src));
+        }
+
+        // Convert back to XYZ.
         steps_.push_back(std::make_unique<ColorTransformMatrix>(
             rec2020_linear.GetPrimaryMatrix()));
-        break;
+      } else {
+        if (options.tone_map_pq_and_hlg_to_dst) {
+          // Apply the HLG OOTF for the specified maximum luminance.
+          steps_.push_back(std::make_unique<ColorTransformHLG_OOTF>());
+        } else {
+          // Scale such that the maximum value is 12 times 203 nits.
+          steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(
+              12.f * ColorSpace::kDefaultSDRWhiteLevel,
+              /*use_default_sdr_white=*/false));
+        }
       }
-      default:
-        break;
+      break;
     }
+    case ColorSpace::TransferID::PQ: {
+      // Convert from linear nits-relative space (where 1.0 is 10,000 nits) to
+      // SDR-relative space (where 1.0 is SDR white).
+      steps_.push_back(std::make_unique<ColorTransformNitsToSdrRelative>(
+          kPQRefMaxLumNits, IsHlgPqSdrRelative()));
+
+      if (options.tone_map_pq_and_hlg_to_dst) {
+        // Convert from XYZ to Rec2020 primaries.
+        steps_.push_back(std::make_unique<ColorTransformMatrix>(
+            Invert(rec2020_linear.GetPrimaryMatrix())));
+
+        // Tone map down to the available headroom.
+        steps_.push_back(
+            std::make_unique<ColorTransformToneMapInRec2020Linear>(src));
+
+        // Convert back to XYZ.
+        steps_.push_back(std::make_unique<ColorTransformMatrix>(
+            rec2020_linear.GetPrimaryMatrix()));
+      }
+      break;
+    }
+    default:
+      break;
   }
 
   steps_.push_back(
@@ -1145,7 +1258,7 @@
       break;
     case ColorSpace::TransferID::PQ:
       steps_.push_back(
-          std::make_unique<ColorTransformSdrToNitsRelative>(10000.f));
+          std::make_unique<ColorTransformSdrToNitsRelative>(kPQRefMaxLumNits));
       steps_.push_back(std::make_unique<ColorTransformPQFromLinear>());
       break;
     case ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
diff --git a/ui/gfx/color_transform.h b/ui/gfx/color_transform.h
index 3bdb707b..9fff8de 100644
--- a/ui/gfx/color_transform.h
+++ b/ui/gfx/color_transform.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/feature_list.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/effects/SkRuntimeEffect.h"
@@ -18,6 +19,9 @@
 
 namespace gfx {
 
+COLOR_SPACE_EXPORT BASE_DECLARE_FEATURE(kHlgPqUnifiedTonemap);
+COLOR_SPACE_EXPORT BASE_DECLARE_FEATURE(kHlgPqSdrRelative);
+
 class COLOR_SPACE_EXPORT ColorTransform {
  public:
   // Parameters that must be specified at creation time. Changing these
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index 1e30336..ccbb997 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/effects/SkRuntimeEffect.h"
 #include "ui/gfx/color_space.h"
@@ -19,7 +20,8 @@
 namespace gfx {
 
 // Allowed math error.
-const float kMathEpsilon = 0.001f;
+constexpr float kMathEpsilon = 0.001f;
+constexpr float kMathLargeEpsilon = 0.025f;
 
 // Internal functions, exposted for testing.
 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id);
@@ -629,6 +631,9 @@
 
   // PQ's 80 nits maps to 80 nits.
   {
+    base::test::ScopedFeatureList features;
+    features.InitWithFeatures({}, {kHlgPqSdrRelative});
+
     ColorSpace src_pq = ColorSpace::CreateHDR10();
 
     ColorTransform::Options options;
@@ -683,8 +688,12 @@
   }
 
   // HLG's maximum value will be 12 times 203 nits.
-  // TODO(https://crbug.com/1442884): This is not an appropriate value.
+  // TODO(https://crbug.com/1442884): This is not an appropriate value. This
+  // path is to be deleted.
   {
+    base::test::ScopedFeatureList features;
+    features.InitWithFeatures({}, {kHlgPqUnifiedTonemap, kHlgPqSdrRelative});
+
     constexpr float kSdrWhite = 300.f;
 
     ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
@@ -704,10 +713,13 @@
   }
 
   // HLG's maximum maps to the maximum value when tonemapped.
+  // TODO(https://crbug.com/1442884): This path is to be deleted.
   {
+    base::test::ScopedFeatureList features;
+    features.InitWithFeatures({}, {kHlgPqUnifiedTonemap, kHlgPqSdrRelative});
+
     constexpr float kSdrWhite = 200.f;
     constexpr float kDstMaxLumRel = 2.f;
-    constexpr float kMathLargeEpsilon = 0.025f;
 
     ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
                        ColorSpace::TransferID::HLG);
@@ -736,7 +748,240 @@
   }
 }
 
+TEST(ColorSpaceTest, HLGTonemap) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({kHlgPqUnifiedTonemap}, {kHlgPqSdrRelative});
+
+  ColorSpace dst(ColorSpace::PrimaryID::BT2020,
+                 ColorSpace::TransferID::SCRGB_LINEAR_80_NITS);
+  ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
+                     ColorSpace::TransferID::HLG);
+  ColorTransform::Options options;
+  options.tone_map_pq_and_hlg_to_dst = true;
+
+  std::unique_ptr<ColorTransform> xform(
+      ColorTransform::NewColorTransform(src_hlg, dst, options));
+
+  // If the headroom is low enough that HLG will exceed it, then we will map to
+  // the headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 100.f;
+    constexpr float kDstMaxLumRel = 2.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), kDstMaxLumRel * kSdrWhite / 80.f, kMathLargeEpsilon);
+  }
+
+  // We will max out at the reference maximum if it is below the headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 250.f;
+    constexpr float kDstMaxLumRel = 6.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1000.f / 80.f, kMathLargeEpsilon);
+  }
+}
+
+TEST(ColorSpaceTest, HLGNoTonemap) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({kHlgPqUnifiedTonemap}, {kHlgPqSdrRelative});
+
+  ColorSpace dst(ColorSpace::PrimaryID::BT2020,
+                 ColorSpace::TransferID::SCRGB_LINEAR_80_NITS);
+  ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
+                     ColorSpace::TransferID::HLG);
+  ColorTransform::Options options;
+  options.tone_map_pq_and_hlg_to_dst = false;
+
+  std::unique_ptr<ColorTransform> xform(
+      ColorTransform::NewColorTransform(src_hlg, dst, options));
+
+  ColorTransform::RuntimeOptions runtime_options;
+  constexpr float kSdrWhite = 100.f;
+  constexpr float kDstMaxLumRel = 2.f;
+  runtime_options.sdr_max_luminance_nits = kSdrWhite;
+  runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+  // HLG 75% will match 203 nits.
+  {
+    ColorTransform::TriStim val(0.75f, 0.75f, 0.75f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 203.f / 80.f, kMathLargeEpsilon);
+  }
+
+  // HLG 100% will match 1000 nits.
+  {
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1000.f / 80.f, kMathLargeEpsilon);
+  }
+}
+
+TEST(ColorSpaceTest, HLGTonemapSdrRelative) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({kHlgPqUnifiedTonemap, kHlgPqSdrRelative}, {});
+
+  ColorSpace dst(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR);
+  ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
+                     ColorSpace::TransferID::HLG);
+  ColorTransform::Options options;
+  options.tone_map_pq_and_hlg_to_dst = true;
+
+  std::unique_ptr<ColorTransform> xform(
+      ColorTransform::NewColorTransform(src_hlg, dst, options));
+
+  // If the headroom is low enough that HLG will exceed it, then we will map to
+  // the headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 100.f;
+    constexpr float kDstMaxLumRel = 2.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), kDstMaxLumRel, kMathLargeEpsilon);
+  }
+
+  // We will max out at the reference maximum if it is below the headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 250.f;
+    constexpr float kDstMaxLumRel = 6.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1000.f / ColorSpace::kDefaultSDRWhiteLevel,
+                kMathLargeEpsilon);
+  }
+}
+
+TEST(ColorSpaceTest, HLGNoTonemapSdrRelative) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({kHlgPqUnifiedTonemap, kHlgPqSdrRelative}, {});
+
+  ColorSpace dst(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR);
+  ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020,
+                     ColorSpace::TransferID::HLG);
+  ColorTransform::Options options;
+  options.tone_map_pq_and_hlg_to_dst = false;
+
+  std::unique_ptr<ColorTransform> xform(
+      ColorTransform::NewColorTransform(src_hlg, dst, options));
+
+  ColorTransform::RuntimeOptions runtime_options;
+  constexpr float kSdrWhite = 100.f;
+  constexpr float kDstMaxLumRel = 2.f;
+  runtime_options.sdr_max_luminance_nits = kSdrWhite;
+  runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+  // HLG 75% will match 203 nits.
+  {
+    ColorTransform::TriStim val(0.75f, 0.75f, 0.75f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1.f, kMathLargeEpsilon);
+  }
+
+  // HLG 100% will match 1000 nits.
+  {
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1000.f / ColorSpace::kDefaultSDRWhiteLevel,
+                kMathLargeEpsilon);
+  }
+}
+
+TEST(ColorSpaceTest, PQTonemapSdrRelative) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({kHlgPqUnifiedTonemap, kHlgPqSdrRelative}, {});
+
+  ColorSpace dst(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR);
+  ColorSpace src_hlg(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::PQ);
+  ColorTransform::Options options;
+  options.tone_map_pq_and_hlg_to_dst = true;
+
+  std::unique_ptr<ColorTransform> xform(
+      ColorTransform::NewColorTransform(src_hlg, dst, options));
+
+  constexpr float kPQ1000Nits = 0.751827096247041f;
+
+  // If the headroom is low enough that the maximum PQ value will exceed it,
+  // then we will map to the headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 100.f;
+    constexpr float kDstMaxLumRel = 2.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), kDstMaxLumRel, kMathLargeEpsilon);
+  }
+
+  // Ensure that the maximum value specified in metadata is mapped to the
+  // headroom.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 100.f;
+    constexpr float kDstMaxLumRel = 2.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+    runtime_options.src_hdr_metadata =
+        HDRMetadata(ColorVolumeMetadata(), 1000.f, 100.f);
+
+    ColorTransform::TriStim val(kPQ1000Nits, kPQ1000Nits, kPQ1000Nits);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 2.f, kMathLargeEpsilon);
+  }
+
+  // If we do not reach the headroom, then no tonemapping is applied.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 90.f;
+    constexpr float kDstMaxLumRel = 51.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+
+    ColorTransform::TriStim val(1.f, 1.f, 1.f);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 10000.f / ColorSpace::kDefaultSDRWhiteLevel,
+                kMathLargeEpsilon);
+  }
+
+  // If we do not reach the headroom (because of metadata), then no tonemapping
+  // is applied.
+  {
+    ColorTransform::RuntimeOptions runtime_options;
+    constexpr float kSdrWhite = 100.f;
+    constexpr float kDstMaxLumRel = 6.f;
+    runtime_options.sdr_max_luminance_nits = kSdrWhite;
+    runtime_options.dst_max_luminance_relative = kDstMaxLumRel;
+    runtime_options.src_hdr_metadata =
+        HDRMetadata(ColorVolumeMetadata(), 1000.f, 100.f);
+
+    ColorTransform::TriStim val(kPQ1000Nits, kPQ1000Nits, kPQ1000Nits);
+    xform->Transform(&val, 1, runtime_options);
+    EXPECT_NEAR(val.x(), 1000.f / ColorSpace::kDefaultSDRWhiteLevel,
+                kMathLargeEpsilon);
+  }
+}
+
 TEST(ColorSpaceTest, PQSDRWhiteLevel) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({}, {kHlgPqSdrRelative});
+
   // The PQ function maps |pq_encoded_nits| to |nits|. We mangle it a bit with
   // the SDR white level.
   float pq_encoded_nits[] = {
@@ -799,6 +1044,9 @@
 }
 
 TEST(ColorSpaceTest, HLGSDRWhiteLevel) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures({}, {kHlgPqUnifiedTonemap, kHlgPqSdrRelative});
+
   // These values are (1.0f * nits[i] / kDefaultSDRWhiteLevel) converted to
   // LINEAR_HDR via the HLG transfer function.
   constexpr float hlg_encoded_nits[] = {
diff --git a/ui/gfx/overlay_plane_data.h b/ui/gfx/overlay_plane_data.h
index 002a9aef..65e5182 100644
--- a/ui/gfx/overlay_plane_data.h
+++ b/ui/gfx/overlay_plane_data.h
@@ -56,7 +56,7 @@
   // Whether alpha blending should be enabled.
   bool enable_blend = false;
 
-  // Damage on the buffer.
+  // Damage in viz::Display space, the same space as |display_bounds|;
   Rect damage_rect;
 
   // Opacity of overlay plane. For a blending buffer (|enable_blend|) the total
diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc
index cbdfb60..df3caf8 100644
--- a/ui/gfx/switches.cc
+++ b/ui/gfx/switches.cc
@@ -18,11 +18,6 @@
 const char kDisableFontSubpixelPositioning[] =
     "disable-font-subpixel-positioning";
 
-// Disables new code to run SharedImages for NaCL swapchain. This overrides
-// value of kPPAPISharedImagesSwapChain feature flag.
-const char kDisablePPAPISharedImagesSwapChain[] =
-    "disable-ppapi-shared-images-swapchain";
-
 // Enable native CPU-mappable GPU memory buffer support on Linux.
 const char kEnableNativeGpuMemoryBuffers[] = "enable-native-gpu-memory-buffers";
 
@@ -62,10 +57,6 @@
 #endif
 );
 
-BASE_FEATURE(kPPAPISharedImagesSwapChain,
-             "PPAPISharedImagesSwapChain",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 #if BUILDFLAG(IS_CHROMEOS)
 BASE_FEATURE(kVariableGoogleSansFont,
              "VariableGoogleSansFont",
diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h
index df35209..ebeb73e7 100644
--- a/ui/gfx/switches.h
+++ b/ui/gfx/switches.h
@@ -14,7 +14,6 @@
 
 GFX_SWITCHES_EXPORT extern const char kAnimationDurationScale[];
 GFX_SWITCHES_EXPORT extern const char kDisableFontSubpixelPositioning[];
-GFX_SWITCHES_EXPORT extern const char kDisablePPAPISharedImagesSwapChain[];
 GFX_SWITCHES_EXPORT extern const char kEnableNativeGpuMemoryBuffers[];
 GFX_SWITCHES_EXPORT extern const char kForcePrefersReducedMotion[];
 GFX_SWITCHES_EXPORT extern const char kHeadless[];
@@ -30,7 +29,6 @@
 
 GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kOddHeightMultiPlanarBuffers);
 GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kOddWidthMultiPlanarBuffers);
-GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kPPAPISharedImagesSwapChain);
 
 #if BUILDFLAG(IS_CHROMEOS)
 GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kVariableGoogleSansFont);
diff --git a/ui/ozone/platform/wayland/common/wayland_overlay_config.h b/ui/ozone/platform/wayland/common/wayland_overlay_config.h
index 43e2f24..34661e1 100644
--- a/ui/ozone/platform/wayland/common/wayland_overlay_config.h
+++ b/ui/ozone/platform/wayland/common/wayland_overlay_config.h
@@ -62,8 +62,8 @@
   // This sets the source rectangle of Wayland Viewport.
   gfx::RectF crop_rect = {1.f, 1.f};
 
-  // Describes the changed region of the buffer. Optional to hint a partial
-  // swap.
+  // Damage in viz::Display space, the same space as |bounds_rect|. Optional
+  // to hint a partial swap.
   gfx::Rect damage_region;
 
   // Opacity of the overlay independent of buffer alpha.
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index a529cab..c1feacee 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -343,7 +343,7 @@
     // Also, we expect no buffer committed on primary subsurface.
     EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*mock_primary_surface, Damage(_, _, _, _)).Times(0);
     // 1 buffer committed on root surface.
     EXPECT_CALL(*root_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*root_surface, Frame(_)).Times(0);
@@ -371,7 +371,7 @@
   // Give mojo the chance to pass the callbacks if any.
   base::RunLoop().RunUntilIdle();
 
-  // We have just received Attach/DamageBuffer/Commit for buffer with swap
+  // We have just received Attach/Damage/Commit for buffer with swap
   // id=0u. The SwapCompletionCallback must be executed automatically as long as
   // we didn't have any buffers attached to the surface before.
   EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
@@ -438,17 +438,17 @@
     // Expect no buffer committed on primary subsurface.
     EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*mock_primary_surface, Damage(_, _, _, _)).Times(0);
     // Expect 1 buffer to be committed on overlay subsurface, with frame
     // callback.
     EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(1);
-    EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_overlay_surface, Damage(_, _, _, _)).Times(1);
     EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
     // Expect no buffer committed on root surface.
     EXPECT_CALL(*root_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*root_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*root_surface, Damage(_, _, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Commit()).Times(1);
 
     auto params_vector = server->zwp_linux_dmabuf_v1()->buffer_params();
@@ -529,15 +529,15 @@
     // Expect 1 buffer committed on primary subsurface, with frame callback.
     EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
-    EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_primary_surface, Damage(_, _, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
     // Expect no buffer to be committed on overlay subsurface.
     EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*mock_overlay_surface, Damage(_, _, _, _)).Times(0);
     // Expect no buffer committed on root surface.
     EXPECT_CALL(*root_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*root_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*root_surface, Damage(_, _, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Commit()).Times(1);
 
     auto params_vector = server->zwp_linux_dmabuf_v1()->buffer_params();
@@ -707,7 +707,7 @@
 
     EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
-    EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_primary_surface, Damage(_, _, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
     EXPECT_CALL(*root_surface, Frame(_)).Times(0);
     EXPECT_CALL(*root_surface, Commit()).Times(1);
@@ -737,7 +737,7 @@
   // Give mojo the chance to pass the callbacks.
   base::RunLoop().RunUntilIdle();
 
-  // We have just received Attach/DamageBuffer/Commit for buffer with swap
+  // We have just received Attach/Damage/Commit for buffer with swap
   // id=0u. The SwapCompletionCallback must be executed automatically as long as
   // we didn't have any buffers attached to the surface before.
   EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
@@ -816,19 +816,19 @@
     // surface in the frame it does not setup frame callback.
     EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_primary_surface, Damage(_, _, _, _)).Times(1);
     EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
 
     // Expect overlay buffer to be committed, and sets up frame callback.
     EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
     EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(1);
-    EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_overlay_surface, Damage(_, _, _, _)).Times(1);
     EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
 
     // Expect root surface to be committed without buffer.
     EXPECT_CALL(*root_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*root_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*root_surface, Damage(_, _, _, _)).Times(0);
     EXPECT_CALL(*root_surface, Commit()).Times(1);
 
     testing::Mock::VerifyAndClearExpectations(server->zwp_linux_dmabuf_v1());
@@ -926,17 +926,26 @@
     auto* sk_canvas = canvas->GetCanvas();
     ASSERT_TRUE(sk_canvas);
 
+    const gfx::Rect damage(5, 10, 20, 15);
+    // Surface damage will be affected by the scale, which must be an integer.
+    const gfx::Rect expected_damage = ScaleToEnclosingRect(
+        gfx::Rect(5, 10, 20, 15), 1.f / std::ceil(scale_factor));
+
     const uint32_t surface_id = window_->root_surface()->get_surface_id();
-    PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) {
+    PostToServerAndWait([surface_id,
+                         expected_damage](wl::TestWaylandServerThread* server) {
       auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id);
       ASSERT_FALSE(mock_surface->attached_buffer());
       Expectation damage =
-          EXPECT_CALL(*mock_surface, DamageBuffer(5, 10, 20, 15)).Times(1);
+          EXPECT_CALL(*mock_surface,
+                      Damage(expected_damage.x(), expected_damage.y(),
+                             expected_damage.width(), expected_damage.height()))
+              .Times(1);
       Expectation attach = EXPECT_CALL(*mock_surface, Attach(_, 0, 0)).Times(1);
       EXPECT_CALL(*mock_surface, Commit()).After(damage, attach);
     });
 
-    canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15));
+    canvas->PresentCanvas(damage);
     canvas->OnSwapBuffers(base::DoNothing(), gfx::FrameData());
 
     // Wait until the mojo calls are done.
@@ -979,7 +988,7 @@
   PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) {
     auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id);
     Expectation damage =
-        EXPECT_CALL(*mock_surface, DamageBuffer(0, 0, 100, 50)).Times(1);
+        EXPECT_CALL(*mock_surface, Damage(0, 0, 100, 50)).Times(1);
     Expectation attach = EXPECT_CALL(*mock_surface, Attach(_, 0, 0)).Times(1);
     EXPECT_CALL(*mock_surface, Commit()).After(damage, attach);
   });
@@ -1338,18 +1347,11 @@
   });
 
   gfx::Size test_buffer_size = {300, 100};
-  gfx::RectF test_buffer_dmg_uv = {0.2f, 0.3f, 0.6, 0.32f};
-  gfx::Rect test_buffer_dmg = gfx::ToEnclosingRect(gfx::ScaleRect(
-      test_buffer_dmg_uv, test_buffer_size.width(), test_buffer_size.height()));
   gfx::RectF crop_uv = {0.1f, 0.2f, 0.5, 0.5f};
   gfx::Rect expected_src = gfx::ToEnclosingRect(
       gfx::ScaleRect({0.2f, 0.4f, 0.5f, 0.5f}, test_buffer_size.height(),
                      test_buffer_size.width()));
-  gfx::RectF expected_combined_uv = {0.2, 0.f, 0.64, 0.8};
-
-  auto size_px = window_->applied_state().size_px;
-  gfx::Rect expected_surface_dmg = gfx::ToEnclosingRect(
-      gfx::ScaleRect(expected_combined_uv, size_px.width(), size_px.height()));
+  gfx::Rect surface_damage_rect = window_->GetBoundsInPixels();
 
   // Create buffer and FakeGlImageNativePixmap.
   std::vector<scoped_refptr<OverlayImageHolder>> fake_overlay_image;
@@ -1380,7 +1382,7 @@
         gfx::OverlayPlaneData(
             INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_ROTATE_270,
             gfx::RectF(window_->GetBoundsInPixels()), crop_uv, false,
-            gfx::Rect(test_buffer_dmg), 1.0f, gfx::OverlayPriorityHint::kNone,
+            surface_damage_rect, 1.0f, gfx::OverlayPriorityHint::kNone,
             gfx::RRectF(), gfx::ColorSpace::CreateSRGB(), absl::nullopt));
 
     std::vector<scoped_refptr<OverlayImageHolder>> overlay_images;
@@ -1400,7 +1402,7 @@
 
   PostToServerAndWait(
       [surface_id, expected_src, bounds_dip = window_->GetBoundsInDIP(),
-       expected_surface_dmg](wl::TestWaylandServerThread* server) {
+       surface_damage_rect](wl::TestWaylandServerThread* server) {
         auto* root_surface = server->GetObject<wl::MockSurface>(surface_id);
         auto* test_viewport = root_surface->viewport();
         ASSERT_TRUE(test_viewport);
@@ -1415,10 +1417,10 @@
         EXPECT_CALL(*root_surface, SetBufferTransform(WL_OUTPUT_TRANSFORM_90))
             .Times(1);
         Expectation damage =
-            EXPECT_CALL(*root_surface, Damage(expected_surface_dmg.origin().x(),
-                                              expected_surface_dmg.origin().y(),
-                                              expected_surface_dmg.width(),
-                                              expected_surface_dmg.height()))
+            EXPECT_CALL(*root_surface, Damage(surface_damage_rect.origin().x(),
+                                              surface_damage_rect.origin().y(),
+                                              surface_damage_rect.width(),
+                                              surface_damage_rect.height()))
                 .Times(1);
         Expectation attach =
             EXPECT_CALL(*root_surface, Attach(_, 0, 0)).Times(1);
@@ -1440,7 +1442,7 @@
   // Give mojo the chance to pass the callbacks.
   base::RunLoop().RunUntilIdle();
 
-  // We have just received Attach/DamageBuffer/Commit for buffer with swap
+  // We have just received Attach/Damage/Commit for buffer with swap
   // id=0u. The SwapCompletionCallback must be executed automatically as long as
   // we didn't have any buffers attached to the surface before.
   EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
diff --git a/ui/ozone/platform/wayland/host/wayland_frame_manager.cc b/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
index 2a196b5..51204bd 100644
--- a/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
@@ -372,7 +372,14 @@
   // If we don't attach a released buffer, graphics freeze will occur.
   DCHECK(will_attach || !buffer_handle->released(surface));
 
-  surface->UpdateBufferDamageRegion(config.damage_region);
+  // |damage_region| is specified in viz::Display space, the same as
+  // |bounds_rect|. To get the damage in surface space we need to offset the
+  // origin by the surface's position.
+  // Note: The damage may be enlarged if bounds_rect is sub-pixel positioned
+  // because |damage_region| is a Rect, and |bounds_rect| is a RectF.
+  gfx::RectF surface_damage = gfx::RectF(config.damage_region);
+  surface_damage -= config.bounds_rect.OffsetFromOrigin();
+  surface->UpdateBufferDamageRegion(ToEnclosingRect(surface_damage));
   if (!config.access_fence_handle.is_null())
     surface->set_acquire_fence(std::move(config.access_fence_handle));
 
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index a6aa149..f32a035e 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -782,42 +782,18 @@
   }
 
   DCHECK(pending_state_.buffer);
-  if (wl::get_version_of_object(surface_.get()) >=
-      WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
-    // wl_surface_damage_buffer relies on compositor API version 4. See
-    // https://bit.ly/2u00lv6 for details.
-    // We don't need to apply any scaling because pending_state_.damage_px is
-    // already in buffer coordinates.
-    wl_surface_damage_buffer(surface_.get(),
-                             pending_state_.damage_px.back().x(),
-                             pending_state_.damage_px.back().y(),
-                             pending_state_.damage_px.back().width(),
-                             pending_state_.damage_px.back().height());
-  } else {
-    gfx::RectF damage_uv =
-        gfx::ScaleRect(gfx::RectF(pending_state_.damage_px.back()),
-                       1.0f / pending_state_.buffer_size_px.width(),
-                       1.0f / pending_state_.buffer_size_px.height());
 
-    if (!crop.IsEmpty()) {
-      damage_uv.Offset(-crop.OffsetFromOrigin());
-      damage_uv.InvScale(crop.width(), crop.height());
-    }
-    damage_uv.Intersect(gfx::RectF(1, 1));
+  // Lacros on Ash will always have a scale factory of 1, so damage will be
+  // unchanged on Ash, but that won't always be true on other compositors.
+  gfx::Rect damage = ScaleToEnclosingRect(
+      pending_state_.damage_px.back(), 1.f / GetWaylandScale(pending_state_));
 
-    gfx::RectF damage_uv_transformed = wl::ApplyWaylandTransform(
-        damage_uv, gfx::SizeF(1, 1),
-        wl::ToWaylandTransform(pending_state_.buffer_transform));
-
-    gfx::RectF damage_float =
-        gfx::ScaleRect(damage_uv_transformed, viewport_dst_dip.width(),
-                       viewport_dst_dip.height());
-    constexpr float kAcceptableSubDipDamageError = 0.001f;
-    gfx::Rect damage = gfx::ToEnclosingRectIgnoringError(
-        damage_float, kAcceptableSubDipDamageError);
-    wl_surface_damage(surface_.get(), damage.x(), damage.y(), damage.width(),
-                      damage.height());
-  }
+  // TODO(fangzhoug): The newer wl_surface_damage_buffer API is not currently
+  // supported by Ash. Damage is specified in viz::Display space, so if we want
+  // to use that API in the future, some math will be required to transform the
+  // damage into buffer space.
+  wl_surface_damage(surface_.get(), damage.x(), damage.y(), damage.width(),
+                    damage.height());
 
   pending_state_.damage_px.clear();
   state_ = pending_state_;
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
index e4d1b7a..67fc2cc 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -2065,7 +2065,7 @@
         EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
         EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
         EXPECT_CALL(*mock_surface,
-                    DamageBuffer(0, 0, bounds.width(), bounds.height()))
+                    Damage(0, 0, bounds.width(), bounds.height()))
             .Times(1);
         EXPECT_CALL(*mock_surface, Commit()).Times(1);
       });
@@ -2090,7 +2090,7 @@
         EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
         EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
         EXPECT_CALL(*mock_surface,
-                    DamageBuffer(0, 0, bounds.width(), bounds.height()))
+                    Damage(0, 0, bounds.width(), bounds.height()))
             .Times(1);
         EXPECT_CALL(*mock_surface, Commit()).Times(1);
       });
@@ -2115,7 +2115,7 @@
 
     EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*mock_surface, Damage(_, _, _, _)).Times(0);
     EXPECT_CALL(*mock_surface, Commit()).Times(0);
 
     mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
@@ -2142,7 +2142,7 @@
         EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
         EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
         EXPECT_CALL(*mock_surface,
-                    DamageBuffer(0, 0, bounds.width(), bounds.height()))
+                    Damage(0, 0, bounds.width(), bounds.height()))
             .Times(1);
         EXPECT_CALL(*mock_surface, Commit()).Times(1);
       });
@@ -2165,7 +2165,7 @@
 
     EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
     EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
-    EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0);
+    EXPECT_CALL(*mock_surface, Damage(_, _, _, _)).Times(0);
     EXPECT_CALL(*mock_surface, Commit()).Times(0);
 
     mock_surface->SendFrameCallback();
@@ -2188,7 +2188,7 @@
         EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
         EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
         EXPECT_CALL(*mock_surface,
-                    DamageBuffer(0, 0, bounds.width(), bounds.height()))
+                    Damage(0, 0, bounds.width(), bounds.height()))
             .Times(1);
         EXPECT_CALL(*mock_surface, Commit()).Times(1);
       });
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 6f46fb1..8faa59e 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -575,6 +575,13 @@
   return render_text ? !render_text->selection().is_empty() : false;
 }
 
+bool Label::HasFullSelection() const {
+  const gfx::RenderText* render_text = GetRenderTextForSelectionController();
+  return render_text
+             ? render_text->selection().length() == render_text->text().length()
+             : false;
+}
+
 void Label::SelectAll() {
   gfx::RenderText* render_text = GetRenderTextForSelectionController();
   if (!render_text)
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index cdaa989..711dc633 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -295,6 +295,9 @@
   // Returns true if the label has a selection.
   bool HasSelection() const;
 
+  // Returns true if the label has the whole text selected.
+  bool HasFullSelection() const;
+
   // Selects the entire text. NO-OP if the label is not selectable.
   void SelectAll();
 
@@ -324,6 +327,9 @@
   WordLookupClient* GetWordLookupClient() override;
   std::u16string GetTooltipText(const gfx::Point& p) const override;
 
+  // ui::SimpleMenuModel::Delegate:
+  void ExecuteCommand(int command_id, int event_flags) override;
+
  protected:
   // Create a single RenderText instance to actually be painted.
   virtual std::unique_ptr<gfx::RenderText> CreateRenderText() const;
@@ -398,7 +404,6 @@
   // ui::SimpleMenuModel::Delegate overrides:
   bool IsCommandIdChecked(int command_id) const override;
   bool IsCommandIdEnabled(int command_id) const override;
-  void ExecuteCommand(int command_id, int event_flags) override;
   bool GetAcceleratorForCommandId(int command_id,
                                   ui::Accelerator* accelerator) const override;
 
diff --git a/ui/views_content_client/BUILD.gn b/ui/views_content_client/BUILD.gn
index e01d44b..d397b0d0 100644
--- a/ui/views_content_client/BUILD.gn
+++ b/ui/views_content_client/BUILD.gn
@@ -25,6 +25,7 @@
 
   if (is_mac) {
     sources += [ "views_content_client_main_parts_mac.mm" ]
+    configs += [ "//build/config/compiler:enable_arc" ]
   }
 
   defines = [ "VIEWS_CONTENT_CLIENT_IMPLEMENTATION" ]
diff --git a/ui/views_content_client/views_content_client_main_parts_mac.mm b/ui/views_content_client/views_content_client_main_parts_mac.mm
index acc24e2..3a2842c 100644
--- a/ui/views_content_client/views_content_client_main_parts_mac.mm
+++ b/ui/views_content_client/views_content_client_main_parts_mac.mm
@@ -9,7 +9,6 @@
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/mac/scoped_nsobject.h"
 #include "base/path_service.h"
 #include "content/public/browser/context_factory.h"
 #include "content/public/common/content_paths.h"
@@ -20,9 +19,13 @@
 #include "ui/views_content_client/views_content_client.h"
 #include "ui/views_content_client/views_content_client_main_parts.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 // A simple NSApplicationDelegate that provides a basic mainMenu and can
 // activate a task when the application has finished loading.
-@interface ViewsContentClientAppController : NSObject<NSApplicationDelegate> {
+@interface ViewsContentClientAppController : NSObject <NSApplicationDelegate> {
  @private
   base::OnceClosure _onApplicationDidFinishLaunching;
 }
@@ -52,7 +55,7 @@
   int PreMainMessageLoopRun() override;
 
  private:
-  base::scoped_nsobject<ViewsContentClientAppController> app_controller_;
+  ViewsContentClientAppController* __strong app_controller_;
 };
 
 ViewsContentClientMainPartsMac::ViewsContentClientMainPartsMac(
@@ -62,8 +65,8 @@
   base::FilePath child_process_exe;
   base::PathService::Get(content::CHILD_PROCESS_EXE, &child_process_exe);
 
-  app_controller_.reset([[ViewsContentClientAppController alloc] init]);
-  [[NSApplication sharedApplication] setDelegate:app_controller_];
+  app_controller_ = [[ViewsContentClientAppController alloc] init];
+  NSApplication.sharedApplication.delegate = app_controller_;
 }
 
 int ViewsContentClientMainPartsMac::PreMainMessageLoopRun() {
@@ -86,7 +89,7 @@
 }
 
 ViewsContentClientMainPartsMac::~ViewsContentClientMainPartsMac() {
-  [[NSApplication sharedApplication] setDelegate:nil];
+  NSApplication.sharedApplication.delegate = nil;
 }
 
 }  // namespace
@@ -121,13 +124,14 @@
   [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
 
   // Create a basic mainMenu object using the executable filename.
-  base::scoped_nsobject<NSMenu> mainMenu([[NSMenu alloc] initWithTitle:@""]);
-  NSMenuItem* appMenuItem =
-      [mainMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
+  NSMenu* mainMenu = [[NSMenu alloc] initWithTitle:@""];
+  NSMenuItem* appMenuItem = [mainMenu addItemWithTitle:@""
+                                                action:nullptr
+                                         keyEquivalent:@""];
   [NSApp setMainMenu:mainMenu];
 
-  base::scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:@""]);
-  NSString* appName = [[NSProcessInfo processInfo] processName];
+  NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@""];
+  NSString* appName = NSProcessInfo.processInfo.processName;
   // TODO(tapted): Localize "Quit" if this is ever used for a released binary.
   // At the time of writing, ui_strings.grd has "Close" but not "Quit".
   NSString* quitTitle = [@"Quit " stringByAppendingString:appName];
diff --git a/ui/webui/resources/cr_components/app_management/util.ts b/ui/webui/resources/cr_components/app_management/util.ts
index be948dfe..00795b4 100644
--- a/ui/webui/resources/cr_components/app_management/util.ts
+++ b/ui/webui/resources/cr_components/app_management/util.ts
@@ -4,11 +4,11 @@
 
 import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 
-import {App, Permission, PermissionType} from './app_management.mojom-webui.js';
+import {App, Permission, PermissionType, TriState} from './app_management.mojom-webui.js';
 import {BrowserProxy} from './browser_proxy.js';
 import {AppManagementUserAction, AppType, OptionalBool} from './constants.js';
 import {PermissionTypeIndex} from './permission_constants.js';
-import {isPermissionEnabled} from './permission_util.js';
+import {isBoolValue, isPermissionEnabled, isTriStateValue} from './permission_util.js';
 
 /**
  * @fileoverview Utility functions for the App Management page.
@@ -49,6 +49,26 @@
 }
 
 /**
+ * Returns the TriState value of a permission. If the permission value is not
+ * already a TriState, it will be converted based on the boolean value.
+ */
+export function getPermissionValueAsTriState(
+    app: App, permissionType: PermissionTypeIndex): TriState {
+  const permission = getPermission(app, permissionType);
+  assert(permission);
+
+  if (isTriStateValue(permission.value)) {
+    return permission.value.tristateValue!;
+  }
+
+  if (isBoolValue(permission.value)) {
+    return permission.value.boolValue!? TriState.kAllow : TriState.kBlock;
+  }
+
+  assertNotReached();
+}
+
+/**
  * Undefined is returned when the app does not request a permission.
  */
 export function getPermission(
diff --git a/weblayer/browser/webapps/webapk_install_scheduler.cc b/weblayer/browser/webapps/webapk_install_scheduler.cc
index e97003be..09a8c3a 100644
--- a/weblayer/browser/webapps/webapk_install_scheduler.cc
+++ b/weblayer/browser/webapps/webapk_install_scheduler.cc
@@ -64,7 +64,7 @@
   //
   // We redownload the icon in order to take the Murmur2 hash. The redownload
   // should be fast because the icon should be in the HTTP cache.
-  std::set<GURL> icons = shortcut_info_->GetWebApkIcons();
+  std::vector<webapps::WebappIcon> icons = shortcut_info_->GetWebApkIcons();
 
   webapps::WebApkIconHasher::DownloadAndComputeMurmur2Hash(
       web_contents->GetBrowserContext()